diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000000..ce8cd12235
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,555 @@
+[*]
+charset = utf-8
+end_of_line = lf
+indent_size = 4
+indent_style = space
+insert_final_newline = false
+max_line_length = 120
+tab_width = 4
+ij_continuation_indent_size = 8
+ij_formatter_off_tag = @formatter:off
+ij_formatter_on_tag = @formatter:on
+ij_formatter_tags_enabled = false
+ij_smart_tabs = false
+ij_visual_guides = none
+ij_wrap_on_typing = false
+
+[*.java]
+ij_java_align_consecutive_assignments = false
+ij_java_align_consecutive_variable_declarations = false
+ij_java_align_group_field_declarations = false
+ij_java_align_multiline_annotation_parameters = false
+ij_java_align_multiline_array_initializer_expression = false
+ij_java_align_multiline_assignment = false
+ij_java_align_multiline_binary_operation = false
+ij_java_align_multiline_chained_methods = false
+ij_java_align_multiline_extends_list = false
+ij_java_align_multiline_for = true
+ij_java_align_multiline_method_parentheses = false
+ij_java_align_multiline_parameters = true
+ij_java_align_multiline_parameters_in_calls = false
+ij_java_align_multiline_parenthesized_expression = false
+ij_java_align_multiline_records = true
+ij_java_align_multiline_resources = true
+ij_java_align_multiline_ternary_operation = false
+ij_java_align_multiline_text_blocks = false
+ij_java_align_multiline_throws_list = false
+ij_java_align_subsequent_simple_methods = false
+ij_java_align_throws_keyword = false
+ij_java_align_types_in_multi_catch = true
+ij_java_annotation_parameter_wrap = off
+ij_java_array_initializer_new_line_after_left_brace = false
+ij_java_array_initializer_right_brace_on_new_line = false
+ij_java_array_initializer_wrap = off
+ij_java_assert_statement_colon_on_next_line = false
+ij_java_assert_statement_wrap = off
+ij_java_assignment_wrap = off
+ij_java_binary_operation_sign_on_next_line = false
+ij_java_binary_operation_wrap = off
+ij_java_blank_lines_after_anonymous_class_header = 0
+ij_java_blank_lines_after_class_header = 0
+ij_java_blank_lines_after_imports = 1
+ij_java_blank_lines_after_package = 1
+ij_java_blank_lines_around_class = 1
+ij_java_blank_lines_around_field = 0
+ij_java_blank_lines_around_field_in_interface = 0
+ij_java_blank_lines_around_initializer = 1
+ij_java_blank_lines_around_method = 1
+ij_java_blank_lines_around_method_in_interface = 1
+ij_java_blank_lines_before_class_end = 0
+ij_java_blank_lines_before_imports = 1
+ij_java_blank_lines_before_method_body = 0
+ij_java_blank_lines_before_package = 0
+ij_java_block_brace_style = end_of_line
+ij_java_block_comment_add_space = false
+ij_java_block_comment_at_first_column = true
+ij_java_builder_methods = none
+ij_java_call_parameters_new_line_after_left_paren = false
+ij_java_call_parameters_right_paren_on_new_line = false
+ij_java_call_parameters_wrap = off
+ij_java_case_statement_on_separate_line = true
+ij_java_catch_on_new_line = false
+ij_java_class_annotation_wrap = split_into_lines
+ij_java_class_brace_style = end_of_line
+ij_java_class_count_to_use_import_on_demand = 99
+ij_java_class_names_in_javadoc = 1
+ij_java_do_not_indent_top_level_class_members = false
+ij_java_do_not_wrap_after_single_annotation = false
+ij_java_do_not_wrap_after_single_annotation_in_parameter = false
+ij_java_do_while_brace_force = never
+ij_java_doc_add_blank_line_after_description = true
+ij_java_doc_add_blank_line_after_param_comments = false
+ij_java_doc_add_blank_line_after_return = false
+ij_java_doc_add_p_tag_on_empty_lines = true
+ij_java_doc_align_exception_comments = true
+ij_java_doc_align_param_comments = true
+ij_java_doc_do_not_wrap_if_one_line = false
+ij_java_doc_enable_formatting = true
+ij_java_doc_enable_leading_asterisks = true
+ij_java_doc_indent_on_continuation = false
+ij_java_doc_keep_empty_lines = true
+ij_java_doc_keep_empty_parameter_tag = true
+ij_java_doc_keep_empty_return_tag = true
+ij_java_doc_keep_empty_throws_tag = true
+ij_java_doc_keep_invalid_tags = true
+ij_java_doc_param_description_on_new_line = false
+ij_java_doc_preserve_line_breaks = false
+ij_java_doc_use_throws_not_exception_tag = true
+ij_java_else_on_new_line = false
+ij_java_enum_constants_wrap = off
+ij_java_extends_keyword_wrap = off
+ij_java_extends_list_wrap = off
+ij_java_field_annotation_wrap = split_into_lines
+ij_java_finally_on_new_line = false
+ij_java_for_brace_force = never
+ij_java_for_statement_new_line_after_left_paren = false
+ij_java_for_statement_right_paren_on_new_line = false
+ij_java_for_statement_wrap = off
+ij_java_generate_final_locals = false
+ij_java_generate_final_parameters = false
+ij_java_if_brace_force = never
+ij_java_imports_layout = $android.**,$androidx.**,$com.**,$junit.**,$net.**,$org.**,$java.**,$javax.**,$*,|,android.**,|,androidx.**,|,com.**,|,junit.**,|,net.**,|,org.**,|,java.**,|,javax.**,|,*,|
+ij_java_indent_case_from_switch = true
+ij_java_insert_inner_class_imports = false
+ij_java_insert_override_annotation = true
+ij_java_keep_blank_lines_before_right_brace = 2
+ij_java_keep_blank_lines_between_package_declaration_and_header = 2
+ij_java_keep_blank_lines_in_code = 2
+ij_java_keep_blank_lines_in_declarations = 2
+ij_java_keep_builder_methods_indents = false
+ij_java_keep_control_statement_in_one_line = true
+ij_java_keep_first_column_comment = true
+ij_java_keep_indents_on_empty_lines = false
+ij_java_keep_line_breaks = true
+ij_java_keep_multiple_expressions_in_one_line = false
+ij_java_keep_simple_blocks_in_one_line = false
+ij_java_keep_simple_classes_in_one_line = false
+ij_java_keep_simple_lambdas_in_one_line = false
+ij_java_keep_simple_methods_in_one_line = false
+ij_java_label_indent_absolute = false
+ij_java_label_indent_size = 0
+ij_java_lambda_brace_style = end_of_line
+ij_java_layout_static_imports_separately = true
+ij_java_line_comment_add_space = false
+ij_java_line_comment_add_space_on_reformat = false
+ij_java_line_comment_at_first_column = true
+ij_java_method_annotation_wrap = split_into_lines
+ij_java_method_brace_style = end_of_line
+ij_java_method_call_chain_wrap = off
+ij_java_method_parameters_new_line_after_left_paren = false
+ij_java_method_parameters_right_paren_on_new_line = false
+ij_java_method_parameters_wrap = off
+ij_java_modifier_list_wrap = false
+ij_java_multi_catch_types_wrap = normal
+ij_java_names_count_to_use_import_on_demand = 99
+ij_java_new_line_after_lparen_in_annotation = false
+ij_java_new_line_after_lparen_in_record_header = false
+ij_java_parameter_annotation_wrap = off
+ij_java_parentheses_expression_new_line_after_left_paren = false
+ij_java_parentheses_expression_right_paren_on_new_line = false
+ij_java_place_assignment_sign_on_next_line = false
+ij_java_prefer_longer_names = true
+ij_java_prefer_parameters_wrap = false
+ij_java_record_components_wrap = normal
+ij_java_repeat_synchronized = true
+ij_java_replace_instanceof_and_cast = false
+ij_java_replace_null_check = true
+ij_java_replace_sum_lambda_with_method_ref = true
+ij_java_resource_list_new_line_after_left_paren = false
+ij_java_resource_list_right_paren_on_new_line = false
+ij_java_resource_list_wrap = off
+ij_java_rparen_on_new_line_in_annotation = false
+ij_java_rparen_on_new_line_in_record_header = false
+ij_java_space_after_closing_angle_bracket_in_type_argument = false
+ij_java_space_after_colon = true
+ij_java_space_after_comma = true
+ij_java_space_after_comma_in_type_arguments = true
+ij_java_space_after_for_semicolon = true
+ij_java_space_after_quest = true
+ij_java_space_after_type_cast = true
+ij_java_space_before_annotation_array_initializer_left_brace = false
+ij_java_space_before_annotation_parameter_list = false
+ij_java_space_before_array_initializer_left_brace = false
+ij_java_space_before_catch_keyword = true
+ij_java_space_before_catch_left_brace = true
+ij_java_space_before_catch_parentheses = true
+ij_java_space_before_class_left_brace = true
+ij_java_space_before_colon = true
+ij_java_space_before_colon_in_foreach = true
+ij_java_space_before_comma = false
+ij_java_space_before_do_left_brace = true
+ij_java_space_before_else_keyword = true
+ij_java_space_before_else_left_brace = true
+ij_java_space_before_finally_keyword = true
+ij_java_space_before_finally_left_brace = true
+ij_java_space_before_for_left_brace = true
+ij_java_space_before_for_parentheses = true
+ij_java_space_before_for_semicolon = false
+ij_java_space_before_if_left_brace = true
+ij_java_space_before_if_parentheses = true
+ij_java_space_before_method_call_parentheses = false
+ij_java_space_before_method_left_brace = true
+ij_java_space_before_method_parentheses = false
+ij_java_space_before_opening_angle_bracket_in_type_parameter = false
+ij_java_space_before_quest = true
+ij_java_space_before_switch_left_brace = true
+ij_java_space_before_switch_parentheses = true
+ij_java_space_before_synchronized_left_brace = true
+ij_java_space_before_synchronized_parentheses = true
+ij_java_space_before_try_left_brace = true
+ij_java_space_before_try_parentheses = true
+ij_java_space_before_type_parameter_list = false
+ij_java_space_before_while_keyword = true
+ij_java_space_before_while_left_brace = true
+ij_java_space_before_while_parentheses = true
+ij_java_space_inside_one_line_enum_braces = false
+ij_java_space_within_empty_array_initializer_braces = false
+ij_java_space_within_empty_method_call_parentheses = false
+ij_java_space_within_empty_method_parentheses = false
+ij_java_spaces_around_additive_operators = true
+ij_java_spaces_around_annotation_eq = true
+ij_java_spaces_around_assignment_operators = true
+ij_java_spaces_around_bitwise_operators = true
+ij_java_spaces_around_equality_operators = true
+ij_java_spaces_around_lambda_arrow = true
+ij_java_spaces_around_logical_operators = true
+ij_java_spaces_around_method_ref_dbl_colon = false
+ij_java_spaces_around_multiplicative_operators = true
+ij_java_spaces_around_relational_operators = true
+ij_java_spaces_around_shift_operators = true
+ij_java_spaces_around_type_bounds_in_type_parameters = true
+ij_java_spaces_around_unary_operator = false
+ij_java_spaces_within_angle_brackets = false
+ij_java_spaces_within_annotation_parentheses = false
+ij_java_spaces_within_array_initializer_braces = false
+ij_java_spaces_within_braces = false
+ij_java_spaces_within_brackets = false
+ij_java_spaces_within_cast_parentheses = false
+ij_java_spaces_within_catch_parentheses = false
+ij_java_spaces_within_for_parentheses = false
+ij_java_spaces_within_if_parentheses = false
+ij_java_spaces_within_method_call_parentheses = false
+ij_java_spaces_within_method_parentheses = false
+ij_java_spaces_within_parentheses = false
+ij_java_spaces_within_record_header = false
+ij_java_spaces_within_switch_parentheses = false
+ij_java_spaces_within_synchronized_parentheses = false
+ij_java_spaces_within_try_parentheses = false
+ij_java_spaces_within_while_parentheses = false
+ij_java_special_else_if_treatment = true
+ij_java_subclass_name_suffix = Impl
+ij_java_ternary_operation_signs_on_next_line = false
+ij_java_ternary_operation_wrap = off
+ij_java_test_name_suffix = Test
+ij_java_throws_keyword_wrap = off
+ij_java_throws_list_wrap = off
+ij_java_use_external_annotations = false
+ij_java_use_fq_class_names = false
+ij_java_use_relative_indents = false
+ij_java_use_single_class_imports = true
+ij_java_variable_annotation_wrap = off
+ij_java_visibility = public
+ij_java_while_brace_force = never
+ij_java_while_on_new_line = false
+ij_java_wrap_comments = false
+ij_java_wrap_first_method_in_call_chain = false
+ij_java_wrap_long_lines = false
+
+[.editorconfig]
+ij_editorconfig_align_group_field_declarations = false
+ij_editorconfig_space_after_colon = false
+ij_editorconfig_space_after_comma = true
+ij_editorconfig_space_before_colon = false
+ij_editorconfig_space_before_comma = false
+ij_editorconfig_spaces_around_assignment_operators = true
+
+[{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.rng,*.tld,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul}]
+ij_continuation_indent_size = 4
+ij_xml_align_attributes = false
+ij_xml_align_text = false
+ij_xml_attribute_wrap = normal
+ij_xml_block_comment_add_space = false
+ij_xml_block_comment_at_first_column = true
+ij_xml_keep_blank_lines = 2
+ij_xml_keep_indents_on_empty_lines = false
+ij_xml_keep_line_breaks = false
+ij_xml_keep_line_breaks_in_text = true
+ij_xml_keep_whitespaces = false
+ij_xml_keep_whitespaces_around_cdata = preserve
+ij_xml_keep_whitespaces_inside_cdata = false
+ij_xml_line_comment_at_first_column = true
+ij_xml_space_after_tag_name = false
+ij_xml_space_around_equals_in_attribute = false
+ij_xml_space_inside_empty_tag = true
+ij_xml_text_wrap = normal
+ij_xml_use_custom_settings = true
+
+[{*.gant,*.groovy,*.gy}]
+ij_groovy_align_group_field_declarations = false
+ij_groovy_align_multiline_array_initializer_expression = false
+ij_groovy_align_multiline_assignment = false
+ij_groovy_align_multiline_binary_operation = false
+ij_groovy_align_multiline_chained_methods = false
+ij_groovy_align_multiline_extends_list = false
+ij_groovy_align_multiline_for = true
+ij_groovy_align_multiline_list_or_map = true
+ij_groovy_align_multiline_method_parentheses = false
+ij_groovy_align_multiline_parameters = true
+ij_groovy_align_multiline_parameters_in_calls = false
+ij_groovy_align_multiline_resources = true
+ij_groovy_align_multiline_ternary_operation = false
+ij_groovy_align_multiline_throws_list = false
+ij_groovy_align_named_args_in_map = true
+ij_groovy_align_throws_keyword = false
+ij_groovy_array_initializer_new_line_after_left_brace = false
+ij_groovy_array_initializer_right_brace_on_new_line = false
+ij_groovy_array_initializer_wrap = off
+ij_groovy_assert_statement_wrap = off
+ij_groovy_assignment_wrap = off
+ij_groovy_binary_operation_wrap = off
+ij_groovy_blank_lines_after_class_header = 0
+ij_groovy_blank_lines_after_imports = 1
+ij_groovy_blank_lines_after_package = 1
+ij_groovy_blank_lines_around_class = 1
+ij_groovy_blank_lines_around_field = 0
+ij_groovy_blank_lines_around_field_in_interface = 0
+ij_groovy_blank_lines_around_method = 1
+ij_groovy_blank_lines_around_method_in_interface = 1
+ij_groovy_blank_lines_before_imports = 1
+ij_groovy_blank_lines_before_method_body = 0
+ij_groovy_blank_lines_before_package = 0
+ij_groovy_block_brace_style = end_of_line
+ij_groovy_block_comment_add_space = false
+ij_groovy_block_comment_at_first_column = true
+ij_groovy_call_parameters_new_line_after_left_paren = false
+ij_groovy_call_parameters_right_paren_on_new_line = false
+ij_groovy_call_parameters_wrap = off
+ij_groovy_catch_on_new_line = false
+ij_groovy_class_annotation_wrap = split_into_lines
+ij_groovy_class_brace_style = end_of_line
+ij_groovy_class_count_to_use_import_on_demand = 5
+ij_groovy_do_while_brace_force = never
+ij_groovy_else_on_new_line = false
+ij_groovy_enable_groovydoc_formatting = true
+ij_groovy_enum_constants_wrap = off
+ij_groovy_extends_keyword_wrap = off
+ij_groovy_extends_list_wrap = off
+ij_groovy_field_annotation_wrap = split_into_lines
+ij_groovy_finally_on_new_line = false
+ij_groovy_for_brace_force = never
+ij_groovy_for_statement_new_line_after_left_paren = false
+ij_groovy_for_statement_right_paren_on_new_line = false
+ij_groovy_for_statement_wrap = off
+ij_groovy_if_brace_force = never
+ij_groovy_import_annotation_wrap = 2
+ij_groovy_imports_layout = *,|,javax.**,java.**,|,$*
+ij_groovy_indent_case_from_switch = true
+ij_groovy_indent_label_blocks = true
+ij_groovy_insert_inner_class_imports = false
+ij_groovy_keep_blank_lines_before_right_brace = 2
+ij_groovy_keep_blank_lines_in_code = 2
+ij_groovy_keep_blank_lines_in_declarations = 2
+ij_groovy_keep_control_statement_in_one_line = true
+ij_groovy_keep_first_column_comment = true
+ij_groovy_keep_indents_on_empty_lines = false
+ij_groovy_keep_line_breaks = true
+ij_groovy_keep_multiple_expressions_in_one_line = false
+ij_groovy_keep_simple_blocks_in_one_line = false
+ij_groovy_keep_simple_classes_in_one_line = true
+ij_groovy_keep_simple_lambdas_in_one_line = true
+ij_groovy_keep_simple_methods_in_one_line = true
+ij_groovy_label_indent_absolute = false
+ij_groovy_label_indent_size = 0
+ij_groovy_lambda_brace_style = end_of_line
+ij_groovy_layout_static_imports_separately = true
+ij_groovy_line_comment_add_space = false
+ij_groovy_line_comment_add_space_on_reformat = false
+ij_groovy_line_comment_at_first_column = true
+ij_groovy_method_annotation_wrap = split_into_lines
+ij_groovy_method_brace_style = end_of_line
+ij_groovy_method_call_chain_wrap = off
+ij_groovy_method_parameters_new_line_after_left_paren = false
+ij_groovy_method_parameters_right_paren_on_new_line = false
+ij_groovy_method_parameters_wrap = off
+ij_groovy_modifier_list_wrap = false
+ij_groovy_names_count_to_use_import_on_demand = 3
+ij_groovy_packages_to_use_import_on_demand = java.awt.*,javax.swing.*
+ij_groovy_parameter_annotation_wrap = off
+ij_groovy_parentheses_expression_new_line_after_left_paren = false
+ij_groovy_parentheses_expression_right_paren_on_new_line = false
+ij_groovy_prefer_parameters_wrap = false
+ij_groovy_resource_list_new_line_after_left_paren = false
+ij_groovy_resource_list_right_paren_on_new_line = false
+ij_groovy_resource_list_wrap = off
+ij_groovy_space_after_assert_separator = true
+ij_groovy_space_after_colon = true
+ij_groovy_space_after_comma = true
+ij_groovy_space_after_comma_in_type_arguments = true
+ij_groovy_space_after_for_semicolon = true
+ij_groovy_space_after_quest = true
+ij_groovy_space_after_type_cast = true
+ij_groovy_space_before_annotation_parameter_list = false
+ij_groovy_space_before_array_initializer_left_brace = false
+ij_groovy_space_before_assert_separator = false
+ij_groovy_space_before_catch_keyword = true
+ij_groovy_space_before_catch_left_brace = true
+ij_groovy_space_before_catch_parentheses = true
+ij_groovy_space_before_class_left_brace = true
+ij_groovy_space_before_closure_left_brace = true
+ij_groovy_space_before_colon = true
+ij_groovy_space_before_comma = false
+ij_groovy_space_before_do_left_brace = true
+ij_groovy_space_before_else_keyword = true
+ij_groovy_space_before_else_left_brace = true
+ij_groovy_space_before_finally_keyword = true
+ij_groovy_space_before_finally_left_brace = true
+ij_groovy_space_before_for_left_brace = true
+ij_groovy_space_before_for_parentheses = true
+ij_groovy_space_before_for_semicolon = false
+ij_groovy_space_before_if_left_brace = true
+ij_groovy_space_before_if_parentheses = true
+ij_groovy_space_before_method_call_parentheses = false
+ij_groovy_space_before_method_left_brace = true
+ij_groovy_space_before_method_parentheses = false
+ij_groovy_space_before_quest = true
+ij_groovy_space_before_record_parentheses = false
+ij_groovy_space_before_switch_left_brace = true
+ij_groovy_space_before_switch_parentheses = true
+ij_groovy_space_before_synchronized_left_brace = true
+ij_groovy_space_before_synchronized_parentheses = true
+ij_groovy_space_before_try_left_brace = true
+ij_groovy_space_before_try_parentheses = true
+ij_groovy_space_before_while_keyword = true
+ij_groovy_space_before_while_left_brace = true
+ij_groovy_space_before_while_parentheses = true
+ij_groovy_space_in_named_argument = true
+ij_groovy_space_in_named_argument_before_colon = false
+ij_groovy_space_within_empty_array_initializer_braces = false
+ij_groovy_space_within_empty_method_call_parentheses = false
+ij_groovy_spaces_around_additive_operators = true
+ij_groovy_spaces_around_assignment_operators = true
+ij_groovy_spaces_around_bitwise_operators = true
+ij_groovy_spaces_around_equality_operators = true
+ij_groovy_spaces_around_lambda_arrow = true
+ij_groovy_spaces_around_logical_operators = true
+ij_groovy_spaces_around_multiplicative_operators = true
+ij_groovy_spaces_around_regex_operators = true
+ij_groovy_spaces_around_relational_operators = true
+ij_groovy_spaces_around_shift_operators = true
+ij_groovy_spaces_within_annotation_parentheses = false
+ij_groovy_spaces_within_array_initializer_braces = false
+ij_groovy_spaces_within_braces = true
+ij_groovy_spaces_within_brackets = false
+ij_groovy_spaces_within_cast_parentheses = false
+ij_groovy_spaces_within_catch_parentheses = false
+ij_groovy_spaces_within_for_parentheses = false
+ij_groovy_spaces_within_gstring_injection_braces = false
+ij_groovy_spaces_within_if_parentheses = false
+ij_groovy_spaces_within_list_or_map = false
+ij_groovy_spaces_within_method_call_parentheses = false
+ij_groovy_spaces_within_method_parentheses = false
+ij_groovy_spaces_within_parentheses = false
+ij_groovy_spaces_within_switch_parentheses = false
+ij_groovy_spaces_within_synchronized_parentheses = false
+ij_groovy_spaces_within_try_parentheses = false
+ij_groovy_spaces_within_tuple_expression = false
+ij_groovy_spaces_within_while_parentheses = false
+ij_groovy_special_else_if_treatment = true
+ij_groovy_ternary_operation_wrap = off
+ij_groovy_throws_keyword_wrap = off
+ij_groovy_throws_list_wrap = off
+ij_groovy_use_flying_geese_braces = false
+ij_groovy_use_fq_class_names = false
+ij_groovy_use_fq_class_names_in_javadoc = true
+ij_groovy_use_relative_indents = false
+ij_groovy_use_single_class_imports = true
+ij_groovy_variable_annotation_wrap = off
+ij_groovy_while_brace_force = never
+ij_groovy_while_on_new_line = false
+ij_groovy_wrap_chain_calls_after_dot = false
+ij_groovy_wrap_long_lines = false
+
+[{*.kt,*.kts,*.main.kts}]
+ij_kotlin_align_in_columns_case_branch = false
+ij_kotlin_align_multiline_binary_operation = false
+ij_kotlin_align_multiline_extends_list = false
+ij_kotlin_align_multiline_method_parentheses = false
+ij_kotlin_align_multiline_parameters = true
+ij_kotlin_align_multiline_parameters_in_calls = false
+ij_kotlin_allow_trailing_comma = false
+ij_kotlin_allow_trailing_comma_on_call_site = false
+ij_kotlin_assignment_wrap = normal
+ij_kotlin_blank_lines_after_class_header = 0
+ij_kotlin_blank_lines_around_block_when_branches = 0
+ij_kotlin_blank_lines_before_declaration_with_comment_or_annotation_on_separate_line = 1
+ij_kotlin_block_comment_add_space = false
+ij_kotlin_block_comment_at_first_column = true
+ij_kotlin_call_parameters_new_line_after_left_paren = true
+ij_kotlin_call_parameters_right_paren_on_new_line = true
+ij_kotlin_call_parameters_wrap = on_every_item
+ij_kotlin_catch_on_new_line = false
+ij_kotlin_class_annotation_wrap = split_into_lines
+ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL
+ij_kotlin_continuation_indent_for_chained_calls = false
+ij_kotlin_continuation_indent_for_expression_bodies = false
+ij_kotlin_continuation_indent_in_argument_lists = false
+ij_kotlin_continuation_indent_in_elvis = false
+ij_kotlin_continuation_indent_in_if_conditions = false
+ij_kotlin_continuation_indent_in_parameter_lists = false
+ij_kotlin_continuation_indent_in_supertype_lists = false
+ij_kotlin_else_on_new_line = false
+ij_kotlin_enum_constants_wrap = off
+ij_kotlin_extends_list_wrap = normal
+ij_kotlin_field_annotation_wrap = split_into_lines
+ij_kotlin_finally_on_new_line = false
+ij_kotlin_if_rparen_on_new_line = true
+ij_kotlin_import_nested_classes = false
+ij_kotlin_imports_layout = *,java.**,javax.**,kotlin.**,^
+ij_kotlin_insert_whitespaces_in_simple_one_line_method = true
+ij_kotlin_keep_blank_lines_before_right_brace = 2
+ij_kotlin_keep_blank_lines_in_code = 2
+ij_kotlin_keep_blank_lines_in_declarations = 2
+ij_kotlin_keep_first_column_comment = true
+ij_kotlin_keep_indents_on_empty_lines = false
+ij_kotlin_keep_line_breaks = true
+ij_kotlin_lbrace_on_next_line = false
+ij_kotlin_line_comment_add_space = false
+ij_kotlin_line_comment_add_space_on_reformat = false
+ij_kotlin_line_comment_at_first_column = true
+ij_kotlin_method_annotation_wrap = split_into_lines
+ij_kotlin_method_call_chain_wrap = normal
+ij_kotlin_method_parameters_new_line_after_left_paren = true
+ij_kotlin_method_parameters_right_paren_on_new_line = true
+ij_kotlin_method_parameters_wrap = on_every_item
+ij_kotlin_name_count_to_use_star_import = 5
+ij_kotlin_name_count_to_use_star_import_for_members = 3
+ij_kotlin_packages_to_use_import_on_demand = java.util.*,kotlinx.android.synthetic.**,io.ktor.**
+ij_kotlin_parameter_annotation_wrap = off
+ij_kotlin_space_after_comma = true
+ij_kotlin_space_after_extend_colon = true
+ij_kotlin_space_after_type_colon = true
+ij_kotlin_space_before_catch_parentheses = true
+ij_kotlin_space_before_comma = false
+ij_kotlin_space_before_extend_colon = true
+ij_kotlin_space_before_for_parentheses = true
+ij_kotlin_space_before_if_parentheses = true
+ij_kotlin_space_before_lambda_arrow = true
+ij_kotlin_space_before_type_colon = false
+ij_kotlin_space_before_when_parentheses = true
+ij_kotlin_space_before_while_parentheses = true
+ij_kotlin_spaces_around_additive_operators = true
+ij_kotlin_spaces_around_assignment_operators = true
+ij_kotlin_spaces_around_equality_operators = true
+ij_kotlin_spaces_around_function_type_arrow = true
+ij_kotlin_spaces_around_logical_operators = true
+ij_kotlin_spaces_around_multiplicative_operators = true
+ij_kotlin_spaces_around_range = false
+ij_kotlin_spaces_around_relational_operators = true
+ij_kotlin_spaces_around_unary_operator = false
+ij_kotlin_spaces_around_when_arrow = true
+ij_kotlin_use_custom_formatting_for_modifiers = true
+ij_kotlin_variable_annotation_wrap = off
+ij_kotlin_while_on_new_line = false
+ij_kotlin_wrap_elvis_expressions = 1
+ij_kotlin_wrap_expression_body_functions = 1
+ij_kotlin_wrap_first_method_in_call_chain = false
\ No newline at end of file
diff --git a/.gitmodules b/.gitmodules
index 07ed87e91f..02337707d1 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -5,3 +5,6 @@
[submodule "assistant_flutter"]
path = assistant_flutter
url = git@git.shanqu.cc:halo/android/flutter-module.git
+[submodule "vspace-bridge"]
+ path = vspace-bridge
+ url = git@git.shanqu.cc:cwzs/android/vspace-bridge.git
diff --git a/app/build.gradle b/app/build.gradle
index 732c8e0c22..b482fa465a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -47,12 +47,10 @@ android {
multiDexEnabled true
ndk {
- // 如果不添加 `arm64` 调用系统的 PackageManager 的方法读取安装包信息的时候会出现 native 层闪退,草
- // 添加了 `arm64` 以后部分 5.0 的设备会报用错 so 的问题,
- // couldn't find DSO to load: libimagepipeline.so caused by: dlopen failed: "/data/data/com.gh.gamecenter/lib-main/libimagepipeline.so" is 64-bit instead of 32-bit result: 0
- // 以 OPPO R7PLUS 为例,明明设备是骁龙 615,ARMv8-64 bit 的设备却不支持 arm64 的 abi,限制了只使用 java 后还是报错,只有 5.0,5.1 设备无法复现 : (
- // 惊了
- abiFilters "armeabi-v7a", "arm64-v8a", "x86"
+ // x86 本来是为了模拟器用户使用 RenderScript 用的,但是其实用到 RenderScript 的人本来就不多 (一天不到 100),用模拟器的人就更少了
+ // 加了 x86 反而会导致用户没法使用微博登录,因为微博没有提供 x86 的 SO ...
+ // 还会增大 APK 体积,所以还是去掉吧。数据可见 https://sentry.shanqu.cc/organizations/lightgame/issues/144232/?project=22
+ abiFilters "armeabi-v7a", "arm64-v8a"
}
renderscriptTargetApi 18
@@ -74,6 +72,7 @@ android {
*/
buildConfigField "String", "API_HOST", "\"${API_HOST}\""
buildConfigField "String", "NEW_API_HOST", "\"${NEW_API_HOST}\""
+ buildConfigField "String", "VAPI_HOST", "\"${VAPI_HOST}\""
buildConfigField "String", "WECHAT_APPID", "\"${WECHAT_APPID}\""
buildConfigField "String", "WECHAT_SECRET", "\"${WECHAT_SECRET}\""
buildConfigField "String", "TENCENT_APPID", "\"${TENCENT_APPID}\""
@@ -157,14 +156,16 @@ android {
buildConfigField "String", "DEV_API_HOST", "\"${DEV_API_HOST}\""
buildConfigField "String", "NEW_DEV_API_HOST", "\"${NEW_DEV_API_HOST}\""
+ buildConfigField "String", "DEV_VAPI_HOST", "\"${DEV_VAPI_HOST}\""
}
- // publish release host˛
+ // publish release host
publish {
dimension "env"
buildConfigField "String", "DEV_API_HOST", "\"${API_HOST}\""
buildConfigField "String", "NEW_DEV_API_HOST", "\"${NEW_API_HOST}\""
+ buildConfigField "String", "DEV_VAPI_HOST", "\"${VAPI_HOST}\""
}
tea {
@@ -172,6 +173,7 @@ android {
buildConfigField "String", "DEV_API_HOST", "\"${API_HOST}\""
buildConfigField "String", "NEW_DEV_API_HOST", "\"${NEW_API_HOST}\""
+ buildConfigField "String", "DEV_VAPI_HOST", "\"${VAPI_HOST}\""
manifestPlaceholders.put("APPLOG_SCHEME", "rangersapplog.byAx6uYt".toLowerCase())
}
@@ -264,7 +266,9 @@ dependencies {
compileOnly "com.github.axen1314.lancet:lancet-base:${lancet_version}"
kapt "com.alibaba:arouter-compiler:$arouterVersion"
- implementation(project(':module_common')) {
+ implementation project(':vspace-bridge:vspace')
+
+ implementation (project(':module_common')) {
exclude group: 'androidx.swiperefreshlayout'
}
}
@@ -397,6 +401,9 @@ andResGuard {
"R.id.bottomShareTv",
"R.id.recommendStarPref",
"R.id.recommendStar",
+ "R.id.iv_vmode_badge",
+ "R.id.tv_vmode",
+ "R.id.iv_vmode",
"R.drawable.help_search_delete",
"R.drawable.suggest_type_normal",
"R.drawable.suggest_type_crash",
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 09b9b95b80..7244e45ff1 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -3,6 +3,9 @@
xmlns:tools="http://schemas.android.com/tools"
package="com.gh.gamecenter">
+
+
+
@@ -735,6 +738,14 @@
android:name="com.gh.gamecenter.toolbox.ToolBoxBlockActivity"
android:screenOrientation="portrait" />
+
+
+
+
diff --git a/app/src/main/assets/lottie/switch_turnoff_dark.json b/app/src/main/assets/lottie/switch_turnoff_dark.json
new file mode 100644
index 0000000000..4e0290ccb4
--- /dev/null
+++ b/app/src/main/assets/lottie/switch_turnoff_dark.json
@@ -0,0 +1 @@
+{"v":"5.9.1","fr":60,"ip":0,"op":36,"w":120,"h":66,"nm":"开关动画-关闭","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"按钮手柄","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.667,"y":0},"t":0,"s":[87,33,0],"to":[7.682,0,0],"ti":[-13.443,0,0]},{"i":{"x":0.333,"y":1},"o":{"x":0.333,"y":0},"t":18,"s":[31,33,0],"to":[2.306,0,0],"ti":[-1.318,0,0]},{"t":24,"s":[33,33,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"指示器-on","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[100]},{"t":18,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,33,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.667,0.667],"y":[0,0]},"t":0,"s":[6.5,6.5]},{"t":18,"s":[4.5,4.5]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":40,"ix":4},"w":{"a":0,"k":1.5,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"指示器-off","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[87,33,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.667,0.667],"y":[0,0]},"t":0,"s":[1.5,4]},{"t":18,"s":[1.5,6]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0.75,"ix":4},"nm":"矩形路径 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":20,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":90,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[0]},{"t":18,"s":[100]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"按钮背景","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[60,33,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[40,22],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12,"ix":4},"nm":"矩形路径 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[0.156862750649,0.533333361149,0.878431379795,1]},{"t":18,"s":[1,1,1,1]}],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[100]},{"t":18,"s":[8]}],"ix":5},"r":1,"bm":0,"nm":"filling","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0.118,0.006],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/app/src/main/assets/lottie/switch_turnoff_light.json b/app/src/main/assets/lottie/switch_turnoff_light.json
new file mode 100644
index 0000000000..7b0d088767
--- /dev/null
+++ b/app/src/main/assets/lottie/switch_turnoff_light.json
@@ -0,0 +1 @@
+{"v":"5.9.1","fr":60,"ip":0,"op":36,"w":120,"h":66,"nm":"开关动画-关闭","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"按钮手柄","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.667,"y":0},"t":0,"s":[87,33,0],"to":[7.682,0,0],"ti":[-13.443,0,0]},{"i":{"x":0.333,"y":1},"o":{"x":0.333,"y":0},"t":18,"s":[31,33,0],"to":[2.306,0,0],"ti":[-1.318,0,0]},{"t":24,"s":[33,33,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"指示器-on","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[100]},{"t":18,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,33,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.667,0.667],"y":[0,0]},"t":0,"s":[6.5,6.5]},{"t":18,"s":[4.5,4.5]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":40,"ix":4},"w":{"a":0,"k":1.5,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"指示器-off","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[87,33,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.667,0.667],"y":[0,0]},"t":0,"s":[1.5,4]},{"t":18,"s":[1.5,6]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0.75,"ix":4},"nm":"矩形路径 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":5,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":90,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[0]},{"t":18,"s":[100]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"按钮背景","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[60,33,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[40,22],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12,"ix":4},"nm":"矩形路径 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[0.141176477075,0.588235318661,1,1]},{"t":18,"s":[0.933333337307,0.933333337307,0.933333337307,1]}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"filling","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0.118,0.006],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/app/src/main/assets/lottie/switch_turnon.json b/app/src/main/assets/lottie/switch_turnon.json
deleted file mode 100644
index ae34bc0d48..0000000000
--- a/app/src/main/assets/lottie/switch_turnon.json
+++ /dev/null
@@ -1 +0,0 @@
-{"v":"5.6.9","fr":60,"ip":0,"op":36,"w":120,"h":66,"nm":"开关动画-打开","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"按钮手柄","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.667,"y":0},"t":0,"s":[33,33,0],"to":[7.682,0,0],"ti":[-13.443,0,0]},{"i":{"x":0.333,"y":1},"o":{"x":0.333,"y":0},"t":18,"s":[89,33,0],"to":[2.306,0,0],"ti":[-1.318,0,0]},{"t":24,"s":[87,33,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"指示器-on","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[0]},{"t":18,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,33,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.667,0.667],"y":[0,0]},"t":0,"s":[4.5,4.5]},{"t":18,"s":[6.5,6.5]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.966666666667,0.966666666667,0.966666666667,0.420000005762],"ix":3},"o":{"a":0,"k":40,"ix":4},"w":{"a":0,"k":1.5,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"指示器-off","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[87,33,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.667,0.667],"y":[0,0]},"t":0,"s":[1.5,6]},{"t":18,"s":[1.5,4]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0.75,"ix":4},"nm":"矩形路径 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":5,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":90,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[100]},{"t":18,"s":[0]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"按钮背景","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[60,33,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"sy":[{"c":{"a":0,"k":[0,0,0,1],"ix":2},"o":{"a":0,"k":5,"ix":3},"a":{"a":0,"k":120,"ix":5},"s":{"a":0,"k":1,"ix":8},"d":{"a":0,"k":0,"ix":6},"ch":{"a":0,"k":100,"ix":7},"bm":{"a":0,"k":5,"ix":1},"no":{"a":0,"k":0,"ix":9},"ty":2,"nm":"内阴影"}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[40,22],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12,"ix":4},"nm":"矩形路径 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[0.933332979679,0.933332979679,0.933332979679,1]},{"t":18,"s":[0.141176477075,0.588235318661,1,1]}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"filling","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0.118,0.006],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/app/src/main/assets/lottie/switch_turnon_dark.json b/app/src/main/assets/lottie/switch_turnon_dark.json
new file mode 100644
index 0000000000..a897cea988
--- /dev/null
+++ b/app/src/main/assets/lottie/switch_turnon_dark.json
@@ -0,0 +1 @@
+{"v":"5.9.1","fr":60,"ip":0,"op":36,"w":120,"h":66,"nm":"开关动画-打开","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"按钮手柄","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.667,"y":0},"t":0,"s":[33,33,0],"to":[7.682,0,0],"ti":[-13.443,0,0]},{"i":{"x":0.333,"y":1},"o":{"x":0.333,"y":0},"t":18,"s":[89,33,0],"to":[2.306,0,0],"ti":[-1.318,0,0]},{"t":24,"s":[87,33,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"指示器-on","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[0]},{"t":18,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,33,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.667,0.667],"y":[0,0]},"t":0,"s":[4.5,4.5]},{"t":18,"s":[6.5,6.5]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":40,"ix":4},"w":{"a":0,"k":1.5,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"指示器-off","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[87,33,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.667,0.667],"y":[0,0]},"t":0,"s":[1.5,6]},{"t":18,"s":[1.5,4]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0.75,"ix":4},"nm":"矩形路径 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":20,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":90,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[100]},{"t":18,"s":[0]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"按钮背景","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[60,33,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[40,22],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12,"ix":4},"nm":"矩形路径 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[1,1,1,1]},{"t":18,"s":[0.156862750649,0.533333361149,0.878431379795,1]}],"ix":4},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[8]},{"t":18,"s":[100]}],"ix":5},"r":1,"bm":0,"nm":"filling","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0.118,0.006],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/app/src/main/assets/lottie/switch_turnon_light.json b/app/src/main/assets/lottie/switch_turnon_light.json
new file mode 100644
index 0000000000..31f139b617
--- /dev/null
+++ b/app/src/main/assets/lottie/switch_turnon_light.json
@@ -0,0 +1 @@
+{"v":"5.9.1","fr":60,"ip":0,"op":36,"w":120,"h":66,"nm":"开关动画-打开","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"按钮手柄","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.667,"y":0},"t":0,"s":[33,33,0],"to":[7.682,0,0],"ti":[-13.443,0,0]},{"i":{"x":0.333,"y":1},"o":{"x":0.333,"y":0},"t":18,"s":[89,33,0],"to":[2.306,0,0],"ti":[-1.318,0,0]},{"t":24,"s":[87,33,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[16,16],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"指示器-on","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[0]},{"t":18,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,33,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.667,0.667],"y":[0,0]},"t":0,"s":[4.5,4.5]},{"t":18,"s":[6.5,6.5]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":40,"ix":4},"w":{"a":0,"k":1.5,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"指示器-off","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[87,33,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.667,0.667],"y":[0,0]},"t":0,"s":[1.5,6]},{"t":18,"s":[1.5,4]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0.75,"ix":4},"nm":"矩形路径 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":5,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":90,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[100]},{"t":18,"s":[0]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"按钮背景","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[60,33,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[40,22],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12,"ix":4},"nm":"矩形路径 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":0,"s":[0.933332979679,0.933332979679,0.933332979679,1]},{"t":18,"s":[0.141176477075,0.588235318661,1,1]}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"filling","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0.118,0.006],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[300,300],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"矩形","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":37,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/base/GlobalActivityLifecycleObserver.kt b/app/src/main/java/com/gh/base/GlobalActivityLifecycleObserver.kt
index ef4524f652..9ece998764 100644
--- a/app/src/main/java/com/gh/base/GlobalActivityLifecycleObserver.kt
+++ b/app/src/main/java/com/gh/base/GlobalActivityLifecycleObserver.kt
@@ -15,6 +15,7 @@ import com.gh.gamecenter.forum.list.ForumListActivity
import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity
import com.gh.gamecenter.qa.questions.newdetail.NewQuestionDetailActivity
import com.gh.gamecenter.qa.video.detail.ForumVideoDetailActivity
+import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
// TODO:移动到对应的模块
@@ -59,6 +60,10 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
if (PackageFlavorHelper.IS_TEST_FLAVOR && activity is AppCompatActivity) {
NightModeSwitchHelper.showNightModeSwitchFloatingView(activity)
}
+
+ if (activity is AppCompatActivity && activity !is SplashScreenActivity) {
+ VHelper.showFeedbackDialogIfLastSuccessfulLaunchedGameExitUnexpectedly(activity)
+ }
}
private fun shouldShowActivityBackView(activity: Activity): Boolean {
diff --git a/app/src/main/java/com/gh/common/DefaultUrlHandler.kt b/app/src/main/java/com/gh/common/DefaultUrlHandler.kt
index b02bf3d072..31a5a16ff9 100644
--- a/app/src/main/java/com/gh/common/DefaultUrlHandler.kt
+++ b/app/src/main/java/com/gh/common/DefaultUrlHandler.kt
@@ -502,6 +502,13 @@ object DefaultUrlHandler {
@JvmStatic
fun transformNormalScheme(context: Context, url: String, entrance: String): Boolean {
+ val b = transformNewNormalScheme(context, url, entrance)
+ if (b) return b
+ return transformOldNormalScheme(context, url, entrance)
+ }
+
+ @JvmStatic
+ fun transformOldNormalScheme(context: Context, url: String, entrance: String): Boolean {
val uri = Uri.parse(url)
if (uri.host == "www.ghzs666.com"
|| uri.host == "www.ghzs.com"
@@ -513,8 +520,7 @@ object DefaultUrlHandler {
uri.path?.apply {
when {
contains("game") -> {
- val gameId = uri.getQueryParameter("gameId") ?: uri.pathSegments.last()
- ?: ""
+ val gameId = uri.getQueryParameter("gameId") ?: uri.pathSegments.last() ?: ""
DirectUtils.directToGameDetail(context, gameId, entrance, autoDownload = false, traceEvent = null)
}
contains("question") -> {
@@ -580,6 +586,55 @@ object DefaultUrlHandler {
return false
}
+ @JvmStatic
+ fun transformNewNormalScheme(context: Context, url: String, entrance: String): Boolean {
+ val uri = Uri.parse(url)
+ if (uri.host == "www.ghzs666.com"
+ || uri.host == "www.ghzs.com"
+ || uri.host == "ask.ghzs.com"
+ || uri.host == "m.ghzs.com"
+ || uri.host == "m.ghzs666.com"
+ || uri.host == "dev-bbs-mobile.ghzs.com"
+ ) {
+ Utils.log(uri.path)
+ uri.path?.apply {
+ val splits = split("/")
+ when {
+ //https://m.ghzs666.com/bbs/thread-帖子ID
+ splits.size >= 3 && splits[1] == "bbs" && splits[2].startsWith("thread-") -> {
+ val articleId = splits[2].substring(7)
+ DirectUtils.directToCommunityArticle(
+ context, articleId, "",
+ entrance, "文章链接"
+ )
+ }
+ //https://m.ghzs666.com/article/文章ID
+ splits.size >= 3 && splits[1] == "article" -> {
+ val articleId = splits[2]
+ DirectUtils.directToArticle(context, articleId, entrance)
+ }
+ //https://m.ghzs666.com/column/专题ID
+ splits.size >= 3 && splits[1] == "column" -> {
+ val columnId = splits[2]
+ DirectUtils.directToSubject(context, columnId, "", entrance)
+ }
+ //https://m.ghzs666.com/zone/游戏ID
+ splits.size >= 3 && splits[1] == "zone" -> {
+ DirectUtils.directToWebView(context, url, entrance)
+ }
+ //https://m.ghzs666.com/bbs/video-视频ID
+ splits.size >= 3 && splits[1] == "bbs" && splits[2].startsWith("video-") -> {
+ val videoId = splits[2].substring(6)
+ DirectUtils.directToVideoDetail(context, videoId, entrance)
+ }
+ else -> return false
+ }
+ }
+ return true
+ }
+ return false
+ }
+
/**
* 将 url 转换为 LinkEntity (实际只有 type 和 link 两个字段,仅供日志,不保证能用)
*/
diff --git a/app/src/main/java/com/gh/common/FixedRateJobHelper.kt b/app/src/main/java/com/gh/common/FixedRateJobHelper.kt
index 4f39d60084..6896535c4a 100644
--- a/app/src/main/java/com/gh/common/FixedRateJobHelper.kt
+++ b/app/src/main/java/com/gh/common/FixedRateJobHelper.kt
@@ -2,13 +2,14 @@ package com.gh.common
import com.gh.common.exposure.ExposureManager
import com.gh.common.filter.RegionSettingHelper
-import com.gh.gamecenter.common.loghub.LoghubUtils
-import com.gh.gamecenter.common.utils.doOnMainProcessOnly
-import com.gh.gamecenter.common.utils.tryCatchInRelease
import com.gh.common.videolog.VideoRecordUtils
import com.gh.download.DownloadDataHelper
-import com.gh.gamecenter.entity.TimeEntity
+import com.gh.gamecenter.common.loghub.LoghubUtils
import com.gh.gamecenter.common.retrofit.Response
+import com.gh.gamecenter.common.utils.doOnMainProcessOnly
+import com.gh.gamecenter.common.utils.tryCatchInRelease
+import com.gh.gamecenter.core.runOnUiThread
+import com.gh.gamecenter.entity.TimeEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.schedulers.Schedulers
@@ -60,7 +61,9 @@ object FixedRateJobHelper {
// 提交普通 loghub 数据
if ((mExecuteCount * CHECKER_PERIOD) % LOGHUB_PERIOD == 0L) {
- LoghubUtils.commitSavedLoghubEvents()
+ runOnUiThread {
+ LoghubUtils.commitSavedLoghubEvents(true)
+ }
}
// 更新游戏屏蔽信息
diff --git a/app/src/main/java/com/gh/common/constant/Config.java b/app/src/main/java/com/gh/common/constant/Config.java
index c0f7371ed5..3f1b7c0955 100644
--- a/app/src/main/java/com/gh/common/constant/Config.java
+++ b/app/src/main/java/com/gh/common/constant/Config.java
@@ -20,10 +20,12 @@ import com.gh.gamecenter.entity.GameGuidePopupEntity;
import com.gh.gamecenter.entity.NewSettingsEntity;
import com.gh.gamecenter.entity.NewsEntity;
import com.gh.gamecenter.entity.SettingsEntity;
+import com.gh.gamecenter.entity.VSetting;
import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.common.retrofit.BiResponse;
import com.gh.gamecenter.common.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
+import com.gh.vspace.VHelper;
import com.halo.assistant.HaloApp;
import com.lightgame.utils.Utils;
@@ -44,6 +46,7 @@ public class Config {
// 这个 API_HOST 在测试包里会随着选择的环境切换,正式包里会一直保持正式 host
public static final String API_HOST = EnvHelper.getHost();
public static final String NEW_API_HOST = EnvHelper.getNewHost();
+ public static final String VAPI_HOST = EnvHelper.getVHost();
// Third-Party confs
public static final String WECHAT_APPID = BuildConfig.WECHAT_APPID;
@@ -59,6 +62,7 @@ public class Config {
private static SettingsEntity mSettingsEntity;
private static NewSettingsEntity mNewSettingsEntity;
+ private static VSetting mVSetting;
private static GameGuidePopupEntity mGameGuidePopupEntity;
private static SharedPreferences mDefaultSharedPreferences;
@@ -112,6 +116,17 @@ public class Config {
return false;
}
+ /**
+ * 是否启用畅玩游戏
+ */
+ public static boolean isVGameEnabled() {
+ if (getSettings() == null) {
+ return false;
+ }
+
+ return !"off".equals(getSettings().getGameSmooth());
+ }
+
public static boolean isShowPlugin(String gameId) {
SharedPreferences preferences = getPreferences();
@@ -182,6 +197,9 @@ public class Config {
// 加载完设置后刷新下
PackageHelper.initList();
+
+ // 初始化畅玩相关的东西
+ VHelper.init(HaloApp.getInstance());
}
@Nullable
@@ -214,6 +232,21 @@ public class Config {
return mNewSettingsEntity;
}
+ @Nullable
+ public static VSetting getVSettingEntity() {
+ if (mVSetting == null) {
+ try {
+ String json = SPUtils.getString(Constants.SP_V_SETTINGS);
+ if (!TextUtils.isEmpty(json)) {
+ mVSetting = GsonUtils.fromJson(json, VSetting.class);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ return mVSetting;
+ }
+
@Nullable
public static GameGuidePopupEntity getGameGuidePopupEntity() {
return mGameGuidePopupEntity;
@@ -307,6 +340,17 @@ public class Config {
}
});
+ RetrofitManager.getInstance()
+ .getVApi().getSettings(BuildConfig.VERSION_NAME)
+ .subscribeOn(Schedulers.io())
+ .subscribe(new BiResponse() {
+ @Override
+ public void onSuccess(VSetting data) {
+ mVSetting = data;
+ SPUtils.setString(Constants.SP_V_SETTINGS, GsonUtils.toJson(data));
+ }
+ });
+
RetrofitManager.getInstance()
.getApi().getGameGuidePopup(Build.MANUFACTURER, Build.VERSION.RELEASE, Build.MODEL, channel, BuildConfig.VERSION_NAME)
.subscribeOn(Schedulers.io())
diff --git a/app/src/main/java/com/gh/common/databind/BindingAdapters.java b/app/src/main/java/com/gh/common/databind/BindingAdapters.java
index bc66ad23de..1226c9bd27 100644
--- a/app/src/main/java/com/gh/common/databind/BindingAdapters.java
+++ b/app/src/main/java/com/gh/common/databind/BindingAdapters.java
@@ -39,7 +39,6 @@ import com.gh.common.util.NewsUtils;
import com.gh.common.util.PackageInstaller;
import com.gh.common.util.PackageUtils;
import com.gh.common.util.PlatformUtils;
-import com.gh.common.util.RealNameHelper;
import com.gh.common.util.ReservationHelper;
import com.gh.common.view.DownloadProgressBar;
import com.gh.common.view.GameIconView;
@@ -70,6 +69,8 @@ import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment;
import com.gh.gamecenter.manager.PackagesManager;
import com.gh.gamecenter.qa.entity.CommunityVideoEntity;
+import com.gh.vspace.VDownloadManagerActivity;
+import com.gh.vspace.VHelper;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.FileUtils;
import com.lightgame.utils.Utils;
@@ -359,9 +360,13 @@ public class BindingAdapters {
switch (progressBar.getDownloadType()) {
case DOWNLOADING_PLUGIN:
case DOWNLOADING_NORMAL:
- Intent intent = DownloadManagerActivity.getDownloadMangerIntent(v.getContext(),
- gameEntity.getApk().get(0).getUrl(), entrance);
- v.getContext().startActivity(intent);
+ if (gameEntity.isVGame()) {
+ v.getContext().startActivity(VDownloadManagerActivity.getIntent(v.getContext(), true));
+ } else {
+ Intent intent = DownloadManagerActivity.getDownloadMangerIntent(v.getContext(),
+ gameEntity.getApk().get(0).getUrl(), entrance);
+ v.getContext().startActivity(intent);
+ }
break;
case NONE:
Utils.toast(v.getContext(), "该游戏已关闭下载");
@@ -383,9 +388,9 @@ public class BindingAdapters {
return;
}
}
- RealNameHelper.checkIfAuth(v.getContext(), gameEntity, () -> {
+ VHelper.validateVSpaceBeforeAction(v.getContext(), gameEntity, true, () -> {
GamePermissionDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity, gameEntity.getInfo(), () -> {
- BrowserInstallHelper.showBrowserInstallHintDialog(v.getContext(), () -> {
+ BrowserInstallHelper.showBrowserInstallHintDialog(v.getContext(), gameEntity.isVGame(), () -> {
PackageCheckDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity, () -> {
DownloadDialogHelper.findAvailableDialogAndShow(v.getContext(), gameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(v.getContext(), gameEntity, () -> {
@@ -402,17 +407,15 @@ public class BindingAdapters {
});
});
} else {
- RealNameHelper.checkIfAuth(v.getContext(), gameEntity, () -> {
- GamePermissionDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity, gameEntity.getInfo(), () -> {
- CertificationDialog.showCertificationDialog(v.getContext(), gameEntity, () -> {
- DialogUtils.showVersionNumberDialog(v.getContext(), gameEntity, () -> {
- DownloadDialog.showDownloadDialog(
- v.getContext(),
- gameEntity,
- traceEvent,
- entrance,
- location + ":" + gameEntity.getName());
- });
+ GamePermissionDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity, gameEntity.getInfo(), () -> {
+ CertificationDialog.showCertificationDialog(v.getContext(), gameEntity, () -> {
+ DialogUtils.showVersionNumberDialog(v.getContext(), gameEntity, () -> {
+ DownloadDialog.showDownloadDialog(
+ v.getContext(),
+ gameEntity,
+ traceEvent,
+ entrance,
+ location + ":" + gameEntity.getName());
});
});
});
@@ -435,6 +438,12 @@ public class BindingAdapters {
}
return;
}
+
+ if (gameEntity.isVGame()) {
+ VHelper.installOrLaunch((AppCompatActivity) v.getContext(), gameEntity.getApk().get(0).getPackageName());
+ return;
+ }
+
PackageUtils.launchApplicationByPackageName(v.getContext(), gameEntity.getApk().get(0).getPackageName());
} else {
DownloadDialog.showDownloadDialog(
@@ -448,20 +457,25 @@ public class BindingAdapters {
case INSTALL_PLUGIN:
case INSTALL_NORMAL:
if (gameEntity.getApk().size() == 1) {
- DownloadEntity downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshotByUrl(gameEntity.getApk().get(0).getUrl());
+ DownloadEntity downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(gameEntity);
+ String packageName = gameEntity.getApk().get(0).getPackageName();
+
+ if (gameEntity.isVGame()) {
+ VHelper.installOrLaunch(v.getContext(), packageName);
+ return;
+ }
+
if (downloadEntity != null) {
PackageInstaller.install(v.getContext(), downloadEntity);
}
}
break;
case RESERVABLE:
- RealNameHelper.checkIfAuth(v.getContext(), gameEntity, () -> {
- GamePermissionDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity, gameEntity.getInfo(), () -> {
- CheckLoginUtils.checkLogin(progressBar.getContext(), "", () -> {
- ReservationHelper.reserve(v.getContext(), gameEntity.getId(), () -> {
- LogUtils.logReservation(gameEntity, traceEvent);
- updateReservation(progressBar, gameEntity);
- });
+ GamePermissionDialogFragment.show((AppCompatActivity) v.getContext(), gameEntity, gameEntity.getInfo(), () -> {
+ CheckLoginUtils.checkLogin(progressBar.getContext(), "", () -> {
+ ReservationHelper.reserve(v.getContext(), gameEntity.getId(), () -> {
+ LogUtils.logReservation(gameEntity, traceEvent);
+ updateReservation(progressBar, gameEntity);
});
});
});
@@ -556,7 +570,7 @@ public class BindingAdapters {
// 显示下载过程状态
if (gameEntity.getApk().size() == 1) {
- DownloadEntity downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshotByUrl(gameEntity.getApk().get(0).getUrl());
+ DownloadEntity downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(gameEntity);
if (downloadEntity != null) {
progressBar.setProgress((int) (downloadEntity.getPercent() * 10));
switch (downloadEntity.getStatus()) {
@@ -587,6 +601,7 @@ public class BindingAdapters {
case uncertificated:
case unqualified:
case unavailable:
+ case banned:
break;
default:
break;
@@ -782,7 +797,7 @@ public class BindingAdapters {
public static void setCommunityVideoDuration(TextView mVideoDuration, List videos) {
if (videos != null && videos.size() > 0) {
CommunityVideoEntity videoEntity = videos.get(0);
- mVideoDuration.setBackground(DrawableView.getOvalDrawable(R.color.black_alpha_80, 999F));
+ mVideoDuration.setBackground(DrawableView.getOvalDrawable(R.color.black_alpha_50, 999F));
mVideoDuration.setText(videoEntity.getDuration());
mVideoDuration.setVisibility(View.VISIBLE);
} else {
diff --git a/app/src/main/java/com/gh/common/exposure/ExposureConverters.kt b/app/src/main/java/com/gh/common/exposure/ExposureConverters.kt
deleted file mode 100644
index 8b3392b110..0000000000
--- a/app/src/main/java/com/gh/common/exposure/ExposureConverters.kt
+++ /dev/null
@@ -1,62 +0,0 @@
-package com.gh.common.exposure
-
-import androidx.room.TypeConverter
-import com.gh.gamecenter.common.entity.ExposureEntity
-import com.gh.gamecenter.common.exposure.meta.Meta
-import com.gh.gamecenter.core.utils.GsonUtils
-import java.util.*
-import kotlin.collections.ArrayList
-
-class ExposureConverters {
-
- @TypeConverter
- fun convertPayload2String(any: ExposureEntity): String {
- return GsonUtils.toJson(any)
- }
-
- @TypeConverter
- fun convertString2Payload(string: String): ExposureEntity {
- return GsonUtils.fromJson(string, ExposureEntity::class.java)
- }
-
- @TypeConverter
- fun convertSource2String(sourceList: List): String {
- return GsonUtils.toJson(sourceList)
- }
-
- @TypeConverter
- fun convertString2Source(sourceList: String): List {
- return ArrayList(Arrays.asList(GsonUtils.fromJson(sourceList, Array::class.java))) as List
- }
-
- @TypeConverter
- fun convertETrace2String(sourceList: List?): String {
- return GsonUtils.toJson(sourceList)
- }
-
- @TypeConverter
- fun convertStringToETrace(sourceList: String): List {
- return ArrayList(Arrays.asList(GsonUtils.fromJson(sourceList, Array::class.java))) as List
- }
-
- @TypeConverter
- fun convertExposeType2String(exposureType: ExposureType): String {
- return exposureType.toString()
- }
-
- @TypeConverter
- fun convertStringToExposeType(exposureType: String): ExposureType {
- return ExposureType.valueOf(exposureType)
- }
-
- @TypeConverter
- fun convertMeta2String(any: Meta): String {
- return GsonUtils.toJson(any)
- }
-
- @TypeConverter
- fun convertString2Meta(string: String): Meta {
- return GsonUtils.fromJson(string, Meta::class.java)
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/common/exposure/ExposureDatabase.kt b/app/src/main/java/com/gh/common/exposure/ExposureDatabase.kt
deleted file mode 100644
index 9bd3cad34d..0000000000
--- a/app/src/main/java/com/gh/common/exposure/ExposureDatabase.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.gh.common.exposure
-
-import androidx.room.Database
-import androidx.room.Room
-import androidx.room.RoomDatabase
-import androidx.room.TypeConverters
-import android.content.Context
-
-@TypeConverters(ExposureConverters::class)
-@Database(entities = [ExposureEvent::class], version = 1, exportSchema = false)
-abstract class ExposureDatabase : RoomDatabase() {
- companion object {
- private const val DATABASE = "exposure_database"
-
- fun buildDatabase(context: Context): ExposureDatabase {
- return Room.databaseBuilder(context, ExposureDatabase::class.java, DATABASE)
- .fallbackToDestructiveMigration()
- .build()
- }
- }
-
- abstract fun logHubEventDao(): ExposureEventDao
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/common/exposure/ExposureEvent.kt b/app/src/main/java/com/gh/common/exposure/ExposureEvent.kt
index 9b5ff1cc4d..9b582f938e 100644
--- a/app/src/main/java/com/gh/common/exposure/ExposureEvent.kt
+++ b/app/src/main/java/com/gh/common/exposure/ExposureEvent.kt
@@ -4,22 +4,20 @@ import android.os.Parcelable
import androidx.annotation.Keep
import androidx.room.Entity
import androidx.room.PrimaryKey
+import com.gh.common.exposure.time.TimeUtil
+import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.common.constant.Constants
+import com.gh.gamecenter.common.entity.ExposureEntity
import com.gh.gamecenter.common.exposure.meta.Meta
import com.gh.gamecenter.common.exposure.meta.MetaUtil
-import com.gh.common.exposure.time.TimeUtil
import com.gh.gamecenter.common.utils.getFirstElementDividedByDivider
-import com.gh.download.server.BrowserInstallHelper
-import com.gh.gamecenter.common.entity.ExposureEntity
import com.gh.gamecenter.entity.GameEntity
import com.lightgame.download.DownloadEntity
import kotlinx.parcelize.Parcelize
import java.util.*
-import kotlin.collections.ArrayList
@Keep
@Parcelize
-@Entity(tableName = "exposureEvent")
data class ExposureEvent(
var payload: ExposureEntity,
val source: List,
@@ -27,8 +25,9 @@ data class ExposureEvent(
val event: ExposureType,
val meta: Meta = MetaUtil.getMeta(),
val time: Int = TimeUtil.currentTime(),
+ val timeInMillisecond: Long = System.currentTimeMillis(),
@PrimaryKey
- val id: String = UUID.randomUUID().toString()
+ val id: String = UUID.randomUUID().toString(),
) : Parcelable {
companion object {
diff --git a/app/src/main/java/com/gh/common/exposure/ExposureEventDao.kt b/app/src/main/java/com/gh/common/exposure/ExposureEventDao.kt
deleted file mode 100644
index 03c16aa0f9..0000000000
--- a/app/src/main/java/com/gh/common/exposure/ExposureEventDao.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.gh.common.exposure
-
-import androidx.room.*
-
-@Dao
-interface ExposureEventDao {
- @Insert(onConflict = OnConflictStrategy.REPLACE)
- fun insertMany(eventList: List)
-
- @Insert(onConflict = OnConflictStrategy.REPLACE)
- fun insert(event: ExposureEvent)
-
- @Query("SELECT * FROM exposureEvent")
- fun getAll(): List
-
- @Delete
- fun deleteMany(eventList: List)
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/common/exposure/ExposureManager.kt b/app/src/main/java/com/gh/common/exposure/ExposureManager.kt
index 2251c86967..9d8244ab91 100644
--- a/app/src/main/java/com/gh/common/exposure/ExposureManager.kt
+++ b/app/src/main/java/com/gh/common/exposure/ExposureManager.kt
@@ -1,14 +1,11 @@
package com.gh.common.exposure
import com.aliyun.sls.android.producer.Log
-import com.gh.gamecenter.common.loghub.LoghubHelper
-import com.gh.gamecenter.common.utils.toJson
-import com.gh.gamecenter.common.utils.tryWithDefaultCatch
import com.gh.gamecenter.BuildConfig
+import com.gh.gamecenter.common.loghub.LoghubHelper
import com.gh.gamecenter.common.utils.FixedSizeLinkedHashSet
-import com.halo.assistant.HaloApp
+import com.gh.gamecenter.common.utils.toJson
import com.lightgame.utils.Utils
-import java.util.concurrent.ExecutorService
/**
* A handful tool for committing logs to aliyun loghub.
@@ -26,40 +23,17 @@ object ExposureManager {
// exposureCache 用来过滤掉具有相同 id 的曝光事件,避免重复发送事件
private val exposureSet by lazy { hashSetOf() }
- private var exposureExecutor: ExecutorService? = null
private val exposureCache by lazy { FixedSizeLinkedHashSet(300) }
- private val exposureDao by lazy { ExposureDatabase.buildDatabase(HaloApp.getInstance().application).logHubEventDao() }
-
- @JvmStatic
- fun init(excutor: ExecutorService) {
- exposureExecutor = excutor
- exposureExecutor?.execute {
- tryWithDefaultCatch {
- val eventList = exposureDao.getAll()
- exposureSet.addAll(eventList)
- }
- }
- }
/**
* Log a single exposure event.
*/
fun log(event: ExposureEvent) {
- exposureExecutor?.execute {
- try {
- if (!exposureCache.contains(event.id)) {
- // Catch `android.database.sqlite.SQLiteFullException: database or disk is full` exception.
-
- exposureSet.add(event)
- exposureDao.insert(event)
- exposureCache.add(event.id)
-
- } else {
- Utils.log("Exposure", "遇到重复曝光事件,自动过滤 (${event.id} - ${event.payload.gameName})")
- }
- } catch (e: Exception) {
- e.printStackTrace()
- }
+ if (!exposureCache.contains(event.id)) {
+ exposureSet.add(event)
+ exposureCache.add(event.id)
+ } else {
+ Utils.log("Exposure", "遇到重复曝光事件,自动过滤 (${event.id} - ${event.payload.gameName})")
}
}
@@ -67,51 +41,36 @@ object ExposureManager {
* Log a collection of exposure event.
*/
fun log(eventList: List) {
- exposureExecutor?.execute {
- for (event in eventList) {
- try {
- if (!exposureCache.contains(event.id)) {
- // Catch `android.database.sqlite.SQLiteFullException: database or disk is full` exception.
- exposureSet.add(event)
- exposureDao.insert(event)
- exposureCache.add(event.id)
- } else {
- Utils.log("Exposure", "遇到重复曝光事件,自动过滤 (${event.id} - ${event.payload.gameName})")
- }
- } catch (e: Exception) {
- e.printStackTrace()
- }
+ for (event in eventList) {
+ if (!exposureCache.contains(event.id)) {
+ exposureSet.add(event)
+ exposureCache.add(event.id)
+ } else {
+ Utils.log("Exposure", "遇到重复曝光事件,自动过滤 (${event.id} - ${event.payload.gameName})")
}
- commitSavedExposureEvents()
}
+ commitSavedExposureEvents()
}
/**
- * @param forced Ignore all restrictions.
+ * @param forcedUpload Ignore all restrictions.
*/
- fun commitSavedExposureEvents(forced: Boolean = false) {
- exposureExecutor?.execute {
- tryWithDefaultCatch {
- // TODO 初始化 loghubHelper 去掉这个 tryCatch 块
- if (exposureSet.size < STORE_SIZE && !forced || exposureSet.size == 0) return@execute
+ fun commitSavedExposureEvents(forcedUpload: Boolean = false) {
+ if (exposureSet.size < STORE_SIZE && !forcedUpload || exposureSet.size == 0) return
- val exposureList = exposureSet.toList()
- uploadExposures(exposureList)
+ uploadExposures(exposureSet.toList(), forcedUpload)
- Utils.log("Exposure", "提交了${exposureList.size}条曝光记录")
- exposureSet.removeAll(exposureList)
- exposureDao.deleteMany(exposureList)
- }
- }
+ Utils.log("Exposure", "提交了${exposureSet.size}条曝光记录")
+ exposureSet.clear()
}
private fun eliminateMultipleBrackets(jsonWithMultipleBracket: String): String {
return jsonWithMultipleBracket.replace("[[", "[").replace("]]", "]")
}
- private fun uploadExposures(eventList: List) {
+ private fun uploadExposures(eventList: List, forced: Boolean) {
eventList.forEach {
- LoghubHelper.uploadLog(buildLog(it), LOG_STORE)
+ LoghubHelper.uploadLog(buildLog(it), LOG_STORE, forced)
}
}
@@ -121,9 +80,12 @@ object ExposureManager {
putContent("event", event.event.toString())
putContent("source", eliminateMultipleBrackets(event.source.toJson()))
putContent("meta", event.meta.toJson())
- putContent("e-traces", if (event.eTrace != null) {
- eliminateMultipleBrackets(event.eTrace?.toJson() ?: "")
- } else "")
+ putContent("real_millisecond", event.timeInMillisecond.toString())
+ putContent(
+ "e-traces", if (event.eTrace != null) {
+ eliminateMultipleBrackets(event.eTrace?.toJson() ?: "")
+ } else ""
+ )
logTime = event.time.toLong()
}
diff --git a/app/src/main/java/com/gh/common/exposure/ExposureUtils.kt b/app/src/main/java/com/gh/common/exposure/ExposureUtils.kt
index 63e0018513..72f92e2a25 100644
--- a/app/src/main/java/com/gh/common/exposure/ExposureUtils.kt
+++ b/app/src/main/java/com/gh/common/exposure/ExposureUtils.kt
@@ -7,6 +7,7 @@ import com.gh.gamecenter.common.utils.FixedSizeLinkedHashSet
import com.gh.gamecenter.common.utils.toObject
import com.gh.gamecenter.entity.ApkEntity
import com.gh.gamecenter.entity.GameEntity
+import com.gh.gamecenter.manager.PackagesManager
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
@@ -75,12 +76,18 @@ object ExposureUtils {
exposureEvent.payload.host = host
exposureEvent.payload.path = path
ExposureManager.log(exposureEvent)
- ExposureManager.commitSavedExposureEvents(forced = true)
+ ExposureManager.commitSavedExposureEvents(forcedUpload = true)
}
@JvmStatic
- fun getDownloadType(apkEntity: ApkEntity, gameId: String): DownloadType {
- return if (PackageUtils.isInstalled(
+ fun getDownloadType(apkEntity: ApkEntity, gameId: String, isVGame: Boolean): DownloadType {
+ return if (isVGame) {
+ if (PackagesManager.isCanUpdate(gameId, apkEntity.packageName)) {
+ DownloadType.FUN_UPDATE
+ } else {
+ DownloadType.FUN_DOWNLOAD
+ }
+ } else if (PackageUtils.isInstalled(
HaloApp.getInstance().application,
apkEntity.packageName
)
@@ -143,6 +150,10 @@ object ExposureUtils {
PLUGIN_UPDATE,
- PLUGIN_DOWNLOAD
+ PLUGIN_DOWNLOAD,
+
+ FUN_DOWNLOAD,
+
+ FUN_UPDATE
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/common/filter/RegionSetting.kt b/app/src/main/java/com/gh/common/filter/RegionSetting.kt
index b699a530d7..3ec3808451 100644
--- a/app/src/main/java/com/gh/common/filter/RegionSetting.kt
+++ b/app/src/main/java/com/gh/common/filter/RegionSetting.kt
@@ -12,7 +12,9 @@ data class RegionSetting(
@SerializedName("channel_control")
var channelControl: ChannelControl,
@SerializedName("game_h5_download")
- var gameH5DownloadList: List
+ var gameH5DownloadList: List,
+ @SerializedName("game_special_download")
+ var gameSpecialDownloadInfoList: List
) {
@Keep
@@ -34,4 +36,14 @@ data class RegionSetting(
@SerializedName("button_text")
var buttonText: String,// 按钮文案
)
+ data class GameSpecialDownloadInfo(
+ @SerializedName("game_id")
+ var gameId: String = "",
+ @SerializedName("bbs_id")
+ var bbsId: String = "",
+ @SerializedName("top_id")
+ var topId: String = "",
+ @SerializedName("hint_text")
+ var hintText: String = ""
+ )
}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/common/filter/RegionSettingHelper.kt b/app/src/main/java/com/gh/common/filter/RegionSettingHelper.kt
index be4ae2fb75..edf632204f 100644
--- a/app/src/main/java/com/gh/common/filter/RegionSettingHelper.kt
+++ b/app/src/main/java/com/gh/common/filter/RegionSettingHelper.kt
@@ -20,6 +20,7 @@ object RegionSettingHelper {
private var mFilterGameIdSet: HashSet? = hashSetOf()
private var mDisplayMirrorIfoGameIdSet: HashSet? = hashSetOf()
private var mGameH5DownloadList: List? = listOf()
+ private var mGameSpecialDownloadInfoList: List? = listOf()
private const val SP_SETTING = "region_setting"
@@ -32,6 +33,11 @@ object RegionSettingHelper {
return mFilterGameIdSet?.contains(gameId) ?: false
}
+ fun shouldThisGameShowSpecialDownload(gameId: String) = mGameSpecialDownloadInfoList?.any { it.gameId == gameId } ?: false
+
+ @JvmStatic
+ fun getGameSpecialDownloadInfo(gameId: String) = mGameSpecialDownloadInfoList?.find { it.gameId == gameId }
+
@JvmStatic
fun filterGame(list: List?): ArrayList {
if (list == null) return arrayListOf()
@@ -94,6 +100,7 @@ object RegionSettingHelper {
mDisplayMirrorIfoGameIdSet = data.mirrorGameIdSet
mChannelControl = data.channelControl
mGameH5DownloadList = data.gameH5DownloadList
+ mGameSpecialDownloadInfoList = data.gameSpecialDownloadInfoList
}
/**
diff --git a/app/src/main/java/com/gh/common/provider/ActivationProviderImpl.kt b/app/src/main/java/com/gh/common/provider/ActivationProviderImpl.kt
index 4c7fa2f3b8..a172d9cc2e 100644
--- a/app/src/main/java/com/gh/common/provider/ActivationProviderImpl.kt
+++ b/app/src/main/java/com/gh/common/provider/ActivationProviderImpl.kt
@@ -7,7 +7,7 @@ import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.core.provider.IActivationProvider
@Route(path = RouteConsts.provider.activation, name = "ActivationHelper暴露服务")
-interface ActivationProviderImpl : IActivationProvider {
+class ActivationProviderImpl : IActivationProvider {
override fun init(context: Context?) {
}
diff --git a/app/src/main/java/com/gh/common/provider/BuildConfigImpl.kt b/app/src/main/java/com/gh/common/provider/BuildConfigImpl.kt
index 9ce6c309f8..d90113b6a4 100644
--- a/app/src/main/java/com/gh/common/provider/BuildConfigImpl.kt
+++ b/app/src/main/java/com/gh/common/provider/BuildConfigImpl.kt
@@ -28,4 +28,7 @@ class BuildConfigImpl : IBuildConfigProvider {
override fun getNewDevApiHost(): String = BuildConfig.NEW_DEV_API_HOST
+ override fun getVApiHost(): String = BuildConfig.VAPI_HOST
+
+ override fun getVDevApiHost(): String = BuildConfig.DEV_VAPI_HOST
}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/common/simulator/SimulatorDownloadManager.kt b/app/src/main/java/com/gh/common/simulator/SimulatorDownloadManager.kt
index 7c5bd38bab..4ac8603d0e 100644
--- a/app/src/main/java/com/gh/common/simulator/SimulatorDownloadManager.kt
+++ b/app/src/main/java/com/gh/common/simulator/SimulatorDownloadManager.kt
@@ -9,15 +9,19 @@ import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import com.g00fy2.versioncompare.Version
-import com.gh.gamecenter.core.AppExecutor.uiExecutor
-import com.gh.gamecenter.common.constant.Constants
-import com.gh.gamecenter.common.base.TrackableDialog
-import com.gh.common.util.*
import com.gh.common.util.LogUtils
+import com.gh.common.util.PackageInstaller
+import com.gh.common.util.PackageUtils
import com.gh.download.DownloadManager
import com.gh.gamecenter.R
+import com.gh.gamecenter.common.base.TrackableDialog
+import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.*
-import com.gh.gamecenter.core.utils.*
+import com.gh.gamecenter.core.AppExecutor.uiExecutor
+import com.gh.gamecenter.core.utils.DisplayUtils
+import com.gh.gamecenter.core.utils.MtaHelper
+import com.gh.gamecenter.core.utils.SpeedUtils
+import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.entity.ApkEntity
import com.gh.gamecenter.entity.SimulatorEntity
import com.gh.gamecenter.entity.TrackableEntity
@@ -73,7 +77,7 @@ class SimulatorDownloadManager private constructor() {
val fileName = downloadEntity.path.substring(downloadEntity.path.lastIndexOf('/') + 1).removeSuffix(".apk")
val startTime = downloadEntity.getMetaExtra(Constants.SIMULATOR_DOWNLOAD_START_TIME)
LogUtils.uploadSimulatorDownload("simulator_download_complete", fileName, simulator?.id, downloadEntity.name, gameId, locationStr, downloadType, startTime)
- DownloadManager.getInstance().cancel(downloadEntity.url, false, true)
+ DownloadManager.getInstance().cancel(downloadEntity.url, false, true, false)
val activity = mContextRef?.get() as? AppCompatActivity
if (activity?.isFinishing == false) {
downloadDialog?.dismiss()
@@ -97,6 +101,9 @@ class SimulatorDownloadManager private constructor() {
DownloadStatus.unavailable == downloadEntity.status -> {
ToastUtils.showToast("该游戏未接入防沉迷系统,暂不支持下载")
}
+ DownloadStatus.banned == downloadEntity.status -> {
+ ToastUtils.showToast("网络异常")
+ }
DownloadStatus.hijack == downloadEntity.status -> {
ToastUtils.showToast("网络劫持,请稍后重试")
}
diff --git a/app/src/main/java/com/gh/common/simulator/SimulatorGameManager.kt b/app/src/main/java/com/gh/common/simulator/SimulatorGameManager.kt
index dc2cb49cc8..157783bfcb 100644
--- a/app/src/main/java/com/gh/common/simulator/SimulatorGameManager.kt
+++ b/app/src/main/java/com/gh/common/simulator/SimulatorGameManager.kt
@@ -7,19 +7,21 @@ import android.graphics.Bitmap
import android.net.Uri
import android.text.TextUtils
import com.g00fy2.versioncompare.Version
-import com.gh.gamecenter.common.json.json
-import com.gh.common.util.*
+import com.gh.common.util.ApkActiveUtils
import com.gh.common.util.LogUtils
+import com.gh.common.util.PackageUtils
import com.gh.download.DownloadManager
import com.gh.gamecenter.common.callback.BiCallback
-import com.gh.gamecenter.common.utils.*
-import com.gh.gamecenter.core.utils.*
-import com.gh.gamecenter.entity.GameEntity
-import com.gh.gamecenter.entity.SimulatorGameRecordEntity
-import com.gh.gamecenter.manager.UserManager
+import com.gh.gamecenter.common.json.json
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.retrofit.EmptyResponse
import com.gh.gamecenter.common.retrofit.Response
+import com.gh.gamecenter.common.utils.*
+import com.gh.gamecenter.core.utils.ToastUtils
+import com.gh.gamecenter.core.utils.UrlFilterUtils
+import com.gh.gamecenter.entity.GameEntity
+import com.gh.gamecenter.entity.SimulatorGameRecordEntity
+import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.room.AppDatabase
import com.halo.assistant.HaloApp
@@ -72,7 +74,7 @@ object SimulatorGameManager {
@JvmStatic
fun findDownloadEntityByUrl(url: String?): DownloadEntity? {
- val downloadEntity = DownloadDao.getInstance(HaloApp.getInstance().application).get(url)
+ val downloadEntity = DownloadManager.getInstance().getDownloadEntityByUrl(url)
if (downloadEntity != null) {
val isFileCompleted = DownloadManager.getInstance().isDownloadCompleted(url)
if (downloadEntity.isSimulatorGame() && isFileCompleted) {
diff --git a/app/src/main/java/com/gh/common/util/CommentHelper.kt b/app/src/main/java/com/gh/common/util/CommentHelper.kt
index 4ecfc6f8b1..c95b80b8c6 100644
--- a/app/src/main/java/com/gh/common/util/CommentHelper.kt
+++ b/app/src/main/java/com/gh/common/util/CommentHelper.kt
@@ -5,21 +5,21 @@ import android.view.LayoutInflater
import android.view.View
import android.widget.LinearLayout
import android.widget.TextView
-import com.gh.gamecenter.common.constant.Constants
-import com.gh.gamecenter.common.json.json
import com.gh.common.util.CommentUtils.copyText
-import com.gh.gamecenter.common.view.BugFixedPopupWindow
import com.gh.gamecenter.CommentDetailActivity
import com.gh.gamecenter.R
+import com.gh.gamecenter.common.constant.Constants
+import com.gh.gamecenter.common.json.json
+import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.DialogHelper
import com.gh.gamecenter.common.utils.ifLogin
import com.gh.gamecenter.common.utils.showAutoOrientation
+import com.gh.gamecenter.common.view.BugFixedPopupWindow
import com.gh.gamecenter.entity.CommentEntity
import com.gh.gamecenter.entity.MeEntity
import com.gh.gamecenter.entity.Permissions
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.qa.comment.OnCommentOptionClickListener
-import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
@@ -237,8 +237,6 @@ object CommentHelper {
}
articleId != null -> {
PostCommentUtils.reportCommunityArticleComment(
- communityId,
- articleId,
commentEntity.id,
reportType,
commentListener
@@ -440,11 +438,7 @@ object CommentHelper {
context, highlight, highlightDialogHintContent,
"确定", "取消", {
RetrofitManager.getInstance().api
- .highlightCommunityArticleComment(
- communityId,
- articleId,
- comment.id
- )
+ .highlightCommunityArticleComment(comment.id)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(highlightObserver)
@@ -502,7 +496,7 @@ object CommentHelper {
context, hide, hideDialogHintContent,
"确定", "取消", {
RetrofitManager.getInstance().api
- .hideCommunityArticleComment(communityId, articleId, comment.id)
+ .hideCommunityArticleComment(comment.id)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(hideObserver)
diff --git a/app/src/main/java/com/gh/common/util/CommentUtils.java b/app/src/main/java/com/gh/common/util/CommentUtils.java
index 93a1721937..d809b4b562 100644
--- a/app/src/main/java/com/gh/common/util/CommentUtils.java
+++ b/app/src/main/java/com/gh/common/util/CommentUtils.java
@@ -298,7 +298,7 @@ public class CommentUtils {
commentLikeCountTv.setText(NumberUtils.transSimpleCount(commentEntity.getVote()));
commentLikeCountTv.setVisibility(View.VISIBLE);
- PostCommentUtils.likeComment(answerId, articleId, articleCommunityId, videoId, questionId, commentEntity.getId(),
+ PostCommentUtils.likeComment(answerId, articleId, videoId, questionId, commentEntity.getId(),
new PostCommentUtils.PostCommentListener() {
@Override
public void postSuccess(JSONObject response) {
@@ -352,7 +352,7 @@ public class CommentUtils {
String entrance = "视频流-评论-点赞";
CheckLoginUtils.checkLogin(context, entrance, () -> {
- PostCommentUtils.likeComment(answerId, articleId, articleCommunityId, videoId, "", commentEntity.getId(),
+ PostCommentUtils.likeComment(answerId, articleId, videoId, "", commentEntity.getId(),
new PostCommentUtils.PostCommentListener() {
@Override
public void postSuccess(JSONObject response) {
@@ -420,7 +420,7 @@ public class CommentUtils {
commentLikeCountTv.setVisibility(View.VISIBLE);
try {
if (e != null && e.response().errorBody() != null) {
- ErrorHelper.handleError(context, e.response().errorBody().string(), false);
+ ErrorHelper.handleError(context, e.response().errorBody().string(), false, null);
}
} catch (IOException ex) {
ex.printStackTrace();
diff --git a/app/src/main/java/com/gh/common/util/DataUtils.java b/app/src/main/java/com/gh/common/util/DataUtils.java
index 065b1bb468..5bc1a0e664 100644
--- a/app/src/main/java/com/gh/common/util/DataUtils.java
+++ b/app/src/main/java/com/gh/common/util/DataUtils.java
@@ -43,7 +43,7 @@ import kotlin.Pair;
/**
* Created by LGT on 2016/6/15.
- * 数据收集 工具类 (TalkingData、MTA)
+ * 数据收集工具类
*/
public class DataUtils {
@@ -161,8 +161,8 @@ public class DataUtils {
values.put(GhContentProvider.KEY_IS_ADULT, false);
}
- new GhContentProvider().localInsert( HaloApp.getInstance().getApplication(),values);
-// HaloApp.getInstance().getContentResolver().insert(Uri.parse("content://com.gh.gamecenter.provider/certification"), values);
+// new GhContentProvider().localInsert( HaloApp.getInstance().getApplication(),values);
+ HaloApp.getInstance().getContentResolver().insert(Uri.parse("content://com.gh.gamecenter.provider/certification"), values);
}
});
}
diff --git a/app/src/main/java/com/gh/common/util/DetailDownloadUtils.java b/app/src/main/java/com/gh/common/util/DetailDownloadUtils.java
index 94e1e1a775..0e7b1ab723 100644
--- a/app/src/main/java/com/gh/common/util/DetailDownloadUtils.java
+++ b/app/src/main/java/com/gh/common/util/DetailDownloadUtils.java
@@ -19,6 +19,7 @@ import com.gh.gamecenter.core.utils.SPUtils;
import com.gh.gamecenter.entity.LinkEntity;
import com.gh.gamecenter.entity.PluginLocation;
import com.gh.gamecenter.manager.PackagesManager;
+import com.gh.vspace.VHelper;
import com.lightgame.download.DownloadEntity;
/**
@@ -30,6 +31,9 @@ public class DetailDownloadUtils {
public static void detailInitDownload(DetailViewHolder viewHolder, boolean isCheck) {
String downloadAddWord = viewHolder.gameEntity.getDownloadAddWord();
+ if (viewHolder.getOverlayTv() != null) {
+ viewHolder.getOverlayTv().setVisibility(View.GONE);
+ }
if (viewHolder.gameEntity != null
&& Config.isShowDownload(viewHolder.gameEntity.getId())
@@ -46,9 +50,14 @@ public class DetailDownloadUtils {
return;
}
+ if (viewHolder.gameEntity.isSpecialDownload()) {
+ viewHolder.mDownloadPb.setText("查看下载资源");
+ viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.SPECIAL_DOWNLOAD);
+ return;
+ }
+
if (viewHolder.gameEntity.isReservable()) {
if (!ReservationRepository.thisGameHasBeenReserved(viewHolder.gameEntity.getId())) {
-
if (TextUtils.isEmpty(downloadAddWord)) {
viewHolder.mDownloadPb.setText(String.format("预约" + "《%s》", viewHolder.gameEntity.getName()));
} else {
@@ -61,12 +70,55 @@ public class DetailDownloadUtils {
}
return;
}
+
final RegionSetting.GameH5Download gameH5Download = RegionSettingHelper.getGameH5DownloadByGameId(viewHolder.gameEntity.getId());
if (gameH5Download != null) {
viewHolder.mDownloadPb.setText(TextUtils.isEmpty(viewHolder.gameEntity.getDownloadOffText()) ? "查看详情" : viewHolder.gameEntity.getDownloadOffText());
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.NORMAL);
return;
}
+
+ if (viewHolder.gameEntity.isVGame() && !viewHolder.gameEntity.getApk().isEmpty()) {
+ String status = GameUtils.getDownloadBtnText(viewHolder.context, viewHolder.gameEntity, PluginLocation.only_game);
+ if (viewHolder.context.getString(R.string.launch).equals(status)) {
+ viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.LAUNCH_OR_OPEN);
+ } else if (viewHolder.context.getString(R.string.install).equals(status)) {
+ viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.INSTALL_NORMAL);
+ } else {
+ viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.NORMAL);
+ }
+
+ String downloadText;
+ if (viewHolder.context.getString(R.string.launch).equals(status) || viewHolder.context.getString(R.string.install).equals(status) || viewHolder.context.getString(R.string.download).equals(status)) {
+ downloadText = "";
+ if (viewHolder.getOverlayTv() != null) {
+ viewHolder.getOverlayTv().setVisibility(View.VISIBLE);
+ }
+ } else if (viewHolder.context.getString(R.string.attempt).equals(status)) {
+ downloadText = status + getDownloadSizeText(viewHolder);
+ } else {
+ downloadText = status + (TextUtils.isEmpty(downloadAddWord) ? "" : downloadAddWord) + getDownloadSizeText(viewHolder);
+ }
+ viewHolder.mDownloadPb.setText(downloadText);
+
+ DownloadEntity downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(viewHolder.gameEntity);
+
+ // 在下载管理找不到下载实体,到畅玩数据库里找
+ if (downloadEntity == null && viewHolder.gameEntity.isVGame()) {
+ String packageName = viewHolder.gameEntity.getUniquePackageName();
+ if (!TextUtils.isEmpty(packageName)) {
+ downloadEntity = VHelper.getDownloadEntitySnapshot(viewHolder.gameEntity.getId(), packageName);
+ }
+ }
+
+ if (downloadEntity != null) {
+ viewHolder.downloadEntity = downloadEntity;
+ detailInvalidate(viewHolder);
+ }
+
+ return;
+ }
+
if (viewHolder.gameEntity.getApk().isEmpty() || viewHolder.gameEntity.getDownloadOffStatus() != null) {
LinkEntity h5LinkEntity = viewHolder.gameEntity.getH5Link();
@@ -121,9 +173,18 @@ public class DetailDownloadUtils {
viewHolder.mDownloadPb.setText("选择下载你的版本" + (TextUtils.isEmpty(downloadAddWord) ? "" : "-" + downloadAddWord) + " >");
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.NORMAL);
}
+
if (isCheck && viewHolder.gameEntity.getApk().size() == 1) {
- String url = viewHolder.gameEntity.getApk().get(0).getUrl();
- DownloadEntity downloadEntity = DownloadManager.getInstance().getDownloadEntityByUrl(url);
+ DownloadEntity downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(viewHolder.gameEntity);
+
+ // 在下载管理找不到下载实体,到畅玩数据库里找
+ if (downloadEntity == null && viewHolder.gameEntity.isVGame()) {
+ String packageName = viewHolder.gameEntity.getUniquePackageName();
+ if (!TextUtils.isEmpty(packageName)) {
+ downloadEntity = VHelper.getDownloadEntitySnapshot(viewHolder.gameEntity.getId(), packageName);
+ }
+ }
+
if (downloadEntity != null) {
viewHolder.downloadEntity = downloadEntity;
detailInvalidate(viewHolder);
@@ -148,6 +209,15 @@ public class DetailDownloadUtils {
}
viewHolder.mDownloadPb.setProgress((int) (viewHolder.downloadEntity.getPercent() * 10));
+ if (viewHolder.getOverlayTv() != null) {
+ viewHolder.getOverlayTv().setVisibility(View.GONE);
+ }
+
+ if (viewHolder.gameEntity.isVGame()) {
+ updateVStyleButton(viewHolder);
+ return;
+ }
+
switch (downloadEntity.getStatus()) {
case downloading:
case pause:
@@ -188,6 +258,19 @@ public class DetailDownloadUtils {
}
viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.INSTALL_NORMAL);
}
+ } else if (viewHolder.gameEntity.isVGame()) {
+ if (!viewHolder.mDownloadPb.getText().contains("更新")) {
+ if (VHelper.isInstalled(downloadEntity.getPackageName())) {
+ viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.LAUNCH_OR_OPEN);
+ } else {
+ viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.INSTALL_NORMAL);
+ }
+
+ viewHolder.mDownloadPb.setText("");
+ if (viewHolder.getOverlayTv() != null) {
+ viewHolder.getOverlayTv().setVisibility(View.VISIBLE);
+ }
+ }
} else {
if (SPUtils.getBoolean(Constants.SP_USE_BROWSER_TO_INSTALL)) {
viewHolder.mDownloadPb.setText(R.string.browser_install_install);
@@ -209,10 +292,48 @@ public class DetailDownloadUtils {
case uncertificated:
case unqualified:
case unavailable:
+ case banned:
detailInitDownload(viewHolder, false);
break;
default:
break;
}
}
+
+ private static void updateVStyleButton(DetailViewHolder viewHolder) {
+ switch (viewHolder.downloadEntity.getStatus()) {
+ case downloading:
+ case overflow:
+ viewHolder.mDownloadPb.setText("游戏加载中 " + viewHolder.downloadEntity.getPercent() + "%");
+ viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.DOWNLOADING_NORMAL);
+ break;
+ case timeout:
+ case neterror:
+ case waiting:
+ case subscribe:
+ viewHolder.mDownloadPb.setText(R.string.waiting);
+ viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.DOWNLOADING_NORMAL);
+ break;
+ case pause:
+ viewHolder.mDownloadPb.setText("继续加载 " + viewHolder.downloadEntity.getPercent() + "%");
+ viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.DOWNLOADING_NORMAL);
+ break;
+ case done:
+ if (!viewHolder.mDownloadPb.getText().contains("更新")) {
+ if (VHelper.isInstalled(viewHolder.downloadEntity.getPackageName())) {
+ viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.LAUNCH_OR_OPEN);
+ } else {
+ viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.INSTALL_NORMAL);
+ }
+
+ viewHolder.mDownloadPb.setText("");
+ if (viewHolder.getOverlayTv() != null) {
+ viewHolder.getOverlayTv().setVisibility(View.VISIBLE);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
}
diff --git a/app/src/main/java/com/gh/common/util/DirectUtils.kt b/app/src/main/java/com/gh/common/util/DirectUtils.kt
index 2b45a6c673..fe58c6f34f 100644
--- a/app/src/main/java/com/gh/common/util/DirectUtils.kt
+++ b/app/src/main/java/com/gh/common/util/DirectUtils.kt
@@ -72,6 +72,7 @@ import com.gh.gamecenter.video.detail.VideoDetailActivity
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
import com.gh.gamecenter.video.game.GameVideoActivity
import com.gh.gamecenter.video.videomanager.VideoManagerActivity
+import com.gh.vspace.VDownloadManagerActivity
import com.halo.assistant.HaloApp
import com.halo.assistant.fragment.WebFragment
import com.lightgame.utils.Utils
@@ -81,6 +82,7 @@ import org.greenrobot.eventbus.EventBus
import retrofit2.HttpException
import java.net.URLEncoder
import java.util.*
+import kotlin.collections.ArrayList
import kotlin.math.roundToInt
/**
@@ -154,7 +156,8 @@ object DirectUtils {
"category_v2",
"common_collection",
"game_list",
- "game_list_detail"
+ "game_list_detail",
+ "bbs_video"
)
fun directToLinkPage(
@@ -190,7 +193,7 @@ object DirectUtils {
"column", "游戏专题" -> directToSubject(
context, linkEntity.link
- ?: "", linkEntity.text, BaseActivity.mergeEntranceAndPath(entrance, path)
+ ?: "", linkEntity.text, BaseActivity.mergeEntranceAndPath(entrance, path), exposureEvent
)
"question", "社区问题" -> directToQuestionDetail(
@@ -240,7 +243,7 @@ object DirectUtils {
"catalog" -> directCatalog(context, linkEntity.link!!, linkEntity.text!!, entrance, path)
- "category_v2" -> directCategoryV2(context, linkEntity.link!!, linkEntity.text!!, entrance, path)
+ "category_v2" -> directCategoryV2(context, linkEntity.link!!, linkEntity.text!!, entrance, path, exposureEvent)
"block", "版块" -> {
if (linkEntity.link.isNullOrEmpty()) return
@@ -264,7 +267,7 @@ object DirectUtils {
"wechat_bind" -> context.startActivity(WebActivity.getBindWechatIntent(context))
- "video", "video_stream", "视频" -> directToVideoDetail(
+ "video", "bbs_video", "video_stream", "视频" -> directToVideoDetail(
context,
videoId = linkEntity.link!!,
fromLocation = VideoDetailContainerViewModel.Location.VIDEO_CHOICENESS.value,
@@ -630,13 +633,14 @@ object DirectUtils {
// 专栏
@JvmStatic
- fun directToSubject(context: Context, id: String, subjectName: String? = "", entrance: String? = null) {
+ fun directToSubject(context: Context, id: String, subjectName: String? = "", entrance: String? = null, exposureEvent: ExposureEvent? = null) {
if (id.isEmpty()) return
val bundle = Bundle()
val subjectData = SubjectData(subjectId = id, subjectName = subjectName, isOrder = false)
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_TO, SubjectActivity::class.java.name)
bundle.putParcelable(EntranceConsts.KEY_SUBJECT_DATA, subjectData)
+ if (exposureEvent != null) bundle.putParcelableArrayList(KEY_EXPOSURE_SOURCE_LIST, ArrayList(exposureEvent.source))
jumpActivity(context, bundle)
}
@@ -1184,6 +1188,7 @@ object DirectUtils {
categoryTitle: String,
entrance: String? = null,
path: String? = "",
+ exposureEvent: ExposureEvent? = null,
) {
if (categoryId.isEmpty()) return
val bundle = Bundle()
@@ -1191,6 +1196,7 @@ object DirectUtils {
bundle.putString(KEY_CATEGORY_ID, categoryId)
bundle.putString(KEY_CATEGORY_TITLE, categoryTitle)
bundle.putString(KEY_ENTRANCE, BaseActivity.mergeEntranceAndPath(entrance, path))
+ if (exposureEvent != null) bundle.putParcelableArrayList(KEY_EXPOSURE_SOURCE_LIST, ArrayList(exposureEvent.source))
jumpActivity(context, bundle)
}
@@ -1704,7 +1710,13 @@ object DirectUtils {
* 跳转至游戏单广场
*/
@JvmStatic
- fun directToGameCollectionSquare(context: Context, entrance: String = "", forumName: String = "", gameCollectionTitle: String = "", gameCollectionId: String = "") {
+ fun directToGameCollectionSquare(
+ context: Context,
+ entrance: String = "",
+ forumName: String = "",
+ gameCollectionTitle: String = "",
+ gameCollectionId: String = ""
+ ) {
val bundle = Bundle()
bundle.putString(KEY_TO, GameCollectionSquareActivity::class.java.name)
bundle.putString(KEY_ENTRANCE, entrance)
@@ -1766,6 +1778,15 @@ object DirectUtils {
}
}
+ @JvmStatic
+ fun directToVGameDownload(context: Context, switchToDownloadingTab: Boolean = false) {
+ val bundle = Bundle()
+ bundle.putString(KEY_ENTRANCE, ENTRANCE_BROWSER)
+ bundle.putString(KEY_TO, VDownloadManagerActivity::class.java.name)
+ bundle.putInt(KEY_POSITION, if (switchToDownloadingTab) 1 else 0)
+ jumpActivity(context, bundle)
+ }
+
@JvmStatic
fun directToSuggestion(context: Context, type: SuggestType) {
directToSuggestion(context = context, type = type, requestCode = null)
diff --git a/app/src/main/java/com/gh/common/util/DownloadItemUtils.kt b/app/src/main/java/com/gh/common/util/DownloadItemUtils.kt
index 05b1559e7c..b07b69cdb0 100644
--- a/app/src/main/java/com/gh/common/util/DownloadItemUtils.kt
+++ b/app/src/main/java/com/gh/common/util/DownloadItemUtils.kt
@@ -11,7 +11,6 @@ import androidx.collection.ArrayMap
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.constant.Config
-import com.gh.gamecenter.common.constant.Constants
import com.gh.common.dialog.CertificationDialog
import com.gh.common.dialog.DeviceRemindDialog
import com.gh.common.dialog.PackageCheckDialogFragment
@@ -30,7 +29,8 @@ import com.gh.gamecenter.DownloadManagerActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.adapter.viewholder.GameViewHolder
-import com.gh.gamecenter.common.callback.ConfirmListener
+import com.gh.gamecenter.common.constant.Constants
+import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.entity.GameEntity
@@ -39,6 +39,8 @@ import com.gh.gamecenter.entity.PluginLocation
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment
import com.gh.gamecenter.manager.PackagesManager
import com.gh.gamecenter.teenagermode.TeenagerModeActivity
+import com.gh.vspace.VDownloadManagerActivity
+import com.gh.vspace.VHelper
import com.lightgame.download.DownloadConfig
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus
@@ -141,8 +143,11 @@ object DownloadItemUtils {
@JvmStatic
@JvmOverloads
fun updateItem(
- context: Context, gameEntity: GameEntity, holder: GameViewHolder,
- isShowPlatform: Boolean, pluginLocation: PluginLocation? = PluginLocation.only_game,
+ context: Context,
+ gameEntity: GameEntity,
+ holder: GameViewHolder,
+ isShowPlatform: Boolean,
+ pluginLocation: PluginLocation? = PluginLocation.only_game,
hideDownloadBtnIfNoAvailableContent: Boolean = false,
briefStyle: String? = null,
isShowRecommendStar: Boolean = false
@@ -173,8 +178,8 @@ object DownloadItemUtils {
downloadBtn.background = R.drawable.download_button_normal_style.toDrawable(context)
// 控制是否显示下载按钮
downloadBtn.goneIf(!Config.isShowDownload(gameEntity.id) || context.getString(R.string.app_name) == gameEntity.name)
- // 青少年模式显示查看
- if (SPUtils.getBoolean(Constants.SP_TEENAGER_MODE)) {
+ // 青少年模式或者需要特殊处理显示查看
+ if (SPUtils.getBoolean(Constants.SP_TEENAGER_MODE) || gameEntity.isSpecialDownload()) {
downloadBtn.text = "查看"
return
}
@@ -231,7 +236,12 @@ object DownloadItemUtils {
}
}
} else if (gameEntity.getApk().size == 1) {
- val downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshotByUrl(gameEntity.getApk()[0].url)
+ var downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(gameEntity)
+
+ if (downloadEntity == null && gameEntity.isVGame()) {
+ downloadEntity = VHelper.getDownloadEntitySnapshot(gameEntity.id, gameEntity.getUniquePackageName())
+ }
+
if (downloadEntity != null) {
downloadBtn.apply {
val status = downloadEntity.status
@@ -244,15 +254,9 @@ object DownloadItemUtils {
setBackgroundResource(R.drawable.button_round_border_eeeeee)
setTextColor(ContextCompat.getColorStateList(context, R.color.text_subtitleDesc))
} else if (status == DownloadStatus.pause || status == DownloadStatus.timeout || status == DownloadStatus.neterror || status == DownloadStatus.subscribe || status == DownloadStatus.overflow) {
- if (status == DownloadStatus.waiting) {
- setText(R.string.waiting)
- setBackgroundResource(R.drawable.button_round_border_eeeeee)
- setTextColor(ContextCompat.getColorStateList(context, R.color.text_subtitleDesc))
- } else {
- setText(R.string.downloading)
- setBackgroundResource(R.drawable.game_item_btn_downloading_style)
- setTextColor(ContextCompat.getColorStateList(context, R.color.text_downloading_style))
- }
+ setText(R.string.downloading)
+ setBackgroundResource(R.drawable.game_item_btn_downloading_style)
+ setTextColor(ContextCompat.getColorStateList(context, R.color.text_downloading_style))
} else if (status == DownloadStatus.done) {
val xapkStatus = downloadEntity.meta[XapkInstaller.XAPK_UNZIP_STATUS]
if (XapkUnzipStatus.UNZIPPING.name == xapkStatus) {
@@ -261,6 +265,12 @@ object DownloadItemUtils {
}
if (downloadEntity.isSimulatorGame() && gameEntity.simulator != null) {
GameUtils.setDownloadBtnStatus(context, gameEntity, downloadBtn, pluginLocation)
+ } else if (downloadEntity.isVGame()) {
+ if (PackagesManager.isCanUpdate(downloadEntity.gameId, downloadEntity.packageName)) {
+ setText(R.string.update)
+ } else {
+ setText(R.string.launch)
+ }
} else {
setText(R.string.install)
}
@@ -335,10 +345,14 @@ object DownloadItemUtils {
context: Context, holder: GameViewHolder, downloadEntity: DownloadEntity,
isShowPlatform: Boolean, isNormal: Boolean, isShowRecommendStar: Boolean = false
) {
- updateItemViewStatus(holder, true, null, null, isShowRecommendStar)
- holder.gameProgressbar.progressDrawable = R.drawable.progressbar_bg_style.toDrawable()
- val platform = PlatformUtils.getInstance(context).getPlatformName(downloadEntity.platform)
val status = downloadEntity.status
+ // 畅玩游戏下载完成时不再需要显示进度条
+ val shouldShowDownload = !(downloadEntity.isVGame() && status == DownloadStatus.done)
+ val platform = PlatformUtils.getInstance(context).getPlatformName(downloadEntity.platform)
+
+ updateItemViewStatus(holder, shouldShowDownload, null, null, isShowRecommendStar)
+ holder.gameProgressbar.progressDrawable = R.drawable.progressbar_bg_style.toDrawable()
+
if (status == DownloadStatus.downloading) {
if (DownloadStatus.pause != DownloadManager.getInstance().getStatus(downloadEntity.url)) {
holder.gameProgressbar.progress = (downloadEntity.percent * 10).toInt()
@@ -394,12 +408,12 @@ object DownloadItemUtils {
private fun updateItemViewStatus(
holder: GameViewHolder,
- hasDownload: Boolean,
+ showDownload: Boolean,
briefStyle: String?,
recommendStyle: LinkEntity?,
isShowRecommendStar: Boolean = false
) {
- if (hasDownload) {
+ if (showDownload) {
if (holder.gameRating != null) holder.gameRating!!.visibility = View.GONE
holder.gameDes.visibility = View.GONE
holder.gameProgressbar.visibility = View.VISIBLE
@@ -542,6 +556,33 @@ object DownloadItemUtils {
}
return
}
+ if (gameEntity.isSpecialDownload()) {
+ val info = RegionSettingHelper.getGameSpecialDownloadInfo(gameEntity.id) ?: return
+ downloadBtn.setOnClickListener {
+ DialogHelper.showDialog(
+ context,
+ "提示",
+ info.hintText,
+ "前往论坛",
+ "",
+ {
+ if (info.bbsId.isNotBlank()) {
+ if (info.topId.isNotBlank()) {
+ val data = hashMapOf(EntranceConsts.KEY_TOP_ID to info.topId)
+ PageSwitchDataHelper.pushCurrentPageData(data)
+ }
+ DirectUtils.directForumDetail(context, info.bbsId, entrance)
+ }
+ },
+ {},
+ DialogHelper.Config(
+ centerTitle = true,
+ centerContent = true
+ )
+ )
+ }
+ return
+ }
if (gameEntity.isReservable) {
if (!ReservationRepository.thisGameHasBeenReserved(gameEntity.id)) {
downloadBtn.setOnClickListener {
@@ -628,27 +669,17 @@ object DownloadItemUtils {
downloadBtn.setOnClickListener { view: View ->
allStateClickCallback?.onCallback()
clickCallback?.onCallback()
- RealNameHelper.checkIfAuth(view.context, gameEntity, object : EmptyCallback {
- override fun onCallback() {
- GamePermissionDialogFragment.show(context, gameEntity, gameEntity.info, object : ConfirmListener {
- override fun onConfirm() {
- PermissionHelper.checkStoragePermissionBeforeAction(context, object : EmptyCallback {
- override fun onCallback() {
- CertificationDialog.showCertificationDialog(context, gameEntity, object : ConfirmListener {
- override fun onConfirm() {
- DialogUtils.showVersionNumberDialog(context, gameEntity, object : ConfirmListener {
- override fun onConfirm() {
- DownloadDialog.showDownloadDialog(view.context, gameEntity, traceEvent, entrance, location)
- }
- })
- }
- })
- }
- })
- }
- })
- }
- })
+ GamePermissionDialogFragment.show(context, gameEntity, gameEntity.info) {
+ PermissionHelper.checkStoragePermissionBeforeAction(context, object : EmptyCallback {
+ override fun onCallback() {
+ CertificationDialog.showCertificationDialog(context, gameEntity) {
+ DialogUtils.showVersionNumberDialog(context, gameEntity) {
+ DownloadDialog.showDownloadDialog(view.context, gameEntity, traceEvent, entrance, location)
+ }
+ }
+ }
+ })
+ }
}
}
}
@@ -669,96 +700,69 @@ object DownloadItemUtils {
if (gameEntity.getApk().isEmpty()) return
val apk = gameEntity.getApk().safelyGetInRelease(0) ?: return
if (str == context.getString(R.string.download)) {
- // 先弹下载弹窗(如果需要的话)
- RealNameHelper.checkIfAuth(context, gameEntity, object : EmptyCallback {
- override fun onCallback() {
- GamePermissionDialogFragment.show((context as AppCompatActivity), gameEntity, gameEntity.info, object : ConfirmListener {
- override fun onConfirm() {
- BrowserInstallHelper.showBrowserInstallHintDialog(context, object : EmptyCallback {
+ GamePermissionDialogFragment.show((context as AppCompatActivity), gameEntity, gameEntity.info) {
+ BrowserInstallHelper.showBrowserInstallHintDialog(context, gameEntity.isVGame(), object : EmptyCallback {
+ override fun onCallback() {
+ PackageCheckDialogFragment.show(context, gameEntity) {
+ DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, object : EmptyCallback {
override fun onCallback() {
- PackageCheckDialogFragment.show(context, gameEntity, object : ConfirmListener {
- override fun onConfirm() {
- DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, object : EmptyCallback {
- override fun onCallback() {
- CertificationDialog.showCertificationDialog(context, gameEntity, object : ConfirmListener {
- override fun onConfirm() {
- DialogUtils.showOverseaDownloadDialog(context, gameEntity, object : ConfirmListener {
- override fun onConfirm() {
- DialogUtils.checkDownload(context, apk.size) { isSubscribe: Boolean ->
- download(
- context,
- gameEntity,
- downloadBtn,
- entrance,
- location,
- isSubscribe,
- traceEvent
- )
- }
- }
- })
- }
- })
- }
- })
+ CertificationDialog.showCertificationDialog(context, gameEntity) {
+ DialogUtils.showOverseaDownloadDialog(context, gameEntity) {
+ DialogUtils.checkDownload(context, apk.size) { isSubscribe: Boolean ->
+ download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent)
+ }
}
- })
+ }
}
})
-
}
- })
- }
- })
+ }
+ })
+ }
DataLogUtils.uploadGameLog(context, gameEntity.id, gameEntity.name, entrance)
} else if (str == context.getString(R.string.attempt)) {
- RealNameHelper.checkIfAuth(context, gameEntity, object : EmptyCallback {
- override fun onCallback() {
- GamePermissionDialogFragment.show((context as AppCompatActivity), gameEntity, gameEntity.info, object : ConfirmListener {
- override fun onConfirm() {
- BrowserInstallHelper.showBrowserInstallHintDialog(context, object : EmptyCallback {
+ GamePermissionDialogFragment.show((context as AppCompatActivity), gameEntity, gameEntity.info) {
+ BrowserInstallHelper.showBrowserInstallHintDialog(context, gameEntity.isVGame(), object : EmptyCallback {
+ override fun onCallback() {
+ PackageCheckDialogFragment.show(context, gameEntity) {
+ DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, object : EmptyCallback {
override fun onCallback() {
- PackageCheckDialogFragment.show(context, gameEntity, object : ConfirmListener {
- override fun onConfirm() {
- DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, object : EmptyCallback {
- override fun onCallback() {
- CertificationDialog.showCertificationDialog(context, gameEntity, object : ConfirmListener {
- override fun onConfirm() {
- DialogUtils.showVersionNumberDialog(context, gameEntity, object : ConfirmListener {
- override fun onConfirm() {
- DialogUtils.showOverseaDownloadDialog(
- context,
- gameEntity,
- object : ConfirmListener {
- override fun onConfirm() {
- DialogUtils.checkDownload(context, apk.size) { isSubscribe: Boolean ->
- download(
- context,
- gameEntity,
- downloadBtn,
- entrance,
- location,
- isSubscribe,
- traceEvent
- )
- }
- }
- })
- }
- })
- }
- })
+ CertificationDialog.showCertificationDialog(context, gameEntity) {
+ DialogUtils.showVersionNumberDialog(context, gameEntity) {
+ DialogUtils.showOverseaDownloadDialog(context, gameEntity) {
+ DialogUtils.checkDownload(context, apk.size) { isSubscribe: Boolean ->
+ download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent)
}
- })
+ }
}
- })
+ }
}
})
}
+ }
+ })
+ }
+ DataLogUtils.uploadGameLog(context, gameEntity.id, gameEntity.name, entrance)
+ } else if (str == context.getString(R.string.smooth)) {
+ GamePermissionDialogFragment.show((context as AppCompatActivity), gameEntity, gameEntity.info) {
+ PackageCheckDialogFragment.show(context, gameEntity) {
+ DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, object : EmptyCallback {
+ override fun onCallback() {
+ CertificationDialog.showCertificationDialog(context, gameEntity) {
+ DialogUtils.showVersionNumberDialog(context, gameEntity) {
+ DialogUtils.showOverseaDownloadDialog(context, gameEntity) {
+ VHelper.validateVSpaceBeforeAction(context, gameEntity, true) {
+ DialogUtils.checkDownload(context, apk.size) { isSubscribe: Boolean ->
+ download(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent)
+ }
+ }
+ }
+ }
+ }
+ }
})
}
- })
- DataLogUtils.uploadGameLog(context, gameEntity.id, gameEntity.name, entrance)
+ }
} else if (str.contains("化")) {
if (entrance.contains("我的游戏")) {
MtaHelper.onEvent("我的游戏_启动", "插件化", gameEntity.name)
@@ -768,13 +772,11 @@ object DownloadItemUtils {
} else {
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, object : EmptyCallback {
override fun onCallback() {
- CertificationDialog.showCertificationDialog(context, gameEntity, object : ConfirmListener {
- override fun onConfirm() {
- DialogUtils.checkDownload(context, apk.size) { isSubscribe: Boolean ->
- plugin(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent)
- }
+ CertificationDialog.showCertificationDialog(context, gameEntity) {
+ DialogUtils.checkDownload(context, apk.size) { isSubscribe: Boolean ->
+ plugin(context, gameEntity, downloadBtn, entrance, location, isSubscribe, traceEvent)
}
- })
+ }
}
})
}
@@ -790,8 +792,15 @@ object DownloadItemUtils {
return
}
}
- install(context, gameEntity, position, adapter, refreshCallback)
+
+ if (gameEntity.isVGame()) {
+ VHelper.installOrLaunch((context as AppCompatActivity), gameEntity.getUniquePackageName() ?: "")
+ } else {
+ install(context, gameEntity, position, adapter, refreshCallback)
+ }
} else if (str == context.getString(R.string.launch)) {
+ EnergyTaskHelper.postEnergyTask("play_game", gameEntity.id, gameEntity.getApk()[0].packageName)
+
//启动模拟器游戏
if (SimulatorGameManager.isSimulatorGame(gameEntity)) {
val downloadEntity = SimulatorGameManager.findDownloadEntityByUrl(gameEntity.getApk()[0].url)
@@ -805,15 +814,24 @@ object DownloadItemUtils {
}
return
}
+
+ if (gameEntity.isVGame()) {
+ VHelper.installOrLaunch((context as AppCompatActivity), gameEntity.getUniquePackageName() ?: "")
+ return
+ }
+
if (entrance.contains("我的游戏")) {
MtaHelper.onEvent("我的游戏_启动", "启动", gameEntity.name)
}
PackageUtils.launchApplicationByPackageName(context, gameEntity.getApk()[0].packageName)
- EnergyTaskHelper.postEnergyTask("play_game", gameEntity.id, gameEntity.getApk()[0].packageName)
} else if (str == context.getString(R.string.update)) {
if (entrance.contains("我的游戏")) {
MtaHelper.onEvent("我的游戏_启动", "更新", gameEntity.name)
}
+ if (gameEntity.isVGame()) {
+ VHelper.updateOrReDownload(gameEntity)
+ return
+ }
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apk, object : EmptyCallback {
override fun onCallback() {
DialogUtils.checkDownload(context, apk.size) { isSubscribe: Boolean ->
@@ -822,12 +840,16 @@ object DownloadItemUtils {
}
})
} else {
- context.startActivity(
- DownloadManagerActivity.getDownloadMangerIntent(
- context,
- apk.url, entrance + "+(" + location.split(":").toTypedArray()[0] + ")"
+ if (gameEntity.isVGame()) {
+ context.startActivity(VDownloadManagerActivity.getIntent(context, true))
+ } else {
+ context.startActivity(
+ DownloadManagerActivity.getDownloadMangerIntent(
+ context,
+ apk.url, entrance + "+(" + location.split(":").toTypedArray()[0] + ")"
+ )
)
- )
+ }
}
}
@@ -877,7 +899,7 @@ object DownloadItemUtils {
adapter: RecyclerView.Adapter?, refreshCallback: EmptyCallback?
) {
val apkEntity = gameEntity.getApk()[0]
- val downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshotByUrl(apkEntity.url)
+ val downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(gameEntity)
if (downloadEntity != null) {
val path = downloadEntity.path
when {
diff --git a/app/src/main/java/com/gh/common/util/DownloadNotificationHelper.kt b/app/src/main/java/com/gh/common/util/DownloadNotificationHelper.kt
index af208da26f..1dc3edfc91 100644
--- a/app/src/main/java/com/gh/common/util/DownloadNotificationHelper.kt
+++ b/app/src/main/java/com/gh/common/util/DownloadNotificationHelper.kt
@@ -8,17 +8,14 @@ import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.core.app.NotificationCompat
-import com.gh.gamecenter.core.AppExecutor
-import com.gh.gamecenter.common.constant.Constants
import com.gh.common.xapk.XapkInstaller
import com.gh.common.xapk.XapkUnzipStatus
import com.gh.gamecenter.R
+import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
-import com.gh.gamecenter.common.utils.getMetaExtra
-import com.gh.gamecenter.common.utils.isSimulatorGame
-import com.gh.gamecenter.common.utils.toJson
-import com.gh.gamecenter.common.utils.tryCatchInRelease
-import com.gh.gamecenter.core.utils.*
+import com.gh.gamecenter.common.utils.*
+import com.gh.gamecenter.core.AppExecutor
+import com.gh.gamecenter.core.utils.SpeedUtils
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus
@@ -34,6 +31,7 @@ object DownloadNotificationHelper {
const val ACTION_INSTALL = "com.gh.gamecenter.INSTALL"
const val ACTION_DOWNLOAD = "com.gh.gamecenter.DOWNLOAD"
+ const val ACTION_VDOWNLOAD = "com.gh.gamecenter.VDOWNLOAD"
private val mNotifyMap: MutableMap = mutableMapOf()
private val mShouldUseAlternativeNotificationIcon by lazy { RomIdentifier.getRom().versionName == null }
@@ -58,6 +56,8 @@ object DownloadNotificationHelper {
intent.putExtra(EntranceConsts.KEY_DATA, entity.toJson())
intent.putExtra(EntranceConsts.KEY_PATH, entity.path)
intent.action = ACTION_INSTALL
+ } else if (entity.isVGame()) {
+ intent.action = ACTION_VDOWNLOAD
} else {
intent.action = ACTION_DOWNLOAD
}
@@ -119,6 +119,7 @@ object DownloadNotificationHelper {
|| entity.status == DownloadStatus.hijack
|| entity.status == DownloadStatus.unqualified
|| entity.status == DownloadStatus.unavailable
+ || entity.status == DownloadStatus.banned
|| entity.status == DownloadStatus.uncertificated
|| entity.status == DownloadStatus.notfound
|| entity.status == DownloadStatus.overflow
diff --git a/app/src/main/java/com/gh/common/util/DownloadObserver.kt b/app/src/main/java/com/gh/common/util/DownloadObserver.kt
index f0c577ca65..8007d797f1 100644
--- a/app/src/main/java/com/gh/common/util/DownloadObserver.kt
+++ b/app/src/main/java/com/gh/common/util/DownloadObserver.kt
@@ -18,6 +18,7 @@ import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.GsonUtils
import com.gh.gamecenter.core.utils.MtaHelper
import com.gh.gamecenter.core.utils.StringUtils
+import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.entity.SimpleGameEntity
import com.gh.gamecenter.entity.SimulatorEntity
@@ -25,6 +26,7 @@ import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.setting.GameDownloadSettingFragment
import com.gh.gamecenter.suggest.SuggestType
+import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
@@ -115,14 +117,19 @@ object DownloadObserver {
downloadManager.cancel(downloadEntity.url)
} else if (DownloadStatus.unavailable == downloadEntity.status) {
// 未接入防沉迷系统
- val currentActivity = AppManager.getInstance().currentActivity() ?: return
+ val currentActivity = AppManager.getInstance().currentActivity()
- DialogHelper.showDialog(
- context = currentActivity,
- title = "温馨提示",
- content = "该游戏未接入防沉迷系统,暂不支持下载",
- confirmText = "知道了",
- cancelText = "")
+ if (currentActivity != null) {
+ DialogHelper.showDialog(
+ context = currentActivity,
+ title = "温馨提示",
+ content = "该游戏未接入防沉迷系统,暂不支持下载",
+ confirmText = "知道了",
+ cancelText = ""
+ )
+ } else {
+ ToastUtils.toast("该游戏未接入防沉迷系统,暂不支持下载")
+ }
// 删除任务
downloadEntity.status = DownloadStatus.cancel
@@ -131,6 +138,11 @@ object DownloadObserver {
// 未实名
RealNameHelper.showRealNameUncertificatedDialog(downloadEntity)
+ // 删除任务
+ downloadEntity.status = DownloadStatus.cancel
+ downloadManager.cancel(downloadEntity.url)
+ }else if (DownloadStatus.banned == downloadEntity.status) {
+ ToastUtils.showToast("网络异常")
// 删除任务
downloadEntity.status = DownloadStatus.cancel
downloadManager.cancel(downloadEntity.url)
@@ -210,10 +222,20 @@ object DownloadObserver {
)
)
downloadEntity.isPlugin -> Utils.toast(mApplication, downloadEntity.name + " - " + platform + " - 下载完成")
- else -> Utils.toast(mApplication, downloadEntity.name + " - 下载完成")
+ else -> {
+ if (downloadEntity.isVGame()) {
+ VHelper.showFloatingWindow(downloadEntity.packageName)
+ } else {
+ Utils.toast(mApplication, downloadEntity.name + " - 下载完成")
+ }
+ }
}
} else {
- Utils.toast(mApplication, downloadEntity.name + " - 下载完成")
+ if (downloadEntity.isVGame()) {
+ VHelper.showFloatingWindow(downloadEntity.packageName)
+ } else {
+ Utils.toast(mApplication, downloadEntity.name + " - 下载完成")
+ }
}
if (!downloadEntity.isPluggable) {
if (downloadEntity.isSimulatorGame()) {
@@ -244,7 +266,7 @@ object DownloadObserver {
Utils.toast(mApplication, R.string.install_failure_hint)
downloadManager.cancel(downloadEntity.url)
} else {
- if (PackageUtils.isCanLaunchSetup(mApplication, downloadEntity.path)) {
+ if (PackageUtils.isCanLaunchSetup(mApplication, downloadEntity.path) || downloadType == Constants.SMOOTH_GAME) {
downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES"
tryWithDefaultCatch {
PackageInstaller.install(mApplication, downloadEntity, false)
@@ -295,7 +317,7 @@ object DownloadObserver {
override fun onConfirm() {
val simulator = HaloApp.get(downloadEntity.name, true) as? SimulatorEntity
?: return
- DownloadManager.getInstance().cancel(downloadEntity.url, true, true)
+ DownloadManager.getInstance().cancel(downloadEntity.url, true, true, false)
SimulatorDownloadManager.getInstance()
.showDownloadDialog(currentActivity, simulator, SimulatorDownloadManager.SimulatorLocation.SIMULATOR_GAME)
}
@@ -308,12 +330,20 @@ object DownloadObserver {
private fun statDoneEvent(downloadEntity: DownloadEntity) {
var type: ExposureUtils.DownloadType
if (downloadEntity.isUpdate) {
- type = ExposureUtils.DownloadType.UPDATE
- if (downloadEntity.isPlugin) {
- type = ExposureUtils.DownloadType.PLUGIN_UPDATE
+ if (downloadEntity.isVGame()) {
+ type = ExposureUtils.DownloadType.FUN_UPDATE
+ } else {
+ type = ExposureUtils.DownloadType.UPDATE
+ if (downloadEntity.isPlugin) {
+ type = ExposureUtils.DownloadType.PLUGIN_UPDATE
+ }
}
} else {
- type = ExposureUtils.DownloadType.DOWNLOAD
+ type = if (downloadEntity.isVGame()) {
+ ExposureUtils.DownloadType.FUN_DOWNLOAD
+ } else {
+ ExposureUtils.DownloadType.DOWNLOAD
+ }
}
if (downloadEntity.isPluggable) {
diff --git a/app/src/main/java/com/gh/common/util/ErrorHelper.kt b/app/src/main/java/com/gh/common/util/ErrorHelper.kt
index 65456ed0f4..8448d49842 100644
--- a/app/src/main/java/com/gh/common/util/ErrorHelper.kt
+++ b/app/src/main/java/com/gh/common/util/ErrorHelper.kt
@@ -1,13 +1,26 @@
package com.gh.common.util
+import android.app.Activity
import android.content.Context
+import android.content.Intent
+import android.view.View
+import android.view.ViewGroup
+import androidx.appcompat.app.AppCompatActivity
import com.gh.common.constant.Config
import com.gh.gamecenter.R
+import com.gh.gamecenter.ShellActivity
import com.gh.gamecenter.WebActivity
+import com.gh.gamecenter.common.avoidcallback.AvoidOnResultManager
+import com.gh.gamecenter.common.avoidcallback.Callback
+import com.gh.gamecenter.common.callback.ConfirmListener
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.DialogHelper
+import com.gh.gamecenter.common.utils.dip2px
+import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.utils.toObject
import com.gh.gamecenter.entity.ErrorEntity
+import com.halo.assistant.fragment.user.UserInfoEditFragment
+import com.lightgame.utils.AppManager
import com.lightgame.utils.Utils
import retrofit2.HttpException
@@ -26,6 +39,7 @@ object ErrorHelper {
context: Context,
errorString: String?,
showHighPriorityHint: Boolean = false,
+ realNameConfirmListener: ConfirmListener? = null,
customizedHandler: (code: Int) -> Boolean
) {
val errorEntity = errorString?.toObject()
@@ -44,14 +58,14 @@ object ErrorHelper {
return
}
- handleError(context, showHighPriorityHint, errorEntity)
+ handleError(context, showHighPriorityHint, errorEntity, realNameConfirmListener)
}
/**
* [showHighPriorityHint] 用来标识有同样错误码可以触发两种处理时,为 true 时选择重要的
*/
@JvmStatic
- fun handleError(context: Context, errorString: String?, showHighPriorityHint: Boolean = false) {
+ fun handleError(context: Context, errorString: String?, showHighPriorityHint: Boolean = false, realNameConfirmListener: ConfirmListener? = null) {
val errorEntity = errorString?.toObject()
if (errorEntity == null) {
@@ -64,7 +78,7 @@ object ErrorHelper {
return
}
- handleError(context, showHighPriorityHint, errorEntity)
+ handleError(context, showHighPriorityHint, errorEntity, realNameConfirmListener)
}
/***
@@ -87,7 +101,8 @@ object ErrorHelper {
private fun handleError(
context: Context,
showHighPriorityHint: Boolean = false,
- errorEntity: ErrorEntity
+ errorEntity: ErrorEntity,
+ realNameConfirmListener: ConfirmListener? = null
) {
when (errorEntity.code) {
403050,
@@ -163,6 +178,48 @@ object ErrorHelper {
400802 -> {
// 多设备登录同一帐号,不需要这里处理
}
+
+ 403209 -> {
+ DialogHelper.showDialog(
+ context,
+ "实名提醒",
+ errorEntity.data?.title ?: "",
+ "前往实名认证", "以后再说",
+ uiModificationCallback = { binding ->
+ binding.hintTv.visibility = View.VISIBLE
+ binding.hintTv.layoutParams =
+ (binding.hintTv.layoutParams as ViewGroup.MarginLayoutParams).apply { setMargins(0, 8F.dip2px(), 0, 0) }
+ binding.lineView.layoutParams =
+ (binding.lineView.layoutParams as ViewGroup.MarginLayoutParams).apply { setMargins(0, 23F.dip2px(), 0, 0) }
+ binding.hintTv.text = errorEntity.data?.text
+ binding.hintTv.setTextColor(R.color.theme_font.toColor(context))
+ binding.hintTv.setOnClickListener {
+ errorEntity.data?.toLinkEntity()?.let { entity ->
+ DirectUtils.directToLinkPage(context, entity, "实名提醒弹窗", "")
+ }
+ }
+ },
+ confirmClickCallback = {
+ val currentActivity = AppManager.getInstance().currentActivity() ?: return@showDialog
+ AvoidOnResultManager.getInstance(currentActivity as AppCompatActivity)
+ .startForResult(
+ ShellActivity.getIntent(
+ context,
+ ShellActivity.Type.REAL_NAME_INFO,
+ ), object : Callback {
+ override fun onActivityResult(resultCode: Int, data: Intent?) {
+ if (resultCode == Activity.RESULT_OK && data != null) {
+ val isAuthSuccess =
+ data.getBooleanExtra(UserInfoEditFragment.AUTH_SUCCESS, false)
+ if (isAuthSuccess) {
+ realNameConfirmListener?.onConfirm()
+ }
+ }
+ }
+ })
+ }
+ )
+ }
else -> Utils.toast(context, R.string.post_failure_hint)
}
}
@@ -248,6 +305,9 @@ object ErrorHelper {
errorEntity?.code == 403099 -> {
Utils.toast(context, "当前账号正在注销,禁止登录")
}
+ errorEntity?.code == 403401 -> {//禁止登录
+ Utils.toast(context, "网络异常")
+ }
errorEntity?.toast?.isNotEmpty() == true -> {
Utils.toast(context, errorEntity.toast)
}
diff --git a/app/src/main/java/com/gh/common/util/GameActivityDownloadHelper.kt b/app/src/main/java/com/gh/common/util/GameActivityDownloadHelper.kt
index ff45a0a046..b889ef6919 100644
--- a/app/src/main/java/com/gh/common/util/GameActivityDownloadHelper.kt
+++ b/app/src/main/java/com/gh/common/util/GameActivityDownloadHelper.kt
@@ -5,7 +5,6 @@ import android.content.Context
import android.text.TextUtils
import androidx.appcompat.app.AppCompatActivity
import com.gh.common.DefaultJsApi
-import com.gh.gamecenter.common.constant.Constants
import com.gh.common.dialog.CertificationDialog
import com.gh.common.exposure.ExposureEvent
import com.gh.common.exposure.ExposureManager
@@ -13,28 +12,31 @@ import com.gh.common.exposure.ExposureSource
import com.gh.common.exposure.ExposureType
import com.gh.common.history.HistoryHelper
import com.gh.common.repository.ReservationRepository
-import com.gh.gamecenter.core.runOnUiThread
-import com.gh.gamecenter.common.view.dsbridge.CompletionHandler
import com.gh.download.DownloadManager
import com.gh.download.dialog.DownloadDialog
import com.gh.gamecenter.R
import com.gh.gamecenter.WebActivity
-import com.gh.gamecenter.common.callback.ConfirmListener
+import com.gh.gamecenter.common.constant.Constants
+import com.gh.gamecenter.common.retrofit.ApiResponse
+import com.gh.gamecenter.common.retrofit.EmptyResponse
+import com.gh.gamecenter.common.retrofit.Response
+import com.gh.gamecenter.common.utils.DataLogUtils
+import com.gh.gamecenter.common.utils.DialogHelper
import com.gh.gamecenter.common.utils.observableToMain
import com.gh.gamecenter.common.utils.singleToMain
-import com.gh.gamecenter.common.utils.DialogHelper
-import com.gh.gamecenter.core.utils.*
+import com.gh.gamecenter.common.view.dsbridge.CompletionHandler
+import com.gh.gamecenter.core.runOnUiThread
+import com.gh.gamecenter.core.utils.EmptyCallback
+import com.gh.gamecenter.core.utils.SPUtils
+import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.entity.ApkEntity
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.entity.PluginLocation
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment
import com.gh.gamecenter.manager.UserManager
-import com.gh.gamecenter.common.retrofit.EmptyResponse
-import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.teenagermode.TeenagerModeActivity
-import com.gh.gamecenter.common.retrofit.ApiResponse
-import com.gh.gamecenter.common.utils.DataLogUtils
+import com.gh.vspace.VHelper
import com.lightgame.download.FileUtils
/**
@@ -165,52 +167,39 @@ object GameActivityDownloadHelper {
traceEvent: ExposureEvent
) {
val apk = getApk(gameEntity, event, true) ?: return
- val downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshotByUrl(apk.url)
+ val downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(gameEntity)
if (downloadEntity != null) {
ToastUtils.toast("${gameEntity.name}已加入下载队列")
} else {
val str = GameUtils.getDownloadBtnText(context, gameEntity, PluginLocation.only_game)
- if (str == context.getString(R.string.download)) {
- GamePermissionDialogFragment.show((context as AppCompatActivity), gameEntity, gameEntity.info, object : ConfirmListener {
- override fun onConfirm() {
- CertificationDialog.showCertificationDialog(context, gameEntity, object : ConfirmListener {
- override fun onConfirm() {
- DialogUtils.checkDownload(context, apk.size) { isSubscribe: Boolean ->
- download(context, gameEntity, apk, isSubscribe, entrance, location, traceEvent)
- }
- }
- })
+ if (str == context.getString(R.string.download) || str == context.getString(R.string.attempt)) {
+ GamePermissionDialogFragment.show((context as AppCompatActivity), gameEntity, gameEntity.info) {
+ CertificationDialog.showCertificationDialog(context, gameEntity) {
+ DialogUtils.checkDownload(context, apk.size) { isSubscribe: Boolean ->
+ download(context, gameEntity, apk, isSubscribe, entrance, location, traceEvent)
+ }
}
- })
+ }
DataLogUtils.uploadGameLog(context, gameEntity.id, gameEntity.name, entrance)
- } else if (str == context.getString(R.string.attempt)) {
- RealNameHelper.checkIfAuth(context, gameEntity, object : EmptyCallback {
- override fun onCallback() {
- GamePermissionDialogFragment.show((context as AppCompatActivity), gameEntity, gameEntity.info, object : ConfirmListener {
- override fun onConfirm() {
- CertificationDialog.showCertificationDialog(context, gameEntity, object : ConfirmListener {
- override fun onConfirm() {
- DialogUtils.checkDownload(context, apk.size) { isSubscribe: Boolean ->
- download(context, gameEntity, apk, isSubscribe, entrance, location, traceEvent)
- }
- }
- })
+ } else if (str == context.getString(R.string.smooth)) {
+ VHelper.validateVSpaceBeforeAction(context, gameEntity, true) {
+ GamePermissionDialogFragment.show((context as AppCompatActivity), gameEntity, gameEntity.info) {
+ CertificationDialog.showCertificationDialog(context, gameEntity) {
+ DialogUtils.checkDownload(context, apk.size) { isSubscribe: Boolean ->
+ download(context, gameEntity, apk, isSubscribe, entrance, location, traceEvent)
}
- })
+ }
}
- })
- DataLogUtils.uploadGameLog(context, gameEntity.id, gameEntity.name, entrance)
+ }
} else if (str.contains("化")) {
if (gameEntity.pluggableCollection != null) {
DownloadDialog.showDownloadDialog(context, gameEntity, traceEvent, entrance, location)
} else {
- CertificationDialog.showCertificationDialog(context, gameEntity, object : ConfirmListener {
- override fun onConfirm() {
- DialogUtils.checkDownload(context, apk.size) { isSubscribe: Boolean ->
- plugin(context, gameEntity, apk, entrance, location, isSubscribe, traceEvent)
- }
+ CertificationDialog.showCertificationDialog(context, gameEntity) {
+ DialogUtils.checkDownload(context, apk.size) { isSubscribe: Boolean ->
+ plugin(context, gameEntity, apk, entrance, location, isSubscribe, traceEvent)
}
- })
+ }
}
} else if (str == context.getString(R.string.install) || str == context.getString(R.string.launch)) {
ToastUtils.toast("${gameEntity.name}已加入下载队列")
@@ -275,11 +264,8 @@ object GameActivityDownloadHelper {
) {
val msg = FileUtils.isCanDownload(context, apk.size)
if (TextUtils.isEmpty(msg)) {
- DownloadManager.createDownload(
- context, apk, gameEntity, context.getString(
- R.string.download
- ), entrance, location, isSubscribe, traceEvent
- )
+ DownloadManager.createDownload(context, apk, gameEntity, context.getString(
+ R.string.download), entrance, location, isSubscribe, traceEvent)
ToastUtils.toast("${gameEntity.name}已加入下载队列")
} else {
ToastUtils.toast(msg)
@@ -383,8 +369,7 @@ object GameActivityDownloadHelper {
if (PackageUtils.isInstalled(context, apk.packageName)) {
// 是否可更新
if (PackageUtils.isCanUpdate(apk, event.gameId)
- || PackageUtils.isNonPluginUpdatable(apk, gameEntity)
- ) {
+ || PackageUtils.isNonPluginUpdatable(apk, gameEntity)) {
handler.complete(false)
} else {
// 已安装且无更新
diff --git a/app/src/main/java/com/gh/common/util/GameUtils.java b/app/src/main/java/com/gh/common/util/GameUtils.java
index 0593b34e7c..ef51cfa23c 100644
--- a/app/src/main/java/com/gh/common/util/GameUtils.java
+++ b/app/src/main/java/com/gh/common/util/GameUtils.java
@@ -18,6 +18,7 @@ import com.gh.gamecenter.entity.GameUpdateEntity;
import com.gh.gamecenter.entity.PluginLocation;
import com.gh.gamecenter.entity.SettingsEntity;
import com.gh.gamecenter.manager.PackagesManager;
+import com.gh.vspace.VHelper;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.DownloadStatus;
@@ -59,7 +60,6 @@ public class GameUtils {
AppExecutor.getLightWeightIoExecutor().execute(() -> {
String status = getDownloadBtnText(context, gameEntity, pluginLocation);
AppExecutor.getUiExecutor().execute(() -> {
- // TODO 切换线程时可能存在页面已销毁 view 已不存在这些乱七八糟的问题
downloadBtn.setTextColor(Color.WHITE);
downloadBtn.setText(status);
if (context.getString(R.string.pluggable).equals(status)) {
@@ -90,7 +90,7 @@ public class GameUtils {
boolean isRelatedEmulatorInstalled = false; // 若该游戏是模拟器游戏时其对应的模拟器是否已经安装
- DownloadEntity downloadEntity;
+ DownloadEntity downloadEntity = null;
Object gh_id;
apkFor:
for (ApkEntity apkEntity : gameEntity.getApk()) {
@@ -105,7 +105,13 @@ public class GameUtils {
}
}
- downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshotByUrl(apkEntity.getUrl());
+ downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(gameEntity);
+
+ // 在下载管理找不到下载实体,并且为畅玩游戏的时候到畅玩数据库里找
+ if (downloadEntity == null && gameEntity.isVGame()) {
+ downloadEntity = VHelper.getDownloadEntitySnapshot(gameEntity.getId(), apkEntity.getPackageName());
+ }
+
if (downloadEntity != null) {
if (downloadEntity.getStatus().equals(DownloadStatus.done)) {
doneCount++;
@@ -149,6 +155,19 @@ public class GameUtils {
return context.getString(R.string.launch);
}
+ if (gameEntity.isVGame()) {
+ // 如果 doneCount 为 0 或者数据库为空
+ // 表明本地并没有此游戏的数据库数据,需要重新下载
+ if (doneCount == 0
+ || downloadEntity == null
+ || !VHelper.isInstalled(downloadEntity.getPackageName())) {
+ installCount = 0;
+ } else {
+ doneCount = 0;
+ installCount = 1;
+ }
+ }
+
if (doneCount != 0) {
return context.getString(R.string.install);
} else if (pluginCount != 0 && !SimulatorGameManager.isSimulatorGame(gameEntity)) {
@@ -160,50 +179,11 @@ public class GameUtils {
} else if ("demo".equals(gameEntity.getDownloadStatus())) {
return context.getString(R.string.attempt);
} else {
- return context.getString(R.string.download);
- }
- }
-
- /**
- * 获取简单的下载按钮文案,只需要知道是否已下载,是否已安装
- */
- public static String getSimpleDownloadBtnText(Context context, GameEntity gameEntity) {
- int doneCount = 0; // 下载完成数量
- int installCount = 0; // 已安装数量
-
- DownloadEntity downloadEntity;
- Object gh_id;
- apkFor:
- for (ApkEntity apkEntity : gameEntity.getApk()) {
- // filter by packageName
- SettingsEntity settings = Config.getSettings();
- if (settings != null && gameEntity.getApk().size() > 1) {
- for (String pkgName : settings.getGameDownloadBlackList()) {
- if (pkgName.equals(apkEntity.getPackageName())) {
- continue apkFor;
- }
- }
+ if (gameEntity.isVGame()) {
+ return context.getString(R.string.smooth);
+ } else {
+ return context.getString(R.string.download);
}
-
- downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshotByUrl(apkEntity.getUrl());
- if (downloadEntity != null) {
- if (downloadEntity.getStatus().equals(DownloadStatus.done)) {
- doneCount++;
- }
- }
- if (PackagesManager.INSTANCE.isInstalled(apkEntity.getPackageName())) {
- gh_id = PackageUtils.getMetaData(context, apkEntity.getPackageName(), "gh_id");
- if (gh_id == null || gh_id.equals(gameEntity.getId())) {
- installCount++;
- }
- }
- }
- if (doneCount != 0) {
- return context.getString(R.string.install);
- } else if (installCount != 0) {
- return context.getString(R.string.launch);
- } else {
- return context.getString(R.string.download);
}
}
diff --git a/app/src/main/java/com/gh/common/util/NewFlatLogUtils.kt b/app/src/main/java/com/gh/common/util/NewFlatLogUtils.kt
index bc1c3494dd..9346fc4f1f 100644
--- a/app/src/main/java/com/gh/common/util/NewFlatLogUtils.kt
+++ b/app/src/main/java/com/gh/common/util/NewFlatLogUtils.kt
@@ -1,8 +1,10 @@
package com.gh.common.util
import com.gh.gamecenter.common.json.JsonObjectBuilder
+import com.gh.gamecenter.common.json.json
import com.gh.gamecenter.common.loghub.LoghubUtils
import com.lightgame.utils.Utils
+import org.json.JSONArray
import org.json.JSONObject
/**
@@ -25,4 +27,194 @@ object NewFlatLogUtils {
key to value
}
}
+
+ // 畅玩助手相关事件(下载弹窗展示事件/隐私政策点击事件/下载点击事件/授权弹窗展示事件/更新弹窗展示事件)
+ // 畅玩管理删除游戏弹窗展示事件/畅玩管理-畅玩广场入口点击事件/退出畅玩助手提示弹窗展示事件
+ @JvmStatic
+ fun logHaloFunEvent(event: String) {
+ val json = json {
+ "event" to event
+ parseAndPutMeta().invoke(this)
+ }
+ log(json, "event", false)
+ }
+
+ // 关联游戏跳转icon点击事件
+ @JvmStatic
+ fun logHaloFunGameDetailJumpClick(downloadStatus: String, gameId: String) {
+ val json = json {
+ "event" to "halo_fun_game_detail_jump_click"
+ "download_state" to downloadStatus
+ "game_id" to gameId
+ parseAndPutMeta().invoke(this)
+ }
+ log(json, "event", false)
+ }
+
+ // 下载完成提示条点击事件
+ @JvmStatic
+ fun logHaloFunDownloadCompleteTipClick(buttonType: String, gameId: String) {
+ val json = json {
+ "event" to "halo_fun_download_complete_tip_click"
+ "button_type" to buttonType
+ "game_id" to gameId
+ parseAndPutMeta().invoke(this)
+ }
+ log(json, "event", false)
+ }
+
+ // 畅玩助手更新弹窗点击事件
+ @JvmStatic
+ fun logHaloFunUpdateDialogClick(dialogType: String, buttonType: String) {
+ val json = json {
+ "event" to "halo_fun_update_dialog_click"
+ "dialog_type" to dialogType
+ "button_type" to buttonType
+ parseAndPutMeta().invoke(this)
+ }
+ log(json, "event", false)
+ }
+
+ // 畅玩管理展示事件
+ @JvmStatic
+ fun logHaloFunManageShow(entrance: String) {
+ val json = json {
+ "event" to "halo_fun_manage_show"
+ "entrance" to entrance
+ parseAndPutMeta().invoke(this)
+ }
+ log(json, "event", false)
+ }
+
+ // 畅玩管理-最近在玩板块展示管理事件
+ @JvmStatic
+ fun logHaloFunManageRecentGameSwitch(isOn: Boolean) {
+ val json = json {
+ "event" to "halo_fun_manage_recent_game_switch"
+ "is_on" to isOn
+ parseAndPutMeta().invoke(this)
+ }
+ log(json, "event", false)
+ }
+
+ // 畅玩管理删除游戏弹窗点击事件
+ @JvmStatic
+ fun logHaloFunManageGameDeleteDialogClick(buttonType: String, gamesArray: JSONArray) {
+ val json = json {
+ "event" to "halo_fun_manage_game_delete_dialog_click"
+ "button_type" to buttonType
+ "games_array" to gamesArray
+ parseAndPutMeta().invoke(this)
+ }
+ log(json, "event", false)
+ }
+
+ // 退出畅玩助手提示弹窗反馈收集事件
+ @JvmStatic
+ fun logHaloFunGameExitDialogSubmitClick(detail: String, typeTags: JSONArray) {
+ val json = json {
+ "event" to "halo_fun_game_exit_dialog_submit_click"
+ "detail" to detail
+ "type_tags" to typeTags
+ parseAndPutMeta().invoke(this)
+ }
+ log(json, "event", false)
+ }
+
+ // 搜索-点击热门标签
+ @JvmStatic
+ fun logSearchHotTagClick(
+ tag: String,
+ linkType: String,
+ linkId: String,
+ linkText: String
+ ) {
+ val json = json {
+ "event" to "search_click_hot_tag"
+ "tag" to tag
+ "link_type" to linkType
+ "link_id" to linkId
+ "link_text" to linkText
+ parseAndPutMeta().invoke(this)
+ }
+ log(json, "event", false)
+ }
+
+ //版块点击内容卡片
+ @JvmStatic
+ fun logBlockGameContentCardClick(
+ blockId: String,
+ blockName: String,
+ linkType: String,
+ linkId: String,
+ linkText: String
+ ) {
+ val json = json {
+ "event" to "block_game_content_card_click"
+ "block_id" to blockId
+ "block_name" to blockName
+ "link_type" to linkType
+ "link_id" to linkId
+ "link_text" to linkText
+ parseAndPutMeta().invoke(this)
+ }
+ log(json, "event", false)
+ }
+
+ //首页点击内容卡片
+ @JvmStatic
+ fun logHomeGameContentCardClick(
+ linkType: String,
+ linkId: String,
+ linkText: String
+ ) {
+ val json = json {
+ "event" to "home_game_content_card_click"
+ "link_type" to linkType
+ "link_id" to linkId
+ "link_text" to linkText
+ parseAndPutMeta().invoke(this)
+ }
+ log(json, "event", false)
+ }
+
+ //游戏详情点击内容卡片
+ @JvmStatic
+ fun logGameDetailGameContentCardClick(
+ title: String,
+ gameName: String,
+ gameId: String,
+ linkType: String,
+ linkId: String,
+ linkText: String
+ ) {
+ val json = json {
+ "event" to "game_detail_game_content_card_click"
+ "title" to title
+ "game_name" to gameName
+ "game_id" to gameId
+ "link_type" to linkType
+ "link_id" to linkId
+ "link_text" to linkText
+ parseAndPutMeta().invoke(this)
+ }
+ log(json, "event", false)
+ }
+
+ //浏览自定义栏目
+ @JvmStatic
+ fun logGameDetailColumnOrderingView(
+ title: String,
+ gameName: String,
+ gameId: String
+ ) {
+ val json = json {
+ "event" to "game_detail_column_ordering_view"
+ "title" to title
+ "game_name" to gameName
+ "game_id" to gameId
+ parseAndPutMeta().invoke(this)
+ }
+ log(json, "event", false)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/common/util/NewLogUtils.kt b/app/src/main/java/com/gh/common/util/NewLogUtils.kt
index da1aeb639d..9edaa3cff8 100644
--- a/app/src/main/java/com/gh/common/util/NewLogUtils.kt
+++ b/app/src/main/java/com/gh/common/util/NewLogUtils.kt
@@ -4,18 +4,18 @@ import android.annotation.SuppressLint
import com.gh.gamecenter.common.json.JsonObjectBuilder
import com.gh.gamecenter.common.json.json
import com.gh.gamecenter.common.loghub.LoghubUtils
+import com.gh.gamecenter.common.retrofit.EmptyResponse
import com.gh.gamecenter.common.tracker.Tracker
import com.gh.gamecenter.common.utils.toRequestBody
import com.gh.gamecenter.entity.QuoteCountEntity
import com.gh.gamecenter.entity.WechatConfigEntity
-import com.gh.gamecenter.common.retrofit.EmptyResponse
import com.gh.gamecenter.retrofit.RetrofitManager
import com.lightgame.utils.Utils
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
+import org.json.JSONArray
import org.json.JSONObject
-@Deprecated("新埋点请添加至 NewFlatLogUtils")
object NewLogUtils {
private fun log(jsonObject: JSONObject, logStore: String, uploadImmediately: Boolean) {
diff --git a/app/src/main/java/com/gh/common/util/PackageInstaller.kt b/app/src/main/java/com/gh/common/util/PackageInstaller.kt
index 7e86761029..42b3fb113c 100644
--- a/app/src/main/java/com/gh/common/util/PackageInstaller.kt
+++ b/app/src/main/java/com/gh/common/util/PackageInstaller.kt
@@ -13,15 +13,17 @@ import com.gh.common.xapk.XapkInstaller
import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.common.constant.Constants
+import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.DialogHelper
import com.gh.gamecenter.common.utils.getExtension
+import com.gh.gamecenter.common.utils.getMetaExtra
import com.gh.gamecenter.common.utils.toRequestBody
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.core.utils.MD5Utils
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.ToastUtils
-import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.retrofit.RetrofitManager
+import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
import com.lightgame.download.FileUtils
@@ -53,9 +55,15 @@ object PackageInstaller {
fun install(context: Context, downloadEntity: DownloadEntity, showUnzipToast: Boolean) {
val pkgPath = downloadEntity.path
val isXapk = XapkInstaller.XAPK_EXTENSION_NAME == pkgPath.getExtension()
+ val isSmoothGame = downloadEntity.getMetaExtra(Constants.SMOOTH_GAME) == "true"
val currentActivity = CurrentActivityHolder.getCurrentActivity() ?: return
+ if (isSmoothGame) {
+ VHelper.install(currentActivity, downloadEntity)
+ return
+ }
+
// TODO 此处可能遇到 activity 是 WXEntryActivity
// TODO 当 activity 全部出栈,但是应用还在下载游戏,下载完会唤不起安装!
if (currentActivity is AppCompatActivity && !currentActivity.isFinishing) {
@@ -88,7 +96,12 @@ object PackageInstaller {
* 除非你已经确定该文件一定是Apk
*/
@JvmStatic
- fun install(context: Context, isPluggin: Boolean = false, pkgPath: String) {
+ fun install(context: Context, isPluggin: Boolean = false, pkgPath: String?) {
+ if (pkgPath.isNullOrEmpty()) {
+ ToastUtils.toast("下载文件异常")
+ return
+ }
+
try {
// 判断是否需要使用浏览器来进行安装
if (BrowserInstallHelper.isUseBrowserToInstallEnabled()
diff --git a/app/src/main/java/com/gh/common/util/PackageUtils.java b/app/src/main/java/com/gh/common/util/PackageUtils.java
index 0b6332d43d..b053bab97f 100644
--- a/app/src/main/java/com/gh/common/util/PackageUtils.java
+++ b/app/src/main/java/com/gh/common/util/PackageUtils.java
@@ -22,13 +22,19 @@ import com.android.apksig.ApkVerifier;
import com.android.apksig.internal.apk.ApkSigningBlockUtilsLite;
import com.g00fy2.versioncompare.Version;
import com.gh.common.xapk.XapkInstaller;
+import com.gh.download.DownloadManager;
import com.gh.gamecenter.BuildConfig;
+import com.gh.gamecenter.common.constant.Constants;
+import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.core.utils.SentryHelper;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.GameEntity;
import com.gh.gamecenter.entity.GameUpdateEntity;
import com.gh.gamecenter.manager.PackagesManager;
+import com.gh.vspace.VHelper;
+import com.gh.vspace.db.VGameEntity;
import com.halo.assistant.HaloApp;
+import com.lightgame.download.DownloadEntity;
import com.lightgame.utils.Utils;
import net.dongliu.apk.parser.ApkFile;
@@ -107,8 +113,11 @@ public class PackageUtils {
// 是否需要显示更新
boolean shouldShowUpdate = apkEntity.getForce();
+ // 普通游戏根据本地是否有安装来确定是否 qualified,畅玩游戏直接进判断
+ boolean isUpdateQualified =
+ gameEntity.isVGame() || (!TextUtils.isEmpty(versionFromRequest) && !TextUtils.isEmpty(versionFromInstalledApp));
- if (shouldShowUpdate && !TextUtils.isEmpty(versionFromRequest) && !TextUtils.isEmpty(versionFromInstalledApp)) {
+ if (shouldShowUpdate && isUpdateQualified) {
// 根据版本判断是否需要更新
shouldShowUpdate = new Version(versionFromRequest).isHigherThan(versionFromInstalledApp);
@@ -118,11 +127,27 @@ public class PackageUtils {
shouldShowUpdate = versionCodeFromRequest > versionCodeFromInstalledApp;
}
+ // 畅玩游戏根据 md5 是否一致确定是否需要更新
+ if (gameEntity.isVGame()) {
+ VGameEntity vGameEntity = VHelper.getVGameSnapshot(gameEntity.getId(), apkEntity.getPackageName());
+ if (vGameEntity != null) {
+ String md5FromInstalledVGame = ExtensionsKt.getMetaExtra(vGameEntity.getDownloadEntity(), Constants.APK_MD5);
+ String md5FromRequest = apkEntity.getMd5();
+ apkEntity.setPlatform(VHelper.PLATFORM_V);
+
+ shouldShowUpdate = md5FromRequest != null && !md5FromRequest.equals(md5FromInstalledVGame);
+ } else {
+ shouldShowUpdate = false;
+ }
+ }
+
if (shouldShowUpdate) {
GameUpdateEntity updateEntity = new GameUpdateEntity();
updateEntity.setId(gameEntity.getId());
updateEntity.setName(gameEntity.getName());
updateEntity.setIcon(gameEntity.getIcon());
+ updateEntity.setRawIcon(gameEntity.getRawIcon());
+ updateEntity.setIconSubscript(gameEntity.getIconSubscript());
updateEntity.setPackageName(apkEntity.getPackageName());
updateEntity.setSize(apkEntity.getSize());
updateEntity.setVersion(apkEntity.getVersion());
@@ -130,6 +155,8 @@ public class PackageUtils {
updateEntity.setUrl(apkEntity.getUrl());
updateEntity.setPlatform(apkEntity.getPlatform());
updateEntity.setEtag(apkEntity.getEtag());
+ updateEntity.setMd5(apkEntity.getMd5());
+ updateEntity.setDownloadStatus(gameEntity.getDownloadStatus());
updateEntity.setBrief(gameEntity.getBrief());
updateEntity.setTagStyle(gameEntity.getTagStyle());
updateEntity.setIndexPlugin(gameEntity.getIndexPlugin());
@@ -472,8 +499,14 @@ public class PackageUtils {
* 注意:目测只对能启动的app有效(有桌面图标),对一些没有桌面图标的应用无效(参考应用:魅族游戏框架)
*/
public static boolean isInstalled(Context context, String packageName) {
- Intent intent = context.getApplicationContext().getPackageManager().getLaunchIntentForPackage(packageName);
- return intent != null;
+ try {
+ Intent intent = context.getApplicationContext().getPackageManager().getLaunchIntentForPackage(packageName);
+ return intent != null;
+ } catch (IllegalArgumentException exception) {
+ // 一些设备调用获取 intent 的时候会触发 Parcel.readException !
+ exception.printStackTrace();
+ return false;
+ }
}
public static boolean isInstalledFromAllPackage(Context context, String packageName) {
diff --git a/app/src/main/java/com/gh/common/util/PlatformUtils.java b/app/src/main/java/com/gh/common/util/PlatformUtils.java
index 1d5ccc7f4b..b80a7223dd 100644
--- a/app/src/main/java/com/gh/common/util/PlatformUtils.java
+++ b/app/src/main/java/com/gh/common/util/PlatformUtils.java
@@ -12,6 +12,7 @@ import com.gh.gamecenter.entity.PlatformEntity;
import com.gh.gamecenter.eventbus.EBReuse;
import com.gh.gamecenter.common.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
+import com.gh.vspace.VHelper;
import com.halo.assistant.HaloApp;
import com.lightgame.download.FileUtils;
@@ -186,6 +187,11 @@ public class PlatformUtils {
if ("".equals(platform) || "官方版".equals(platform)) {
return "官方版";
}
+
+ if (VHelper.PLATFORM_V.equals(platform)) {
+ return VHelper.PLATFORM_V;
+ }
+
String platformName = platformMap.get(platform);
if (TextUtils.isEmpty(platformName)) {
getPlatform();
diff --git a/app/src/main/java/com/gh/common/util/PostCommentUtils.java b/app/src/main/java/com/gh/common/util/PostCommentUtils.java
index 897bbe4b08..bc55a53b97 100644
--- a/app/src/main/java/com/gh/common/util/PostCommentUtils.java
+++ b/app/src/main/java/com/gh/common/util/PostCommentUtils.java
@@ -3,6 +3,7 @@ package com.gh.common.util;
import android.content.Context;
import android.os.Build;
import android.text.TextUtils;
+
import com.gh.gamecenter.R;
import com.gh.gamecenter.common.retrofit.JSONObjectResponse;
import com.gh.gamecenter.common.retrofit.Response;
@@ -10,7 +11,9 @@ import com.gh.gamecenter.entity.CommentEntity;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.lightgame.utils.Utils;
import com.walkud.rom.checker.RomIdentifier;
+
import org.json.JSONObject;
+
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
@@ -70,48 +73,8 @@ public class PostCommentUtils {
});
}
- public static void addAnswerComment(final String answerId, final String articleId,
- final String articleCommunityId, final String content,
- final CommentEntity commentEntity,
- final PostCommentListener listener) {
- RequestBody body = RequestBody.create(MediaType.parse("application/json"), content);
- Observable observable;
- if (!TextUtils.isEmpty(articleId)) {
- if (commentEntity != null) {
- observable = RetrofitManager.getInstance().getApi().postReplyToCommunityArticleComment(articleCommunityId,
- articleId, commentEntity.getId(), body);
- } else {
- observable = RetrofitManager.getInstance().getApi().postCommentToCommunityArticle(articleCommunityId, articleId, body);
- }
- } else {
- if (commentEntity != null) {
- observable = RetrofitManager.getInstance().getApi().postReplyToAnswerComment(answerId, commentEntity.getId(), body);
- } else {
- observable = RetrofitManager.getInstance().getApi().postNewCommentToAnswer(answerId, body);
- }
- }
- observable.subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(new Response() {
- @Override
- public void onResponse(ResponseBody response) {
- if (listener != null) {
- listener.postSuccess(new JSONObject());// 不需要返回
- }
- }
-
- @Override
- public void onFailure(HttpException e) {
- if (listener != null) {
- listener.postFailed(e);
- }
- }
- });
- }
-
public static void likeComment(final String answerId,
String articleId,
- String articleCommunityId,
String videoId,
String questionId,
final String commentId,
@@ -122,7 +85,7 @@ public class PostCommentUtils {
if (!TextUtils.isEmpty(answerId)) {
observable = RetrofitManager.getInstance().getApi().postVoteAnswerComment(answerId, commentId);
} else if (!TextUtils.isEmpty(articleId)) {
- observable = RetrofitManager.getInstance().getApi().postVoteCommunityArticleComment(articleCommunityId, articleId, commentId);
+ observable = RetrofitManager.getInstance().getApi().postVoteCommunityArticleComment(commentId);
} else if (!TextUtils.isEmpty(questionId)) {
observable = RetrofitManager.getInstance().getApi().postVoteQuestionComment(questionId, commentId);
} else {
@@ -159,8 +122,8 @@ public class PostCommentUtils {
if (!TextUtils.isEmpty(questionId)) {
observable = RetrofitManager.getInstance().getApi().postUnVoteQuestionComment(questionId, commentId);
- } else if (!TextUtils.isEmpty(articleCommunityId) && !TextUtils.isEmpty(articleId)) {
- observable = RetrofitManager.getInstance().getApi().postUnVoteArticleComment(articleCommunityId, articleId, commentId);
+ } else if (!TextUtils.isEmpty(articleId)) {
+ observable = RetrofitManager.getInstance().getApi().postUnVoteArticleComment(commentId);
} else {
observable = RetrofitManager.getInstance().getApi().postUnVoteVideoComment(videoId, commentId);
}
@@ -250,14 +213,12 @@ public class PostCommentUtils {
});
}
- public static void reportCommunityArticleComment(final String communityId,
- final String articleId,
- final String commentId,
+ public static void reportCommunityArticleComment(final String commentId,
final String reportData,
final PostCommentListener listener) {
RequestBody body = RequestBody.create(MediaType.parse("application/json"), reportData);
RetrofitManager.getInstance().getApi()
- .postCommunityArticleCommentReport(communityId, articleId, commentId, body)
+ .postCommunityArticleCommentReport(commentId, body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Response() {
diff --git a/app/src/main/java/com/gh/common/util/RealNameHelper.kt b/app/src/main/java/com/gh/common/util/RealNameHelper.kt
index 13239ee8cb..05720cc4aa 100644
--- a/app/src/main/java/com/gh/common/util/RealNameHelper.kt
+++ b/app/src/main/java/com/gh/common/util/RealNameHelper.kt
@@ -1,15 +1,12 @@
package com.gh.common.util
-import android.content.Context
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.download.DownloadManager
import com.gh.gamecenter.ShellActivity
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.DialogHelper
-import com.gh.gamecenter.core.utils.EmptyCallback
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.common.utils.getMetaExtra
-import com.gh.gamecenter.entity.GameEntity
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus
@@ -17,11 +14,6 @@ object RealNameHelper {
var pendingInstallPkgPath = ""
- @JvmStatic
- fun checkIfAuth(context: Context, gameEntity: GameEntity, callback: EmptyCallback) {
- callback.onCallback()
- }
-
/**
* 弹未成年人不能下载游戏弹窗
*/
diff --git a/app/src/main/java/com/gh/common/view/DownloadProgressBar.java b/app/src/main/java/com/gh/common/view/DownloadProgressBar.java
index 4acc1a178f..e9481040b0 100644
--- a/app/src/main/java/com/gh/common/view/DownloadProgressBar.java
+++ b/app/src/main/java/com/gh/common/view/DownloadProgressBar.java
@@ -41,6 +41,7 @@ public class DownloadProgressBar extends ProgressBar {
H5_GAME,
UPDATING,
TEENAGER_MODEL,
+ SPECIAL_DOWNLOAD,
XAPK_UNZIPPING,
XAPK_SUCCESS,
@@ -231,6 +232,7 @@ public class DownloadProgressBar extends ProgressBar {
mDefaultColor = ContextCompat.getColor(getContext(), R.color.white);
break;
case TEENAGER_MODEL:
+ case SPECIAL_DOWNLOAD:
setProgressDrawable(getResources().getDrawable(R.drawable.download_button_normal_style));
mDefaultColor = ContextCompat.getColor(getContext(), R.color.white);
break;
diff --git a/app/src/main/java/com/gh/common/view/GameIconView.kt b/app/src/main/java/com/gh/common/view/GameIconView.kt
index 459a69984b..75de6c5d99 100644
--- a/app/src/main/java/com/gh/common/view/GameIconView.kt
+++ b/app/src/main/java/com/gh/common/view/GameIconView.kt
@@ -10,12 +10,8 @@ import androidx.cardview.widget.CardView
import com.facebook.drawee.generic.RoundingParams
import com.facebook.drawee.view.SimpleDraweeView
import com.gh.gamecenter.R
-import com.gh.gamecenter.common.utils.dip2px
-import com.gh.gamecenter.common.utils.display
-import com.gh.gamecenter.common.utils.goneIf
-import com.gh.gamecenter.common.utils.toColor
+import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.DisplayUtils
-import com.gh.gamecenter.common.utils.ImageUtils
import com.gh.gamecenter.entity.GameEntity
import splitties.views.dsl.core.add
import splitties.views.dsl.core.lParams
@@ -52,11 +48,11 @@ class GameIconView : CardView {
fun initView(attrs: AttributeSet?) {
val gameIconUi = GameIconUi(context)
- if (attrs != null) {
+ if (attrs != null && !isInEditMode) {
val ta = context.obtainStyledAttributes(attrs, R.styleable.GameIconView)
mCornerRadius = ta.getDimensionPixelSize(
R.styleable.GameIconView_gameIconCornerRadius,
- DisplayUtils.dip2px(0F)
+ DisplayUtils.dip2px(context, 0F)
)
mBorderColor = ta.getColor(R.styleable.GameIconView_gameIconBorderColor, 0)
mGameIconOverlayColor = ta.getColor(R.styleable.GameIconView_gameIconOverlayColor, 0)
@@ -115,7 +111,12 @@ class GameIconView : CardView {
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
- val cornerRadius = getCornerRadius(w)
+ val cornerRadius = if (!isInEditMode) {
+ getCornerRadius(w)
+ } else {
+ 0F
+ }
+
radius = cornerRadius
cardElevation = 0F
diff --git a/app/src/main/java/com/gh/common/view/SimpleToggleView.kt b/app/src/main/java/com/gh/common/view/SimpleToggleView.kt
new file mode 100644
index 0000000000..68474e6ec3
--- /dev/null
+++ b/app/src/main/java/com/gh/common/view/SimpleToggleView.kt
@@ -0,0 +1,26 @@
+package com.gh.common.view
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.View
+import android.widget.TextView
+import androidx.constraintlayout.widget.ConstraintLayout
+import com.airbnb.lottie.LottieAnimationView
+import com.gh.gamecenter.R
+import com.lightgame.view.CheckableImageView
+
+class SimpleToggleView @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0
+) : ConstraintLayout(context, attrs, defStyleAttr) {
+
+ val switchIv by lazy { findViewById(R.id.switchIv) }
+ val hintTv by lazy { findViewById(R.id.hintTv) }
+ val lottieView by lazy { findViewById(R.id.lottieView)}
+
+ init {
+ View.inflate(context, R.layout.view_simple_toggle, this)
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/download/DownloadDataHelper.kt b/app/src/main/java/com/gh/download/DownloadDataHelper.kt
index 4e1a6b2649..5624883246 100644
--- a/app/src/main/java/com/gh/download/DownloadDataHelper.kt
+++ b/app/src/main/java/com/gh/download/DownloadDataHelper.kt
@@ -88,6 +88,8 @@ object DownloadDataHelper {
"未成年"
} else if (status == DownloadStatus.unavailable) {
"未接入防沉迷系统,暂不支持下载"
+ }else if (status == DownloadStatus.banned) {
+ "网络异常"
} else if (status == DownloadStatus.redirected) {
"重定向至最终地址"
} else {
diff --git a/app/src/main/java/com/gh/download/DownloadManager.java b/app/src/main/java/com/gh/download/DownloadManager.java
index e4e9fdb7a8..5435c8a09d 100644
--- a/app/src/main/java/com/gh/download/DownloadManager.java
+++ b/app/src/main/java/com/gh/download/DownloadManager.java
@@ -12,6 +12,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import androidx.collection.ArrayMap;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.core.AppExecutor;
@@ -67,7 +69,9 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
public class DownloadManager implements DownloadStatusListener {
@@ -81,20 +85,17 @@ public class DownloadManager implements DownloadStatusListener {
private final ArrayMap lastTimeMap;
private final ArrayMap> platformMap;
- private final ArrayMap> gameMap;
+ private final Map> gameMap;
private final ArrayMap statusMap;
private final ArrayMap downloadingMap;
- // 下载任务列表快照,非完全实时状态,只保证数量和基础状态,不保证下载进度和速度匹配
- // TODO 使用 mDownloadSnapshotList 来服务 getDownloadEntityByUrl
- // private final List mDownloadSnapshotList;
-
private ArrayList mInvisiblePendingTaskList; // 用户不可见的 pending 任务
-
private final DownloadDao mDownloadDao;
private final DownloadedGameIdAndPackageNameDao mDownloadedGameIdAndPackageNameDao;
+ private final MutableLiveData> mDownloadEntityListLiveData; // 下载任务变更 (主要还是数量变更) 的 LiveData
+
private final Set mUpdateMarks;
@Override
@@ -107,6 +108,8 @@ public class DownloadManager implements DownloadStatusListener {
DownloadManager.getInstance().putStatus(entity.getUrl(), DownloadStatus.delete);
downloadingMap.remove(entity.getUrl());
+
+ notifyDownloadLiveDataChanged();
}
@Override
@@ -117,6 +120,8 @@ public class DownloadManager implements DownloadStatusListener {
downloadingMap.put(entity.getUrl(), entity);
DownloadWorkManager.addWorker();
+
+ notifyDownloadLiveDataChanged();
}
@Override
@@ -125,6 +130,8 @@ public class DownloadManager implements DownloadStatusListener {
if (entity.getStatus() != DownloadStatus.overflow) {
downloadingMap.remove(entity.getUrl());
}
+
+ notifyDownloadLiveDataChanged();
}
@Override
@@ -142,6 +149,8 @@ public class DownloadManager implements DownloadStatusListener {
if (downloadingMap.isEmpty()) {
DownloadWorkManager.cancelWorker();
}
+
+ notifyDownloadLiveDataChanged();
}
@Override
@@ -153,6 +162,7 @@ public class DownloadManager implements DownloadStatusListener {
mContext = HaloApp.getInstance().getApplicationContext();
mDownloadDao = DownloadDao.getInstance(mContext);
mDownloadedGameIdAndPackageNameDao = new DownloadedGameIdAndPackageNameDao();
+ mDownloadEntityListLiveData = new MutableLiveData<>();
mUpdateMarks = SPUtils.getStringSet(UPDATE_IS_READ_MARK);
@@ -165,7 +175,7 @@ public class DownloadManager implements DownloadStatusListener {
lastTimeMap = new ArrayMap<>();
platformMap = new ArrayMap<>();
- gameMap = new ArrayMap<>();
+ gameMap = new ConcurrentHashMap<>();
statusMap = new ArrayMap<>();
downloadingMap = new ArrayMap<>();
// mDownloadSnapshotList = new ArrayList<>();
@@ -309,6 +319,7 @@ public class DownloadManager implements DownloadStatusListener {
downloadEntity.setEntrance(entrance);
downloadEntity.setLocation(location);
downloadEntity.setVersionName(apkEntity.getVersion());
+ ExtensionsKt.addMetaExtra(downloadEntity, Constants.APK_MD5, apkEntity.getMd5());
ExtensionsKt.addMetaExtra(downloadEntity, Constants.DOWNLOAD_ID, downloadId);
ExtensionsKt.addMetaExtra(downloadEntity, Constants.RAW_GAME_ICON, gameEntity.getRawIcon());
ExtensionsKt.addMetaExtra(downloadEntity, Constants.GAME_ICON_SUBSCRIPT, gameEntity.getIconSubscript());
@@ -319,6 +330,12 @@ public class DownloadManager implements DownloadStatusListener {
ExtensionsKt.addMetaExtra(downloadEntity, Constants.SIMULATOR, GsonUtils.toJson(gameEntity.getSimulator()));
}
+ if (gameEntity.isVGame()) {
+ ExtensionsKt.addMetaExtra(downloadEntity, Constants.SMOOTH_GAME, "true");
+ ExtensionsKt.addMetaExtra(downloadEntity, Constants.EXTRA_DOWNLOAD_TYPE, Constants.SMOOTH_GAME);
+ ExtensionsKt.addMetaExtra(downloadEntity, DownloadConfig.KEY_PROGRESS_CALLBACK_INTERVAL, "200");
+ }
+
HashMap map = PageSwitchDataHelper.popLastPageData();
if (map != null && map.containsKey(PageSwitchDataHelper.PAGE_GAME_DETAIL_RECOMMEND)) {
ExtensionsKt.addMetaExtra(downloadEntity, PageSwitchDataHelper.PAGE_GAME_DETAIL_RECOMMEND, "true");
@@ -342,7 +359,7 @@ public class DownloadManager implements DownloadStatusListener {
downloadEntity.setPlugin(!TextUtils.isEmpty(apkEntity.getGhVersion()));
- ExposureUtils.DownloadType downloadType = ExposureUtils.getDownloadType(apkEntity, gameEntity.getId());
+ ExposureUtils.DownloadType downloadType = ExposureUtils.getDownloadType(apkEntity, gameEntity.getId(), gameEntity.isVGame());
gameEntity.setIsPlatformRecommend(apkEntity.getRecommend() != null);
ExposureEvent downloadExposureEvent = ExposureUtils.logADownloadExposureEvent(gameEntity, apkEntity.getPlatform(), traceEvent, downloadType);
@@ -531,15 +548,61 @@ public class DownloadManager implements DownloadStatusListener {
}
/**
- * 根据 url 获取下载任务 (仅保证下载状态一致)
+ * 获取所有的下载任务快照
+ *
+ * @return 下载任务快照列表
+ */
+ @NonNull
+ private ArrayList getAllDownloadEntitySnapshots() {
+ return mDownloadDao.getAllSnapshots();
+ }
+
+ /**
+ * 获取快照
+ *
+ * @param gameEntity 游戏实体
+ */
+ @Nullable
+ public DownloadEntity getDownloadEntitySnapshot(GameEntity gameEntity) {
+ if (gameEntity == null || gameEntity.getApk().size() == 0) return null;
+ return getDownloadEntitySnapshot(gameEntity.getApk().get(0).getUrl(), gameEntity.getId(), gameEntity.isVGame());
+ }
+
+ /**
+ * 获取快照
+ *
+ * 畅玩游戏优先根据游戏 ID 获取,非畅玩游戏根据 url 获取
*
* @param url 下载链接
+ * @param isVGame 是不是畅玩游戏
+ * @param gameId 游戏 ID
* @return null表示下载列表中不存在该任务,否则返回下载任务
*/
@Nullable
- public DownloadEntity getDownloadEntitySnapshotByUrl(String url) {
- if (TextUtils.isEmpty(url)) return null;
- return mDownloadDao.getSnapshot(url);
+ private DownloadEntity getDownloadEntitySnapshot(String url, String gameId, boolean isVGame) {
+ DownloadEntity snapshot = null;
+
+ if (isVGame && !TextUtils.isEmpty(gameId)) {
+ snapshot = mDownloadDao.getSnapshotByGameId(gameId);
+ }
+
+ if (snapshot == null && !TextUtils.isEmpty(url)) {
+ snapshot = mDownloadDao.getSnapshot(url);
+ }
+
+ return snapshot;
+ }
+
+ /**
+ * 根据 url 获取下载任务快照 (仅保证下载状态一致)
+ *
+ * @param packageName 包名 (多包名一样时取第一个,若使用场景里有多包名,请使用 url 获取下载任务)
+ * @return null 表示下载列表中不存在该任务,否则返回下载任务
+ */
+ @Nullable
+ public DownloadEntity getDownloadEntitySnapshotByPackageName(String packageName) {
+ if (TextUtils.isEmpty(packageName)) return null;
+ return mDownloadDao.getSnapshotByPackageName(packageName);
}
/**
@@ -587,8 +650,8 @@ public class DownloadManager implements DownloadStatusListener {
public void initGameMap() {
gameMap.clear();
- List list = getAllDownloadEntity();
- if (list != null && list.size() != 0) {
+ List list = getAllDownloadEntitySnapshots();
+ if (list.size() != 0) {
String name;
for (DownloadEntity downloadEntity : list) {
name = downloadEntity.getName();
@@ -623,13 +686,30 @@ public class DownloadManager implements DownloadStatusListener {
}
/**
- * 获取所有下载列表中的任务排除静默更新
+ * 获取下载列表中除静默下载、模拟器下载、畅玩下载以外的任务
*/
- public List getAllDownloadEntityExcludeSilentUpdate() {
+ public List getAllDownloadEntityExcludeSilentTask() {
List all = getAllDownloadEntity();
return filterSilentDownloadTask(all);
}
+ /**
+ * 获取下载列表中的畅玩下载任务快照
+ */
+ public ArrayList getAllVDownloadTaskSnapshots() {
+ List downloadList = getAllDownloadEntitySnapshots();
+
+ ArrayList filteredDownloadEntityList = new ArrayList<>();
+
+ for (DownloadEntity downloadEntity : downloadList) {
+ if (Constants.SMOOTH_GAME.equals(ExtensionsKt.getMetaExtra(downloadEntity, Constants.EXTRA_DOWNLOAD_TYPE))) {
+ filteredDownloadEntityList.add(downloadEntity);
+ }
+ }
+
+ return filteredDownloadEntityList;
+ }
+
private ArrayList filterSilentDownloadTask(List downloadEntityList) {
ArrayList filteredDownloadEntityList = new ArrayList<>();
@@ -637,9 +717,10 @@ public class DownloadManager implements DownloadStatusListener {
for (DownloadEntity downloadEntity : downloadEntityList) {
if (!ExtensionsKt.isSimulatorGame(downloadEntity)) {
- if (!Constants.SILENT_UPDATE.equals(ExtensionsKt.getMetaExtra(downloadEntity, Constants.EXTRA_DOWNLOAD_TYPE)) &&
- !Constants.SIMULATOR_DOWNLOAD.equals(ExtensionsKt.getMetaExtra(downloadEntity, Constants.EXTRA_DOWNLOAD_TYPE))) {
-
+ if (!Constants.SILENT_UPDATE.equals(ExtensionsKt.getMetaExtra(downloadEntity, Constants.EXTRA_DOWNLOAD_TYPE))
+ && !Constants.SIMULATOR_DOWNLOAD.equals(ExtensionsKt.getMetaExtra(downloadEntity, Constants.EXTRA_DOWNLOAD_TYPE))
+ && !Constants.SMOOTH_GAME.equals(ExtensionsKt.getMetaExtra(downloadEntity, Constants.EXTRA_DOWNLOAD_TYPE))
+ ) {
filteredDownloadEntityList.add(downloadEntity);
}
} else {
@@ -647,7 +728,6 @@ public class DownloadManager implements DownloadStatusListener {
filteredDownloadEntityList.add(downloadEntity);
}
}
-
}
return filteredDownloadEntityList;
@@ -677,7 +757,7 @@ public class DownloadManager implements DownloadStatusListener {
* 根据url取消下载,并删除已下载的文件
*/
public void cancel(String url) {
- cancel(url, true, false);
+ cancel(url, true, false, false);
}
/**
@@ -685,8 +765,8 @@ public class DownloadManager implements DownloadStatusListener {
*
* @param automatic 是否是安装完自动删除
*/
- public void cancel(String url, boolean isDeleteFile, boolean automatic) {
- DownloadEntity entry = mDownloadDao.get(url);
+ public void cancel(String url, boolean isDeleteFile, boolean automatic, boolean cancelSilently) {
+ DownloadEntity entry = mDownloadDao.getSnapshot(url);
if (entry != null) {
AppExecutor.getIoExecutor().execute(() -> {
mDownloadDao.delete(url);
@@ -695,54 +775,48 @@ public class DownloadManager implements DownloadStatusListener {
FileUtils.deleteFile(entry.getPath());
}
Utils.log(DownloadManager.class.getSimpleName(), "cancel==>record were deleted!");
+
+ if (automatic) {
+ entry.getMeta().put(DownloadDataHelper.DOWNLOAD_CANCEL_WAY, DownloadDataHelper.DOWNLOAD_CANCEL_AUTO);
+ } else {
+ entry.getMeta().put(DownloadDataHelper.DOWNLOAD_CANCEL_WAY, DownloadDataHelper.DOWNLOAD_CANCEL_MANUAL);
+ }
+ entry.setStatus(DownloadStatus.cancel);
+
+ initGameMap();
+
+ if (cancelSilently) {
+ cancelAndNotify(entry, true);
+ return;
+ }
+
+ // 将原来安装完成后在 downloadService 完成的功能放到这里,避免因为 ANR 造成闪退
+ AppExecutor.getUiExecutor().executeWithDelay(() -> {
+ cancelAndNotify(entry, false);
+ }, 0);
});
}
- if (entry != null) {
- if (automatic) {
- entry.getMeta().put(DownloadDataHelper.DOWNLOAD_CANCEL_WAY, DownloadDataHelper.DOWNLOAD_CANCEL_AUTO);
- } else {
- entry.getMeta().put(DownloadDataHelper.DOWNLOAD_CANCEL_WAY, DownloadDataHelper.DOWNLOAD_CANCEL_MANUAL);
- }
- entry.setStatus(DownloadStatus.cancel);
+ }
- // 将原来安装完成后在 downloadService 完成的功能放到这里,避免因为 ANR 造成闪退
- AppExecutor.getUiExecutor().executeWithDelay(() -> {
- mDownloadDao.removeErrorMessage(entry.getUrl());
+ private void cancelAndNotify(DownloadEntity entry, boolean cancelSilently) {
+ mDownloadDao.removeErrorMessage(entry.getUrl());
- DownloadTask task = DataChanger.INSTANCE.getDownloadingTasks().get(entry.getUrl());
- if (task != null) {
- task.cancel();
- // 改任务队列的状态
- DataChanger.INSTANCE.getDownloadingTasks().remove(entry.getUrl());
- DataChanger.INSTANCE.notifyDataChanged(entry);
- }
- DataChanger.INSTANCE.getDownloadEntries().remove(entry.getUrl());
+ DownloadTask task = DataChanger.INSTANCE.getDownloadingTasks().get(entry.getUrl());
+ if (task != null) {
+ task.cancel();
+ // 改任务队列的状态
+ DataChanger.INSTANCE.getDownloadingTasks().remove(entry.getUrl());
+ if (!cancelSilently) {
DataChanger.INSTANCE.notifyDataChanged(entry);
- DownloadStatusManager.getInstance().onTaskCancelled(entry);
-
- Utils.log(DownloadManager.class.getSimpleName(), "cancel");
- }, 0);
+ }
}
- }
-
- /**
- * 取消并删除所有下载任务(包括下载中、等待、暂停状态的任务)
- */
- public void cancelAll() {
- for (DownloadEntity entry : DataChanger.INSTANCE.getDownloadEntries().values()) {
- cancel(entry.getUrl(), true, false);
+ DataChanger.INSTANCE.getDownloadEntries().remove(entry.getUrl());
+ if (!cancelSilently) {
+ DataChanger.INSTANCE.notifyDataChanged(entry);
+ DownloadStatusManager.getInstance().onTaskCancelled(entry);
}
- Utils.log(DownloadManager.class.getSimpleName(), "cancel all");
- }
- /**
- * 开始所有下载任务
- */
- public void startAll() {
- for (DownloadEntity entry : downloadingMap.values()) {
- add(entry);
- }
- Utils.log(DownloadManager.class.getSimpleName(), "start all");
+ Utils.log(DownloadManager.class.getSimpleName(), "cancel");
}
/**
@@ -797,6 +871,8 @@ public class DownloadManager implements DownloadStatusListener {
public void addObserver(DataWatcher dataWatcher) {
Utils.log(DownloadManager.class.getSimpleName(), "addObserver");
DataChanger.INSTANCE.addObserver(dataWatcher);
+
+ notifyDownloadedStatusASAP(dataWatcher);
}
/**
@@ -807,6 +883,18 @@ public class DownloadManager implements DownloadStatusListener {
DataChanger.INSTANCE.deleteObserver(dataWatcher);
}
+ /**
+ * 立马通知 dataWatcher 更新已下载完的任务状态,这里的下载完成是持久状态,不是瞬时状态
+ *
+ */
+ private void notifyDownloadedStatusASAP(DataWatcher dataWatcher) {
+ for (DownloadEntity downloadEntity : getAllDownloadEntitySnapshots()) {
+ if (downloadEntity.getStatus() == DownloadStatus.done) {
+ dataWatcher.onDataInit(downloadEntity);
+ }
+ }
+ }
+
/**
* 初始化下载服务
*/
@@ -868,7 +956,7 @@ public class DownloadManager implements DownloadStatusListener {
public void checkAndRetryDownload() {
if (!NetworkUtils.isWifiConnected(mContext)) return;
- for (DownloadEntity downloadEntity : DownloadManager.getInstance().getAllDownloadEntityExcludeSilentUpdate()) {
+ for (DownloadEntity downloadEntity : DownloadManager.getInstance().getAllDownloadEntityExcludeSilentTask()) {
if (DownloadStatus.neterror.equals(downloadEntity.getStatus())
|| DownloadStatus.timeout.equals(downloadEntity.getStatus())
|| DownloadStatus.subscribe.equals(downloadEntity.getStatus())) {
@@ -894,7 +982,7 @@ public class DownloadManager implements DownloadStatusListener {
boolean showRedPoint = false;
int downloadingSize = 0;
- for (DownloadEntity downloadEntity : getAllDownloadEntityExcludeSilentUpdate()) {
+ for (DownloadEntity downloadEntity : getAllDownloadEntityExcludeSilentTask()) {
if (DownloadStatus.done.equals(downloadEntity.getStatus())) {
String mark = downloadEntity.getMeta().get(DOWNLOADED_IS_READ_MARK);
if (TextUtils.isEmpty(mark)) showRedPoint = true;
@@ -961,7 +1049,7 @@ public class DownloadManager implements DownloadStatusListener {
* @return 是否存在未读的下载完成任务
*/
public boolean isContainsUnreadDownloadedTask() {
- for (DownloadEntity downloadEntity : getAllDownloadEntityExcludeSilentUpdate()) {
+ for (DownloadEntity downloadEntity : getAllDownloadEntityExcludeSilentTask()) {
if (DownloadStatus.done.equals(downloadEntity.getStatus())) {
String mark = downloadEntity.getMeta().get(DOWNLOADED_IS_READ_MARK);
if (TextUtils.isEmpty(mark)) {
@@ -979,7 +1067,7 @@ public class DownloadManager implements DownloadStatusListener {
AppExecutor.getIoExecutor().execute(() -> {
boolean markHasChanged = false;
- List all = getAllDownloadEntityExcludeSilentUpdate();
+ List all = getAllDownloadEntityExcludeSilentTask();
for (DownloadEntity downloadEntity : all) {
DownloadStatus status = downloadEntity.getStatus();
if (status == DownloadStatus.done) {
@@ -1019,7 +1107,7 @@ public class DownloadManager implements DownloadStatusListener {
AppExecutor.getIoExecutor().execute(() -> {
boolean markHasChanged = false;
- List all = getAllDownloadEntityExcludeSilentUpdate();
+ List all = getAllDownloadEntityExcludeSilentTask();
for (DownloadEntity downloadEntity : all) {
if (downloadEntity.getStatus() != DownloadStatus.done) {
if (isRead) {
@@ -1134,6 +1222,17 @@ public class DownloadManager implements DownloadStatusListener {
mInvisiblePendingTaskList.clear();
}
+ public LiveData> getDownloadEntityLiveData() {
+ return mDownloadEntityListLiveData;
+ }
+
+ /**
+ * 手动触发下载 LiveData 变更
+ */
+ public void notifyDownloadLiveDataChanged() {
+ AppExecutor.getIoExecutor().execute(() -> mDownloadEntityListLiveData.postValue(getAllDownloadEntity()));
+ }
+
/**
* 更新下载请求头的相关信息
*/
diff --git a/app/src/main/java/com/gh/download/PackageObserver.kt b/app/src/main/java/com/gh/download/PackageObserver.kt
index cbed3f39c2..8c2c1a29b2 100644
--- a/app/src/main/java/com/gh/download/PackageObserver.kt
+++ b/app/src/main/java/com/gh/download/PackageObserver.kt
@@ -3,11 +3,17 @@ package com.gh.download
import android.annotation.SuppressLint
import android.preference.PreferenceManager
import android.text.TextUtils
+import com.gh.common.util.ConcernUtils
+import com.gh.common.util.DataCollectionUtils
+import com.gh.common.util.PackageInstaller
+import com.gh.common.util.PackageUtils
+import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.loghub.LoghubUtils
+import com.gh.gamecenter.common.retrofit.EmptyResponse
+import com.gh.gamecenter.common.retrofit.Response
+import com.gh.gamecenter.common.utils.isVGame
import com.gh.gamecenter.core.runOnIoThread
-import com.gh.common.util.*
-import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.core.utils.ThirdPartyPackageHelper
import com.gh.gamecenter.core.utils.UrlFilterUtils
import com.gh.gamecenter.entity.GameDigestEntity
@@ -15,12 +21,11 @@ import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.packagehelper.PackageRepository
import com.gh.gamecenter.packagehelper.PackageViewModel
-import com.gh.gamecenter.common.retrofit.EmptyResponse
-import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.setting.GameDownloadSettingFragment.Companion.CONCERN_GAME_SP_KEY
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
+import com.lightgame.download.FileUtils
import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
@@ -34,11 +39,23 @@ object PackageObserver {
private val mPackageViewModel: PackageViewModel
by lazy { PackageViewModel(HaloApp.getInstance().application, PackageRepository) }
+ private val mPackageChangeListenerList: ArrayList = arrayListOf()
+
+ fun registerPackageChangeChangeListener(listener: PackageChangeListener) {
+ mPackageChangeListenerList.add(listener)
+ }
+
+ fun unregisterPackageChangeChangeListener(listener: PackageChangeListener) {
+ mPackageChangeListenerList.remove(listener)
+ }
+
@JvmStatic
fun onPackageChanged(busFour: EBPackage) {
val application = HaloApp.getInstance().application
val packageName = busFour.packageName
val versionName = busFour.versionName
+ val preciseGameId = busFour.gameId
+
var gameId = ""
var mDownloadEntity: DownloadEntity? = null
val sp = PreferenceManager.getDefaultSharedPreferences(application)
@@ -47,7 +64,8 @@ object PackageObserver {
var foundMatchedGame = false // 是否找到準確的遊戲 (有可能出現同包名同版本的情況)
for (downloadEntity in DownloadManager.getInstance().allDownloadEntity) {
- if (packageName == downloadEntity.packageName) {
+ if (packageName == downloadEntity.packageName
+ && (preciseGameId == null || preciseGameId == downloadEntity.gameId)) {
mDownloadEntity = downloadEntity
gameId = mDownloadEntity.gameId
if (TextUtils.isEmpty(busFour.versionName)) {
@@ -84,13 +102,17 @@ object PackageObserver {
if (gh_id == null) {
ThirdPartyPackageHelper.saveGameId(mDownloadEntity.packageName, mDownloadEntity.gameId)
}
- DownloadManager.getInstance().cancel(
- mDownloadEntity.url, false, true) // 默认不删除安装包 mSp.getBoolean("autodelete", true)
- }
- if (sp.getBoolean(CONCERN_GAME_SP_KEY, true)) { //设置页面控制是否安装后自动关注
- // 安装后关注游戏
- val finalDownloadEntity = mDownloadEntity
- RetrofitManager.getInstance().api
+ if (mDownloadEntity.isVGame()) {
+ // 畅玩游戏安装完成的同时直接删除文件
+ runOnIoThread { FileUtils.deleteFile(mDownloadEntity.path) }
+ }
+
+ DownloadManager.getInstance().cancel(mDownloadEntity.url, false, true, false)
+
+ if (sp.getBoolean(CONCERN_GAME_SP_KEY, true)) { //设置页面控制是否安装后自动关注
+ // 安装后关注游戏
+ val finalDownloadEntity = mDownloadEntity
+ RetrofitManager.getInstance().api
.getGameDigestByPackageName(UrlFilterUtils.getFilterQuery("package", packageName))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
@@ -98,13 +120,14 @@ object PackageObserver {
override fun onResponse(response: List?) {
for (gameDigestEntity in response!!) {
if (!TextUtils.isEmpty(gameDigestEntity?.id)) { // 关注游戏
- if (finalDownloadEntity != null && gameDigestEntity?.id == finalDownloadEntity.gameId) {
+ if (gameDigestEntity?.id == finalDownloadEntity.gameId) {
ConcernUtils.postConcernGameId(application, gameDigestEntity?.id ?: "", null, false)
}
}
}
}
})
+ }
}
runOnIoThread { postNewlyInstalledApp(gameId, packageName) }
@@ -113,6 +136,8 @@ object PackageObserver {
if ("卸载" == busFour.type) {
mPackageViewModel.addUninstalledGame(packageName)
mDownloadEntity?.let {
+ if (it.isVGame()) return@let
+
if (it.isPluggable || it.isUpdate) {
PackageInstaller.install(application, mDownloadEntity)
}
@@ -121,6 +146,11 @@ object PackageObserver {
// 更新已安装游戏
deleteInstalledPackage(packageName)
}
+
+ for (packageChangeListener in mPackageChangeListenerList) {
+ packageChangeListener.onChanged(busFour)
+ }
+
DataCollectionUtils.uploadInorunstall(application, busFour.type, busFour.packageName)
}
@@ -181,6 +211,9 @@ object PackageObserver {
e.printStackTrace()
}
LoghubUtils.log(wrapperObject, "halo-api-device-installed", true)
+ }
+ fun interface PackageChangeListener {
+ fun onChanged(data:EBPackage)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/download/dialog/DownloadDialogAdapter.kt b/app/src/main/java/com/gh/download/dialog/DownloadDialogAdapter.kt
index 8ddb08ae09..cf2ec826d9 100644
--- a/app/src/main/java/com/gh/download/dialog/DownloadDialogAdapter.kt
+++ b/app/src/main/java/com/gh/download/dialog/DownloadDialogAdapter.kt
@@ -125,11 +125,11 @@ class DownloadDialogAdapter(
rightLink.text = if (links?.size ?: 0 > 1) links?.get(1)?.title else ""
leftLink.background = GradientDrawable().apply {
cornerRadius = 8F.dip2px().toFloat()
- setStroke(0.5F.dip2px(), R.color.divider.toColor())
+ setStroke(0.5F.dip2px(), R.color.divider.toColor(mContext))
}
rightLink.background = GradientDrawable().apply {
cornerRadius = 8F.dip2px().toFloat()
- setStroke(0.5F.dip2px(), R.color.divider.toColor())
+ setStroke(0.5F.dip2px(), R.color.divider.toColor(mContext))
}
}
}
diff --git a/app/src/main/java/com/gh/download/dialog/DownloadDialogItemViewHolder.kt b/app/src/main/java/com/gh/download/dialog/DownloadDialogItemViewHolder.kt
index 6b75fae923..af829676c0 100644
--- a/app/src/main/java/com/gh/download/dialog/DownloadDialogItemViewHolder.kt
+++ b/app/src/main/java/com/gh/download/dialog/DownloadDialogItemViewHolder.kt
@@ -6,23 +6,26 @@ import android.widget.RelativeLayout
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
-import com.gh.gamecenter.common.base.activity.BaseActivity
-import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.common.constant.Config
import com.gh.common.dialog.CertificationDialog
import com.gh.common.dialog.DeviceRemindDialog
import com.gh.common.dialog.PackageCheckDialogFragment
import com.gh.common.exposure.ExposureEvent
-import com.gh.common.util.*
import com.gh.common.util.DialogUtils
import com.gh.common.util.DirectUtils.directToLinkPage
+import com.gh.common.util.DownloadDialogHelper
+import com.gh.common.util.PackageInstaller
+import com.gh.common.util.PackageUtils
import com.gh.download.DownloadManager
import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.DownloadManagerActivity
import com.gh.gamecenter.R
+import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
+import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.callback.ConfirmListener
import com.gh.gamecenter.common.utils.*
-import com.gh.gamecenter.core.utils.*
+import com.gh.gamecenter.core.utils.EmptyCallback
+import com.gh.gamecenter.core.utils.SpeedUtils
import com.gh.gamecenter.databinding.DownloadDialogItemBinding
import com.gh.gamecenter.entity.ApkEntity
import com.gh.gamecenter.entity.GameCollectionEntity
@@ -211,8 +214,11 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
} else 8f.dip2px()
binding.root.layoutParams = this
}
- if (apkEntity.recommend != null) {
+ val downloadEntity = DownloadManager.getInstance().getDownloadEntityByUrl(apkEntity.url)
+ if (apkEntity.recommend != null && downloadEntity == null) {
binding.containerView.background = ContextCompat.getDrawable(binding.root.context, R.drawable.bg_download_dialog_item_recommend)
+ } else {
+ binding.containerView.background = ContextCompat.getDrawable(binding.root.context, R.drawable.download_dialog_item_background)
}
}
@@ -351,7 +357,7 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
// todo 有时间存储判断统一处理
val msg = FileUtils.isCanDownload(context, apkEntity.size)
if (msg.isNullOrEmpty()) {
- BrowserInstallHelper.showBrowserInstallHintDialog(context, object : EmptyCallback {
+ BrowserInstallHelper.showBrowserInstallHintDialog(context, gameEntity.isVGame(), object : EmptyCallback {
override fun onCallback() {
DownloadDialogHelper.findAvailableDialogAndShow(context, gameEntity, apkEntity, object : EmptyCallback {
override fun onCallback() {
diff --git a/app/src/main/java/com/gh/download/server/BrowserInstallHelper.kt b/app/src/main/java/com/gh/download/server/BrowserInstallHelper.kt
index c5993f66bd..2415efd587 100644
--- a/app/src/main/java/com/gh/download/server/BrowserInstallHelper.kt
+++ b/app/src/main/java/com/gh/download/server/BrowserInstallHelper.kt
@@ -123,8 +123,8 @@ object BrowserInstallHelper {
}
@JvmStatic
- fun showBrowserInstallHintDialog(context: Context, callback: EmptyCallback) {
- if (!shouldShowUseBrowserToInstallHint()) {
+ fun showBrowserInstallHintDialog(context: Context, skipBrowserInstallDialog: Boolean = false, callback: EmptyCallback) {
+ if (skipBrowserInstallDialog || !shouldShowUseBrowserToInstallHint()) {
callback.onCallback()
return
}
diff --git a/app/src/main/java/com/gh/gamecenter/DownloadManagerActivity.java b/app/src/main/java/com/gh/gamecenter/DownloadManagerActivity.java
index e804703ad3..aa82ffe434 100644
--- a/app/src/main/java/com/gh/gamecenter/DownloadManagerActivity.java
+++ b/app/src/main/java/com/gh/gamecenter/DownloadManagerActivity.java
@@ -3,12 +3,16 @@ package com.gh.gamecenter;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
+import android.view.MenuItem;
+import com.gh.common.util.DirectUtils;
+import com.gh.common.util.NewFlatLogUtils;
import com.gh.gamecenter.common.base.activity.ToolBarActivity;
import com.gh.gamecenter.common.base.fragment.BaseFragment_TabLayout;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.download.DownloadFragment;
+import com.gh.vspace.VHelper;
/**
* 下载更新管理页面
@@ -26,6 +30,9 @@ public class DownloadManagerActivity extends ToolBarActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ExtensionsKt.updateStatusBarColor(this, R.color.background_white, R.color.background_white);
+ if (VHelper.isVGameOn()) {
+ setToolbarMenu(R.menu.menu_download_manager);
+ }
}
@Override
@@ -57,6 +64,13 @@ public class DownloadManagerActivity extends ToolBarActivity {
return getTargetIntent(context, DownloadManagerActivity.class, DownloadFragment.class, bundle);
}
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ NewFlatLogUtils.logHaloFunManageShow("下载管理");
+ DirectUtils.directToVGameDownload(this, false);
+ return true;
+ }
+
@Override
protected void onNightModeChange() {
super.onNightModeChange();
diff --git a/app/src/main/java/com/gh/gamecenter/GameDetailActivity.kt b/app/src/main/java/com/gh/gamecenter/GameDetailActivity.kt
index 7c11a0424c..5767fc9c48 100644
--- a/app/src/main/java/com/gh/gamecenter/GameDetailActivity.kt
+++ b/app/src/main/java/com/gh/gamecenter/GameDetailActivity.kt
@@ -80,7 +80,7 @@ class GameDetailActivity : DownloadToolbarActivity() {
override fun isAutoResetViewBackgroundEnabled(): Boolean = true
override fun updateStaticViewBackground(view: View?) {
- updateStaticView(view, listOf(R.id.menu_download_iv, R.id.gameBigEvent))
+ updateStaticView(view, listOf(R.id.menu_download_iv, R.id.gameBigEvent, R.id.cardContainer))
}
companion object {
diff --git a/app/src/main/java/com/gh/gamecenter/ImageViewerActivity.kt b/app/src/main/java/com/gh/gamecenter/ImageViewerActivity.kt
index e01afdec38..b14def2324 100644
--- a/app/src/main/java/com/gh/gamecenter/ImageViewerActivity.kt
+++ b/app/src/main/java/com/gh/gamecenter/ImageViewerActivity.kt
@@ -368,7 +368,7 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
if (mUseEnterAndExitAnimation) {
mBigImageView?.translationX = mTranslationX
mBigImageView?.translationY = mTranslationY
- if (mScaleX < Float.MAX_VALUE) {
+ if (!mScaleX.isNaN() && mScaleX < Float.MAX_VALUE) {
mBigImageView?.scaleX = mScaleX
mBigImageView?.scaleY = mScaleY
}
@@ -439,10 +439,18 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
addUpdateListener { va -> mBigImageView?.y = (va.animatedValue as Float) }
}
val scaleYAnimator = ValueAnimator.ofFloat(1F, mScaleY).apply {
- addUpdateListener { va -> mBigImageView?.scaleY = (va.animatedValue as Float) }
+ addUpdateListener { va ->
+ if (va.animatedValue is Float && !(va.animatedValue as Float).isNaN() && (va.animatedValue as Float) < Float.MAX_VALUE) {
+ mBigImageView?.scaleY = (va.animatedValue as Float)
+ }
+ }
}
val scaleXAnimator = ValueAnimator.ofFloat(1F, mScaleX).apply {
- addUpdateListener { va -> mBigImageView?.scaleX = (va.animatedValue as Float) }
+ addUpdateListener { va ->
+ if (va.animatedValue is Float && !(va.animatedValue as Float).isNaN() && (va.animatedValue as Float) < Float.MAX_VALUE) {
+ mBigImageView?.scaleX = (va.animatedValue as Float)
+ }
+ }
}
val backgroundAlphaAnimation = ValueAnimator.ofFloat(1F, 0F).apply {
addUpdateListener { va -> mBackgroundView.alpha = (va.animatedValue as Float) }
@@ -591,10 +599,18 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
addUpdateListener { va -> mBigImageView?.y = (va.animatedValue as Float) }
}
val scaleYAnimator = ValueAnimator.ofFloat(mScaleY, 1F).apply {
- addUpdateListener { va -> mBigImageView?.scaleY = (va.animatedValue as Float) }
+ addUpdateListener { va ->
+ if (va.animatedValue is Float && !(va.animatedValue as Float).isNaN() && (va.animatedValue as Float) < Float.MAX_VALUE) {
+ mBigImageView?.scaleY = (va.animatedValue as Float)
+ }
+ }
}
val scaleXAnimator = ValueAnimator.ofFloat(mScaleX, 1F).apply {
- addUpdateListener { va -> mBigImageView?.scaleX = (va.animatedValue as Float) }
+ addUpdateListener { va ->
+ if (va.animatedValue is Float && !(va.animatedValue as Float).isNaN() && (va.animatedValue as Float) < Float.MAX_VALUE) {
+ mBigImageView?.scaleX = (va.animatedValue as Float)
+ }
+ }
}
val backgroundAlphaAnimator = ValueAnimator.ofFloat(0F, 1F).apply {
addUpdateListener { va -> mBackgroundView.alpha = (va.animatedValue as Float) }
@@ -625,8 +641,10 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener {
val scaleAnimator = ValueAnimator.ofFloat(scale, finalScale).apply {
addUpdateListener { va ->
- view.scaleX = (va.animatedValue as Float)
- view.scaleY = (va.animatedValue as Float)
+ if (va.animatedValue is Float && !(va.animatedValue as Float).isNaN() && (va.animatedValue as Float) < Float.MAX_VALUE) {
+ view.scaleX = (va.animatedValue as Float)
+ view.scaleY = (va.animatedValue as Float)
+ }
}
}
val translateXAnimator = ValueAnimator.ofFloat(view.x, finalTranslationX).apply {
diff --git a/app/src/main/java/com/gh/gamecenter/LibaoDetailActivity.java b/app/src/main/java/com/gh/gamecenter/LibaoDetailActivity.java
index 12650cb58e..6ed2dd08f5 100644
--- a/app/src/main/java/com/gh/gamecenter/LibaoDetailActivity.java
+++ b/app/src/main/java/com/gh/gamecenter/LibaoDetailActivity.java
@@ -142,6 +142,11 @@ public class LibaoDetailActivity extends ToolBarActivity implements LibaoDetailA
}
}
}
+
+ @Override
+ public void onDataInit(@NonNull DownloadEntity downloadEntity) {
+ onDataChanged(downloadEntity);
+ }
};
diff --git a/app/src/main/java/com/gh/gamecenter/MainActivity.java b/app/src/main/java/com/gh/gamecenter/MainActivity.java
index dadcb9b729..1c5f59eb8f 100644
--- a/app/src/main/java/com/gh/gamecenter/MainActivity.java
+++ b/app/src/main/java/com/gh/gamecenter/MainActivity.java
@@ -609,7 +609,7 @@ public class MainActivity extends BaseActivity {
if (downloadEntity != null) {
File file = new File(downloadEntity.getPath());
if (!file.exists()) {
- ToastUtils.INSTANCE.showToast("文件已被删除,无法启动");
+ ToastUtils.showToast("文件已被删除,无法启动");
return;
}
@@ -620,8 +620,8 @@ public class MainActivity extends BaseActivity {
toast("模拟器游戏启动失败,请联系客服反馈相关信息");
SentryHelper.INSTANCE.onEvent(
"SIMULATOR_SHORTCUT_LAUNCH_ERROR",
- "raw_json",
- json
+ "error_digest",
+ exception.getLocalizedMessage()
);
}
break;
@@ -665,7 +665,7 @@ public class MainActivity extends BaseActivity {
public void onFailure(@Nullable HttpException e) {
super.onFailure(e);
try {
- ErrorHelper.handleErrorWithCustomizedHandler(MainActivity.this, e.response().errorBody().string(), false, new Function1() {
+ ErrorHelper.handleErrorWithCustomizedHandler(MainActivity.this, e.response().errorBody().string(), false, null, new Function1() {
@Override
public Boolean invoke(Integer code) {
if (code == 404001) {
@@ -701,7 +701,7 @@ public class MainActivity extends BaseActivity {
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0 && !mMainWrapperFragment.onHandleBackPressed()) {
DownloadEntity downloadEntity = null;
- for (DownloadEntity entity : DownloadManager.getInstance().getAllDownloadEntityExcludeSilentUpdate()) {
+ for (DownloadEntity entity : DownloadManager.getInstance().getAllDownloadEntityExcludeSilentTask()) {
if (entity.getStatus().equals(DownloadStatus.done)) {
if (PackageUtils.isInstalled(getApplicationContext(), entity.getPackageName())
&& (!entity.isPlugin()
diff --git a/app/src/main/java/com/gh/gamecenter/NewsDetailActivity.java b/app/src/main/java/com/gh/gamecenter/NewsDetailActivity.java
index 6d1ec9dcd3..2a528c0daa 100644
--- a/app/src/main/java/com/gh/gamecenter/NewsDetailActivity.java
+++ b/app/src/main/java/com/gh/gamecenter/NewsDetailActivity.java
@@ -140,6 +140,11 @@ public class NewsDetailActivity extends DownloadToolbarActivity implements OnCli
}
}
}
+
+ @Override
+ public void onDataInit(@NonNull DownloadEntity downloadEntity) {
+ onDataChanged(downloadEntity);
+ }
};
Runnable runnable = new Runnable() {
diff --git a/app/src/main/java/com/gh/gamecenter/SkipActivity.java b/app/src/main/java/com/gh/gamecenter/SkipActivity.java
index c98d7e6b82..e815ac95e5 100644
--- a/app/src/main/java/com/gh/gamecenter/SkipActivity.java
+++ b/app/src/main/java/com/gh/gamecenter/SkipActivity.java
@@ -112,7 +112,7 @@ public class SkipActivity extends BaseActivity {
DirectUtils.directToGameDetail(this, path, ENTRANCE_BROWSER, "true".equals(uri.getQueryParameter("auto_download")), to, null);
break;
case HOST_COLUMN:
- DirectUtils.directToSubject(this, path, uri.getQueryParameter(KEY_NAME), ENTRANCE_BROWSER);
+ DirectUtils.directToSubject(this, path, uri.getQueryParameter(KEY_NAME), ENTRANCE_BROWSER, null);
break;
case HOST_SUGGESTION:
String platform = uri.getQueryParameter(KEY_PLATFORM);
diff --git a/app/src/main/java/com/gh/gamecenter/SplashScreenActivity.kt b/app/src/main/java/com/gh/gamecenter/SplashScreenActivity.kt
index 053aa98dff..f4ec821f01 100644
--- a/app/src/main/java/com/gh/gamecenter/SplashScreenActivity.kt
+++ b/app/src/main/java/com/gh/gamecenter/SplashScreenActivity.kt
@@ -30,13 +30,14 @@ import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.tracker.TrackerLogger
import com.gh.gamecenter.common.utils.DialogHelper
import com.gh.gamecenter.common.utils.PackageFlavorHelper
+import com.gh.gamecenter.common.utils.PermissionHelper
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.EmptyCallback
-import com.gh.gamecenter.core.utils.MtaHelper.onEvent
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.entity.PrivacyPolicyEntity
+import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.lightgame.download.FileUtils
import pub.devrel.easypermissions.AfterPermissionGranted
@@ -59,7 +60,8 @@ class SplashScreenActivity : BaseActivity() {
private val mPermissions = arrayOf(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
- Manifest.permission.READ_PHONE_STATE
+ Manifest.permission.READ_PHONE_STATE,
+ PermissionHelper.PERMISSION_GET_INSTALLED_LIST
)
override fun onCreate(savedInstanceState: Bundle?) {
@@ -178,7 +180,7 @@ class SplashScreenActivity : BaseActivity() {
val all = DownloadManager.getInstance().allDownloadEntity
for (downloadEntity in all) {
if (downloadEntity.packageName == packageName) {
- DownloadManager.getInstance().cancel(downloadEntity.url, true, true)
+ DownloadManager.getInstance().cancel(downloadEntity.url, true, true, false)
break
}
}
@@ -282,7 +284,9 @@ class SplashScreenActivity : BaseActivity() {
@AfterPermissionGranted(REQUEST_PERMISSION_TAG)
private fun checkAndRequestPermission() {
if (EasyPermissions.hasPermissions(this, *mPermissions)) {
- onEvent("授权情况", "启动授权", "都授权")
+ // 恢复畅玩数据
+ VHelper.recoverVDataIfPossible()
+
// 检查是否有旧版本光环,有就删掉
AppExecutor.ioExecutor.execute { deleteOutdatedUpdatePackage() }
if (mStartMainActivityDirectly) {
diff --git a/app/src/main/java/com/gh/gamecenter/adapter/viewholder/DetailViewHolder.java b/app/src/main/java/com/gh/gamecenter/adapter/viewholder/DetailViewHolder.java
index 44bd6e17d4..08a553588c 100644
--- a/app/src/main/java/com/gh/gamecenter/adapter/viewholder/DetailViewHolder.java
+++ b/app/src/main/java/com/gh/gamecenter/adapter/viewholder/DetailViewHolder.java
@@ -4,6 +4,7 @@ import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
import android.view.View;
+import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
@@ -23,12 +24,12 @@ import com.gh.common.simulator.SimulatorGameManager;
import com.gh.common.util.CheckLoginUtils;
import com.gh.common.util.DetailDownloadUtils;
import com.gh.common.util.DialogUtils;
+import com.gh.common.util.DirectUtils;
import com.gh.common.util.DownloadDialogHelper;
import com.gh.common.util.EnergyTaskHelper;
import com.gh.common.util.LogUtils;
import com.gh.common.util.PackageInstaller;
import com.gh.common.util.PackageUtils;
-import com.gh.common.util.RealNameHelper;
import com.gh.common.util.ReservationHelper;
import com.gh.common.view.DownloadProgressBar;
import com.gh.download.DownloadManager;
@@ -38,10 +39,12 @@ import com.gh.gamecenter.DownloadManagerActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.WebActivity;
import com.gh.gamecenter.common.constant.Constants;
+import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.utils.DataLogUtils;
import com.gh.gamecenter.common.utils.DialogHelper;
import com.gh.gamecenter.common.utils.PermissionHelper;
import com.gh.gamecenter.core.utils.MtaHelper;
+import com.gh.gamecenter.core.utils.PageSwitchDataHelper;
import com.gh.gamecenter.core.utils.StringUtils;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.GameEntity;
@@ -51,6 +54,9 @@ import com.gh.gamecenter.eventbus.EBScroll;
import com.gh.gamecenter.gamedetail.GameDetailFragment;
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment;
import com.gh.gamecenter.teenagermode.TeenagerModeActivity;
+import com.gh.vspace.VDownloadManagerActivity;
+import com.gh.vspace.VHelper;
+import com.gh.vspace.VSpaceLoadingActivity;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.FileUtils;
import com.lightgame.utils.Utils;
@@ -58,6 +64,7 @@ import com.lightgame.utils.Utils;
import org.greenrobot.eventbus.EventBus;
import java.io.File;
+import java.util.HashMap;
/**
* Created by khy on 27/06/17.
@@ -77,12 +84,14 @@ public class DetailViewHolder {
public View downloadBottom;
public DownloadProgressBar mDownloadPb;
+ public TextView mOverlayTv; // 额外的文字 (用于一些含图片的情况)
// 注意View的命名
public DetailViewHolder(View view, GameEntity gameEntity, DownloadEntity downloadEntity,
boolean isNewsDetail, String entrance, String name, String title, @Nullable ExposureEvent traceEvent) {
downloadBottom = view.findViewById(R.id.detail_ll_bottom);
mDownloadPb = view.findViewById(R.id.detail_progressbar);
+ mOverlayTv = view.findViewById(R.id.overlayTv);
this.gameEntity = gameEntity;
this.downloadEntity = downloadEntity;
@@ -96,6 +105,10 @@ public class DetailViewHolder {
restoreDialogFragment();
}
+ public TextView getOverlayTv() {
+ return mOverlayTv;
+ }
+
private void restoreDialogFragment() {
DialogFragment gamePermissionDialogFragment =
(DialogFragment) ((AppCompatActivity) context).getSupportFragmentManager().findFragmentByTag(GamePermissionDialogFragment.class.getName());
@@ -153,7 +166,9 @@ public class DetailViewHolder {
MtaHelper.onEvent("游戏详情_新", "预约", mGameEntity.getName());
break;
case LAUNCH_OR_OPEN:
- EnergyTaskHelper.postEnergyTask("play_game", mGameEntity.getId(), mGameEntity.getApk().get(0).getPackageName());
+ if (!mGameEntity.getApk().isEmpty()) {
+ EnergyTaskHelper.postEnergyTask("play_game", mGameEntity.getId(), mGameEntity.getApk().get(0).getPackageName());
+ }
break;
}
// 由于部分状态不包含在 downloadType 里,所以还是需要手动获取下载按钮文字判断点击时的状态
@@ -194,12 +209,12 @@ public class DetailViewHolder {
DataLogUtils.uploadGameLog(mViewHolder.context, mGameEntity.getId(), mGameEntity.getName(), mEntrance);
}
case PLUGIN:
- RealNameHelper.checkIfAuth(v.getContext(), mGameEntity, () -> {
+ VHelper.validateVSpaceBeforeAction(mViewHolder.context, mGameEntity, true, () -> {
GamePermissionDialogFragment.show((AppCompatActivity) mViewHolder.context, mGameEntity, mGameEntity.getInfo(), () -> {
PermissionHelper.checkStoragePermissionBeforeAction(mViewHolder.context, () -> {
if (mGameEntity.getApk().size() == 1) {
ApkEntity apk = mGameEntity.getApk().get(0);
- BrowserInstallHelper.showBrowserInstallHintDialog(mViewHolder.context, () -> {
+ BrowserInstallHelper.showBrowserInstallHintDialog(mViewHolder.context, mGameEntity.isVGame(), () -> {
PackageCheckDialogFragment.show((AppCompatActivity) mViewHolder.context, mGameEntity, () -> {
DownloadDialogHelper.findAvailableDialogAndShow(mViewHolder.context, mGameEntity, apk, () -> {
CertificationDialog.showCertificationDialog(mViewHolder.context, mGameEntity, () -> {
@@ -244,6 +259,11 @@ public class DetailViewHolder {
return;
}
+ if (mGameEntity.isVGame()) {
+ VHelper.installOrLaunch(mViewHolder.context, mGameEntity.getApk().get(0).getPackageName());
+ return;
+ }
+
PackageUtils.launchApplicationByPackageName(mViewHolder.context, mGameEntity.getApk().get(0).getPackageName());
} else {
GamePermissionDialogFragment.show((AppCompatActivity) mViewHolder.context, mGameEntity, mGameEntity.getInfo(), () -> {
@@ -271,10 +291,16 @@ public class DetailViewHolder {
}
}
+ if (mGameEntity.isVGame()) {
+ VHelper.installOrLaunch(v.getContext(), mGameEntity.getApk().get(0).getPackageName());
+ return;
+ }
+
PermissionHelper.checkStoragePermissionBeforeAction(mViewHolder.context, () -> {
if (mDownloadEntity == null) {
mDownloadEntity = DownloadManager.getInstance().getDownloadEntityByUrl(mGameEntity.getApk().get(0).getUrl());
}
+
if (mDownloadEntity != null) {
final String path = mDownloadEntity.getPath();
if (FileUtils.isEmptyFile(path)) {
@@ -337,8 +363,23 @@ public class DetailViewHolder {
}
);
break;
+ case SPECIAL_DOWNLOAD:
+ RegionSetting.GameSpecialDownloadInfo info = RegionSettingHelper.getGameSpecialDownloadInfo(mGameEntity.getId());
+ if (info != null) {
+ if (!TextUtils.isEmpty(info.getBbsId())) {
+ if (!TextUtils.isEmpty(info.getTopId())) {
+ HashMap map = new HashMap<>();
+ map.put(EntranceConsts.KEY_TOP_ID, info.getTopId());
+ PageSwitchDataHelper.pushCurrentPageData(map);
+ }
+ DirectUtils.directForumDetail(mViewHolder.context, info.getBbsId(), mEntrance);
+ }
+ }
+ break;
default:
- if (!mGameEntity.getApk().isEmpty()) {
+ if (mGameEntity.isVGame()) {
+ mViewHolder.context.startActivity(VDownloadManagerActivity.getIntent(mViewHolder.context, true));
+ } else if (!mGameEntity.getApk().isEmpty()) {
Intent intent = DownloadManagerActivity.getDownloadMangerIntent(mViewHolder.context,
mGameEntity.getApk().get(0).getUrl(),
StringUtils.buildString(mEntrance, "+(", mName, "[", mTitle, "])"));
@@ -378,19 +419,27 @@ public class DetailViewHolder {
ApkEntity apkEntity = mGameEntity.getApk().get(0);
String msg = FileUtils.isCanDownload(mViewHolder.context, apkEntity.getSize());
if (TextUtils.isEmpty(msg)) {
- DownloadManager.createDownload(mViewHolder.context,
- apkEntity,
- mGameEntity,
- method,
- StringUtils.buildString(mEntrance, "+(", mName, "[", mTitle, "])"),
- mName + ":" + mTitle,
- isSubscribe,
- mTraceEvent);
+ if (mGameEntity.isVGame() && "更新".equals(method)) {
+ VHelper.updateOrReDownload(mGameEntity);
+ } else {
+ DownloadManager.createDownload(mViewHolder.context,
+ apkEntity,
+ mGameEntity,
+ method,
+ StringUtils.buildString(mEntrance, "+(", mName, "[", mTitle, "])"),
+ mName + ":" + mTitle,
+ isSubscribe,
+ mTraceEvent);
+ }
mViewHolder.mDownloadPb.setProgress(0);
mViewHolder.mDownloadPb.setDownloadType("插件化".equals(method) ?
DownloadProgressBar.DownloadType.DOWNLOADING_PLUGIN : DownloadProgressBar.DownloadType.DOWNLOADING_NORMAL);
DeviceRemindDialog.Companion.showDeviceRemindDialog(mViewHolder.context, mGameEntity);
+
+ if (mGameEntity.isVGame() && mViewHolder.context.getString(R.string.download).equals(method)) {
+ mViewHolder.context.startActivity(VSpaceLoadingActivity.getIntent(mViewHolder.context, mGameEntity, false));
+ }
} else {
Utils.toast(mViewHolder.context, msg);
}
diff --git a/app/src/main/java/com/gh/gamecenter/amway/AmwayFragment.kt b/app/src/main/java/com/gh/gamecenter/amway/AmwayFragment.kt
index cc7ac99b15..a1514979d0 100644
--- a/app/src/main/java/com/gh/gamecenter/amway/AmwayFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/amway/AmwayFragment.kt
@@ -9,12 +9,9 @@ import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.recyclerview.widget.RecyclerView
import com.ethanhua.skeleton.Skeleton
-import com.gh.gamecenter.core.utils.TimeElapsedHelper
import com.gh.common.exposure.ExposureListener
import com.gh.common.exposure.ExposureSource
-import com.gh.common.util.*
import com.gh.common.util.DialogUtils
-import com.gh.gamecenter.common.view.VerticalItemDecoration
import com.gh.common.xapk.XapkInstaller
import com.gh.common.xapk.XapkUnzipStatus
import com.gh.download.DownloadManager
@@ -24,7 +21,11 @@ import com.gh.gamecenter.baselist.LazyListFragment
import com.gh.gamecenter.baselist.ListAdapter
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.*
-import com.gh.gamecenter.core.utils.*
+import com.gh.gamecenter.common.view.VerticalItemDecoration
+import com.gh.gamecenter.core.utils.ClickUtils
+import com.gh.gamecenter.core.utils.DisplayUtils
+import com.gh.gamecenter.core.utils.MtaHelper
+import com.gh.gamecenter.core.utils.TimeElapsedHelper
import com.gh.gamecenter.databinding.FragmentAmwayAlBinding
import com.gh.gamecenter.databinding.FragmentAmwayBinding
import com.gh.gamecenter.entity.RatingComment
@@ -64,6 +65,10 @@ class AmwayFragment : LazyListFragment() {
showUnzipFailureDialog(downloadEntity)
}
}
+
+ override fun onDataInit(downloadEntity: DownloadEntity) {
+ mAdapter?.notifyItemByDownload(downloadEntity)
+ }
}
override fun onCreate(savedInstanceState: Bundle?) {
diff --git a/app/src/main/java/com/gh/gamecenter/baselist/DiffUtilAdapter.kt b/app/src/main/java/com/gh/gamecenter/baselist/DiffUtilAdapter.kt
index 45c2b59719..788fe2f025 100644
--- a/app/src/main/java/com/gh/gamecenter/baselist/DiffUtilAdapter.kt
+++ b/app/src/main/java/com/gh/gamecenter/baselist/DiffUtilAdapter.kt
@@ -5,6 +5,8 @@ import android.content.Context
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.gh.gamecenter.common.utils.safelyGetInRelease
+import com.gh.gamecenter.common.utils.testChannelOnly
+import com.gh.gamecenter.core.utils.ToastUtils
import com.lightgame.adapter.BaseRecyclerAdapter
abstract class DiffUtilAdapter(context: Context) :
@@ -24,55 +26,43 @@ abstract class DiffUtilAdapter(context: Context) :
// 这里用新的数组包裹原数据
val updateDataCopy = ArrayList(updateData)
- if (mDataList.size > updateData.size) {
- mDataList = updateDataCopy
- notifyDataSetChanged()
- return
- }
-
- ListExecutor.workerExecutor.execute {
- val diffResult = DiffUtil.calculateDiff(object : DiffUtil.Callback() {
- override fun getOldListSize(): Int {
- return mDataList.size
- }
-
- override fun getNewListSize(): Int {
- return updateDataCopy.size
- }
-
- override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
- if (oldItemPosition != newItemPosition
- || oldItemPosition >= mDataList.size
- || newItemPosition >= updateDataCopy.size
- ) {
- return false
+ try {
+ ListExecutor.workerExecutor.execute {
+ val diffResult = DiffUtil.calculateDiff(object : DiffUtil.Callback() {
+ override fun getOldListSize(): Int {
+ return mDataList.size
}
- val oldItem = mDataList.safelyGetInRelease(oldItemPosition)
- val newItem = updateDataCopy.safelyGetInRelease(newItemPosition)
- return areItemsTheSame(oldItem, newItem)
- }
+ override fun getNewListSize(): Int {
+ return updateDataCopy.size
+ }
- override fun areContentsTheSame(
- oldItemPosition: Int,
- newItemPosition: Int
- ): Boolean {
- if (oldItemPosition >= mDataList.size) return false
- if (newItemPosition >= updateDataCopy.size) return false
+ override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
+ val oldItem = mDataList.safelyGetInRelease(oldItemPosition)
+ val newItem = updateDataCopy.safelyGetInRelease(newItemPosition)
+ return areItemsTheSame(oldItem, newItem)
+ }
- val oldItem = mDataList.safelyGetInRelease(oldItemPosition)
- val newItem = updateDataCopy.safelyGetInRelease(newItemPosition)
- return areContentsTheSame(oldItem, newItem)
- }
- })
- ListExecutor.uiExecutor.execute {
- mDataList = ArrayList(updateData)
- if (diffResult != null) {
+ override fun areContentsTheSame(
+ oldItemPosition: Int,
+ newItemPosition: Int
+ ): Boolean {
+ val oldItem = mDataList.safelyGetInRelease(oldItemPosition)
+ val newItem = updateDataCopy.safelyGetInRelease(newItemPosition)
+ return areContentsTheSame(oldItem, newItem)
+ }
+ })
+ ListExecutor.uiExecutor.execute {
+ mDataList = updateDataCopy
diffResult.dispatchUpdatesTo(this@DiffUtilAdapter)
- } else {
- notifyDataSetChanged()
}
}
+ } catch (e: IndexOutOfBoundsException) {
+ testChannelOnly {
+ ToastUtils.toast("DiffUtilAdapter 遇到数组越界异常,请检查")
+ }
+ mDataList = updateDataCopy
+ notifyDataSetChanged()
}
}
diff --git a/app/src/main/java/com/gh/gamecenter/baselist/ListAdapter.java b/app/src/main/java/com/gh/gamecenter/baselist/ListAdapter.java
index 9e65c7ab71..a11051f56b 100644
--- a/app/src/main/java/com/gh/gamecenter/baselist/ListAdapter.java
+++ b/app/src/main/java/com/gh/gamecenter/baselist/ListAdapter.java
@@ -46,6 +46,10 @@ public abstract class ListAdapter extends BaseRecyclerAdapter {
return;
}
+ calculateDiff(updateData);
+ }
+
+ protected void calculateDiff(List updateData) {
// 若直接传 updateData 给 DiffUtils 可能因为其它地方操作 updateData 这个列表而出现 ArrayIndexOutOfBounds 异常
// 这里用新的数组包裹原数据
ArrayList updateDataCopy = new ArrayList<>(updateData);
diff --git a/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListFragment.kt b/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListFragment.kt
index 979389be63..0c94c8485a 100644
--- a/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/catalog/NewCatalogListFragment.kt
@@ -3,22 +3,24 @@ package com.gh.gamecenter.catalog
import android.os.Bundle
import android.view.View
import com.ethanhua.skeleton.Skeleton
-import com.gh.gamecenter.common.constant.Constants
import com.gh.common.exposure.ExposureListener
import com.gh.common.exposure.ExposureSource
import com.gh.common.util.DialogUtils
-import com.gh.gamecenter.common.constant.EntranceConsts
-import com.gh.gamecenter.common.utils.observeNonNull
-import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.common.view.CatalogFilterView
import com.gh.common.xapk.XapkInstaller
import com.gh.common.xapk.XapkUnzipStatus
import com.gh.download.DownloadManager
import com.gh.gamecenter.R
import com.gh.gamecenter.baselist.ListFragment
+import com.gh.gamecenter.common.constant.Constants
+import com.gh.gamecenter.common.constant.EntranceConsts
+import com.gh.gamecenter.common.utils.observeNonNull
import com.gh.gamecenter.common.utils.toColor
+import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.databinding.FragmentCatalogListBinding
-import com.gh.gamecenter.entity.*
+import com.gh.gamecenter.entity.CatalogEntity
+import com.gh.gamecenter.entity.GameEntity
+import com.gh.gamecenter.entity.SubjectSettingEntity
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBPackage
import com.lightgame.download.DataWatcher
@@ -42,6 +44,10 @@ class NewCatalogListFragment : ListFragment
showUnzipFailureDialog(downloadEntity)
}
}
+
+ override fun onDataInit(downloadEntity: DownloadEntity) {
+ mAdapter?.notifyItemByDownload(downloadEntity)
+ }
}
private var mBinding: FragmentCatalogListBinding? = null
diff --git a/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogFragment.kt b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogFragment.kt
index 20093e678d..7c9788fbc6 100644
--- a/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/catalog/SpecialCatalogFragment.kt
@@ -32,7 +32,7 @@ class SpecialCatalogFragment : ListFragment(application) {
+ private val mExposureSourceList: List?) : ListViewModel(application) {
private val mApi = RetrofitManager.getInstance().api
val basicExposureSource by lazy {
arrayListOf().apply {
- mExposureSource?.let { add(it) }
+ if (!mExposureSourceList.isNullOrEmpty()) {
+ addAll(mExposureSourceList)
+ }
add(ExposureSource("分类", mCatalogTitle))
}
}
@@ -98,7 +100,7 @@ class SpecialCatalogViewModel(application: Application,
class Factory(private val mCatalogId: String,
private val mCatalogTitle: String,
private val mIsCategoryV2: Boolean,
- private val mExposureSource: ExposureSource?
+ private val mExposureSourceList: List?
) : ViewModelProvider.NewInstanceFactory() {
override fun create(modelClass: Class): T {
return SpecialCatalogViewModel(
@@ -106,7 +108,7 @@ class SpecialCatalogViewModel(application: Application,
mCatalogId,
mCatalogTitle,
mIsCategoryV2,
- mExposureSource
+ mExposureSourceList
) as T
}
}
diff --git a/app/src/main/java/com/gh/gamecenter/category/NewCategoryListFragment.kt b/app/src/main/java/com/gh/gamecenter/category/NewCategoryListFragment.kt
index 0cede00121..15acd24cf0 100644
--- a/app/src/main/java/com/gh/gamecenter/category/NewCategoryListFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/category/NewCategoryListFragment.kt
@@ -4,9 +4,8 @@ import android.os.Bundle
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import com.ethanhua.skeleton.Skeleton
-import com.gh.gamecenter.common.constant.Constants
import com.gh.common.exposure.ExposureListener
-import com.gh.common.util.*
+import com.gh.common.util.DialogUtils
import com.gh.common.view.ConfigFilterView
import com.gh.common.xapk.XapkInstaller
import com.gh.common.xapk.XapkUnzipStatus
@@ -14,6 +13,7 @@ import com.gh.download.DownloadManager
import com.gh.gamecenter.R
import com.gh.gamecenter.baselist.ListAdapter
import com.gh.gamecenter.baselist.ListFragment
+import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.observeNonNull
import com.gh.gamecenter.common.utils.toColor
@@ -45,6 +45,10 @@ class NewCategoryListFragment : ListFragment(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST),
EntranceConsts.KEY_LAST_PAGE_DATA to mLastPageDataMap
)
childFragmentManager
@@ -331,7 +331,7 @@ class CategoryV2Fragment : LazyFragment() {
EntranceConsts.KEY_CATEGORY_ID to id,
EntranceConsts.KEY_SUB_CATEGORY_ID to sidebars[selectedCategoryPosition].categoryId,
EntranceConsts.KEY_CATEGORY_TITLE to mCategoryTitle,
- EntranceConsts.KEY_EXPOSURE_SOURCE to arguments?.getParcelable(EntranceConsts.KEY_EXPOSURE_SOURCE),
+ EntranceConsts.KEY_EXPOSURE_SOURCE_LIST to arguments?.getParcelableArrayList(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST),
EntranceConsts.KEY_LAST_PAGE_DATA to mLastPageDataMap
)
childFragmentManager
@@ -360,7 +360,7 @@ class CategoryV2Fragment : LazyFragment() {
EntranceConsts.KEY_CATEGORY_ID to id,
EntranceConsts.KEY_SUB_CATEGORY_ID to sidebars[position].categoryId,
EntranceConsts.KEY_CATALOG_TITLE to mCategoryTitle,
- EntranceConsts.KEY_EXPOSURE_SOURCE to arguments?.getParcelable(EntranceConsts.KEY_EXPOSURE_SOURCE),
+ EntranceConsts.KEY_EXPOSURE_SOURCE_LIST to arguments?.getParcelableArrayList(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST),
EntranceConsts.KEY_LAST_PAGE_DATA to mLastPageDataMap
)
childFragmentManager
@@ -378,7 +378,7 @@ class CategoryV2Fragment : LazyFragment() {
EntranceConsts.KEY_IS_CATEGORY_V2 to true,
EntranceConsts.KEY_CATALOG_ID to id,
EntranceConsts.KEY_CATALOG_TITLE to mCategoryTitle,
- EntranceConsts.KEY_EXPOSURE_SOURCE to arguments?.getParcelable(EntranceConsts.KEY_EXPOSURE_SOURCE),
+ EntranceConsts.KEY_EXPOSURE_SOURCE_LIST to arguments?.getParcelableArrayList(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST),
EntranceConsts.KEY_LAST_PAGE_DATA to mLastPageDataMap
)
childFragmentManager
@@ -391,7 +391,7 @@ class CategoryV2Fragment : LazyFragment() {
EntranceConsts.KEY_CATEGORY_ID to id,
EntranceConsts.KEY_SUB_CATEGORY_ID to sidebars[position].categoryId,
EntranceConsts.KEY_CATALOG_TITLE to mCategoryTitle,
- EntranceConsts.KEY_EXPOSURE_SOURCE to arguments?.getParcelable(EntranceConsts.KEY_EXPOSURE_SOURCE),
+ EntranceConsts.KEY_EXPOSURE_SOURCE_LIST to arguments?.getParcelableArrayList(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST),
EntranceConsts.KEY_LAST_PAGE_DATA to mLastPageDataMap
)
}
@@ -413,7 +413,7 @@ class CategoryV2Fragment : LazyFragment() {
EntranceConsts.KEY_CATEGORY_ID to id,
EntranceConsts.KEY_SUB_CATEGORY_ID to sidebars[position].categoryId,
EntranceConsts.KEY_CATALOG_TITLE to mCategoryTitle,
- EntranceConsts.KEY_EXPOSURE_SOURCE to arguments?.getParcelable(EntranceConsts.KEY_EXPOSURE_SOURCE),
+ EntranceConsts.KEY_EXPOSURE_SOURCE_LIST to arguments?.getParcelableArrayList(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST),
EntranceConsts.KEY_LAST_PAGE_DATA to mLastPageDataMap
)
}
diff --git a/app/src/main/java/com/gh/gamecenter/category2/CategoryV2ListAdapter.kt b/app/src/main/java/com/gh/gamecenter/category2/CategoryV2ListAdapter.kt
index 36459ce123..d612c7b9c3 100644
--- a/app/src/main/java/com/gh/gamecenter/category2/CategoryV2ListAdapter.kt
+++ b/app/src/main/java/com/gh/gamecenter/category2/CategoryV2ListAdapter.kt
@@ -110,7 +110,9 @@ class CategoryV2ListAdapter(
val sortSize = mViewModel.sortSize.text
val exposureSources = ArrayList()
- mViewModel.exposureSource?.let { exposureSources.add(it) }
+ if (!mViewModel.exposureSourceList.isNullOrEmpty()) {
+ exposureSources.addAll(mViewModel.exposureSourceList!!)
+ }
exposureSources.add(ExposureSource("分类", categoryTitle))
exposureSources.add(ExposureSource(selectedCategoryName))
exposureSources.add(ExposureSource("二级分类详情", "$selectedSubCatalogName+$sortType+$sortSize"))
diff --git a/app/src/main/java/com/gh/gamecenter/category2/CategoryV2ListFragment.kt b/app/src/main/java/com/gh/gamecenter/category2/CategoryV2ListFragment.kt
index c0ba61b88f..a6552429e4 100644
--- a/app/src/main/java/com/gh/gamecenter/category2/CategoryV2ListFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/category2/CategoryV2ListFragment.kt
@@ -4,9 +4,7 @@ import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import com.ethanhua.skeleton.Skeleton
-import com.gh.gamecenter.common.constant.Constants
import com.gh.common.exposure.ExposureListener
-import com.gh.common.util.*
import com.gh.common.util.DialogUtils
import com.gh.common.view.CategoryFilterView
import com.gh.common.xapk.XapkInstaller
@@ -14,6 +12,7 @@ import com.gh.common.xapk.XapkUnzipStatus
import com.gh.download.DownloadManager
import com.gh.gamecenter.R
import com.gh.gamecenter.baselist.ListFragment
+import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.databinding.FragmentCategoryListBinding
@@ -47,6 +46,10 @@ class CategoryV2ListFragment : ListFragment
showUnzipFailureDialog(downloadEntity)
}
}
+
+ override fun onDataInit(downloadEntity: DownloadEntity) {
+ mAdapter?.notifyItemByDownload(downloadEntity)
+ }
}
override fun getLayoutId() = 0
@@ -57,7 +60,7 @@ class CategoryV2ListFragment : ListFragment
viewModelProvider(CategoryV2ListViewModel.Factory(
mCategoryId,
mSubCategoryId,
- arguments?.getParcelable(EntranceConsts.KEY_EXPOSURE_SOURCE)))
+ arguments?.getParcelableArrayList(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST)))
override fun provideListAdapter() = mAdapter
?: CategoryV2ListAdapter(
diff --git a/app/src/main/java/com/gh/gamecenter/category2/CategoryV2ListViewModel.kt b/app/src/main/java/com/gh/gamecenter/category2/CategoryV2ListViewModel.kt
index 10c19a6b3b..afc2bce771 100644
--- a/app/src/main/java/com/gh/gamecenter/category2/CategoryV2ListViewModel.kt
+++ b/app/src/main/java/com/gh/gamecenter/category2/CategoryV2ListViewModel.kt
@@ -20,7 +20,7 @@ import io.reactivex.Single
class CategoryV2ListViewModel(application: Application,
val categoryId: String,
var categoryIds: String,
- var exposureSource: ExposureSource?) : ListViewModel(application) {
+ var exposureSourceList: List?) : ListViewModel(application) {
val refresh = MutableLiveData()
@@ -85,13 +85,13 @@ class CategoryV2ListViewModel(application: Application,
}
}
- class Factory(val categoryId: String, val categoryIds: String, val exposureSource: ExposureSource?): ViewModelProvider.NewInstanceFactory() {
+ class Factory(val categoryId: String, val categoryIds: String, val exposureSourceList: List?): ViewModelProvider.NewInstanceFactory() {
override fun create(modelClass: Class): T {
return CategoryV2ListViewModel(
HaloApp.getInstance().application,
categoryId,
categoryIds,
- exposureSource
+ exposureSourceList
) as T
}
}
diff --git a/app/src/main/java/com/gh/gamecenter/collection/CommunityArticleViewModel.kt b/app/src/main/java/com/gh/gamecenter/collection/CommunityArticleViewModel.kt
index 5e2daac106..d3a958dda0 100644
--- a/app/src/main/java/com/gh/gamecenter/collection/CommunityArticleViewModel.kt
+++ b/app/src/main/java/com/gh/gamecenter/collection/CommunityArticleViewModel.kt
@@ -88,7 +88,7 @@ class CommunityArticleViewModel(application: Application) : ListViewModel() {
diff --git a/app/src/main/java/com/gh/gamecenter/download/DownloadFragment.kt b/app/src/main/java/com/gh/gamecenter/download/DownloadFragment.kt
index 6e7d87a6fa..e94e5e0db3 100644
--- a/app/src/main/java/com/gh/gamecenter/download/DownloadFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/download/DownloadFragment.kt
@@ -148,7 +148,7 @@ class DownloadFragment : BaseFragment_TabLayout() {
private fun updateDownloadHint() {
if (!::mDownloadNumberTv.isInitialized || !isAdded) return
- val downloadData = DownloadManager.getInstance().allDownloadEntityExcludeSilentUpdate
+ val downloadData = DownloadManager.getInstance().allDownloadEntityExcludeSilentTask
if (downloadData.size > 0) {
mDownloadNumberTv.visibility = View.VISIBLE
} else {
diff --git a/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragment.java b/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragment.java
index ac1f1aef3a..6d303ed94b 100644
--- a/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragment.java
+++ b/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragment.java
@@ -169,12 +169,10 @@ public class GameDownloadFragment extends BaseFragment implements View.OnClickLi
if (status.equals(DownloadStatus.downloading)
|| status.equals(DownloadStatus.waiting)
|| status.equals(DownloadStatus.subscribe)) {
- // 静默更新任务不需要添加
- if (ExtensionsKt.isSilentUpdate(downloadEntity)) {
- return;
- }
- //下载模拟器任务不需要添加
- if (ExtensionsKt.isSimulatorDownload(downloadEntity)) {
+ // 静默更新任务,下载模拟器任务,畅玩游戏不需要添加
+ if (ExtensionsKt.isSilentUpdate(downloadEntity)
+ || ExtensionsKt.isSimulatorDownload(downloadEntity)
+ || ExtensionsKt.isVGame(downloadEntity)) {
return;
}
diff --git a/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragmentAdapter.java b/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragmentAdapter.java
index 123dd4d8df..d3de316826 100644
--- a/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragmentAdapter.java
+++ b/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragmentAdapter.java
@@ -47,6 +47,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import androidx.annotation.NonNull;
import androidx.collection.ArrayMap;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
@@ -57,19 +58,19 @@ import androidx.recyclerview.widget.RecyclerView.ViewHolder;
*/
class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
- private LinearLayout mNoDataSkip;
+ private final LinearLayout mNoDataSkip;
- private List downloadingList;
- private List doneList;
+ private final List mDownloadingList;
+ private final List mDownloadedList;
// 1、此处的所有MAP只是对DownloadManager内部Map的引用,
// 2、任何对下载器任务的操作,通过DownloadManager处理,由DownloadManager处理之后抛出对应的状态变化事件
// 3、监听下载任务状态变化,刷新界面
// 4、对状态只读不写。
- private ArrayMap locationMap;
- private ArrayMap statusMap;
- private ArrayMap urlMap;
- private ArrayList deleteList;
+ private final ArrayMap locationMap;
+ private final ArrayMap statusMap;
+ private final ArrayMap urlMap;
+ private final ArrayList deleteList;
private String url;
@@ -80,21 +81,19 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
mNoDataSkip = textView;
-// statusMap = DownloadManager.getInstance().getStatusMap();
-// downloadingList = new ArrayList<>(DownloadManager.getInstance().getDownloadingMap().values());
-
statusMap = new ArrayMap<>();
- downloadingList = new ArrayList<>();
+ mDownloadingList = new ArrayList<>();
locationMap = new ArrayMap<>();
urlMap = new ArrayMap<>();
deleteList = new ArrayList<>();
- doneList = new ArrayList<>();
+ mDownloadedList = new ArrayList<>();
}
+ @NonNull
@Override
- public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == 0) {
return new DownloadHeadViewHolder(DownloadmanagerItemHeadBinding.inflate(mLayoutInflater, parent, false));
} else {
@@ -103,7 +102,7 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
}
@Override
- public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
+ public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, int position) {
if (holder instanceof GameDownloadViewHolder) {
final GameDownloadViewHolder viewHolder = (GameDownloadViewHolder) holder;
@@ -116,12 +115,12 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
viewHolder.binding.dmItemTvSpeed.setTextColor(ContextCompat.getColor(mContext, R.color.text_9a9a9a));
final DownloadEntity downloadEntity;
- if (doneList.size() != 0 && position > 0 && position <= doneList.size()) {
- downloadEntity = doneList.get(position - 1);
- } else if (doneList.isEmpty()) {
- downloadEntity = downloadingList.get(position - 1);
+ if (mDownloadedList.size() != 0 && position > 0 && position <= mDownloadedList.size()) {
+ downloadEntity = mDownloadedList.get(position - 1);
+ } else if (mDownloadedList.isEmpty()) {
+ downloadEntity = mDownloadingList.get(position - 1);
} else {
- downloadEntity = downloadingList.get(position - doneList.size() - 2);
+ downloadEntity = mDownloadingList.get(position - mDownloadedList.size() - 2);
}
String icon = downloadEntity.getIcon();
String rawIcon = ExtensionsKt.getMetaExtra(downloadEntity, Constants.RAW_GAME_ICON);
@@ -172,7 +171,7 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
viewHolder.binding.dmItemTvStartorpause.setTextColor(Color.WHITE);
if (downloadEntity.isPluggable()
- && PackagesManager.INSTANCE.isInstalled(downloadEntity.getPackageName())) {
+ && PackagesManager.isInstalled(downloadEntity.getPackageName())) {
viewHolder.binding.dmItemTvStartorpause.setText("安装");
viewHolder.binding.dmItemTvStartorpause.setBackgroundResource(R.drawable.download_button_pluggable_style);
} else {
@@ -281,7 +280,8 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
if (isSubscribe) {
DownloadManager.getInstance().subscribe(downloadEntity);
statusMap.put(url, DownloadStatus.subscribe.getStatus());
- notifyItemChanged(doneList.isEmpty() ? 0 : 1 + doneList.size());
+ notifyItemChanged(mDownloadedList.isEmpty() ? 0 : 1 + mDownloadedList
+ .size());
} else {
LinearLayout.LayoutParams lparams = new LinearLayout.LayoutParams(
0, LinearLayout.LayoutParams.WRAP_CONTENT);
@@ -298,7 +298,8 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
viewHolder.binding.dmItemTvStartorpause.setText("暂停");
viewHolder.binding.dmItemTvStartorpause.setTextColor(ContextCompat.getColor(mContext, R.color.theme_font));
statusMap.put(url, DownloadStatus.downloading.getStatus());
- notifyItemChanged(doneList.isEmpty() ? 0 : 1 + doneList.size());
+ notifyItemChanged(mDownloadedList.isEmpty() ? 0 : 1 + mDownloadedList
+ .size());
Message msg = Message.obtain();
msg.what = DownloadConfig.CONTINUE_DOWNLOAD_TASK;
@@ -312,7 +313,7 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
PermissionHelper.checkStoragePermissionBeforeAction(mContext, () -> {
final String path = downloadEntity.getPath();
if (downloadEntity.isPluggable()
- && PackagesManager.INSTANCE.isInstalled(downloadEntity.getPackageName())) {
+ && PackagesManager.isInstalled(downloadEntity.getPackageName())) {
showPluginDialog(downloadEntity.getPath());
} else {
if (FileUtils.isEmptyFile(path)) {
@@ -335,7 +336,7 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
viewHolder.binding.dmItemTvDownloads.setText("已暂停");
viewHolder.binding.dmItemIvDelete.setVisibility(View.VISIBLE);
statusMap.put(url, DownloadStatus.pause.getStatus());
- notifyItemChanged(doneList.isEmpty() ? 0 : 1 + doneList.size());
+ notifyItemChanged(mDownloadedList.isEmpty() ? 0 : 1 + mDownloadedList.size());
Message msg = Message.obtain();
msg.what = DownloadConfig.PAUSE_DOWNLOAD_TASK;
msg.obj = url;
@@ -344,7 +345,7 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
// DownloadManager.getInstance().pause(downloadEntity);
break;
case "等待":
- Utils.toast(mContext, "最多只能同时启动3个下载任务");
+ Utils.toast(mContext, "最多只能同时下载三个任务,请稍等");
break;
case "启动":
PackageUtils.launchApplicationByPackageName(mContext, downloadEntity.getPackageName());
@@ -398,7 +399,7 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
viewHolder.binding.dmItemHeadTvTask.setTextColor(ContextCompat.getColor(mContext, R.color.text_6c6c6c));
viewHolder.binding.dmItemHeadTvAllstart.setTextColor(ContextCompat.getColor(mContext, R.color.theme_font));
- if (position == 0 && doneList.size() != 0) {
+ if (position == 0 && mDownloadedList.size() != 0) {
viewHolder.binding.dmItemHeadTvTask.setText("已完成");
viewHolder.binding.dmItemHeadTvAllstart.setVisibility(View.GONE);
} else {
@@ -407,14 +408,14 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
int dlNumber = 0;
int wtNumber = 0;
- for (DownloadEntity downloadEntity : downloadingList) {
+ for (DownloadEntity downloadEntity : mDownloadingList) {
if (DownloadStatus.downloading.equals(downloadEntity.getStatus())) {
dlNumber++;
} else if (DownloadStatus.waiting.equals(downloadEntity.getStatus())) {
wtNumber++;
}
}
- if ((dlNumber + wtNumber) == downloadingList.size()) {
+ if ((dlNumber + wtNumber) == mDownloadingList.size()) {
viewHolder.binding.dmItemHeadTvAllstart.setText(R.string.download_all_push);
viewHolder.binding.dmItemHeadTvAllstart.setTextColor(ContextCompat.getColor(mContext, R.color.btn_gray));
} else {
@@ -439,7 +440,7 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
}
public void startAll(DownloadHeadViewHolder viewHolder) {
- for (DownloadEntity downloadEntity : downloadingList) {
+ for (DownloadEntity downloadEntity : mDownloadingList) {
DownloadManager.getInstance().put(downloadEntity.getUrl(),
System.currentTimeMillis());
Message msg = Message.obtain();
@@ -457,7 +458,7 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
}
public void pauseAll(DownloadHeadViewHolder viewHolder) {
- for (DownloadEntity downloadEntity : downloadingList) {
+ for (DownloadEntity downloadEntity : mDownloadingList) {
DownloadManager.getInstance().put(downloadEntity.getUrl(),
System.currentTimeMillis());
Message msg = Message.obtain();
@@ -476,7 +477,7 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
@Override
public int getItemViewType(int position) {
- if (position == 0 || (doneList.size() > 0 && position == 1 + doneList.size())) {
+ if (position == 0 || (mDownloadedList.size() > 0 && position == 1 + mDownloadedList.size())) {
return 0;
}
return 1;
@@ -484,16 +485,16 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
@Override
public int getItemCount() {
- if (doneList.isEmpty() && downloadingList.isEmpty()) {
+ if (mDownloadedList.isEmpty() && mDownloadingList.isEmpty()) {
return 0;
}
- if (doneList.isEmpty()) {
- return 1 + downloadingList.size();
+ if (mDownloadedList.isEmpty()) {
+ return 1 + mDownloadingList.size();
}
- if (downloadingList.isEmpty()) {
- return 1 + doneList.size();
+ if (mDownloadingList.isEmpty()) {
+ return 1 + mDownloadedList.size();
}
- return 1 + doneList.size() + 1 + downloadingList.size();
+ return 1 + mDownloadedList.size() + 1 + mDownloadingList.size();
}
// 显示插件化
@@ -516,62 +517,62 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
return;
}
boolean isDone = false;
- for (DownloadEntity downloadEntity : doneList) {
+ for (DownloadEntity downloadEntity : mDownloadedList) {
if (entry.getUrl().equals(downloadEntity.getUrl())) {
isDone = true;
break;
}
}
if (isDone) {
- if (downloadingList.isEmpty() && doneList.size() == 1) {
- doneList.remove(location.intValue());
+ if (mDownloadingList.isEmpty() && mDownloadedList.size() == 1) {
+ mDownloadedList.remove(location.intValue());
locationMap.clear();
notifyDataSetChanged();
EventBus.getDefault().post(new EBDownloadChanged("download", View.GONE, 0));
if (mNoDataSkip.getVisibility() == View.GONE) {
mNoDataSkip.setVisibility(View.VISIBLE);
}
- } else if (doneList.size() == 1) {
- doneList.remove(location.intValue());
+ } else if (mDownloadedList.size() == 1) {
+ mDownloadedList.remove(location.intValue());
initLocationMap();
notifyItemRangeRemoved(0, 2);
EventBus.getDefault().post(new EBDownloadChanged("download", View.VISIBLE,
- downloadingList.size()));
+ mDownloadingList.size()));
} else {
- doneList.remove(location.intValue());
+ mDownloadedList.remove(location.intValue());
initLocationMap();
notifyItemRemoved(location + 1);
EventBus.getDefault().post(new EBDownloadChanged("download", View.VISIBLE,
- downloadingList.size()));
+ mDownloadingList.size()));
}
} else {
- if (doneList.isEmpty() && downloadingList.size() == 1) {
- downloadingList.remove(location.intValue());
+ if (mDownloadedList.isEmpty() && mDownloadingList.size() == 1) {
+ mDownloadingList.remove(location.intValue());
locationMap.clear();
notifyDataSetChanged();
EventBus.getDefault().post(new EBDownloadChanged("download", View.GONE, 0));
if (mNoDataSkip.getVisibility() == View.GONE) {
mNoDataSkip.setVisibility(View.VISIBLE);
}
- } else if (downloadingList.size() == 1) {
- downloadingList.remove(location.intValue());
+ } else if (mDownloadingList.size() == 1) {
+ mDownloadingList.remove(location.intValue());
initLocationMap();
notifyItemRangeRemoved(getBase(), 2);
EventBus.getDefault().post(new EBDownloadChanged("download", View.VISIBLE,
- downloadingList.size()));
+ mDownloadingList.size()));
} else {
- downloadingList.remove(location.intValue());
+ mDownloadingList.remove(location.intValue());
initLocationMap();
notifyDataSetChanged();
EventBus.getDefault().post(new EBDownloadChanged("download", View.VISIBLE,
- downloadingList.size()));
+ mDownloadingList.size()));
}
}
deleteList.add(entry.getUrl());
statusMap.remove(entry.getUrl());
- notifyItemChanged(doneList.isEmpty() ? 0 : 1 + doneList.size());
+ notifyItemChanged(mDownloadedList.isEmpty() ? 0 : 1 + mDownloadedList.size());
}
// 显示删除提示框
@@ -580,7 +581,7 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
String msg;
if (XapkUnzipStatus.UNZIPPING.name().equals(xapkStatus)) {
msg = "游戏正在解压安装哦,确定删除?";
- } else if (doneList.size() != 0 && position <= doneList.size()) {
+ } else if (mDownloadedList.size() != 0 && position <= mDownloadedList.size()) {
msg = "游戏还没安装哦,确定删除?";
} else {
msg = "游戏还没下载完,确定删除?";
@@ -596,24 +597,24 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
public void initLocationMap() {
locationMap.clear();
- for (int i = 0; i < doneList.size(); i++) {
- locationMap.put(doneList.get(i).getUrl(), i);
+ for (int i = 0; i < mDownloadedList.size(); i++) {
+ locationMap.put(mDownloadedList.get(i).getUrl(), i);
}
- for (int i = 0; i < downloadingList.size(); i++) {
- locationMap.put(downloadingList.get(i).getUrl(), i);
+ for (int i = 0; i < mDownloadingList.size(); i++) {
+ locationMap.put(mDownloadingList.get(i).getUrl(), i);
}
}
public int getBase() {
- return doneList.isEmpty() ? 0 : 1 + doneList.size();
+ return mDownloadedList.isEmpty() ? 0 : 1 + mDownloadedList.size();
}
List getDownloadingList() {
- return downloadingList;
+ return mDownloadingList;
}
List getDoneList() {
- return doneList;
+ return mDownloadedList;
}
public ArrayMap getLocationMap() {
@@ -641,20 +642,20 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
}
void initMap() {
- downloadingList.clear();
- doneList.clear();
+ mDownloadingList.clear();
+ mDownloadedList.clear();
statusMap.clear();
urlMap.clear();
- for (DownloadEntity downloadEntity : DownloadManager.getInstance().getAllDownloadEntityExcludeSilentUpdate()) {
+ for (DownloadEntity downloadEntity : DownloadManager.getInstance().getAllDownloadEntityExcludeSilentTask()) {
statusMap.put(downloadEntity.getUrl(), downloadEntity.getStatus().name());
if (DownloadStatus.done.equals(downloadEntity.getStatus())) {
if (!ExtensionsKt.isSimulatorGame(downloadEntity)) {
urlMap.put(PackageUtils.getPackageNameByPath(mContext,
downloadEntity.getPath()), downloadEntity.getUrl());
- doneList.add(downloadEntity);
+ mDownloadedList.add(downloadEntity);
}
} else {
- downloadingList.add(downloadEntity);
+ mDownloadingList.add(downloadEntity);
}
}
// 排序
@@ -667,7 +668,7 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
return 0;
}
};
- Collections.sort(downloadingList, comparator);
+ Collections.sort(mDownloadingList, comparator);
comparator = (lhs, rhs) -> {
if (rhs.getEnd() > lhs.getEnd()) {
@@ -678,7 +679,7 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
return 0;
}
};
- Collections.sort(doneList, comparator);
+ Collections.sort(mDownloadedList, comparator);
initLocationMap();
}
diff --git a/app/src/main/java/com/gh/gamecenter/download/InstalledGameViewModel.kt b/app/src/main/java/com/gh/gamecenter/download/InstalledGameViewModel.kt
index 48a52632df..8e3738f2c0 100644
--- a/app/src/main/java/com/gh/gamecenter/download/InstalledGameViewModel.kt
+++ b/app/src/main/java/com/gh/gamecenter/download/InstalledGameViewModel.kt
@@ -9,12 +9,12 @@ import com.gh.common.filter.RegionSettingHelper.shouldThisGameBeFiltered
import com.gh.common.util.ApkActiveUtils
import com.gh.common.util.GameUtils
import com.gh.common.util.PackageUtils
-import com.gh.gamecenter.core.utils.ThirdPartyPackageHelper.getGameId
import com.gh.download.DownloadManager
+import com.gh.gamecenter.common.retrofit.Response
+import com.gh.gamecenter.core.utils.ThirdPartyPackageHelper.getGameId
import com.gh.gamecenter.entity.ApkEntity
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.entity.GameInstall
-import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
@@ -35,6 +35,9 @@ class InstalledGameViewModel(application: Application) : AndroidViewModel(applic
list.add(GameInstall(id = entity.gameId))
}
for (gameInstall in list) {
+ // 畅玩游戏不出现在常规的下载管理里
+ if (gameInstall.isSmoothGame) continue
+
val ghId = PackageUtils.getMetaData(getApplication(), gameInstall.packageName, "gh_id")
if (ghId != null && ghId != gameInstall.id) {
gameInstall.id = ghId.toString()
diff --git a/app/src/main/java/com/gh/gamecenter/download/UpdatableGameViewModel.kt b/app/src/main/java/com/gh/gamecenter/download/UpdatableGameViewModel.kt
index b82a313e66..bb242a8edb 100644
--- a/app/src/main/java/com/gh/gamecenter/download/UpdatableGameViewModel.kt
+++ b/app/src/main/java/com/gh/gamecenter/download/UpdatableGameViewModel.kt
@@ -3,27 +3,31 @@ package com.gh.gamecenter.download
import android.app.Application
import android.view.View
import androidx.lifecycle.*
-import com.gh.gamecenter.common.base.BaseSimpleDao
-import com.gh.gamecenter.common.constant.Constants
import com.gh.common.exposure.ExposureUtils
import com.gh.common.exposure.ExposureUtils.logADownloadExposureEvent
import com.gh.common.history.HistoryHelper.insertGameEntity
-import com.gh.common.util.*
-import com.gh.gamecenter.core.utils.GsonUtils.toJson
+import com.gh.common.util.ApkActiveUtils
+import com.gh.common.util.DataCollectionUtils
import com.gh.common.util.PackageInstaller.createDownloadId
import com.gh.common.util.PackageInstaller.getDownloadPathWithId
+import com.gh.common.util.PackageUtils
+import com.gh.common.util.PlatformUtils
import com.gh.download.DownloadManager
+import com.gh.gamecenter.common.base.BaseSimpleDao
+import com.gh.gamecenter.common.constant.Constants
+import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.addMetaExtra
import com.gh.gamecenter.common.utils.secondOrNull
import com.gh.gamecenter.common.utils.toProperReadableSize
import com.gh.gamecenter.common.utils.tryCatchInRelease
-import com.gh.gamecenter.core.utils.*
+import com.gh.gamecenter.core.utils.GsonUtils.toJson
+import com.gh.gamecenter.core.utils.SPUtils
+import com.gh.gamecenter.core.utils.UrlFilterUtils
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.entity.GameUpdateEntity
import com.gh.gamecenter.entity.PluginLocation
import com.gh.gamecenter.eventbus.EBDownloadChanged
import com.gh.gamecenter.manager.PackagesManager
-import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
@@ -32,7 +36,6 @@ import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import org.greenrobot.eventbus.EventBus
import java.util.*
-import kotlin.collections.ArrayList
class UpdatableGameViewModel(
application: Application,
@@ -72,7 +75,7 @@ class UpdatableGameViewModel(
// 有闪退日志说这个 update 实体可能为空,实在看不原因 :(
if (update == null) continue
// 筛选仅下载管理出现的插件化更新
- if (update.isShowPlugin(PluginLocation.only_index)) {
+ if (update.isShowPlugin(PluginLocation.only_index) && update.downloadStatus != "smooth") {
val platform =
PlatformUtils.getInstance(getApplication()).getPlatformName(update.platform)
if (!platform.isNullOrEmpty() && "官方版" != platform) {
@@ -580,6 +583,7 @@ class UpdatableGameViewModel(
downloadEntity.addMetaExtra(Constants.RAW_GAME_ICON, update.rawIcon)
downloadEntity.addMetaExtra(Constants.GAME_ICON_SUBSCRIPT, update.iconSubscript)
downloadEntity.addMetaExtra(Constants.DOWNLOAD_ID, downloadId)
+ downloadEntity.addMetaExtra(Constants.APK_MD5, update.md5)
val platform = PlatformUtils.getInstance(getApplication()).getPlatformName(update.platform)
if ("官方版" != platform) {
diff --git a/app/src/main/java/com/gh/gamecenter/entity/ApkEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/ApkEntity.kt
index 1c8db5a4e4..b599df9036 100644
--- a/app/src/main/java/com/gh/gamecenter/entity/ApkEntity.kt
+++ b/app/src/main/java/com/gh/gamecenter/entity/ApkEntity.kt
@@ -25,6 +25,7 @@ data class ApkEntity(@SerializedName("package")
var apkLink: ApkLink? = null,
var plugin: String? = "",/*控制是否显示插件化 默认:open,取值有:open/only_index/only_game/close*/
var time: Long? = null,
+ var md5: String? = null, // 包体的 MD5 用于内型为畅玩的游戏使用用来更新
@SerializedName("platform_name")
private var platformName: String = "",
val remark: String = "",
diff --git a/app/src/main/java/com/gh/gamecenter/entity/AppEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/AppEntity.kt
index 9e84ad9f36..70b391b6fd 100644
--- a/app/src/main/java/com/gh/gamecenter/entity/AppEntity.kt
+++ b/app/src/main/java/com/gh/gamecenter/entity/AppEntity.kt
@@ -1,25 +1,27 @@
package com.gh.gamecenter.entity
+import android.os.Parcelable
import com.google.gson.annotations.SerializedName
+import kotlinx.parcelize.Parcelize
-class AppEntity {
-
- var version: String? = null
+@Parcelize
+data class AppEntity(
+ var version: String? = null,
@SerializedName("version_code")
- var versionCode: Int = 0
+ var versionCode: Int = 0,
- var url: String? = null
+ var url: String? = null,
- var size: String? = null
+ var size: String? = null,
- var content: String? = null
+ var content: String? = null,
@SerializedName("force")
- var isForce: Boolean = false
+ var isForce: Boolean = false,
@SerializedName("spare_link")
- var spareLink: String? = ""
+ var spareLink: String? = "",
/**
* NEVER(从不)
@@ -28,5 +30,11 @@ class AppEntity {
* ONCE_A_DAY(每天一次)
* EVERY_TIME_OPEN(每次打开)
*/
- var alert: String? = null
+ var alert: String? = null,
+) : Parcelable {
+ fun isAlertEveryTime() = alert == "EVERY_TIME_OPEN"
+
+ fun isAlertOnceADay() = alert == "ONCE_A_DAY"
}
+
+
diff --git a/app/src/main/java/com/gh/gamecenter/entity/CommentEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/CommentEntity.kt
index 470985fb90..d0b60ec451 100644
--- a/app/src/main/java/com/gh/gamecenter/entity/CommentEntity.kt
+++ b/app/src/main/java/com/gh/gamecenter/entity/CommentEntity.kt
@@ -30,7 +30,7 @@ data class CommentEntity(
var choiceness: Boolean = false,//是否已加精,问题评论用
var images: ArrayList? = arrayListOf(),
- // 楼数,本地字段
+ // 楼层
var floor: Int = 0,
var isExpand: Boolean = false,
@SerializedName("attached") // 楼中楼
diff --git a/app/src/main/java/com/gh/gamecenter/entity/ErrorEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/ErrorEntity.kt
index 82950e6a2f..4ee0c1cd5b 100644
--- a/app/src/main/java/com/gh/gamecenter/entity/ErrorEntity.kt
+++ b/app/src/main/java/com/gh/gamecenter/entity/ErrorEntity.kt
@@ -24,12 +24,28 @@ data class ErrorEntity(var code: Int? = 0,
var answerCount: Int = 0,
@SerializedName("follow_count")
private var followCount: Int = 0,
- val content: String = ""
+ val content: String = "",
+ val title: String = "",
+ val type: String = "",
+ val link: String = "",
+ val text: String = "",
+ @SerializedName("link_community", alternate = ["community"])
+ var community: CommunityEntity? = CommunityEntity()
) {
// 问题关注数默认是1
fun getFollowCount(): Int {
if (followCount > 0) return followCount
return 1
}
+
+ fun toLinkEntity(): LinkEntity {
+ return LinkEntity(
+ title = title,
+ link = link,
+ type = type,
+ text = text,
+ community = community
+ )
+ }
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt
index cdfeebcf25..f46300e47e 100644
--- a/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt
+++ b/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt
@@ -3,19 +3,21 @@ package com.gh.gamecenter.entity
import android.os.Parcelable
import android.text.TextUtils
import com.gh.common.constant.Config
-import com.gh.gamecenter.common.constant.Constants
import com.gh.common.exposure.ExposureEvent
import com.gh.common.filter.RegionSettingHelper
import com.gh.gamecenter.R
+import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.game.data.GameSubjectData
import com.gh.gamecenter.gamedetail.entity.GameInfo
import com.gh.gamecenter.gamedetail.entity.ZoneEntity
+import com.gh.vspace.VHelper
import com.google.gson.annotations.SerializedName
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
import kotlinx.parcelize.IgnoredOnParcel
import kotlinx.parcelize.Parcelize
import java.util.*
+import kotlin.collections.ArrayList
@Parcelize
data class GameEntity(
@@ -212,7 +214,7 @@ data class GameEntity(
private var mH5Link: LinkEntity? = null,
val visit: Int = 0,
@SerializedName("played_time")
- val playedTime: Long = 0,
+ var playedTime: Long = 0,
@SerializedName("played_game_id")
val playedGameId: String = "",
@SerializedName("mutex_package")
@@ -266,8 +268,16 @@ data class GameEntity(
@SerializedName("recommend_text")
var recommendText: String = "",
+ // 专题封面图
+ @SerializedName("column_image")
+ var columnImage: String = "",
+
// 本地字段,使用镜像信息
var useMirrorInfo: Boolean = false,
+
+ // 本地字段,最后打开时间
+ var lastPlayedTime: Long = 0,
+
// 本地字段,曝光用
var displayContent: String = "",
var isPlatformRecommend: Boolean = false,
@@ -475,12 +485,31 @@ data class GameEntity(
fun getApk(): ArrayList {
if (shouldUseMirrorInfo()) return mirrorData?.getApk() ?: arrayListOf()
- if (apk == null) apk = ArrayList()
- if (!Config.isShowPlugin(id)) return getApkNormal()
- if (gameLocation == GameLocation.INDEX && apkIndex != null) return apkIndex!!
- if (gameLocation == GameLocation.SEARCH && apkSearch != null) return apkSearch!!
+ var rawApk = apk ?: ArrayList()
- return apk!!
+ if (!Config.isShowPlugin(id)) {
+ rawApk = getApkNormal()
+ } else if (gameLocation == GameLocation.INDEX && apkIndex != null) {
+ rawApk = apkIndex!!
+ } else if (gameLocation == GameLocation.SEARCH && apkSearch != null) {
+ rawApk = apkSearch!!
+ }
+
+ if (isVGame()) {
+ rawApk.forEach {
+ it.setPlatform(VHelper.PLATFORM_V)
+ it.url = VHelper.getVUrl(it.url)
+ }
+ }
+
+ return rawApk
+ }
+
+ /**
+ * 获取唯一的包名,仅单版本游戏有效,多版本的游戏请不要调用
+ */
+ fun getUniquePackageName(): String? {
+ return getApk().firstOrNull()?.packageName
}
fun getOriginalApk(): ArrayList {
@@ -563,6 +592,16 @@ data class GameEntity(
&& (useMirrorInfo || RegionSettingHelper.shouldThisGameDisplayMirrorInfo(id)))
}
+ fun isVGame(): Boolean {
+ return if (!VHelper.isVGameOn()) {
+ false
+ } else {
+ downloadStatus == "smooth"
+ }
+ }
+
+ fun isSpecialDownload() = RegionSettingHelper.shouldThisGameShowSpecialDownload(id)
+
fun toSimpleGame(): SimpleGame {
val simpleGame = SimpleGame()
simpleGame.id = id
@@ -818,6 +857,8 @@ data class SimpleGame(
//游戏单推荐理由
@SerializedName("recommend_text")
var recommendText: String = "",
+ @SerializedName("download_status")
+ var downloadStatus: String = ""
) : Parcelable {
@IgnoredOnParcel
@@ -842,6 +883,7 @@ data class SimpleGame(
gameEntity.mirrorData = mirrorData?.toGameEntity()
gameEntity.recommendStar = recommendStar
gameEntity.recommendText = recommendText
+ gameEntity.downloadStatus = downloadStatus
return gameEntity
}
}
diff --git a/app/src/main/java/com/gh/gamecenter/entity/GameInstall.kt b/app/src/main/java/com/gh/gamecenter/entity/GameInstall.kt
index b7ba454688..1d27db820e 100644
--- a/app/src/main/java/com/gh/gamecenter/entity/GameInstall.kt
+++ b/app/src/main/java/com/gh/gamecenter/entity/GameInstall.kt
@@ -14,6 +14,7 @@ data class GameInstall(
var isSignByGh: Boolean = false,
var installTime: Long = 0,
var version: String = "",
+ var isSmoothGame: Boolean = false, // 是否是畅玩游戏
var tag: Any? = null) {
companion object {
@@ -28,6 +29,7 @@ data class GameInstall(
gameInstall.iconSubScript = game.iconSubscript
gameInstall.version = PackageUtils.getVersionNameByPackageName(installedPkgName) ?: "unknown"
gameInstall.packageName = installedPkgName
+ gameInstall.isSmoothGame = game.isVGame()
return gameInstall
}
}
diff --git a/app/src/main/java/com/gh/gamecenter/entity/GameUpdateEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/GameUpdateEntity.kt
index eead9177dd..579f42a0bf 100644
--- a/app/src/main/java/com/gh/gamecenter/entity/GameUpdateEntity.kt
+++ b/app/src/main/java/com/gh/gamecenter/entity/GameUpdateEntity.kt
@@ -40,7 +40,9 @@ data class GameUpdateEntity(
var pluggableCollection: GameCollectionEntity? = null, // 插件化包所在的合集
var format: String = "",
var signature: String? = "",
- var category: String? = ""
+ var category: String? = "",
+ var md5: String? = "",
+ var downloadStatus: String? = ""
) {
fun isShowPlugin(location: PluginLocation): Boolean {
diff --git a/app/src/main/java/com/gh/gamecenter/entity/HomeContent.kt b/app/src/main/java/com/gh/gamecenter/entity/HomeContent.kt
index cb7ece6001..7a8e58bacf 100644
--- a/app/src/main/java/com/gh/gamecenter/entity/HomeContent.kt
+++ b/app/src/main/java/com/gh/gamecenter/entity/HomeContent.kt
@@ -22,5 +22,12 @@ data class HomeContent(
@SerializedName("recommend_text")
val recommendText: String = "",
@SerializedName("common_collection")
- val commonCollection: CommonCollectionEntity? = null
+ val commonCollection: CommonCollectionEntity? = null,
+ val image: String = "",
+ @SerializedName("first_line_recommend")
+ val firstLineRecommend: String = "",
+ @SerializedName("second_line_recommend")
+ val secondLineRecommend: String = "",
+ @SerializedName("recommend_tag")
+ val recommendTag: String = "",
)
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/entity/HomeDataEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/HomeDataEntity.kt
new file mode 100644
index 0000000000..b440818656
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/entity/HomeDataEntity.kt
@@ -0,0 +1,16 @@
+package com.gh.gamecenter.entity
+
+import com.google.gson.annotations.SerializedName
+
+data class HomeDataEntity(
+ @SerializedName("home_tab")
+ val homeTab: ArrayList = arrayListOf(),
+ @SerializedName("home_slide")
+ val homeSlide: ArrayList = arrayListOf(),
+ @SerializedName("home_recommend")
+ val homeRecommend: ArrayList = arrayListOf(),
+ @SerializedName("home_content")
+ val homeContent: ArrayList = arrayListOf(),
+ @SerializedName("home_navbar_v2")
+ val homeNavbarV2: SubjectRecommendEntity? = null
+)
diff --git a/app/src/main/java/com/gh/gamecenter/entity/HomeSetting.kt b/app/src/main/java/com/gh/gamecenter/entity/HomeSetting.kt
index 4371691f53..c09c00259d 100644
--- a/app/src/main/java/com/gh/gamecenter/entity/HomeSetting.kt
+++ b/app/src/main/java/com/gh/gamecenter/entity/HomeSetting.kt
@@ -5,8 +5,12 @@ import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
@Parcelize
-data class HomeSetting(var image: String = "",
- @SerializedName("text_color")
- val textColor: String = "#FFFFFF",
- @SerializedName("placeholder_color")
- val placeholderColor: String = "#5C9599") : Parcelable
\ No newline at end of file
+data class HomeSetting(
+ var image: String = "",
+ @SerializedName("text_color")
+ val textColor: String = "#FFFFFF",
+ @SerializedName("placeholder_color")
+ val placeholderColor: String = "#5C9599",
+ @SerializedName("download_btn_switch")
+ val downloadBtnSwitch: String = ""//下载按钮是否显示,on 显示
+) : Parcelable
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/entity/SettingsEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/SettingsEntity.kt
index 0195e44f3f..38162da908 100644
--- a/app/src/main/java/com/gh/gamecenter/entity/SettingsEntity.kt
+++ b/app/src/main/java/com/gh/gamecenter/entity/SettingsEntity.kt
@@ -32,7 +32,9 @@ data class SettingsEntity(
@SerializedName("permission_popup_switch")
var permissionPopupSwitch: String = "off",//权限引导弹窗开关,on/off
@SerializedName("permission_popup_applied_versions")
- var permissionPopupAppliedVersions: PermissionPopupAppliedVersions = PermissionPopupAppliedVersions()
+ var permissionPopupAppliedVersions: PermissionPopupAppliedVersions = PermissionPopupAppliedVersions(),
+ @SerializedName("game_smooth")
+ var gameSmooth: String = "off" // 畅玩功能,on/off,默认off
) {
fun setCommunityEntrance(communityEntrance: String) {
@@ -180,7 +182,7 @@ data class SettingsEntity(
@SerializedName("icon_subscript")
var iconSubscript: String? = null,
@SerializedName("recommend_type")
- var recommendType: String? = "none",//none:无、hot: 热门、new: 上新、surge: 飙升
+ var recommendType: String? = "none",//none:无、hot: 热门、new: 上新、surge: 飙升、update: 更新
var type: String? = ""//论坛类型
) {
var exposureEvent: ExposureEvent? = null
diff --git a/app/src/main/java/com/gh/gamecenter/entity/SubjectEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/SubjectEntity.kt
index 0017bb9298..5f2b5e2e8f 100644
--- a/app/src/main/java/com/gh/gamecenter/entity/SubjectEntity.kt
+++ b/app/src/main/java/com/gh/gamecenter/entity/SubjectEntity.kt
@@ -51,11 +51,25 @@ data class SubjectEntity(
var indexRightTopLink: LinkEntity? = null,
var remark: String? = null, // 开测表备注
+ var image: String = "",
+ @SerializedName("first_line_recommend")
+ var firstLineRecommend: String = "",
+ @SerializedName("second_line_recommend")
+ var secondLineRecommend: String = "",
+ @SerializedName("recommend_tag")
+ var recommendTag: String = "",
+ @SerializedName("column_name")
+ var columnName: String = "",
+
// 专题合集,用于首页专题合集-排行榜样式
var columns: MutableList = mutableListOf(),
// 专题背景,用于首页专题合集-排行榜样式
var background: String = "",
+ // 专题内游戏item是否显示下载按钮(目前只针对横向专题)
+ @SerializedName("show_download")
+ var showDownload: Boolean = false,
+
// 本地字段,用来标记在外部页面中的序号,仅用于曝光记录,具体细节可见 https://git.ghzs.com/pm/halo-app-issues/-/issues/1087
var outerSequence: Int = -1
) : Parcelable {
diff --git a/app/src/main/java/com/gh/gamecenter/entity/VSetting.kt b/app/src/main/java/com/gh/gamecenter/entity/VSetting.kt
new file mode 100644
index 0000000000..905ac2573d
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/entity/VSetting.kt
@@ -0,0 +1,26 @@
+package com.gh.gamecenter.entity
+
+import com.google.gson.annotations.SerializedName
+
+class VSetting {
+ @SerializedName("va")
+ var va: Va? = null
+
+ data class Va(
+ @SerializedName("32-bit")
+ val arch32: VaArch? = null,
+ @SerializedName("64-bit")
+ val arch64: VaArch? = null,
+ )
+
+ data class VaArch(
+ val size: String,
+ @SerializedName("package")
+ val packageName: String,
+ @SerializedName("version")
+ val versionName: String,
+ @SerializedName("version_code")
+ val versionCode: Int,
+ val url: String
+ )
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/eventbus/EBPackage.java b/app/src/main/java/com/gh/gamecenter/eventbus/EBPackage.java
deleted file mode 100644
index 79b5736e40..0000000000
--- a/app/src/main/java/com/gh/gamecenter/eventbus/EBPackage.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.gh.gamecenter.eventbus;
-
-public class EBPackage {
-
- private String type;
- private String packageName;
- private String versionName;
-
- public EBPackage(String type, String packageName, String versionName) {
- this.type = type;
- this.packageName = packageName;
- this.versionName = versionName;
- }
-
- public String getType() {
- return type;
- }
-
- public void setType(String type) {
- this.type = type;
- }
-
- public String getPackageName() {
- return packageName;
- }
-
- public void setPackageName(String packageName) {
- this.packageName = packageName;
- }
-
- public String getVersionName() {
- return versionName;
- }
-
- public void setVersionName(String versionName) {
- this.versionName = versionName;
- }
-}
diff --git a/app/src/main/java/com/gh/gamecenter/eventbus/EBPackage.kt b/app/src/main/java/com/gh/gamecenter/eventbus/EBPackage.kt
new file mode 100644
index 0000000000..b5806fbbd0
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/eventbus/EBPackage.kt
@@ -0,0 +1,6 @@
+package com.gh.gamecenter.eventbus
+
+class EBPackage(var type: String, var packageName: String, var versionName: String?) {
+ var gameId: String? = null
+}
+
diff --git a/app/src/main/java/com/gh/gamecenter/forum/detail/ForumArticleAskListFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/detail/ForumArticleAskListFragment.kt
index 31cdb894e6..5835bdaf78 100644
--- a/app/src/main/java/com/gh/gamecenter/forum/detail/ForumArticleAskListFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/forum/detail/ForumArticleAskListFragment.kt
@@ -269,7 +269,7 @@ class ForumArticleAskListFragment : LazyListFragment> {
return when (mPath) {
"全部" -> {
- RetrofitManager.getInstance().api.getAllForumList(bbsId, UrlFilterUtils.getFilterQuery(sort, "-1"), page)
+ val data = PageSwitchDataHelper.popLastPageData()
+ val map = hashMapOf()
+ if (data != null && data.containsKey(EntranceConsts.KEY_TOP_ID)) {
+ map["top_id"] = data[EntranceConsts.KEY_TOP_ID]
+ }
+ RetrofitManager.getInstance().api.getAllForumList(bbsId, UrlFilterUtils.getFilterQuery(sort, "-1"), page, map)
}
"精华" -> {
RetrofitManager.getInstance().api.getEssenceForumList(bbsId, page)
diff --git a/app/src/main/java/com/gh/gamecenter/forum/detail/ForumDetailFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/detail/ForumDetailFragment.kt
index cc1ab90948..230214d725 100644
--- a/app/src/main/java/com/gh/gamecenter/forum/detail/ForumDetailFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/forum/detail/ForumDetailFragment.kt
@@ -739,8 +739,8 @@ class ForumDetailFragment : BaseLazyTabFragment(), IScrollable {
when (requestCode) {
CommunityHomeFragment.ARTICLE_REQUEST_CODE -> {
val articleId = data?.getStringExtra("article_id") ?: return
- val communityId = data?.getStringExtra("community_id") ?: return
- mViewModel?.getArticleData(communityId, articleId)
+// val communityId = data?.getStringExtra("community_id") ?: return
+ mViewModel?.getArticleData(articleId)
}
CommunityHomeFragment.QUESTION_REQUEST_CODE -> {
@@ -798,7 +798,7 @@ class ForumDetailFragment : BaseLazyTabFragment(), IScrollable {
updateToolbarStyle(mIsToolbarWhite)
mBinding.allOrderSfv.run {
setContainerBackground(R.drawable.button_round_f5f5f5.toDrawable(requireContext()))
- setIndicatorBackground(R.drawable.progressbar_game_collection_primary.toDrawable(requireContext()))
+ setIndicatorBackground(R.drawable.bg_game_collection_sfv_indicator.toDrawable(requireContext()))
setTextColor(ContextCompat.getColorStateList(context, R.color.game_collection_rg_button_selector))
}
}
diff --git a/app/src/main/java/com/gh/gamecenter/forum/detail/ForumDetailViewModel.kt b/app/src/main/java/com/gh/gamecenter/forum/detail/ForumDetailViewModel.kt
index a12da10a59..532cbd6714 100644
--- a/app/src/main/java/com/gh/gamecenter/forum/detail/ForumDetailViewModel.kt
+++ b/app/src/main/java/com/gh/gamecenter/forum/detail/ForumDetailViewModel.kt
@@ -40,29 +40,29 @@ class ForumDetailViewModel(application: Application, val bbsId: String) : Androi
@SuppressLint("CheckResult")
fun postForumRead() {
mApi.postForumRead(bbsId)
- .compose(singleToMain())
- .subscribe(EmptyResponse())
+ .compose(singleToMain())
+ .subscribe(EmptyResponse())
}
fun getForumDetail() {
mApi.getForumDetail(bbsId)
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(object : Response() {
- override fun onResponse(response: ForumDetailEntity?) {
- super.onResponse(response)
- forumDetail.postValue(Resource.success(response))
- response?.run {
- mForumDao.addForum(convertForumDetailEntityToForumEntity())
- EventBus.getDefault().post(EBForumRecordChange(convertForumDetailEntityToForumEntity()))
- }
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(object : Response() {
+ override fun onResponse(response: ForumDetailEntity?) {
+ super.onResponse(response)
+ forumDetail.postValue(Resource.success(response))
+ response?.run {
+ mForumDao.addForum(convertForumDetailEntityToForumEntity())
+ EventBus.getDefault().post(EBForumRecordChange(convertForumDetailEntityToForumEntity()))
}
+ }
- override fun onFailure(e: HttpException?) {
- super.onFailure(e)
- forumDetail.postValue(Resource.error(e))
- }
- })
+ override fun onFailure(e: HttpException?) {
+ super.onFailure(e)
+ forumDetail.postValue(Resource.error(e))
+ }
+ })
}
fun getModeratorsApplyStatus() {
@@ -85,64 +85,64 @@ class ForumDetailViewModel(application: Application, val bbsId: String) : Androi
@SuppressLint("CheckResult")
fun followForum(onSuccess: () -> Unit) {
RetrofitManager.getInstance().api
- .followForum(bbsId)
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(object : BiResponse() {
- override fun onSuccess(data: ResponseBody) {
- onSuccess.invoke()
- }
- })
+ .followForum(bbsId)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(object : BiResponse() {
+ override fun onSuccess(data: ResponseBody) {
+ onSuccess.invoke()
+ }
+ })
}
@SuppressLint("CheckResult")
fun unFollowForum(onSuccess: () -> Unit) {
RetrofitManager.getInstance().api
- .unFollowForum(bbsId)
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(object : BiResponse() {
- override fun onSuccess(data: ResponseBody) {
- onSuccess.invoke()
- }
- })
+ .unFollowForum(bbsId)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(object : BiResponse() {
+ override fun onSuccess(data: ResponseBody) {
+ onSuccess.invoke()
+ }
+ })
}
- fun getArticleData(communityId: String, articleId: String) {
- mApi.getCommunityArticleDetail(communityId, articleId)
- .compose(observableToMain())
- .subscribe(object : Response() {
- override fun onResponse(response: ArticleDetailEntity?) {
- response?.run {
- answerLiveData.postValue(convertArticleDetailToAnswer(response))
- }
-
+ fun getArticleData(articleId: String) {
+ mApi.getCommunityArticleDetail(articleId)
+ .compose(observableToMain())
+ .subscribe(object : Response() {
+ override fun onResponse(response: ArticleDetailEntity?) {
+ response?.run {
+ answerLiveData.postValue(convertArticleDetailToAnswer(response))
}
- })
+
+ }
+ })
}
fun getQuestionDetail(questionId: String) {
mApi.getQuestionsById(questionId)
- .compose(observableToMain())
- .subscribe(object : Response() {
- override fun onResponse(response: QuestionsDetailEntity?) {
- response?.run {
- answerLiveData.postValue(convertQuestionDetailToAnswer(response))
- }
+ .compose(observableToMain())
+ .subscribe(object : Response() {
+ override fun onResponse(response: QuestionsDetailEntity?) {
+ response?.run {
+ answerLiveData.postValue(convertQuestionDetailToAnswer(response))
}
- })
+ }
+ })
}
fun getVideoDetail(videoId: String) {
mApi.getBbsVideoDetail(videoId)
- .compose(observableToMain())
- .subscribe(object : Response() {
- override fun onResponse(response: ForumVideoEntity?) {
- response?.run {
- answerLiveData.postValue(convertVideoDetailToAnswer(response))
- }
+ .compose(observableToMain())
+ .subscribe(object : Response() {
+ override fun onResponse(response: ForumVideoEntity?) {
+ response?.run {
+ answerLiveData.postValue(convertVideoDetailToAnswer(response))
}
- })
+ }
+ })
}
fun convertArticleDetailToAnswer(articleDetailEntity: ArticleDetailEntity): AnswerEntity {
@@ -159,7 +159,7 @@ class ForumDetailViewModel(application: Application, val bbsId: String) : Androi
answerEntity.images = articleDetailEntity.images
answerEntity.imagesInfo = articleDetailEntity.imagesInfo
answerEntity.videos = articleDetailEntity.videos
- answerEntity.status = articleDetailEntity.status ?:""
+ answerEntity.status = articleDetailEntity.status ?: ""
answerEntity.type = "community_article"
return answerEntity
@@ -201,12 +201,13 @@ class ForumDetailViewModel(application: Application, val bbsId: String) : Androi
answerEntity.time = forumVideoEntity.time.upload
forumVideoEntity.user.run {
answerEntity.user = UserEntity(
- id = id,
- name = name,
- icon = icon,
- auth = auth,
- badge = badge,
- border = border)
+ id = id,
+ name = name,
+ icon = icon,
+ auth = auth,
+ badge = badge,
+ border = border
+ )
}
answerEntity.type = "video"
diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/CommunityHomeFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/home/CommunityHomeFragment.kt
index 2e3f334b12..20ce0dc489 100644
--- a/app/src/main/java/com/gh/gamecenter/forum/home/CommunityHomeFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/forum/home/CommunityHomeFragment.kt
@@ -141,15 +141,15 @@ class CommunityHomeFragment : LazyFragment() {
mFragmentList.clear()
val tag = "android:switcher:${viewPager.id}:"
val forumArticleListFragment = childFragmentManager.findFragmentByTag("${tag}0")
- ?: ForumArticleListFragment().with(bundleOf(EntranceConsts.KEY_ENTRANCE to "社区", EntranceConsts.KEY_PATH to "推荐"))
+ ?: ForumArticleListFragment().with(bundleOf(EntranceConsts.KEY_ENTRANCE to "社区", EntranceConsts.KEY_PATH to "推荐"))
mFragmentList.add(forumArticleListFragment)
val forumFragment = childFragmentManager.findFragmentByTag("${tag}1")
- ?: ForumFragment().with(bundleOf(EntranceConsts.KEY_ENTRANCE to "社区"))
+ ?: ForumFragment().with(bundleOf(EntranceConsts.KEY_ENTRANCE to "社区"))
mFragmentList.add(forumFragment)
val activityFragment = childFragmentManager.findFragmentByTag("${tag}2")
- ?: ForumActivityFragment().with(bundleOf(EntranceConsts.KEY_ENTRANCE to "活动"))
+ ?: ForumActivityFragment().with(bundleOf(EntranceConsts.KEY_ENTRANCE to "活动"))
mFragmentList.add(activityFragment)
viewPager.run {
@@ -195,13 +195,25 @@ class CommunityHomeFragment : LazyFragment() {
(mTabList[position] as TextView).run {
layoutParams.width = (DEFAULT_TAB_TEXT_WIDTH + ((1 - positionOffset) * 4F.dip2px())).roundToInt()
textSize = (DEFAULT_TAB_TEXT_SIZE + ((1 - positionOffset) * 4)).roundTo(1)
- setTextColor(ColorUtils.blendARGB(TAB_DEFAULT_COLOR.toColor(requireContext()), TAB_SELECTED_COLOR.toColor(requireContext()), 1 - positionOffset))
+ setTextColor(
+ ColorUtils.blendARGB(
+ TAB_DEFAULT_COLOR.toColor(requireContext()),
+ TAB_SELECTED_COLOR.toColor(requireContext()),
+ 1 - positionOffset
+ )
+ )
}
if (mTabList[position + 1] is TextView) {
(mTabList[position + 1] as TextView).run {
layoutParams.width = (DEFAULT_TAB_TEXT_WIDTH + ((positionOffset) * 4F.dip2px())).roundToInt()
textSize = (DEFAULT_TAB_TEXT_SIZE + ((positionOffset) * 4)).roundTo(1)
- setTextColor(ColorUtils.blendARGB(TAB_DEFAULT_COLOR.toColor(requireContext()), TAB_SELECTED_COLOR.toColor(requireContext()), positionOffset))
+ setTextColor(
+ ColorUtils.blendARGB(
+ TAB_DEFAULT_COLOR.toColor(requireContext()),
+ TAB_SELECTED_COLOR.toColor(requireContext()),
+ positionOffset
+ )
+ )
}
} else {
(mTabList[position + 1] as TabItemCommunityBinding).run {
@@ -211,7 +223,13 @@ class CommunityHomeFragment : LazyFragment() {
tabImg.scaleY = (DEFAULT_TAB_IMG_HEIGHT + ((positionOffset) * 4)).roundTo(1) / DEFAULT_TAB_IMG_HEIGHT
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
tabImg.imageTintList =
- ColorStateList.valueOf(ColorUtils.blendARGB(TAB_DEFAULT_COLOR.toColor(requireContext()), TAB_SELECTED_COLOR.toColor(requireContext()), positionOffset))
+ ColorStateList.valueOf(
+ ColorUtils.blendARGB(
+ TAB_DEFAULT_COLOR.toColor(requireContext()),
+ TAB_SELECTED_COLOR.toColor(requireContext()),
+ positionOffset
+ )
+ )
}
}
}
@@ -433,8 +451,8 @@ class CommunityHomeFragment : LazyFragment() {
when (requestCode) {
ARTICLE_REQUEST_CODE -> {
val articleId = data?.getStringExtra("article_id") ?: return
- val communityId = data?.getStringExtra("community_id") ?: return
- mViewModel?.getArticleData(communityId, articleId)
+// val communityId = data?.getStringExtra("community_id") ?: return
+ mViewModel?.getArticleData(articleId)
}
QUESTION_REQUEST_CODE -> {
@@ -531,7 +549,11 @@ class CommunityHomeFragment : LazyFragment() {
navigationBg.setBackgroundColor(R.color.transparent.toColor(requireContext()))
navigationBg.setImageDrawable(null)
} else if (viewPager.currentItem == TAB_RECOMMEND_INDEX) {
- navigationBg.setBackgroundColor(if (mNightMode && y > 0) R.color.background_white.toColor(requireContext()) else if (mNightMode && y == 0) R.color.background.toColor(requireContext()) else R.color.transparent.toColor(requireContext()))
+ navigationBg.setBackgroundColor(
+ if (mNightMode && y > 0) R.color.background_white.toColor(requireContext()) else if (mNightMode && y == 0) R.color.background.toColor(
+ requireContext()
+ ) else R.color.transparent.toColor(requireContext())
+ )
navigationBg.setImageDrawable(null)
} else if (mNightMode) {
navigationBg.setBackgroundColor(R.color.background_white.toColor(requireContext()))
@@ -552,7 +574,11 @@ class CommunityHomeFragment : LazyFragment() {
}
}
mBinding?.run {
- root.setBackgroundColor(if (viewPager.currentItem == TAB_FORUM_INDEX) R.color.background_white.toColor(requireContext()) else R.color.background.toColor(requireContext()))
+ root.setBackgroundColor(
+ if (viewPager.currentItem == TAB_FORUM_INDEX) R.color.background_white.toColor(requireContext()) else R.color.background.toColor(
+ requireContext()
+ )
+ )
topBg.run {
visibleIf(!mNightMode)
post {
diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/CommunityHomeViewModel.kt b/app/src/main/java/com/gh/gamecenter/forum/home/CommunityHomeViewModel.kt
index 4fa40e2284..3daf5fad05 100644
--- a/app/src/main/java/com/gh/gamecenter/forum/home/CommunityHomeViewModel.kt
+++ b/app/src/main/java/com/gh/gamecenter/forum/home/CommunityHomeViewModel.kt
@@ -19,8 +19,8 @@ class CommunityHomeViewModel(application: Application) : AndroidViewModel(applic
private val mApi = RetrofitManager.getInstance().api
val articleLiveData = MediatorLiveData()
- fun getArticleData(communityId: String, articleId: String) {
- mApi.getCommunityArticleDetail(communityId, articleId)
+ fun getArticleData(articleId: String) {
+ mApi.getCommunityArticleDetail(articleId)
.compose(observableToMain())
.subscribe(object : Response() {
override fun onResponse(response: ArticleDetailEntity?) {
diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/ForumFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/home/ForumFragment.kt
index b87c82739f..788c5c03be 100644
--- a/app/src/main/java/com/gh/gamecenter/forum/home/ForumFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/forum/home/ForumFragment.kt
@@ -381,7 +381,7 @@ class ForumFragment: LazyFragment(), SwipeRefreshLayout.OnRefreshListener {
cornerRadius = 12F.dip2px().toFloat()
setColor(color)
}
- } else {
+ } else if (bannerBg.background is GradientDrawable) {
(bannerBg.background as GradientDrawable).setColor(color)
}
}
@@ -458,14 +458,6 @@ class ForumFragment: LazyFragment(), SwipeRefreshLayout.OnRefreshListener {
otherWelfareContainer.visibility = View.VISIBLE
otherWelfareRv.layoutManager = GridLayoutManager(requireContext(), 2)
otherWelfareRv.adapter = WelfaresAdapter(requireContext(), welfareLists)
- otherWelfareRv.addItemDecoration(
- GridSpacingItemColorDecoration(
- requireContext(),
- 0,
- 16,
- R.color.transparent
- )
- )
otherWelfareRv.addItemDecoration(GridSpacingItemColorDecoration(requireContext(), 8, 8, R.color.transparent))
}
}
diff --git a/app/src/main/java/com/gh/gamecenter/forum/home/HorizontalForumsAdapter.kt b/app/src/main/java/com/gh/gamecenter/forum/home/HorizontalForumsAdapter.kt
index 2351160541..c56f3bc671 100644
--- a/app/src/main/java/com/gh/gamecenter/forum/home/HorizontalForumsAdapter.kt
+++ b/app/src/main/java/com/gh/gamecenter/forum/home/HorizontalForumsAdapter.kt
@@ -74,7 +74,7 @@ class HorizontalForumsAdapter(
}
root.setOnClickListener {
- handleItemViewClick(this, forumEntity)
+ handleItemViewClick(forumEntity)
}
}
}
@@ -107,14 +107,12 @@ class HorizontalForumsAdapter(
}
}
- private fun handleItemViewClick(binding: HorizontalForumItemBinding, forumEntity: ForumEntity) {
- binding.root.setOnClickListener {
- val bbsType = if (forumEntity.type == "official_bbs") "综合论坛" else "游戏论坛"
- val event = if (mEntrance.contains("最近浏览")) "click_recent_forum" else "click_following_forum"
- val location = if (mEntrance.contains("最近浏览")) "推荐信息流" else "论坛页"
- NewLogUtils.logForumClick(event, location, forumEntity.id, bbsType)
- mContext.startActivity(ForumDetailActivity.getIntent(mContext, forumEntity.id, mEntrance))
- }
+ private fun handleItemViewClick(forumEntity: ForumEntity) {
+ val bbsType = if (forumEntity.type == "official_bbs") "综合论坛" else "游戏论坛"
+ val event = if (mEntrance.contains("最近浏览")) "click_recent_forum" else "click_following_forum"
+ val location = if (mEntrance.contains("最近浏览")) "推荐信息流" else "论坛页"
+ NewLogUtils.logForumClick(event, location, forumEntity.id, bbsType)
+ mContext.startActivity(ForumDetailActivity.getIntent(mContext, forumEntity.id, mEntrance))
}
fun checkResetData(update: List) {
diff --git a/app/src/main/java/com/gh/gamecenter/forum/search/ForumContentSearchListAdapter.kt b/app/src/main/java/com/gh/gamecenter/forum/search/ForumContentSearchListAdapter.kt
index bcca9352cf..dcc4dd7e91 100644
--- a/app/src/main/java/com/gh/gamecenter/forum/search/ForumContentSearchListAdapter.kt
+++ b/app/src/main/java/com/gh/gamecenter/forum/search/ForumContentSearchListAdapter.kt
@@ -212,7 +212,7 @@ class ForumContentSearchListAdapter(context: Context, val mListViewModel: ForumC
durationTv.goneIf(answer.getPassVideos().isEmpty())
durationTv.text = if (answer.getPassVideos().isNotEmpty()) answer.getPassVideos()[0].duration else "00:00"
durationTv.background = GradientDrawable().apply {
- setColor(R.color.black_alpha_40.toColor(mContext))
+ setColor(R.color.black_alpha_60.toColor(mContext))
cornerRadius = 2F.dip2px().toFloat()
}
countTv.text = "${answer.count.comment}评论 · ${answer.count.vote}点赞"
diff --git a/app/src/main/java/com/gh/gamecenter/fragment/HomeSearchToolWrapperFragment.kt b/app/src/main/java/com/gh/gamecenter/fragment/HomeSearchToolWrapperFragment.kt
index 20f78112d8..620ccd075f 100644
--- a/app/src/main/java/com/gh/gamecenter/fragment/HomeSearchToolWrapperFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/fragment/HomeSearchToolWrapperFragment.kt
@@ -116,7 +116,7 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
mBinding?.noConnectionContainer?.reuseNoConnection?.visibility = View.VISIBLE
mBinding?.loadingContainer?.reuseLlLoading?.visibility = View.GONE
mBinding?.noConnectionContainer?.reuseNoConnection?.setOnClickListener {
- mViewModel?.getTabs()
+ mViewModel?.getHomeContentUnion()
mBinding?.noConnectionContainer?.reuseNoConnection?.visibility = View.GONE
mBinding?.loadingContainer?.reuseLlLoading?.visibility = View.VISIBLE
}
diff --git a/app/src/main/java/com/gh/gamecenter/fragment/HomeSearchToolWrapperViewModel.kt b/app/src/main/java/com/gh/gamecenter/fragment/HomeSearchToolWrapperViewModel.kt
index 31440871ac..098dd02eed 100644
--- a/app/src/main/java/com/gh/gamecenter/fragment/HomeSearchToolWrapperViewModel.kt
+++ b/app/src/main/java/com/gh/gamecenter/fragment/HomeSearchToolWrapperViewModel.kt
@@ -9,6 +9,8 @@ import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.SubjectRecommendEntity
import com.gh.gamecenter.common.retrofit.BiResponse
+import com.gh.gamecenter.common.utils.singleToMain
+import com.gh.gamecenter.entity.HomeDataEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.android.schedulers.AndroidSchedulers
@@ -21,49 +23,57 @@ class HomeSearchToolWrapperViewModel(application: Application) : AndroidViewMode
var forumTabPairs: ArrayList> = arrayListOf()
val tabs = MutableLiveData>()
+ val homeDataLiveData = MutableLiveData()
val error = MutableLiveData()
var appBarOffset = 0
init {
- getTabs()
+ getHomeContentUnion()
}
@SuppressLint("CheckResult")
- fun getTabs() {
+ fun getHomeContentUnion(isRefresh: Boolean = false) {
RetrofitManager.getInstance().api
- .getHomeTabs(HaloApp.getInstance().channel, BuildConfig.VERSION_NAME)
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(object : BiResponse>() {
- override fun onSuccess(data: ArrayList) {
- forumTabPairs.clear()
- for ((index, tab) in data.withIndex()) {
- if (tab.type == "top_game_comment") {
- tab.primaryColor = R.color.amway_primary_color.toColor()
- tab.useLightStyle = true
- tab.currentSelectColor = tab.primaryColor
- }
+ .getHomeContentUnion(BuildConfig.VERSION_NAME, HaloApp.getInstance().channel)
+ .compose(singleToMain())
+ .subscribe(object : BiResponse() {
+ override fun onSuccess(data: HomeDataEntity) {
+ val homeTab = data.homeTab
+ if (homeTab.isNotEmpty()) {
+ forumTabPairs.clear()
+ for ((index, tab) in homeTab.withIndex()) {
+ if (tab.type == "top_game_comment") {
+ tab.primaryColor = R.color.amway_primary_color.toColor()
+ tab.useLightStyle = true
+ tab.currentSelectColor = tab.primaryColor
+ }
- if (tab.type == "home") {
- tab.useLightStyle = true
- }
+ if (tab.type == "home") {
+ tab.useLightStyle = true
+ }
- if (tab.type == "bbs") {
- forumTabPairs.add(Pair(index, tab.link ?: ""))
- }
+ if (tab.type == "bbs") {
+ forumTabPairs.add(Pair(index, tab.link ?: ""))
+ }
- if (tab.default) defaultTabPosition = index
+ if (tab.default) defaultTabPosition = index
+ }
+ if (homeTab.size == 0) {
+ homeTab.add(SubjectRecommendEntity(type = "home"))
+ }
+ if (!isRefresh) {
+ tabs.postValue(homeTab)
+ }
}
- if (data.size == 0) {
- data.add(SubjectRecommendEntity(type = "home"))
- }
- tabs.postValue(data)
+ homeDataLiveData.postValue(data)
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
- error.postValue(exception)
+ if (!isRefresh) {
+ error.postValue(exception)
+ }
}
})
}
diff --git a/app/src/main/java/com/gh/gamecenter/game/GameFragment.kt b/app/src/main/java/com/gh/gamecenter/game/GameFragment.kt
index 488be43ddd..d2304afa3f 100644
--- a/app/src/main/java/com/gh/gamecenter/game/GameFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/game/GameFragment.kt
@@ -10,22 +10,22 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.ethanhua.skeleton.Skeleton
import com.ethanhua.skeleton.ViewSkeletonScreen
-import com.gh.gamecenter.common.base.fragment.LazyFragment
-import com.gh.gamecenter.common.constant.Constants
import com.gh.common.exposure.ExposureListener
import com.gh.common.exposure.ExposureSource
-import com.gh.common.util.*
-import com.gh.gamecenter.common.view.FixLinearLayoutManager
+import com.gh.common.util.DialogUtils
import com.gh.common.xapk.XapkInstaller
import com.gh.common.xapk.XapkUnzipStatus
import com.gh.download.DownloadManager
import com.gh.gamecenter.R
import com.gh.gamecenter.baselist.LoadStatus
+import com.gh.gamecenter.common.base.fragment.LazyFragment
+import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.utils.visibleIf
+import com.gh.gamecenter.common.view.FixLinearLayoutManager
import com.gh.gamecenter.databinding.FragmentGameBinding
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBPackage
@@ -58,6 +58,10 @@ class GameFragment : LazyFragment() {
showUnzipFailureDialog(downloadEntity)
}
}
+
+ override fun onDataInit(downloadEntity: DownloadEntity) {
+ mListAdapter.notifyItemByDownload(downloadEntity)
+ }
}
override fun getRealLayoutId() = R.layout.fragment_game
diff --git a/app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.kt b/app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.kt
index a9c76ae845..ddc5408f03 100644
--- a/app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.kt
+++ b/app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.kt
@@ -7,7 +7,6 @@ import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
-import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.constant.Config
@@ -42,10 +41,12 @@ import com.gh.gamecenter.core.utils.StringUtils
import com.gh.gamecenter.databinding.*
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.eventbus.EBDownloadStatus
+import com.gh.gamecenter.game.bigimagerecommend.BigImageRecommendViewHolder
import com.gh.gamecenter.game.columncollection.GameColumnCollectionViewHolder
import com.gh.gamecenter.game.commoncollection.CommonCollectionViewHolder
import com.gh.gamecenter.game.commoncollection.detail.CommonCollectionDetailActivity
import com.gh.gamecenter.game.data.GameItemData
+import com.gh.gamecenter.game.doublecard.DoubleCardListViewHolder
import com.gh.gamecenter.game.gallery.GameGallerySlideViewHolder
import com.gh.gamecenter.game.gallery.GameGalleryViewHolder
import com.gh.gamecenter.game.horizontal.GameHorizontalListViewHolder
@@ -114,6 +115,8 @@ class GameFragmentAdapter(
if (itemData.blankDivider != null) return ItemViewType.BLANK_DIVIDER
if (itemData.rankCollection != null) return ItemViewType.RANK_COLLECTION
if (itemData.gameCollection != null) return ItemViewType.GAME_COLLECTION_ITEM
+ if (itemData.doubleCardColumn != null) return ItemViewType.DOUBLE_CARD_COLUMN
+ if (itemData.bigImageRecommend != null) return ItemViewType.BIG_IMAGE_RECOMMEND
return ItemViewType.LOADING
}
@@ -206,6 +209,12 @@ class GameFragmentAdapter(
)
)
}
+ ItemViewType.DOUBLE_CARD_COLUMN -> {
+ DoubleCardListViewHolder(parent.toBinding())
+ }
+ ItemViewType.BIG_IMAGE_RECOMMEND -> {
+ BigImageRecommendViewHolder(parent.toBinding())
+ }
else -> GameItemViewHolder(GameItemBinding.bind(mLayoutInflater.inflate(R.layout.game_item, parent, false)))
}
}
@@ -228,6 +237,8 @@ class GameFragmentAdapter(
is CommonCollectionViewHolder -> bindCommonCollection(holder, position)
is RankCollectionViewHolder -> bindRankCollection(holder, position)
is HomeGameCollectionViewHolder -> bindGameCollection(holder, position)
+ is DoubleCardListViewHolder -> bindGameDoubleCardList(holder, position)
+ is BigImageRecommendViewHolder -> bindBigImageRecommend(holder, position)
}
}
@@ -389,8 +400,10 @@ class GameFragmentAdapter(
val rankCollection = mItemDataList[position].rankCollection
val rankCollectionAdapter = holder.bindRankCollection(rankCollection!!) {
- NewLogUtils.logColumnCategoryHomeContentClick(it.name ?: "", it.id ?: "", rankCollection.name ?: "",
- rankCollection.id ?: "","版块",mViewModel.blockData?.name?:"")
+ NewLogUtils.logColumnCategoryHomeContentClick(
+ it.name ?: "", it.id ?: "", rankCollection.name ?: "",
+ rankCollection.id ?: "", "版块", mViewModel.blockData?.name ?: ""
+ )
}
val exposureEventList = arrayListOf()
@@ -518,7 +531,7 @@ class GameFragmentAdapter(
val subjectAdapter = holder.bindHorizontalList(subjectEntity!!)
if (subjectEntity.type != "game_horizontal") {
- holder.binding.horizontalRv.doOnScrolledSpecificDistance(distanceX = DisplayUtils.dip2px(24f), singleTimeEvent = true) {
+ holder.binding.recyclerView.doOnScrolledSpecificDistance(distanceX = DisplayUtils.dip2px(24f), singleTimeEvent = true) {
MtaHelper.onEvent("游戏专题", "滑动", subjectEntity.name)
}
}
@@ -649,7 +662,7 @@ class GameFragmentAdapter(
LogUtils.logRecommendClick(
"版块:${blockData?.text ?: ""}",
- entity.name, entity.type, entity.text,entity.link, clickedPosition
+ entity.name, entity.type, entity.text, entity.link, clickedPosition
)
val entrance = "(推荐入口)"
@@ -1105,6 +1118,43 @@ class GameFragmentAdapter(
holder.bindGameCollectionList(gameCollectionItemDataList, "版块内容列表")
}
+ private fun bindGameDoubleCardList(holder: DoubleCardListViewHolder, position: Int) {
+ mItemDataList[position].doubleCardColumn?.data?.run {
+ val subjectEntity = mItemDataList[position].doubleCardColumn!!
+ val subjectAdapter = holder.bindDoubleCardList(subjectEntity)
+
+ val exposureEventList = arrayListOf()
+ runOnIoThread(true) {
+ for (i in 0 until subjectAdapter.itemCount) {
+ if (i >= size) break
+
+ get(i).sequence = i
+ val event = ExposureEvent.createEventWithSourceConcat(
+ gameEntity = get(i),
+ basicSource = mBasicExposureSource,
+ source = listOf(ExposureSource("专题", subjectEntity.name ?: ""))
+ )
+ exposureEventList.add(event)
+ }
+ }
+ mItemDataList[position].exposureEventList = exposureEventList
+ subjectAdapter.exposureEventList = exposureEventList
+ }
+ }
+
+ private fun bindBigImageRecommend(holder: BigImageRecommendViewHolder, position: Int) {
+ mItemDataList[position].bigImageRecommend?.run {
+ holder.bindBigImageRecommend(this, "(板块)") {
+ mViewModel.blockData?.let { blockData ->
+ NewFlatLogUtils.logBlockGameContentCardClick(
+ blockData.link ?: "", blockData.name ?: "",
+ it.type ?: "", it.link ?: "", it.linkText ?: ""
+ )
+ }
+ }
+ }
+ }
+
override fun getItemCount(): Int {
return if (mItemDataList.size > 0) mItemDataList.size + 1 else mItemDataList.size
}
diff --git a/app/src/main/java/com/gh/gamecenter/game/GameViewModel.kt b/app/src/main/java/com/gh/gamecenter/game/GameViewModel.kt
index a74ac8df51..a0f2a37b4a 100644
--- a/app/src/main/java/com/gh/gamecenter/game/GameViewModel.kt
+++ b/app/src/main/java/com/gh/gamecenter/game/GameViewModel.kt
@@ -472,7 +472,7 @@ class GameViewModel(application: Application, var blockData: SubjectRecommendEnt
var isTopItemShown = false
// 轮播图+导航栏+专题入口
- if (blockData == null || blockData?.display?.recommend!! || blockData?.display?.slide!!|| blockData?.display?.navigation!!) {
+ if (blockData == null || blockData?.display?.recommend!! || blockData?.display?.slide!! || blockData?.display?.navigation!!) {
isTopItemShown = true
val itemDataTop = GameItemData()
itemDataTop.slideList = mSlideList
@@ -487,6 +487,19 @@ class GameViewModel(application: Application, var blockData: SubjectRecommendEnt
mSmartSubject = null // 防止重复插入
}
+ val iterator = mSubjectList.iterator()
+ while (iterator.hasNext()) {
+ val item = iterator.next()
+ // 双列卡片专题过滤掉无封面图游戏
+ if (item.type == "game_double_card") {
+ item.data = item.data?.filter { it.columnImage.isNotBlank() }?.toMutableList()
+ // 游戏数量小于2个不显示专题,所以直接去掉
+ if ((item.data?.size ?: 0) < 2) {
+ iterator.remove()
+ }
+ }
+ }
+
// 专题 "type": "image/game_vertical/game_horizontal"
for ((index, subjectEntity) in mSubjectList.withIndex()) {
var containsImageBeforeHead = false // 在专题名上面是否有大图
@@ -552,7 +565,12 @@ class GameViewModel(application: Application, var blockData: SubjectRecommendEnt
if (subjectEntity.type == "image" || subjectEntity.type == "image_slide") continue
}
- if ((subjectEntity.type != "gallery" && subjectEntity.type != "column_collection")
+ if ((subjectEntity.type != "gallery"
+ && subjectEntity.type != "column_collection"
+ && subjectEntity.type != "community_article"
+ && subjectEntity.type != "question"
+ && subjectEntity.type != "bbs_video"
+ && subjectEntity.type != "news")
|| (subjectEntity.type == "column_collection" && subjectEntity.style != "top")
) {
val itemDataHead = GameItemData()
@@ -678,6 +696,25 @@ class GameViewModel(application: Application, var blockData: SubjectRecommendEnt
continue
}
+ if (subjectEntity.type == "game_double_card") {
+ val itemDataSubject = GameItemData()
+ itemDataSubject.doubleCardColumn = subjectEntity
+ appendAdditionalInfoToSubjectGame(subjectEntity, index)
+ mItemDataListCache.add(itemDataSubject)
+ continue
+ }
+
+ if (subjectEntity.type == "community_article"
+ || subjectEntity.type == "question"
+ || subjectEntity.type == "bbs_video"
+ || subjectEntity.type == "news"
+ ) {
+ val itemDataSubject = GameItemData()
+ itemDataSubject.bigImageRecommend = subjectEntity
+ mItemDataListCache.add(itemDataSubject)
+ continue
+ }
+
if (!data.isNullOrEmpty()) {
for (i in 0 until data.size) {
val game = data[i]
diff --git a/app/src/main/java/com/gh/gamecenter/game/bigimagerecommend/BigImageRecommendViewHolder.kt b/app/src/main/java/com/gh/gamecenter/game/bigimagerecommend/BigImageRecommendViewHolder.kt
new file mode 100644
index 0000000000..724f2cde0a
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/game/bigimagerecommend/BigImageRecommendViewHolder.kt
@@ -0,0 +1,28 @@
+package com.gh.gamecenter.game.bigimagerecommend
+
+import com.gh.common.util.DirectUtils
+import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
+import com.gh.gamecenter.common.utils.ImageUtils
+import com.gh.gamecenter.common.utils.goneIf
+import com.gh.gamecenter.databinding.BigImageRecommendItemBinding
+import com.gh.gamecenter.entity.LinkEntity
+import com.gh.gamecenter.entity.SubjectEntity
+
+class BigImageRecommendViewHolder(val binding: BigImageRecommendItemBinding) : BaseRecyclerViewHolder(binding.root) {
+
+ fun bindBigImageRecommend(subjectEntity: SubjectEntity, entrance: String, clickCallback: (LinkEntity) -> Unit) {
+ binding.run {
+ ImageUtils.display(poster, subjectEntity.image)
+ recommendTag.goneIf(subjectEntity.recommendTag.isEmpty())
+ recommendTextTwo.goneIf(subjectEntity.secondLineRecommend.isEmpty())
+ recommendTag.text = subjectEntity.recommendTag
+ recommendTextOne.text = subjectEntity.firstLineRecommend
+ recommendTextTwo.text = subjectEntity.secondLineRecommend
+ root.setOnClickListener {
+ val linkEntity = LinkEntity(link = subjectEntity.id, type = subjectEntity.type, linkText = subjectEntity.columnName)
+ clickCallback.invoke(linkEntity)
+ DirectUtils.directToLinkPage(root.context, linkEntity, entrance, "")
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/game/data/GameItemData.kt b/app/src/main/java/com/gh/gamecenter/game/data/GameItemData.kt
index 18b9be3ab3..a86c73932a 100644
--- a/app/src/main/java/com/gh/gamecenter/game/data/GameItemData.kt
+++ b/app/src/main/java/com/gh/gamecenter/game/data/GameItemData.kt
@@ -25,6 +25,10 @@ class GameItemData {
var gameCollection: List? = null
+ var doubleCardColumn: SubjectEntity? = null // 双列卡片专题
+
+ var bigImageRecommend: SubjectEntity? = null //提问、帖子、视频帖、文章
+
var blankDivider: Float? = null // 空白的空间补全item
var exposureEvent: ExposureEvent? = null
diff --git a/app/src/main/java/com/gh/gamecenter/game/doublecard/DoubleCardListAdapter.kt b/app/src/main/java/com/gh/gamecenter/game/doublecard/DoubleCardListAdapter.kt
new file mode 100644
index 0000000000..a71b3b0fb8
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/game/doublecard/DoubleCardListAdapter.kt
@@ -0,0 +1,94 @@
+package com.gh.gamecenter.game.doublecard
+
+import android.content.Context
+import android.graphics.Color
+import android.graphics.drawable.GradientDrawable
+import android.view.ViewGroup
+import com.gh.common.exposure.ExposureEvent
+import com.gh.gamecenter.core.utils.StringUtils
+import com.gh.gamecenter.GameDetailActivity
+import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
+import com.gh.gamecenter.common.utils.*
+import com.gh.gamecenter.databinding.GameDoubleCardItemBinding
+import com.gh.gamecenter.entity.GameEntity
+import com.gh.gamecenter.entity.SubjectEntity
+import com.lightgame.adapter.BaseRecyclerAdapter
+
+class DoubleCardListAdapter(
+ context: Context,
+ private var mSubjectEntity: SubjectEntity
+) : BaseRecyclerAdapter(context) {
+
+ var exposureEventList: ArrayList? = null
+
+ private var countAndKey: Pair? = null
+
+ init {
+ var dataIds = ""
+ mSubjectEntity.data?.forEach {
+ dataIds += it.id
+ }
+ if (dataIds.isNotEmpty()) countAndKey = Pair(mSubjectEntity.data?.size ?: 0, dataIds)
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = DoubleCardItemViewHolder(parent.toBinding())
+
+ override fun getItemCount() = if (mSubjectEntity.data?.isNotEmpty() == true) mSubjectEntity.data!!.size else 0
+
+ override fun onBindViewHolder(holder: DoubleCardItemViewHolder, position: Int) {
+ val gameEntity = mSubjectEntity.data!![position]
+ holder.binding.run {
+ poster.display(gameEntity.columnImage)
+ gameName.text = gameEntity.name
+ brief.text =
+ if (gameEntity.columnRecommend?.text.isNullOrBlank()) gameEntity.brief
+ else gameEntity.columnRecommend!!.text
+ gameSubtitle.run {
+ goneIf(gameEntity.subtitle.isBlank())
+ text = gameEntity.subtitle
+ if (gameEntity.subtitleStyle != null) {
+ setTextColor(Color.parseColor("#${gameEntity.subtitleStyle?.color}"))
+ background = GradientDrawable().apply {
+ cornerRadius = 2F.dip2px().toFloat()
+ if (gameEntity.subtitleStyle?.style == "border") {
+ setColor(Color.TRANSPARENT)
+ setStroke(0.5F.dip2px(), Color.parseColor("#${gameEntity.subtitleStyle?.background}"))
+ } else {
+ shape = GradientDrawable.RECTANGLE
+ setColor(Color.parseColor("#${gameEntity.subtitleStyle?.background}"))
+ }
+ }
+ }
+ }
+
+ root.setOnClickListener {
+ GameDetailActivity.startGameDetailActivity(
+ mContext,
+ gameEntity,
+ StringUtils.buildString("(游戏-专题:", mSubjectEntity.name, "-列表[", (position + 1).toString(), "])"),
+ traceEvent = exposureEventList?.get(position)
+ )
+ }
+ }
+ }
+
+ // notifyDataSetChanged 会出现页面抖动情况
+ fun checkResetData(subjectEntity: SubjectEntity) {
+ var dataIds = ""
+ subjectEntity.data?.forEach {
+ dataIds += it.id
+ }
+
+ mSubjectEntity = subjectEntity
+ if (countAndKey?.first == subjectEntity.data?.size && countAndKey?.second != dataIds) { // 数量不变,内容发生改变
+ notifyItemRangeChanged(0, itemCount)
+ } else if (countAndKey?.first != subjectEntity.data?.size) { // 数量发生改变
+ notifyDataSetChanged()
+ }
+
+ // 重新刷新数据标识
+ countAndKey = Pair(subjectEntity.data?.size ?: 0, dataIds)
+ }
+
+ inner class DoubleCardItemViewHolder(val binding: GameDoubleCardItemBinding): BaseRecyclerViewHolder(binding.root)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/game/doublecard/DoubleCardListViewHolder.kt b/app/src/main/java/com/gh/gamecenter/game/doublecard/DoubleCardListViewHolder.kt
new file mode 100644
index 0000000000..9a6872a9d3
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/game/doublecard/DoubleCardListViewHolder.kt
@@ -0,0 +1,29 @@
+package com.gh.gamecenter.game.doublecard
+
+import androidx.recyclerview.widget.DefaultItemAnimator
+import androidx.recyclerview.widget.GridLayoutManager
+import com.gh.gamecenter.R
+import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
+import com.gh.gamecenter.common.view.GridSpacingItemColorDecoration
+import com.gh.gamecenter.databinding.GameDoubleCardListBinding
+import com.gh.gamecenter.entity.SubjectEntity
+
+class DoubleCardListViewHolder(val binding: GameDoubleCardListBinding) : BaseRecyclerViewHolder(binding.root) {
+
+ fun bindDoubleCardList(subject: SubjectEntity): DoubleCardListAdapter {
+ return binding.doubleCardList.run {
+ var subjectAdapter = adapter
+ if (subjectAdapter is DoubleCardListAdapter) {
+ subjectAdapter.checkResetData(subject)
+ } else {
+ (itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
+ isNestedScrollingEnabled = false
+ layoutManager = GridLayoutManager(context, 2)
+ subjectAdapter = DoubleCardListAdapter(context, subject)
+ adapter = subjectAdapter
+ addItemDecoration(GridSpacingItemColorDecoration(context, 8, 8, R.color.transparent))
+ }
+ subjectAdapter
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalAdapter.kt b/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalAdapter.kt
index 8b46636ea6..6c8687b98d 100644
--- a/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalAdapter.kt
+++ b/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalAdapter.kt
@@ -5,14 +5,17 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.exposure.ExposureEvent
import com.gh.common.util.DataCollectionUtils
+import com.gh.common.util.DownloadItemUtils
import com.gh.common.util.NewLogUtils
import com.gh.gamecenter.core.utils.MtaHelper
import com.gh.gamecenter.core.utils.StringUtils
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.GameDetailActivity
+import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.databinding.GameHorizontalItemBinding
import com.gh.gamecenter.entity.SubjectEntity
import com.lightgame.adapter.BaseRecyclerAdapter
+import com.lightgame.download.DownloadEntity
class GameHorizontalAdapter(
context: Context,
@@ -56,18 +59,27 @@ class GameHorizontalAdapter(
}
override fun onBindViewHolder(holder: GameHorizontalItemViewHolder, position: Int) {
- if (exposureEventList.isNullOrEmpty()) {
- val params = holder.binding.root.layoutParams as RecyclerView.LayoutParams
- params.width = RecyclerView.LayoutParams.WRAP_CONTENT
- holder.binding.root.layoutParams = params
- }
+ val params = holder.binding.root.layoutParams as RecyclerView.LayoutParams
+ params.width = if (gameName.isNotBlank()) RecyclerView.LayoutParams.WRAP_CONTENT else RecyclerView.LayoutParams.MATCH_PARENT
+ holder.binding.root.layoutParams = params
val gameEntity = mSubjectEntity.data!![position + getIndex()]
holder.binding.simpleGameContainer.run {
gameIcon.displayGameIcon(gameEntity)
GameHorizontalSimpleItemViewHolder.setHorizontalNameAndGravity(gameName, gameEntity.name)
+ downloadBtn.goneIf(!mSubjectEntity.showDownload)
+ gameName.maxLines = if (mSubjectEntity.showDownload) 1 else 2
}
holder.bindGameHorizontalItem(gameEntity, mSubjectEntity)
+ var entranceResult = ""
+ var locationResult = ""
+ if (exposureEventList.isNullOrEmpty()) {
+ entranceResult = StringUtils.buildString(entrance, "+(", "游戏详情", "[", gameName, "]:大家都在玩[", (position + 1).toString(), "])")
+ locationResult = StringUtils.buildString("游戏详情-", gameName, "-大家都在玩", ":", gameEntity.name)
+ } else {
+ entranceResult = StringUtils.buildString("(游戏-专题:", mSubjectEntity.name, "-列表[", (position + 1).toString(), "])")
+ locationResult = StringUtils.buildString("游戏-专题-", mSubjectEntity.name, ":", gameEntity.name)
+ }
holder.itemView.setOnClickListener {
if (exposureEventList.isNullOrEmpty()) {
DataCollectionUtils.uploadClick(mContext, "大家都在玩", "游戏详情", gameEntity.name)
@@ -75,19 +87,63 @@ class GameHorizontalAdapter(
MtaHelper.onEvent("游戏详情_新", "大家都在玩", gameName + "+" + gameEntity.name)
GameDetailActivity.startGameDetailActivity(
- mContext, gameEntity,
- StringUtils.buildString(entrance, "+(", "游戏详情", "[", gameName, "]:大家都在玩[", (position + 1).toString(), "])")
+ mContext,
+ gameEntity,
+ entranceResult
)
} else {
GameDetailActivity.startGameDetailActivity(
mContext,
gameEntity,
- StringUtils.buildString("(游戏-专题:", mSubjectEntity.name, "-列表[", (position + 1).toString(), "])"),
+ entranceResult,
traceEvent = exposureEventList!![position]
)
}
NewLogUtils.logGameDetailPopularClick(gameName, gameId, "game", gameEntity.name ?: "")
}
+
+ if (mSubjectEntity.showDownload) {
+ DownloadItemUtils.setOnClickListener(
+ mContext,
+ holder.binding.simpleGameContainer.downloadBtn,
+ gameEntity,
+ position,
+ this,
+ entranceResult,
+ locationResult,
+ if (position < (exposureEventList?.size ?: 0)) exposureEventList!![position] else null
+ )
+
+ DownloadItemUtils.updateDownloadButton(
+ mContext,
+ holder.binding.simpleGameContainer.downloadBtn,
+ gameEntity
+ )
+ }
+ }
+
+ fun notifyItemByDownload(downloadEntity: DownloadEntity?) {
+ if (downloadEntity == null) {
+ notifyDataSetChanged()
+ } else {
+ mSubjectEntity.data?.forEachIndexed { position, gameEntity ->
+ if (downloadEntity.gameId == gameEntity.id) {
+ notifyItemChanged(position - getIndex())
+ return
+ }
+ }
+ }
+ }
+
+ fun notifyChildItem(packageName: String) {
+ mSubjectEntity.data?.forEachIndexed { position, gameEntity ->
+ gameEntity.getApk().forEach { apkEntity ->
+ if (apkEntity.packageName == packageName) {
+ notifyItemChanged(position - getIndex())
+ return
+ }
+ }
+ }
}
// notifyDataSetChanged 会出现页面抖动情况
diff --git a/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalListViewHolder.kt b/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalListViewHolder.kt
index ddcf3077a1..3b0a98826b 100644
--- a/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalListViewHolder.kt
+++ b/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalListViewHolder.kt
@@ -12,14 +12,14 @@ class GameHorizontalListViewHolder(val binding: GameHorizontalListBinding) : Bas
fun bindHorizontalList(subjectEntity: SubjectEntity): GameHorizontalAdapter {
val context = binding.root.context
- var subjectAdapter = binding.horizontalRv.adapter
+ var subjectAdapter = binding.recyclerView.adapter
if (subjectAdapter == null) {
- binding.horizontalRv.setPadding(5F.dip2px(), 8F.dip2px(), 5F.dip2px(), 8F.dip2px())
- binding.horizontalRv.layoutManager = GridLayoutManager(context, 4)
+ binding.recyclerView.setPadding(5F.dip2px(), 8F.dip2px(), 5F.dip2px(), 8F.dip2px())
+ binding.recyclerView.layoutManager = GridLayoutManager(context, 4)
subjectAdapter = GameHorizontalAdapter(context, subjectEntity)
- (binding.horizontalRv.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
- binding.horizontalRv.adapter = subjectAdapter
- binding.horizontalRv.isNestedScrollingEnabled = false
+ (binding.recyclerView.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
+ binding.recyclerView.adapter = subjectAdapter
+ binding.recyclerView.isNestedScrollingEnabled = false
} else {
(subjectAdapter as GameHorizontalAdapter).checkResetData(subjectEntity)
}
diff --git a/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalSlideAdapter.kt b/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalSlideAdapter.kt
index 3c2141b251..6173fa362d 100644
--- a/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalSlideAdapter.kt
+++ b/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalSlideAdapter.kt
@@ -3,16 +3,15 @@ package com.gh.gamecenter.game.horizontal
import android.content.Context
import android.view.ViewGroup
import com.gh.common.exposure.ExposureEvent
+import com.gh.common.util.DownloadItemUtils
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.R
-import com.gh.gamecenter.common.utils.dip2px
-import com.gh.gamecenter.common.utils.safelyGetInRelease
-import com.gh.gamecenter.common.utils.toBinding
-import com.gh.gamecenter.common.utils.toColor
+import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.databinding.GameHorizontalItemBinding
import com.gh.gamecenter.entity.SubjectEntity
import com.lightgame.adapter.BaseRecyclerAdapter
+import com.lightgame.download.DownloadEntity
class GameHorizontalSlideAdapter(
context: Context,
@@ -56,6 +55,8 @@ class GameHorizontalSlideAdapter(
holder.binding.simpleGameContainer.root.setPadding(8F.dip2px(), 0, 8F.dip2px(), 0)
holder.binding.root.layoutParams =
ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+ holder.binding.simpleGameContainer.downloadBtn.goneIf(!mSubjectEntity.showDownload)
+ holder.binding.simpleGameContainer.gameName.maxLines = if (mSubjectEntity.showDownload) 1 else 2
val gameEntity = mSubjectEntity.data!![position + getIndex()]
holder.binding.simpleGameContainer.run {
@@ -78,8 +79,51 @@ class GameHorizontalSlideAdapter(
)
}
}
+
+ if (mSubjectEntity.showDownload) {
+ DownloadItemUtils.setOnClickListener(
+ mContext,
+ holder.binding.simpleGameContainer.downloadBtn,
+ gameEntity,
+ position,
+ this,
+ StringUtils.buildString("(游戏-专题:", mSubjectEntity.name, "-列表[", (position + 1).toString(), "])"),
+ StringUtils.buildString("游戏-专题-", mSubjectEntity.name, ":", gameEntity.name),
+ if (position < (exposureEventList?.size ?: 0)) exposureEventList!![position] else null
+ )
+
+ DownloadItemUtils.updateDownloadButton(
+ mContext,
+ holder.binding.simpleGameContainer.downloadBtn,
+ gameEntity
+ )
+ }
}
+ fun notifyItemByDownload(downloadEntity: DownloadEntity?) {
+ if (downloadEntity == null) {
+ notifyDataSetChanged()
+ } else {
+ mSubjectEntity.data?.forEachIndexed { position, gameEntity ->
+ if (downloadEntity.gameId == gameEntity.id) {
+ notifyItemChanged(position - getIndex())
+ return
+ }
+ }
+ }
+ }
+ fun notifyChildItem(packageName: String) {
+ mSubjectEntity.data?.forEachIndexed { position, gameEntity ->
+ gameEntity.getApk().forEach { apkEntity ->
+ if (apkEntity.packageName == packageName) {
+ notifyItemChanged(position - getIndex())
+ return
+ }
+ }
+ }
+ }
+
+
// notifyDataSetChanged 会出现页面抖动情况
fun checkResetData(subjectEntity: SubjectEntity) {
var dataIds = ""
diff --git a/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalSlideListViewHolder.kt b/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalSlideListViewHolder.kt
index dc13aadd1b..33d39c2006 100644
--- a/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalSlideListViewHolder.kt
+++ b/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalSlideListViewHolder.kt
@@ -27,17 +27,17 @@ class GameHorizontalSlideListViewHolder(val binding: GameHorizontalListBinding)
offsetable: IOffsetable
): GameHorizontalSlideAdapter {
val context = binding.root.context
- var subjectAdapter = binding.horizontalRv.adapter
+ var subjectAdapter = binding.recyclerView.adapter
binding.fakeRemarkLine.setBackgroundColor(R.color.btn_gray_light.toColor(context))
if (subjectAdapter == null) {
- binding.horizontalRv.setPadding(10F.dip2px(), 8F.dip2px(), 10F.dip2px(), 8F.dip2px())
- binding.horizontalRv.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
- binding.horizontalRv.clipToPadding = false
+ binding.recyclerView.setPadding(10F.dip2px(), 8F.dip2px(), 10F.dip2px(), 8F.dip2px())
+ binding.recyclerView.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
+ binding.recyclerView.clipToPadding = false
subjectAdapter = GameHorizontalSlideAdapter(context, subjectEntity)
- (binding.horizontalRv.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
- binding.horizontalRv.adapter = subjectAdapter
- binding.horizontalRv.setScrollingTouchSlop(RecyclerView.TOUCH_SLOP_PAGING)
- binding.horizontalRv.isNestedScrollingEnabled = false
+ (binding.recyclerView.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
+ binding.recyclerView.adapter = subjectAdapter
+ binding.recyclerView.setScrollingTouchSlop(RecyclerView.TOUCH_SLOP_PAGING)
+ binding.recyclerView.isNestedScrollingEnabled = false
if (subjectEntity.data?.firstOrNull()?.test?.testTime != null && mLastScrolledPosition == 0) {
scrollToSpecificItemForTheFirstTime(subjectEntity)
@@ -52,12 +52,12 @@ class GameHorizontalSlideListViewHolder(val binding: GameHorizontalListBinding)
if (subjectEntity.data?.firstOrNull()?.test?.testTime != null && mLastScrolledPosition == 0) {
scrollToSpecificItemForTheFirstTime(subjectEntity)
} else {
- binding.horizontalRv.scrollToPosition(0)
+ binding.recyclerView.scrollToPosition(0)
}
} else {
// 可能会因为上下复用数据变化而出现 IndexOutOfBoundsException 异常,毕竟有局部更新功能...
tryCatchInRelease {
- binding.horizontalRv.scrollBy(offset, offset)
+ binding.recyclerView.scrollBy(offset, offset)
}
}
}
@@ -77,7 +77,7 @@ class GameHorizontalSlideListViewHolder(val binding: GameHorizontalListBinding)
}
}
- binding.horizontalRv.addOnScrollListener(mScrollListener!!)
+ binding.recyclerView.addOnScrollListener(mScrollListener!!)
}
return subjectAdapter
@@ -85,7 +85,7 @@ class GameHorizontalSlideListViewHolder(val binding: GameHorizontalListBinding)
private fun scrollToSpecificItemForTheFirstTime(subjectEntity: SubjectEntity) {
val position = findTheLatestTestGamePosition(subjectEntity)
- binding.horizontalRv.scrollToPosition(position)
+ binding.recyclerView.scrollToPosition(position)
}
/**
@@ -136,7 +136,7 @@ class GameHorizontalSlideListViewHolder(val binding: GameHorizontalListBinding)
// 这里显示一条假的线供上层 recyclerView 列表使用,因为写在 item 里面很复杂
binding.root.post {
binding.fakeRemarkLine.layoutParams = (binding.fakeRemarkLine.layoutParams as ConstraintLayout.LayoutParams).apply {
- topMargin = getTopOfLineContainer(binding.horizontalRv) + 2F.dip2px() // 这里加上的2F是点的边距
+ topMargin = getTopOfLineContainer(binding.recyclerView) + 2F.dip2px() // 这里加上的2F是点的边距
}
}
binding.fakeRemarkLine.visibility = View.VISIBLE
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionDetailFragment.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionDetailFragment.kt
index ecf8a068aa..5352a83b4b 100644
--- a/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionDetailFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionDetailFragment.kt
@@ -87,6 +87,10 @@ class GameCollectionDetailFragment :
showUnzipFailureDialog(downloadEntity)
}
}
+
+ override fun onDataInit(downloadEntity: DownloadEntity) {
+ mAdapter?.notifyItemByDownload(downloadEntity)
+ }
}
override fun getLayoutId() = 0
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionPosterFragment.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionPosterFragment.kt
index 86f2f2cabc..e509b8afbc 100644
--- a/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionPosterFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionPosterFragment.kt
@@ -5,19 +5,17 @@ import android.os.Build
import android.os.Bundle
import android.view.View
import androidx.annotation.RequiresApi
-import com.gh.gamecenter.core.runOnUiThread
-import com.gh.common.util.*
+import com.gh.common.util.DirectUtils
import com.gh.gamecenter.R
+import com.gh.gamecenter.common.base.fragment.ToolbarFragment
import com.gh.gamecenter.common.callback.BiCallback
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.*
-import com.gh.gamecenter.common.utils.ImageUtils
-import com.gh.gamecenter.common.utils.BitmapUtils
+import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.databinding.FragmentGameCollectionPosterBinding
import com.gh.gamecenter.databinding.LayoutGameCollectionTagBinding
import com.gh.gamecenter.entity.GamesCollectionDetailEntity
import com.gh.gamecenter.manager.UserManager
-import com.gh.gamecenter.common.base.fragment.ToolbarFragment
class GameCollectionPosterFragment : ToolbarFragment() {
@@ -62,9 +60,13 @@ class GameCollectionPosterFragment : ToolbarFragment() {
ImageUtils.getBitmap(cover, object : BiCallback {
@RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
override fun onFirst(first: Bitmap) {
- val blurBitmap = BitmapUtils.getBlurBitmap(requireContext(), first, 16)
- runOnUiThread {
- posterBg.setImageBitmap(blurBitmap)
+ try {
+ val blurBitmap = BitmapUtils.getBlurBitmap(requireContext(), first, 16)
+ runOnUiThread {
+ posterBg.setImageBitmap(blurBitmap)
+ }
+ } catch (t: Throwable) {
+ posterBg.setImageBitmap(first)
}
}
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/detail/conversation/GameCollectionCommentConversationFragment.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/conversation/GameCollectionCommentConversationFragment.kt
index 25a7f929b3..4cf9cc0d2e 100644
--- a/app/src/main/java/com/gh/gamecenter/gamecollection/detail/conversation/GameCollectionCommentConversationFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/conversation/GameCollectionCommentConversationFragment.kt
@@ -274,7 +274,7 @@ class GameCollectionCommentConversationFragment :
orderSfv.run {
setContainerBackground(R.drawable.button_round_f5f5f5.toDrawable(requireContext()))
setIndicatorBackground(
- R.drawable.progressbar_game_collection_primary.toDrawable(
+ R.drawable.bg_game_collection_sfv_indicator.toDrawable(
requireContext()
)
)
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/publish/GameCollectionEditActivity.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/publish/GameCollectionEditActivity.kt
index 70c43a1e89..d09138edf5 100644
--- a/app/src/main/java/com/gh/gamecenter/gamecollection/publish/GameCollectionEditActivity.kt
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/publish/GameCollectionEditActivity.kt
@@ -17,6 +17,7 @@ import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.CropImageActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.WebActivity
+import com.gh.gamecenter.common.callback.ConfirmListener
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.PatternUtils
@@ -228,7 +229,13 @@ class GameCollectionEditActivity : ToolBarActivity() {
}
finish()
} else {
- ErrorHelper.handleError(this, it.exception?.response()?.errorBody()?.string())
+ ErrorHelper.handleError(this, it.exception?.response()?.errorBody()?.string(), false, object : ConfirmListener {
+ override fun onConfirm() {
+ if (::mMenuPost.isInitialized) {
+ onMenuItemClick(mMenuPost)
+ }
+ }
+ })
}
}
mViewModel.detailLiveData.observe(this) {
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/square/GameCollectionSquareFragment.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/square/GameCollectionSquareFragment.kt
index e5b6abda37..88349a4eed 100644
--- a/app/src/main/java/com/gh/gamecenter/gamecollection/square/GameCollectionSquareFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/square/GameCollectionSquareFragment.kt
@@ -545,7 +545,7 @@ class GameCollectionSquareFragment : LazyListFragment(context) {
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder = GameDetailContentCardContentItemViewHolder(parent.toBinding())
+
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+ if (holder is GameDetailContentCardContentItemViewHolder) {
+ holder.binding.root.setTextColor(if (isHighlightBg) R.color.text_subtitle.toColor(mContext) else R.color.text_subtitleDesc.toColor(mContext))
+ if (linkEntity.type == "func_server" && linkEntity.server != null && linkEntity.server?.calendar?.isNotEmpty() == true) {
+ val calendarList = linkEntity.server!!.calendar
+ val realPosition = position % calendarList.size
+ calendarList.safelyGetInRelease(realPosition)?.let {
+ val serverTime =
+ if (TimeUtils.isToday(it.getTime()))
+ it.getFormatTime("今天 HH:mm")
+ else if (TimeUtils.isTomorrow(it.getTime()))
+ it.getFormatTime("明天 HH:mm")
+ else
+ it.getFormatTime("MM-dd HH:mm")
+ holder.binding.root.text = "$serverTime ${it.type}"
+ }
+ }
+ }
+ }
+
+ override fun getItemCount(): Int = Int.MAX_VALUE
+
+ class GameDetailContentCardContentItemViewHolder(var binding: ItemGameDetailContentCardContentBinding) : RecyclerView.ViewHolder(binding.root)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailFragment.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailFragment.kt
index be22a37595..0e3564da3b 100644
--- a/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailFragment.kt
@@ -1,19 +1,22 @@
package com.gh.gamecenter.gamedetail
+import android.animation.Animator
+import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.drawable.GradientDrawable
-import android.os.Build
-import android.os.Bundle
+import android.os.*
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.text.TextUtils
import android.view.*
+import android.view.animation.AccelerateDecelerateInterpolator
import android.widget.FrameLayout
import android.widget.ImageView
+import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
@@ -21,13 +24,16 @@ import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.children
import androidx.core.widget.TextViewCompat
+import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
+import androidx.viewpager2.widget.ViewPager2
import com.ethanhua.skeleton.Skeleton
import com.ethanhua.skeleton.ViewSkeletonScreen
import com.gh.common.constant.Config
import com.gh.common.databind.BindingAdapters
import com.gh.common.exposure.ExposureEvent
+import com.gh.common.exposure.ExposureSource
import com.gh.common.repository.ReservationRepository
import com.gh.common.simulator.SimulatorGameManager
import com.gh.common.util.*
@@ -57,8 +63,10 @@ import com.gh.gamecenter.gamedetail.desc.DescFragment
import com.gh.gamecenter.gamedetail.dialog.GameBigEventDialog
import com.gh.gamecenter.gamedetail.dialog.GameDetailMoreDialog
import com.gh.gamecenter.gamedetail.dialog.GameTagsDialog
+import com.gh.gamecenter.gamedetail.entity.ContentCardEntity
import com.gh.gamecenter.gamedetail.entity.NewGameDetailEntity
import com.gh.gamecenter.gamedetail.fuli.FuLiFragment
+import com.gh.gamecenter.gamedetail.fuli.kaifu.ServersCalendarActivity
import com.gh.gamecenter.gamedetail.rating.RatingFragment
import com.gh.gamecenter.gamedetail.video.TopVideoView
import com.gh.gamecenter.home.video.ScrollCalculatorHelper
@@ -84,6 +92,7 @@ import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import retrofit2.HttpException
+import java.lang.ref.WeakReference
import java.util.*
import kotlin.math.abs
@@ -116,6 +125,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
private var mRecommendDisposable: Disposable? = null
private var mRecommendPopupEntity: RecommendPopupEntity? = null
private var mTabClickEvent: Pair = Pair(0L, "")
+ private var mContentCardServerVp: ViewPager2? = null
private lateinit var mBinding: FragmentGamedetailBinding
private lateinit var mVideoBinding: PieceGameDetailVideoBinding
@@ -127,20 +137,26 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
private lateinit var mPackageViewModel: PackageViewModel
private lateinit var mUserViewModel: UserViewModel
+ private var mShowConcernOnMenu = false
+
private val mFragmentsList = ArrayList()
private val mTabTitleList = ArrayList()
+ private val mLooperHandle = LooperHandle(this)
+ private val mServerLooperKey = 123
private val dataWatcher = object : DataWatcher() {
override fun onDataChanged(downloadEntity: DownloadEntity) {
if (downloadEntity.gameId == mViewModel.gameId) {
- if (downloadEntity.status == DownloadStatus.add || downloadEntity.status == DownloadStatus.done || downloadEntity.status == DownloadStatus.downloading || downloadEntity.status == DownloadStatus.pause || downloadEntity.status == DownloadStatus.redirected) {
+ if (downloadEntity.status == DownloadStatus.add
+ || downloadEntity.status == DownloadStatus.done
+ || downloadEntity.status == DownloadStatus.downloading
+ || downloadEntity.status == DownloadStatus.pause
+ || downloadEntity.status == DownloadStatus.redirected) {
showInstallHint()
SPUtils.setBoolean(Constants.SP_SHOULD_SHOW_GAME_DETAIL_INSTALL_GUIDE, true)
}
- }
- if (mGameEntity != null && mGameEntity!!.getApk().size == 1) {
- val url = mGameEntity!!.getApk()[0].url
- if (downloadEntity.url == url) {
+
+ if (mGameEntity?.getApk()?.size == 1) {
if ("pause" != DownloadManager.getInstance().getStatus(downloadEntity.url)?.status) {
mDownloadEntity = downloadEntity
DetailDownloadUtils.detailInvalidate(detailViewHolder)
@@ -149,43 +165,44 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
if (downloadEntity.meta[XapkInstaller.XAPK_UNZIP_STATUS] == XapkUnzipStatus.FAILURE.name) {
DialogUtils.showUnzipFailureDialog(requireContext(), downloadEntity)
}
- }
- val meta = downloadEntity.getMetaExtra(PageSwitchDataHelper.PAGE_GAME_DETAIL_RECOMMEND)
- if (downloadEntity.status == DownloadStatus.add) {
- if (downloadEntity.gameId == mViewModel.game?.id) {
+
+ val gameDetailRecommendMeta = downloadEntity.getMetaExtra(PageSwitchDataHelper.PAGE_GAME_DETAIL_RECOMMEND)
+ if (downloadEntity.status == DownloadStatus.add) {
mRecommendBinding.recommendView.postDelayed({ showRecommendView() }, 500)
- }
- if (meta.isNotEmpty() && mRecommendPopupEntity != null) {
- LogUtils.uploadRecommendPopup(
- "recommend_pop_download",
- mRecommendPopupEntity?.id,
- mViewModel.game?.id ?: "",
- mViewModel.game?.name ?: "",
- mRecommendPopupEntity?.popupDetail?.link?.type,
- mRecommendPopupEntity?.popupDetail?.link?.text,
- downloadEntity.gameId,
- downloadEntity.name
- )
- }
- } else if (downloadEntity.status == DownloadStatus.done) {
- if (downloadEntity.gameId == mViewModel.game?.id) {
+ if (gameDetailRecommendMeta.isNotEmpty() && mRecommendPopupEntity != null) {
+ LogUtils.uploadRecommendPopup(
+ "recommend_pop_download",
+ mRecommendPopupEntity?.id,
+ mViewModel.game?.id ?: "",
+ mViewModel.game?.name ?: "",
+ mRecommendPopupEntity?.popupDetail?.link?.type,
+ mRecommendPopupEntity?.popupDetail?.link?.text,
+ downloadEntity.gameId,
+ downloadEntity.name
+ )
+ }
+ } else if (downloadEntity.status == DownloadStatus.done) {
hideRecommendView()
- }
- if (meta.isNotEmpty() && mRecommendPopupEntity != null) {
- LogUtils.uploadRecommendPopup(
- "recommend_pop_download_complete",
- mRecommendPopupEntity?.id,
- mViewModel.game?.id ?: "",
- mViewModel.game?.name ?: "",
- mRecommendPopupEntity?.popupDetail?.link?.type,
- mRecommendPopupEntity?.popupDetail?.link?.text,
- downloadEntity.gameId,
- downloadEntity.name
- )
+ if (gameDetailRecommendMeta.isNotEmpty() && mRecommendPopupEntity != null) {
+ LogUtils.uploadRecommendPopup(
+ "recommend_pop_download_complete",
+ mRecommendPopupEntity?.id,
+ mViewModel.game?.id ?: "",
+ mViewModel.game?.name ?: "",
+ mRecommendPopupEntity?.popupDetail?.link?.type,
+ mRecommendPopupEntity?.popupDetail?.link?.text,
+ downloadEntity.gameId,
+ downloadEntity.name
+ )
+ }
}
}
}
}
+
+ override fun onDataInit(downloadEntity: DownloadEntity) {
+ onDataChanged(downloadEntity)
+ }
}
// 下载按钮ViewHolder
@@ -203,8 +220,67 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
mTraceEvent
)
- override fun getLayoutId(): Int = 0
+ private val contentCardClick: (contentCard: ContentCardEntity) -> Unit = { contentCardEntity ->
+ NewFlatLogUtils.logGameDetailGameContentCardClick(contentCardEntity.title ?: "", mGameEntity?.name ?: "", mGameEntity?.id ?: "", contentCardEntity.type ?: "", contentCardEntity.link ?: "", contentCardEntity.text ?: "")
+ when (contentCardEntity.type) {
+ "func_server" -> {
+ if (contentCardEntity.server != null) {
+ requireContext().startActivity(
+ ServersCalendarActivity.getIntent(
+ requireContext(),
+ mViewModel.game!!, contentCardEntity.server!!,
+ mNewGameDetailEntity?.me
+ )
+ )
+ }
+ }
+ "func_libao" -> {
+ mBodyBinding.gamedetailVp.currentItem = 0
+ mBodyBinding.gamedetailAppbar.setExpanded(false, true)
+ val fragment = mFragmentsList[0]
+ if (fragment is DescFragment && fragment.isAdded) {
+ fragment.scrollToLibao()
+ }
+ }
+ "func_related_version" -> {
+ mBodyBinding.gamedetailVp.currentItem = 0
+ mBodyBinding.gamedetailAppbar.setExpanded(false, true)
+ val fragment = mFragmentsList[0]
+ if (fragment is DescFragment && fragment.isAdded) {
+ fragment.scrollToRelatedVersion()
+ }
+ }
+ "func_zone" -> {
+ val gameDetailEntity = mViewModel.gameDetailLiveData.value?.data
+ if (contentCardEntity.zoneTab && gameDetailEntity?.zone != null && gameDetailEntity.zone!!.style == "link") {
+ requireContext().startActivity(WebActivity.getIntent(requireContext(), gameDetailEntity.zone!!.link, true))
+ }
+ }
+ "func_tool_kit" -> {
+ if (contentCardEntity.toolkit.isNotEmpty()) {
+ contentCardEntity.toolkit.safelyGetInRelease(0)?.let {
+ val url = it.url
+ if (url != null && url.contains(Config.URL_ARTICLE)) {
+ val newsId = url.substring(url.lastIndexOf("/") + 1, url.length - 5) // 5: ".html"
+ val intent = NewsDetailActivity.getIntentById(requireContext(), newsId, "游戏详情->内容卡片")
+ requireContext().startActivity(intent)
+ } else {
+ requireContext().startActivity(
+ WebActivity.getWebByCollectionTools(
+ requireContext(),
+ it,
+ false
+ )
+ )
+ }
+ }
+ }
+ }
+ else -> DirectUtils.directToLinkPage(requireContext(), contentCardEntity.toLinkEntity(), mEntrance, "游戏详情->内容卡片", ExposureEvent.createEvent(null, listOf(ExposureSource("游戏详情", mGameEntity?.id ?: ""), ExposureSource("内容卡片", contentCardEntity.id))))
+ }
+ }
+ override fun getLayoutId(): Int = 0
override fun getInflatedLayout(): View {
return FragmentGamedetailBinding.inflate(LayoutInflater.from(requireContext())).apply {
mBinding = this
@@ -234,7 +310,9 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
GameDetailMoreDialog.showMoreDialog(
requireActivity() as AppCompatActivity,
mGameEntity,
- mNewGameDetailEntity?.shortId ?: ""
+ mNewGameDetailEntity?.shortId ?: "",
+ mShowConcernOnMenu,
+ mNewGameDetailEntity!!.me.isGameConcerned
)
MtaHelper.onEvent("游戏详情_新", "更多按钮", mViewModel.game?.name ?: "")
}
@@ -253,7 +331,6 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
mSearchMenuItem?.setOnMenuItemClickListener(menuItemClickListener)
mDownloadMenuItem?.actionView?.setOnClickListener {
MtaHelper.onEvent("游戏详情_新", "下载管理图标", mViewModel.game?.name ?: "")
-// MtaHelper.onEvent("下载管理", "下载管理入口", (requireActivity() as BaseActivity).activityNameInChinese)
val intent = DownloadManagerActivity.getDownloadMangerIntent(requireContext(), mEntrance)
startActivity(intent)
}
@@ -402,6 +479,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
private fun initGameSubtitle(gameTitleTv: TextView, gameSubtitle: String, gameSubtitleStyle: TagStyleEntity? = null, advanceDownload: Boolean = false) {
gameTitleTv.post {
+ if (!isAdded) return@post
gameTitleTv.run {
var lastPosX = 0F
tryCatchInRelease {
@@ -444,7 +522,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
var changeDisplayName = false
if ((lineCount == 2 && layout.getEllipsisCount(1) > 0) || (lineCount == 2 && tagView.measuredWidth > remainWidth)) {
val textCount = calculateTextCountByWidth(this, 2 * gameTitleTv.width - tagView.measuredWidth) - 1
- if (textCount < text.length) {
+ if (textCount in text.indices) {
displayName = text.substring(0, textCount) + "…"
changeDisplayName = true
}
@@ -475,6 +553,7 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
}
private fun subtractGameNameIfNeeded(textView: TextView, name: CharSequence, tagLayout: FrameLayout) {
+ if (!isAdded) return
textView.run {
if (lineCount > 2 || (layout != null && layout.getEllipsisCount(1) > 0)) {
val displayName = name.substring(0, name.length - 2) + "…"
@@ -539,8 +618,6 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
}
mBodyBinding.toolbar.setNavigationOnClickListener { requireActivity().finish() }
- mDownloadBinding.ivConcern.visibility = View.VISIBLE
- mDownloadBinding.tvConcern.visibility = View.VISIBLE
}
@Subscribe(threadMode = ThreadMode.MAIN)
@@ -577,6 +654,11 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
showAlertDialogIfNeeded(data)
initViewPage(data)
+
+ if (data.contentCard.size > 1 && mGameEntity?.shouldUseMirrorInfo() == false) {
+ initGameContentCard(data.contentCard)
+ }
+
updateGameDetailTopArea()
val viewHolder = detailViewHolder
@@ -603,8 +685,11 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
mBinding.errorToolbarContainer.visibility = View.GONE
controlReserveBtn()
- mSkeleton?.hide()
+ showVModeIconAtBottomBarIfNeeded(data.smoothRelatedGame, mGameEntity!!)
+ showConcernIconAtBottomBarIfAvailable()
+
+ mSkeleton?.hide()
} else if (detailResource.status == Status.ERROR) {
loadErrorControl(detailResource.exception)
}
@@ -702,6 +787,9 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
mTabTitleList.add(getString(R.string.game_detail_desc))
data.zone?.let {
+ data.contentCard.forEach { contentCard ->
+ if (data.contentCard.size > 1 && contentCard.type == "func_zone") return@let
+ }
if (it.style == "link") {//显示web页面
val webFragment = childFragmentManager.findFragmentByTag("${tag}${INDEX_TRENDES}") ?: WebFragment()
val webBundle = Bundle()
@@ -960,6 +1048,119 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
}
}
+ private fun initGameContentCard(linkEntityList: List) {
+ mBodyBinding.toolbarGapView.visibility = View.GONE
+ mBodyBinding.contentCardContainer.removeAllViews()
+ mBodyBinding.contentCardContainer.visibility = View.VISIBLE
+ if (linkEntityList.size >= 3) {
+ linkEntityList.safelyGetInRelease(0)?.let {
+ mBodyBinding.contentCardContainer.addView(getLargeContentCardView(it, true), LinearLayout.LayoutParams(0, 56F.dip2px(), 2F))
+ }
+ linkEntityList.safelyGetInRelease(1)?.let {
+ mBodyBinding.contentCardContainer.addView(getSmallContentCardView(it), LinearLayout.LayoutParams(0, 56F.dip2px(), 1F))
+ }
+ linkEntityList.safelyGetInRelease(2)?.let {
+ mBodyBinding.contentCardContainer.addView(getSmallContentCardView(it, true), LinearLayout.LayoutParams(0, 56F.dip2px(), 1F))
+ }
+ } else if (linkEntityList.size == 2) {
+ linkEntityList.safelyGetInRelease(0)?.let {
+ mBodyBinding.contentCardContainer.addView(getLargeContentCardView(it), LinearLayout.LayoutParams(0, 56F.dip2px(), 1F))
+ }
+ linkEntityList.safelyGetInRelease(1)?.let {
+ mBodyBinding.contentCardContainer.addView(getLargeContentCardView(it, isLastView = true), LinearLayout.LayoutParams(0, 56F.dip2px(), 1F))
+ }
+ }
+ }
+
+ private fun getLargeContentCardView(contentCardEntity: ContentCardEntity, isHighlightBg: Boolean = false, isLastView: Boolean = false) = LayoutGameDetailContentCardLargeBinding.inflate(layoutInflater).apply {
+ when {
+ isHighlightBg && !isLastView -> root.background = R.drawable.bg_content_card_large_primary.toDrawable(requireContext())
+ !isHighlightBg && !isLastView -> root.background = R.drawable.bg_content_card_large.toDrawable(requireContext())
+ !isHighlightBg && isLastView -> root.background = R.drawable.bg_content_card_large_right.toDrawable(requireContext())
+ }
+ root.setPadding(if (isLastView) 20F.dip2px() else 12F.dip2px(), 0, if (isLastView) 8F.dip2px() else 12F.dip2px(), 0)
+ titleTv.text = contentCardEntity.title
+ ImageUtils.display(iconIv, contentCardEntity.icon)
+ if (contentCardEntity.des.isNotEmpty() || contentCardEntity.type == "func_libao") {
+ contentTv.visibility = View.VISIBLE
+ contentVp.visibility = View.GONE
+ contentTv.text = if (contentCardEntity.type == "func_libao" && contentCardEntity.des.isEmpty()) "${contentCardEntity.libao?.total}个游戏礼包" else contentCardEntity.des
+ contentTv.setTextColor(if (isHighlightBg) R.color.text_subtitle.toColor(requireContext()) else R.color.text_subtitleDesc.toColor(requireContext()))
+ } else if (contentCardEntity.type == "func_server") {
+ contentTv.visibility = View.GONE
+ contentVp.visibility = View.VISIBLE
+ if (contentCardEntity.type == "func_server") mContentCardServerVp = contentVp
+ contentVp.run {
+ isUserInputEnabled = false
+ orientation = ViewPager2.ORIENTATION_VERTICAL
+ adapter = GameDetailContentCardContentAdapter(requireContext(), contentCardEntity, isHighlightBg)
+ if (contentCardEntity.type == "func_server") {
+ val nowTime = System.currentTimeMillis()
+ var timeDiff = 0L
+ var closestIndex = 0
+ contentCardEntity.server!!.calendar.forEachIndexed { index, serverCalendarEntity ->
+ val diff = abs(nowTime - serverCalendarEntity.getTime() * 1000L)
+ if (diff < timeDiff || index == 0) {
+ timeDiff = diff
+ closestIndex = index
+ }
+ }
+ currentItem = closestIndex
+ if (contentCardEntity.server!!.calendar.size > 1) {
+ startAutoPlay(mServerLooperKey)
+ }
+ }
+ }
+ }
+ redDotTv.goneIf(!((contentCardEntity.type == "func_server" && contentCardEntity.server?.total != 0) || contentCardEntity.type == "func_libao"))
+ if ((contentCardEntity.type == "func_server") && (contentCardEntity.server?.calendar?.isNotEmpty() == true)) redDotTv.text = contentCardEntity.server?.total.toString()
+ if ((contentCardEntity.type == "func_libao") && (contentCardEntity.libao != null)) redDotTv.text = contentCardEntity.libao?.total.toString()
+ root.setOnClickListener {
+ contentCardClick.invoke(contentCardEntity)
+ }
+ }.root
+
+ private fun getSmallContentCardView(contentCardEntity: ContentCardEntity, isLastView: Boolean = false) = LayoutGameDetailContentCardSmallBinding.inflate(layoutInflater).apply {
+ root.background = if (isLastView) R.drawable.bg_content_card_small_right.toDrawable(requireContext()) else R.drawable.bg_content_card_small.toDrawable(requireContext())
+ titleTv.text = contentCardEntity.title
+ ImageUtils.display(iconIv, contentCardEntity.icon)
+ redDotTv.goneIf(!((contentCardEntity.type == "func_server" && contentCardEntity.server?.total != 0) || contentCardEntity.type == "func_libao"))
+ redDotTv.layoutParams = (redDotTv.layoutParams as ViewGroup.MarginLayoutParams).apply { setMargins(0, 8F.dip2px(), if (isLastView) 8F.dip2px() else 12F.dip2px(), 0) }
+ if ((contentCardEntity.type == "func_server") && (contentCardEntity.server?.calendar?.isNotEmpty() == true)) redDotTv.text = contentCardEntity.server?.total.toString()
+ if ((contentCardEntity.type == "func_libao") && (contentCardEntity.libao != null)) redDotTv.text = contentCardEntity.libao?.total.toString()
+ root.setOnClickListener {
+ contentCardClick.invoke(contentCardEntity)
+ }
+ }.root
+
+ private fun scrollToNextContent(viewPager: ViewPager2? = null) {
+ viewPager?.run {
+ val pxToDrag: Int = height
+ val animator = ValueAnimator.ofInt(0, pxToDrag)
+ var previousValue = 0
+ animator.addUpdateListener { valueAnimator ->
+ val currentValue = valueAnimator.animatedValue as Int
+ val currentPxToDrag = (currentValue - previousValue).toFloat()
+ fakeDragBy(-currentPxToDrag)
+ previousValue = currentValue
+ }
+ animator.addListener(object : Animator.AnimatorListener {
+ override fun onAnimationStart(animation: Animator?) { beginFakeDrag() }
+ override fun onAnimationEnd(animation: Animator?) { endFakeDrag() }
+ override fun onAnimationCancel(animation: Animator?) { }
+ override fun onAnimationRepeat(animation: Animator?) { }
+ })
+ animator.interpolator = AccelerateDecelerateInterpolator()
+ animator.duration = 1000
+ animator.start()
+ }
+ }
+
+ private fun startAutoPlay(key: Int) {
+ mLooperHandle.removeMessages(key)
+ mLooperHandle.sendEmptyMessageDelayed(key, CONTENT_CARD_LOOP_TIME)
+ }
+
private fun setUpTopVideo(topVideo: GameDetailEntity.Video) {
GSYVideoOptionBuilder()
.setIsTouchWigetFull(false)
@@ -1609,6 +1810,51 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
}
}
+ /**
+ * 当其它三个按钮不显示的时候才显示收藏按钮
+ */
+ private fun showConcernIconAtBottomBarIfAvailable() {
+ val installSwitchViewIsNotVisible = !mDownloadBinding.ivSwitch.isVisible
+ val reserveBtnIsNotVisible = !mDownloadBinding.ivReserve.isVisible
+ val vmodeViewIsNotVisible = !mDownloadBinding.ivVmode.isVisible
+
+ if (installSwitchViewIsNotVisible || reserveBtnIsNotVisible || vmodeViewIsNotVisible) {
+ mDownloadBinding.ivConcern.visibility = View.VISIBLE
+ mDownloadBinding.tvConcern.visibility = View.VISIBLE
+ } else {
+ mDownloadBinding.ivConcern.visibility = View.GONE
+ mDownloadBinding.tvConcern.visibility = View.GONE
+
+ mShowConcernOnMenu = true
+ }
+ }
+
+ private fun showVModeIconAtBottomBarIfNeeded(simpleGame: SimpleGame?, gameEntity: GameEntity) {
+ mDownloadBinding.groupVmode.goneIf(simpleGame == null)
+ simpleGame?.let {
+ mDownloadBinding.ivVmode.displayGameIcon(simpleGame.getIcon(), simpleGame.iconSubscript)
+ if (gameEntity.isVGame()) {
+ mDownloadBinding.tvVmode.text = "下载 >"
+ mDownloadBinding.ivVmodeBadge.setImageResource(R.drawable.ic_switch_game_download)
+ } else {
+ mDownloadBinding.tvVmode.text = "畅玩 >"
+ mDownloadBinding.ivVmodeBadge.setImageResource(R.drawable.ic_switch_game_smooth)
+ }
+
+ mDownloadBinding.tvVmode.setOnClickListener { mDownloadBinding.ivVmode.performClick() }
+ mDownloadBinding.ivVmode.enlargeTouchArea()
+ mDownloadBinding.ivVmode.setOnClickListener { _ ->
+ val downloadStatus = when (simpleGame.downloadStatus) {
+ "smooth" -> "畅玩"
+ "demo" -> "试玩"
+ else -> "下载"
+ }
+ NewFlatLogUtils.logHaloFunGameDetailJumpClick(downloadStatus, simpleGame.id ?: "")
+ DirectUtils.directToGameDetail(requireContext(), it.id ?: "", mEntrance)
+ }
+ }
+ }
+
override fun onSaveInstanceState(outState: Bundle) {
mBodyBinding.gamedetailVp.let { outState.putInt(LAST_SELECTED_POSITION, it.currentItem) }
super.onSaveInstanceState(outState)
@@ -1644,6 +1890,11 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
}
mBinding.detailLlBottom.detailLlBottom.setBackgroundColor(R.color.background.toColor(requireContext()))
updateToolbarStyle(mBodyBinding.gamedetailThumbSmall.visibility == View.VISIBLE)
+ mViewModel.gameDetailLiveData.value?.data?.let {
+ if (it.contentCard.size > 1 && mGameEntity?.shouldUseMirrorInfo() == false) {
+ initGameContentCard(it.contentCard)
+ }
+ }
}
override fun scrollToTop() {
@@ -1668,8 +1919,25 @@ class GameDetailFragment : ToolbarFragment(), IScrollable {
const val SCROLL_TO_KAIFU = "scrollToKaiFu"
const val EB_SCROLLING = "EB_SCROLLING"
const val INITIAL_DELAY = 500L
+ const val CONTENT_CARD_LOOP_TIME = 3000L
private const val SP_OPENED_DIALOG_TIME_PREFIX = "opened_dialog_time_prefix_"
private const val LAST_SELECTED_POSITION = "last_selected_position"
}
+
+ class LooperHandle(fragment: GameDetailFragment): Handler(
+ Looper.getMainLooper()) {
+ private val mWeakReference: WeakReference = WeakReference(fragment)
+
+ override fun handleMessage(msg: Message) {
+ super.handleMessage(msg)
+ val fragment = mWeakReference.get()
+ if (fragment != null) {
+ if (msg.what == fragment.mServerLooperKey) {
+ fragment.scrollToNextContent(fragment.mContentCardServerVp)
+ }
+ fragment.startAutoPlay(msg.what)
+ }
+ }
+ }
}
diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailViewModel.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailViewModel.kt
index a86ba4a5fd..a2293e0d3f 100644
--- a/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailViewModel.kt
+++ b/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailViewModel.kt
@@ -9,15 +9,19 @@ import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
-import com.gh.gamecenter.common.constant.Constants
import com.gh.common.filter.RegionSettingHelper
import com.gh.common.history.HistoryHelper
-import com.gh.gamecenter.core.runOnUiThread
-import com.gh.common.util.*
-import com.gh.gamecenter.core.utils.GsonUtils
-import com.gh.gamecenter.core.utils.SPUtils
+import com.gh.common.util.ApkActiveUtils
+import com.gh.common.util.CheckLoginUtils
+import com.gh.common.util.ConcernUtils
+import com.gh.common.util.LibaoUtils
+import com.gh.gamecenter.common.constant.Constants
+import com.gh.gamecenter.common.retrofit.BiResponse
+import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.singleToMain
import com.gh.gamecenter.common.utils.toRequestBody
+import com.gh.gamecenter.core.utils.GsonUtils
+import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.UrlFilterUtils
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.gamedetail.entity.BigEvent
@@ -26,8 +30,6 @@ import com.gh.gamecenter.gamedetail.entity.DetailEntity
import com.gh.gamecenter.gamedetail.entity.NewGameDetailEntity
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.mvvm.Resource
-import com.gh.gamecenter.common.retrofit.BiResponse
-import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.android.schedulers.AndroidSchedulers
@@ -40,17 +42,11 @@ class GameDetailViewModel(application: Application,
var gameId: String?,
var game: GameEntity?) : AndroidViewModel(application) {
- init {
- runOnUiThread {
- loadData()
- }
- }
-
private val mApi = RetrofitManager.getInstance().api
private val mSensitiveApi = RetrofitManager.getInstance().api
val concernLiveData = MutableLiveData()
- val gameLiveData = MutableLiveData>()
+ val gameLiveData = MutableLiveData?>()
val gameDetailLiveData = MutableLiveData>()
val bigEventLiveData = MutableLiveData>()
val recommendPopupLiveData = MutableLiveData>()
@@ -64,6 +60,10 @@ class GameDetailViewModel(application: Application,
var videoIsMuted = SPUtils.getBoolean(Constants.SP_VIDEO_PLAY_MUTE, true)
var displayTopVideo: Boolean = false
+ init {
+ loadData()
+ }
+
fun loadData() {
if (RegionSettingHelper.shouldThisGameBeFiltered(gameId)) {
gameId = "invalid"
@@ -72,7 +72,7 @@ class GameDetailViewModel(application: Application,
when {
game != null -> {
- gameLiveData.value = Resource.success(game)
+ gameLiveData.postValue(Resource.success(game))
getGameDetailNew()
getRecommendPopup(game?.id ?: "")
}
@@ -115,6 +115,17 @@ class GameDetailViewModel(application: Application,
}
}
+ private fun removeLatestServerIfNeeded(data: NewGameDetailEntity) {
+ var i = 0
+ while (i < data.detailEntity.size) {
+ if (data.detailEntity[i].type == DetailEntity.Type.LATEST_SERVER.value) {
+ data.detailEntity.removeAt(i)
+ return
+ }
+ i++
+ }
+ }
+
@SuppressLint("CheckResult")
fun getGameDetailNew() {
mSensitiveApi.getGameDetailNew(game?.id)
@@ -127,6 +138,15 @@ class GameDetailViewModel(application: Application,
// 4.4以下设备不显示顶部视频
displayTopVideo = data.topVideo != null
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
+
+ data.contentCard.forEach {
+ // 显示开服内容卡片时,游戏详情-详情tab不显示“最新开服”
+ if (data.contentCard.size > 1 && it.type == "func_server") {
+ removeLatestServerIfNeeded(data)
+ return@forEach
+ }
+ }
+
gameDetailLiveData.postValue(Resource.success(data))
if (CheckLoginUtils.isLogin()) {
getUserRelatedInfo(data)
diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescAdapter.kt
index c44e3fdb9c..ca146dc5ce 100644
--- a/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescAdapter.kt
+++ b/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescAdapter.kt
@@ -26,15 +26,14 @@ import com.gh.common.databind.BindingAdapters
import com.gh.common.exposure.ExposureEvent
import com.gh.common.exposure.ExposureManager
import com.gh.common.exposure.ExposureSource
+import com.gh.common.util.*
import com.gh.common.util.DialogUtils
-import com.gh.common.util.DirectUtils
import com.gh.common.util.LogUtils
import com.gh.common.util.NewLogUtils
import com.gh.gamecenter.GameNewsActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.SuggestionActivity
import com.gh.gamecenter.adapter.viewholder.FooterViewHolder
-import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.callback.OnListClickListener
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.*
@@ -964,8 +963,11 @@ class DescAdapter(
}
}
- class GameDetailCustomColumnViewHolder(var binding: GamedetailItemCustomColumnBinding, handler: Handler) :
- ExposureViewHolder(binding.root, handler)
+ inner class GameDetailCustomColumnViewHolder(var binding: GamedetailItemCustomColumnBinding, handler: Handler) : ExposureViewHolder(binding.root, handler) {
+ override fun exposureLog() {
+ NewFlatLogUtils.logGameDetailColumnOrderingView(binding.titleTv.text.toString(), mViewModel.game?.name ?: "", mViewModel.game?.id ?: "")
+ }
+ }
class GameDetailRelatedVersionViewHolder(var binding: GameGalleryListBinding, handler: Handler) : ExposureViewHolder(binding.root, handler)
class GameVideoGalleryViewHolder(var binding: GameGalleryListBinding, handler: Handler) : ExposureViewHolder(binding.root, handler)
diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescFragment.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescFragment.kt
index 63941da7c3..679fa5e95f 100644
--- a/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescFragment.kt
@@ -270,6 +270,18 @@ class DescFragment : BaseFragment(), IScrollable {
}
}
+ fun scrollToRelatedVersion() {
+ if (mViewModel.getRelatedVersionPosition() != -1) {
+ mLayoutManager?.scrollToPositionWithOffset(mViewModel.getRelatedVersionPosition(), 0)
+ }
+ }
+
+ fun scrollToLibao() {
+ if (mViewModel.getDetailLibaoPosition() != -1) {
+ mLayoutManager?.scrollToPositionWithOffset(mViewModel.getDetailLibaoPosition(), 0)
+ }
+ }
+
override fun onNightModeChange() {
super.onNightModeChange()
mBinding.recyclerview.setBackgroundColor(R.color.background.toColor(requireContext()))
diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescViewModel.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescViewModel.kt
index 4381d820e7..b2eb183847 100644
--- a/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescViewModel.kt
+++ b/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescViewModel.kt
@@ -31,6 +31,7 @@ import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
+import org.json.JSONObject
import retrofit2.HttpException
class DescViewModel(application: Application,
@@ -42,6 +43,8 @@ class DescViewModel(application: Application,
private var mGameInfoPosition = 0
private var mLibaoPosition = -1
private var mServerPosition = -1
+ private var mDetailLibaoPosition = -1
+ private var mRelatedVersionPosition = -1
private var mGameInfo: GameInfo? = null
var list = MutableLiveData>()
@@ -215,6 +218,16 @@ class DescViewModel(application: Application,
super.onResponse(response)
ToastUtils.showToast("感谢您的反馈信息,我们将尽快处理~")
}
+
+ override fun onFailure(e: HttpException?) {
+ super.onFailure(e)
+ e?.response()?.errorBody()?.let {
+ val content = JSONObject(it.string())
+ if (content.getInt("code") == 403208) {
+ ToastUtils.showToast("您已经提交过反馈信息,我们将尽快处理~")
+ }
+ }
+ }
})
}
@@ -349,6 +362,15 @@ class DescViewModel(application: Application,
}
}
+ for ((index, entity) in detailEntityList.withIndex()) {
+ if (entity.libao != null) {
+ mDetailLibaoPosition = index
+ }
+ if (entity.relatedVersion != null) {
+ mRelatedVersionPosition = index
+ }
+ }
+
if (containsFirstTimeExpandCustomColumnTags) {
SPUtils.setBoolean(Constants.SP_HAS_EXPANDED_GAME_DETAIL_TAGS, true)
}
@@ -364,6 +386,10 @@ class DescViewModel(application: Application,
fun getGameInfoPosition() = mGameInfoPosition
+ fun getDetailLibaoPosition() = mDetailLibaoPosition
+
+ fun getRelatedVersionPosition() = mRelatedVersionPosition
+
fun getGameInfo() = mGameInfo
/**
diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/dialog/GameDetailMoreDialog.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/dialog/GameDetailMoreDialog.kt
index b306030f1d..b8a220f590 100644
--- a/app/src/main/java/com/gh/gamecenter/gamedetail/dialog/GameDetailMoreDialog.kt
+++ b/app/src/main/java/com/gh/gamecenter/gamedetail/dialog/GameDetailMoreDialog.kt
@@ -14,28 +14,37 @@ import com.gh.gamecenter.R
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.common.base.fragment.BaseDraggableDialogFragment
import com.gh.gamecenter.common.constant.Constants
-import com.gh.gamecenter.common.utils.ShareUtils
-import com.gh.gamecenter.common.utils.toColor
-import com.gh.gamecenter.common.utils.toDrawable
+import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.MtaHelper
import com.gh.gamecenter.databinding.DialogGameDetailMoreBinding
import com.gh.gamecenter.entity.GameEntity
+import com.gh.gamecenter.gamedetail.GameDetailViewModel
class GameDetailMoreDialog : BaseDraggableDialogFragment() {
private lateinit var binding: DialogGameDetailMoreBinding
- private var mGameEntity: GameEntity? = null
private var mShortId = ""
+ private var mGameEntity: GameEntity? = null
+ private var mShowConcernIcon = false
+ private var mIsConcerned = false
+ private val mViewModel: GameDetailViewModel by lazy { viewModelProviderFromParent() }
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
requireArguments().run {
mGameEntity = getParcelable(KEY_GAME)
mShortId = getString(KEY_SHORT_ID) ?: ""
+ mShowConcernIcon = getBoolean(KEY_SHOW_CONCERN_ICON)
+ mIsConcerned = getBoolean(KEY_IS_CONCERNED)
}
}
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
binding = DialogGameDetailMoreBinding.inflate(inflater, container, false)
return binding.root
}
@@ -46,6 +55,13 @@ class GameDetailMoreDialog : BaseDraggableDialogFragment() {
binding.gameIconView.displayGameIcon(it)
binding.gameNameTv.text = it.name
}
+
+ updateConcernView()
+ mViewModel.concernLiveData.observeNonNull(this) { response ->
+ mIsConcerned = response.isConcern
+ updateConcernView()
+ }
+
binding.shareWechatTv.setOnClickListener {
getShareUtils().wechatShare()
MtaHelper.onEvent("内容分享", "微信好友", mGameEntity?.name)
@@ -122,6 +138,41 @@ class GameDetailMoreDialog : BaseDraggableDialogFragment() {
return requireContext().getString(R.string.share_game_url, mShortId)
}
+ private fun updateConcernView() {
+ if (mShowConcernIcon) {
+ binding.concernTv.visibility = View.VISIBLE
+ if (mIsConcerned) {
+ binding.concernTv.text = "取消关注"
+ binding.concernTv.setCompoundDrawablesWithIntrinsicBounds(
+ null,
+ R.drawable.ic_gamedetail_menu_followed.toDrawable(),
+ null,
+ null
+ )
+ binding.concernTv.setOnClickListener {
+ ifLogin("游戏详情-[关注]") {
+ DialogHelper.showCancelDialog(requireContext(), {
+ mViewModel.concernCommand(false)
+ })
+ }
+ }
+ } else {
+ binding.concernTv.text = "关注游戏"
+ binding.concernTv.setCompoundDrawablesWithIntrinsicBounds(
+ null,
+ R.drawable.ic_gamedetail_menu_follow.toDrawable(),
+ null,
+ null
+ )
+ binding.concernTv.setOnClickListener {
+ ifLogin("游戏详情-[关注]") {
+ mViewModel.concernCommand(true)
+ }
+ }
+ }
+ }
+ }
+
override fun getRootView(): View = binding.root
override fun getDragCloseView(): View = binding.dragClose
@@ -156,16 +207,26 @@ class GameDetailMoreDialog : BaseDraggableDialogFragment() {
}
companion object {
+ const val KEY_SHOW_CONCERN_ICON = "displayed_concern_icon"
+ const val KEY_IS_CONCERNED = "concerned"
private const val KEY_GAME = "game"
private const val KEY_SHORT_ID = "short_id"
@JvmStatic
- fun showMoreDialog(activity: AppCompatActivity, gameEntity: GameEntity?, shortId: String) {
+ fun showMoreDialog(
+ activity: AppCompatActivity,
+ gameEntity: GameEntity?,
+ shortId: String,
+ showConcernIcon: Boolean = false,
+ isConcerned: Boolean = false,
+ ) {
if (gameEntity == null) return
GameDetailMoreDialog().apply {
arguments = Bundle().apply {
putParcelable(KEY_GAME, gameEntity)
putString(KEY_SHORT_ID, shortId)
+ putBoolean(KEY_SHOW_CONCERN_ICON, showConcernIcon)
+ putBoolean(KEY_IS_CONCERNED, isConcerned)
}
}.show(activity.supportFragmentManager, GameDetailMoreDialog::class.java.name)
}
diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/entity/ContentCardEntity.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/entity/ContentCardEntity.kt
new file mode 100644
index 0000000000..a2c0be817c
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamedetail/entity/ContentCardEntity.kt
@@ -0,0 +1,71 @@
+package com.gh.gamecenter.gamedetail.entity
+
+import androidx.annotation.Keep
+import com.gh.gamecenter.entity.*
+import com.google.gson.annotations.SerializedName
+
+@Keep
+data class ContentCardEntity(
+ @SerializedName("_id")
+ var id: String = "",
+ var name: String? = "", // tag
+ var title: String? = "",
+ var image: String? = "",
+ @SerializedName("target", alternate = ["link", "link_id"])
+ var link: String? = "",
+ @SerializedName("type", alternate = ["link_type"])
+ var type: String? = "",
+ var icon: String = "",
+ @SerializedName("game_icon")
+ var gameIcon: String? = "",
+ @SerializedName("game_icon_subscript")
+ var gameIconSubscript: String? = "",
+ var text: String? = "",
+ @SerializedName("link_text")
+ var linkText: String? = "",//游戏详情弹窗,兼容旧版本用
+ var value: String? = "",
+ @SerializedName("community_id")
+ var communityId: String? = "",
+ @SerializedName("link_community", alternate = ["community"])
+ var community: CommunityEntity? = CommunityEntity(),
+ var display: Display? = null, // 板块
+ @SerializedName("close_button")
+ var closeButton: String = "open",//用户判断h5游戏关闭按钮是否显示,hide(隐藏)、open(开启)
+ @SerializedName("button_link")
+ var buttonLink: Boolean = false,
+ @SerializedName("activity_id")
+ var activityId: String = "",
+ var style: String = "",
+
+ var des: String = "",
+ var server: GameDetailServer? = null,
+ var libao: LibaoEntity? = null,
+ @SerializedName("zone_tab")
+ var zoneTab: Boolean = false,
+ @SerializedName("related_version")
+ var relatedVersion: Boolean = false,
+ var toolkit: ArrayList = ArrayList()
+) {
+ fun toLinkEntity(): LinkEntity {
+ return LinkEntity(
+ name = name,
+ title = title,
+ image = image,
+ link = link,
+ type = type,
+ icon = icon,
+ gameIcon = gameIcon,
+ gameIconSubscript = gameIconSubscript,
+ text = text,
+ linkText = linkText,
+ value = value,
+ communityId = communityId,
+ community = community,
+ display = display,
+ closeButton = closeButton,
+ buttonLink = buttonLink,
+ activityId = activityId,
+ style = style
+ )
+ }
+}
diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/entity/NewGameDetailEntity.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/entity/NewGameDetailEntity.kt
index 1bdd9cb435..8cdd272a4f 100644
--- a/app/src/main/java/com/gh/gamecenter/gamedetail/entity/NewGameDetailEntity.kt
+++ b/app/src/main/java/com/gh/gamecenter/gamedetail/entity/NewGameDetailEntity.kt
@@ -45,7 +45,12 @@ data class NewGameDetailEntity(
@SerializedName("bbs_tab")
var bbsTab: LinkEntity? = null,
@SerializedName("certification_tag")
- var certificateTag: Screenshot? = null
+ var certificateTag: Screenshot? = null,
+ @SerializedName("content_card")
+ var contentCard: ArrayList = ArrayList(),
+
+ @SerializedName("smooth_relation_game")
+ var smoothRelatedGame: SimpleGame? = null,
)
@Keep
diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingReplyActivity.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingReplyActivity.kt
index d895cb4cfa..fd783ab392 100644
--- a/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingReplyActivity.kt
+++ b/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingReplyActivity.kt
@@ -12,12 +12,13 @@ import androidx.core.widget.doOnTextChanged
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.exposure.ExposureManager
-import com.gh.common.util.*
import com.gh.common.util.NewLogUtils
+import com.gh.common.util.SyncDataBetweenPageHelper
import com.gh.download.DownloadManager
import com.gh.gamecenter.R
import com.gh.gamecenter.baselist.ListActivity
import com.gh.gamecenter.common.base.fragment.WaitingDialogFragment
+import com.gh.gamecenter.common.callback.ConfirmListener
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.view.VerticalItemDecoration
@@ -65,6 +66,10 @@ class RatingReplyActivity : ListActivity Unit) {
+ fun replyComment(replyId: String?, content: String, successCallback: () -> Unit, realNameConfirmListener: ConfirmListener) {
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("提交中...", true))
val json = json {
@@ -224,7 +225,7 @@ class RatingReplyViewModel(
false
)
)
- ErrorHelper.handleError(getApplication(), e?.response()?.errorBody()?.string())
+ ErrorHelper.handleError(getApplication(), e?.response()?.errorBody()?.string(), false, realNameConfirmListener)
}
})
}
diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/rating/edit/RatingEditActivity.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/rating/edit/RatingEditActivity.kt
index 2ec81b16a8..1a2676c9cb 100644
--- a/app/src/main/java/com/gh/gamecenter/gamedetail/rating/edit/RatingEditActivity.kt
+++ b/app/src/main/java/com/gh/gamecenter/gamedetail/rating/edit/RatingEditActivity.kt
@@ -348,7 +348,11 @@ class RatingEditActivity : ToolBarActivity(), KeyboardHeightObserver {
}, TrackableEntity(event = "游戏评论跳转", key = "意见反馈弹窗")
)
}
- else -> ErrorHelper.handleError(this@RatingEditActivity, errorString)
+ else -> ErrorHelper.handleError(this@RatingEditActivity, errorString, false, object : ConfirmListener {
+ override fun onConfirm() {
+ postGameComment(again = false)
+ }
+ })
}
}
})
diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/video/TopVideoView.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/video/TopVideoView.kt
index 307101cd83..757dd31b6c 100644
--- a/app/src/main/java/com/gh/gamecenter/gamedetail/video/TopVideoView.kt
+++ b/app/src/main/java/com/gh/gamecenter/gamedetail/video/TopVideoView.kt
@@ -11,20 +11,20 @@ import android.widget.SeekBar
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
-import com.gh.gamecenter.common.observer.MuteCallback
-import com.gh.gamecenter.common.observer.VolumeObserver
-import com.gh.gamecenter.core.runOnIoThread
-import com.gh.gamecenter.core.runOnUiThread
-import com.gh.common.util.*
+import com.gh.common.util.LogUtils
import com.gh.download.cache.ExoCacheManager
import com.gh.gamecenter.R
-import com.gh.gamecenter.core.utils.StringUtils
-import com.gh.gamecenter.common.utils.debounceActionWithInterval
-import com.gh.gamecenter.common.utils.rxTimer
+import com.gh.gamecenter.common.observer.MuteCallback
+import com.gh.gamecenter.common.observer.VolumeObserver
import com.gh.gamecenter.common.utils.ImageUtils
import com.gh.gamecenter.common.utils.NetworkUtils
+import com.gh.gamecenter.common.utils.debounceActionWithInterval
+import com.gh.gamecenter.common.utils.rxTimer
+import com.gh.gamecenter.core.runOnIoThread
+import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.core.utils.MD5Utils
import com.gh.gamecenter.core.utils.MtaHelper
+import com.gh.gamecenter.core.utils.StringUtils
import com.gh.gamecenter.entity.GameDetailEntity
import com.gh.gamecenter.gamedetail.GameDetailViewModel
import com.gh.gamecenter.home.video.ScrollCalculatorHelper
@@ -41,7 +41,7 @@ import java.util.*
class TopVideoView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : StandardGSYVideoPlayer(context, attrs) {
private var mMuteCallback: MuteCallback
- private var mVolumeObserver: VolumeObserver
+ private var mVolumeObserver: VolumeObserver? = null
var gameName = ""
var video: GameDetailEntity.Video? = null
@@ -84,7 +84,9 @@ class TopVideoView @JvmOverloads constructor(context: Context, attrs: AttributeS
}
}
- mVolumeObserver = VolumeObserver(mMuteCallback)
+ if (!isInEditMode) {
+ mVolumeObserver = VolumeObserver(mMuteCallback)
+ }
setBackFromFullScreenListener {
if (it.id == R.id.fullscreen) {
@@ -115,14 +117,14 @@ class TopVideoView @JvmOverloads constructor(context: Context, attrs: AttributeS
fun observeVolume(fragment: Fragment?) {
fragment?.context?.applicationContext?.contentResolver?.registerContentObserver(
- android.provider.Settings.System.CONTENT_URI, true, mVolumeObserver
+ android.provider.Settings.System.CONTENT_URI, true, mVolumeObserver!!
)
fragment?.fragmentManager?.registerFragmentLifecycleCallbacks(
object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentPaused(fm: FragmentManager, f: Fragment) {
if (f === fragment) {
- fragment.context?.applicationContext?.contentResolver?.unregisterContentObserver(mVolumeObserver)
+ fragment.context?.applicationContext?.contentResolver?.unregisterContentObserver(mVolumeObserver!!)
fragment.fragmentManager?.unregisterFragmentLifecycleCallbacks(this)
}
}
diff --git a/app/src/main/java/com/gh/gamecenter/home/HomeFragment.kt b/app/src/main/java/com/gh/gamecenter/home/HomeFragment.kt
index f9e8ce0ec0..22d2b22161 100644
--- a/app/src/main/java/com/gh/gamecenter/home/HomeFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/home/HomeFragment.kt
@@ -16,10 +16,7 @@ import com.gh.gamecenter.baselist.LoadStatus
import com.gh.gamecenter.common.base.fragment.LazyFragment
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
-import com.gh.gamecenter.common.utils.goneIf
-import com.gh.gamecenter.common.utils.observeNonNull
-import com.gh.gamecenter.common.utils.safelyGetInRelease
-import com.gh.gamecenter.common.utils.viewModelProvider
+import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.view.OffsetLinearLayoutManager
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.MD5Utils
@@ -31,6 +28,7 @@ import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.eventbus.EBReuse
import com.gh.gamecenter.eventbus.EBUISwitch
import com.gh.gamecenter.fragment.HomeSearchToolWrapperFragment
+import com.gh.gamecenter.fragment.HomeSearchToolWrapperViewModel
import com.gh.gamecenter.fragment.MainWrapperFragment
import com.gh.gamecenter.game.gallery.GameGallerySlideViewHolder
import com.gh.gamecenter.home.slide.HomeSlideListAdapter
@@ -43,6 +41,7 @@ import org.greenrobot.eventbus.ThreadMode
class HomeFragment : LazyFragment() {
private lateinit var mViewModel: HomeViewModel
+ private lateinit var mHomeSearchViewModel: HomeSearchToolWrapperViewModel
private lateinit var mBinding: FragmentMainHomeBinding
private lateinit var mLayoutManager: LinearLayoutManager
private lateinit var mListAdapter: HomeFragmentAdapter
@@ -59,14 +58,18 @@ class HomeFragment : LazyFragment() {
showUnzipFailureDialog(downloadEntity)
}
}
+
+ override fun onDataInit(downloadEntity: DownloadEntity) {
+ mListAdapter.notifyItemByDownload(downloadEntity)
+ }
}
override fun getRealLayoutId() = R.layout.fragment_main_home
override fun onFragmentFirstVisible() {
mViewModel = viewModelProvider()
+ mHomeSearchViewModel = viewModelProviderFromParent()
mViewModel.homeOnlyWithoutOtherTab = arguments?.getInt(EntranceConsts.KEY_TAB_COUNT) == 1
-
super.onFragmentFirstVisible()
mViewModel.itemDataList.observeNonNull(this, callback = {
@@ -82,10 +85,8 @@ class HomeFragment : LazyFragment() {
reuseLoading.root.goneIf(loadStatus != LoadStatus.INIT_LOADING)
}
mListAdapter.setLoadStatus(it)
- mBinding.reuseNoConnection.root.visibility = if (it == LoadStatus.INIT_FAILED) View.VISIBLE else View.GONE
- mBinding.reuseLoading.root.visibility = if (it == LoadStatus.INIT_LOADING) View.VISIBLE else View.GONE
if (it == LoadStatus.INIT_LOADED) {
- AppExecutor.uiExecutor.executeWithDelay(Runnable {
+ AppExecutor.uiExecutor.executeWithDelay({
scroll()
mScrollCalculatorHelper.onScrollStateChanged(
mBinding.gameList,
@@ -94,6 +95,9 @@ class HomeFragment : LazyFragment() {
}, 100)
}
})
+ mHomeSearchViewModel.homeDataLiveData.observe(this){
+ mViewModel.initData(it)
+ }
mScrollCalculatorHelper = ScrollCalculatorHelper(R.id.autoVideoView, 0)
}
@@ -108,13 +112,8 @@ class HomeFragment : LazyFragment() {
R.color.theme
)
)
- val loadStatus = LoadStatus.LIST_LOADED
mBinding.run {
BindingAdapters.isRefreshing(gameRefresh, LoadStatus.LIST_LOADED)
- gameRefresh.goneIf(loadStatus == LoadStatus.INIT_FAILED)
- gameList.goneIf(loadStatus == LoadStatus.INIT_LOADING)
- reuseNoConnection.root.goneIf(loadStatus != LoadStatus.INIT_FAILED)
- reuseLoading.root.goneIf(loadStatus != LoadStatus.INIT_LOADING)
}
mAutomaticLayoutManager = OffsetLinearLayoutManager(requireContext())
mLayoutManager = mAutomaticLayoutManager
@@ -157,12 +156,12 @@ class HomeFragment : LazyFragment() {
mBinding.gameRefresh.setOnRefreshListener {
MtaHelper.onEvent("首页_新", "刷新")
mViewModel.loadStatus.postValue(LoadStatus.LIST_LOADING)
- mViewModel.initData()
+ mHomeSearchViewModel.getHomeContentUnion(true)
}
mBinding.reuseNoConnection.root.setOnClickListener {
mViewModel.loadStatus.postValue(LoadStatus.INIT_LOADING)
- mViewModel.initData()
+ mHomeSearchViewModel.getHomeContentUnion(true)
}
}
@@ -188,7 +187,6 @@ class HomeFragment : LazyFragment() {
override fun onFragmentResume() {
super.onFragmentResume()
resumeVideo()
- if (isEverPause) mListAdapter.notifyDataSetChanged()
super.onResume()
DownloadManager.getInstance().addObserver(dataWatcher)
@@ -284,6 +282,7 @@ class HomeFragment : LazyFragment() {
for (gameAndPosition in data) {
mListAdapter.notifyChildItem(gameAndPosition.position, busFour.packageName)
}
+ mViewModel.refreshRecentVGameIfNeeded()
}
@Subscribe(threadMode = ThreadMode.MAIN)
@@ -291,6 +290,7 @@ class HomeFragment : LazyFragment() {
if (::mListAdapter.isInitialized && "Refresh" == reuse.type) {
mListAdapter.notifyDataSetChanged()
}
+ mViewModel.refreshRecentVGameIfNeeded()
}
@Subscribe(threadMode = ThreadMode.MAIN)
diff --git a/app/src/main/java/com/gh/gamecenter/home/HomeFragmentAdapter.kt b/app/src/main/java/com/gh/gamecenter/home/HomeFragmentAdapter.kt
index e56f00bd62..b0a546a3d0 100644
--- a/app/src/main/java/com/gh/gamecenter/home/HomeFragmentAdapter.kt
+++ b/app/src/main/java/com/gh/gamecenter/home/HomeFragmentAdapter.kt
@@ -6,12 +6,10 @@ import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
-import com.gh.gamecenter.common.constant.ItemViewType
import com.gh.common.exposure.ExposureEvent
import com.gh.common.exposure.ExposureSource
import com.gh.common.exposure.IExposable
-import com.gh.gamecenter.core.runOnIoThread
-import com.gh.common.util.*
+import com.gh.common.util.DirectUtils
import com.gh.common.util.NewLogUtils
import com.gh.gamecenter.AboutActivity
import com.gh.gamecenter.GameDetailActivity
@@ -20,12 +18,16 @@ import com.gh.gamecenter.adapter.viewholder.FooterViewHolder
import com.gh.gamecenter.adapter.viewholder.ReuseViewHolder
import com.gh.gamecenter.baselist.DiffUtilAdapter
import com.gh.gamecenter.baselist.LoadStatus
+import com.gh.gamecenter.common.constant.ItemViewType
import com.gh.gamecenter.common.utils.*
+import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.utils.MtaHelper
-import com.gh.gamecenter.databinding.*
+import com.gh.gamecenter.databinding.HomeDividerItemBinding
import com.gh.gamecenter.entity.AmwayCommentEntity
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.game.GameAndPosition
+import com.gh.gamecenter.game.horizontal.GameHorizontalAdapter
+import com.gh.gamecenter.game.horizontal.GameHorizontalSlideAdapter
import com.gh.gamecenter.game.rank.RankCollectionAdapter
import com.gh.gamecenter.game.vertical.GameVerticalAdapter
import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity
@@ -34,6 +36,9 @@ import com.gh.gamecenter.home.gamecollection.HomeGameCollectionViewHolder
import com.gh.gamecenter.home.slide.HomeSlideListAdapter
import com.gh.gamecenter.home.slide.HomeSlideListViewHolder
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
+import com.gh.vspace.HomeRecentVGameAdapter
+import com.gh.vspace.HomeRecentVGameViewHolder
+import com.gh.vspace.VHelper
import com.halo.assistant.fragment.game.GamePluginAdapter
import com.lightgame.download.DownloadEntity
import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder
@@ -64,6 +69,7 @@ class HomeFragmentAdapter(
if (oldItem?.pluginList != null && newItem?.pluginList != null) return true
if (oldItem?.verticalSlide != null && newItem?.verticalSlide != null) return true
if (oldItem?.horizontalColumn != null && newItem?.horizontalColumn != null) return true
+ if (oldItem?.recentVGame != null && newItem?.recentVGame != null) return true
if (oldItem?.columnHead != null && newItem?.columnHead != null) return true
if (oldItem?.horizontalSlide != null && newItem?.horizontalSlide != null) return true
return super.areItemsTheSame(oldItem, newItem)
@@ -76,6 +82,7 @@ class HomeFragmentAdapter(
if (oldItem?.game?.id != newItem?.game?.id) return false
if (oldItem?.verticalSlide != null && newItem?.verticalSlide != null) return false
if (oldItem?.horizontalColumn != null && newItem?.horizontalColumn != null) return false
+ if (oldItem?.recentVGame != null && newItem?.recentVGame != null) return false
if (oldItem?.columnHead != null && newItem?.columnHead != null) return false
if (oldItem?.horizontalSlide != null && newItem?.horizontalSlide != null) return false
return super.areContentsTheSame(oldItem, newItem)
@@ -100,6 +107,7 @@ class HomeFragmentAdapter(
if (itemData.attachGame != null) return GAME_ITEM
if (itemData.amway != null) return AMWAY_ITEM
if (itemData.gameCollection != null) return GAME_COLLECTION_ITEM
+ if (itemData.recentVGame != null) return RECENT_V_GAME
if (itemData.lineDivider != null) return DIVIDER_ITEM
if (itemData.unknownData != null) return UNKNOWN_ITEM
@@ -109,30 +117,13 @@ class HomeFragmentAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val view: View
return when (viewType) {
- SLIDE_ITEM -> {
- view = mLayoutInflater.inflate(R.layout.home_slide_list, parent, false)
- HomeSlideListViewHolder(HomeSlideListBinding.bind(view), callback)
- }
- RECOMMENDS_ITEM -> {
- view = mLayoutInflater.inflate(R.layout.home_recommend_item, parent, false)
- HomeRecommendItemViewHolder(HomeRecommendItemBinding.bind(view))
- }
- GAME_ITEM -> {
- view = mLayoutInflater.inflate(R.layout.home_game_item, parent, false)
- HomeGameItemViewHolder(HomeGameItemBinding.bind(view))
- }
- AMWAY_ITEM -> {
- view = mLayoutInflater.inflate(R.layout.home_amway_list, parent, false)
- HomeAmwayListViewHolder(HomeAmwayListBinding.bind(view))
- }
- GAME_COLLECTION_ITEM -> {
- view = mLayoutInflater.inflate(R.layout.home_game_collection_item, parent, false)
- HomeGameCollectionViewHolder(HomeGameCollectionItemBinding.bind(view))
- }
- DIVIDER_ITEM -> {
- view = mLayoutInflater.inflate(R.layout.home_divider_item, parent, false)
- HomeDividerViewHolder(HomeDividerItemBinding.bind(view))
- }
+ SLIDE_ITEM -> HomeSlideListViewHolder(parent.toBinding(), callback)
+ RECOMMENDS_ITEM -> HomeRecommendItemViewHolder(parent.toBinding())
+ GAME_ITEM -> HomeGameItemViewHolder(parent.toBinding())
+ AMWAY_ITEM -> HomeAmwayListViewHolder(parent.toBinding())
+ GAME_COLLECTION_ITEM -> HomeGameCollectionViewHolder(parent.toBinding())
+ DIVIDER_ITEM -> HomeDividerViewHolder(parent.toBinding())
+ RECENT_V_GAME -> HomeRecentVGameViewHolder(parent.toBinding())
FOOTER_ITEM -> {
view = mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false)
FooterViewHolder(view)
@@ -169,6 +160,7 @@ class HomeFragmentAdapter(
is ReuseViewHolder -> bindUnknown(holder)
is HomeDividerViewHolder -> holder.bindView(mDataList[position].lineDivider ?: 1F)
is HomeGameCollectionViewHolder -> bindGameCollection(holder, position)
+ is HomeRecentVGameViewHolder -> bindRecentVGame(holder, position)
else -> mLegacyHomeFragmentAdapterAssistant.bindLegacyViewHolder(
holder,
@@ -259,8 +251,7 @@ class HomeFragmentAdapter(
},
basicSource = mBasicExposureSource,
source = gameCollectionSource
- )
- )
+ ))
}
gameCollectionItemData.exposureEventList = gameExposureList
exposureList.addAll(gameExposureList)
@@ -270,12 +261,33 @@ class HomeFragmentAdapter(
holder.bindGameCollectionList(gameCollectionItemDataList, "首页内容列表")
}
+ private fun bindRecentVGame(holder: HomeRecentVGameViewHolder, position: Int) {
+ val homeItemData = mDataList[position]
+
+ val exposureEventList = arrayListOf()
+ runOnIoThread(true) {
+ homeItemData.recentVGame?.forEach {
+ val event = ExposureEvent.createEventWithSourceConcat(
+ gameEntity = VHelper.toGameEntity(it.downloadEntity),
+ basicSource = mBasicExposureSource,
+ source = listOf(ExposureSource("最近在玩", ""))
+ )
+ exposureEventList.add(event)
+ }
+ }
+ homeItemData.exposureEventList = exposureEventList
+
+ if (!homeItemData.recentVGame.isNullOrEmpty()) {
+ holder.bindView(homeItemData.recentVGame!!)
+ }
+ }
+
private fun bindAttachGame(holder: HomeGameItemViewHolder, position: Int) {
val homeItemData = mDataList[position]
val game = homeItemData.attachGame?.linkGame!!
val displayContent = homeItemData.attachGame?.displayContent ?: ""
game.displayContent = displayContent
- holder.bindGame(game)
+ holder.bindGame(homeItemData, this, position)
runOnIoThread(true) {
homeItemData.exposureEvent = ExposureEvent.createEventWithSourceConcat(
@@ -391,10 +403,13 @@ class HomeFragmentAdapter(
val entryMap = gameAndPosition.entity.getEntryMap()
entryMap[download.platform] = download
}
- if (getItemViewType(gameAndPosition.position) == ItemViewType.VERTICAL_SLIDE_ITEM ||
- getItemViewType(gameAndPosition.position) == ItemViewType.GAME_PLUGIN ||
- getItemViewType(gameAndPosition.position) == SLIDE_ITEM ||
- getItemViewType(gameAndPosition.position) == ItemViewType.RANK_COLLECTION
+ if (getItemViewType(gameAndPosition.position) == ItemViewType.VERTICAL_SLIDE_ITEM
+ || getItemViewType(gameAndPosition.position) == ItemViewType.GAME_PLUGIN
+ || getItemViewType(gameAndPosition.position) == SLIDE_ITEM
+ || getItemViewType(gameAndPosition.position) == ItemViewType.RANK_COLLECTION
+ || getItemViewType(gameAndPosition.position) == RECENT_V_GAME
+ || getItemViewType(gameAndPosition.position) == ItemViewType.GAME_SUBJECT
+ || getItemViewType(gameAndPosition.position) == ItemViewType.GAME_SUBJECT_SLIDE
) {
val view = layoutManager.findViewByPosition(gameAndPosition.position)
val recyclerView = view?.findViewById(R.id.recycler_view)
@@ -403,6 +418,9 @@ class HomeFragmentAdapter(
is GamePluginAdapter -> adapter.notifyItemByDownload(download)
is HomeSlideListAdapter -> adapter.notifyItemByDownload(download)
is RankCollectionAdapter -> adapter.notifyItemByDownload(download)
+ is GameHorizontalAdapter -> adapter.notifyItemByDownload(download)
+ is GameHorizontalSlideAdapter -> adapter.notifyItemByDownload(download)
+ is HomeRecentVGameAdapter -> adapter.notifyItemByDownload(download)
}
} else {
notifyItemChanged(gameAndPosition.position)
@@ -421,16 +439,20 @@ class HomeFragmentAdapter(
}
fun notifyChildItem(position: Int, packageName: String) {
- if (getItemViewType(position) == ItemViewType.VERTICAL_SLIDE_ITEM ||
- getItemViewType(position) == ItemViewType.GAME_PLUGIN ||
- getItemViewType(position) == SLIDE_ITEM ||
- getItemViewType(position) == ItemViewType.RANK_COLLECTION
+ if (getItemViewType(position) == ItemViewType.VERTICAL_SLIDE_ITEM
+ || getItemViewType(position) == ItemViewType.GAME_PLUGIN
+ || getItemViewType(position) == SLIDE_ITEM
+ || getItemViewType(position) == ItemViewType.RANK_COLLECTION
+ || getItemViewType(position) == ItemViewType.GAME_SUBJECT
+ || getItemViewType(position) == ItemViewType.GAME_SUBJECT_SLIDE
) {
val view = layoutManager.findViewByPosition(position)
val recyclerView = view?.findViewById(R.id.recycler_view)
- when (recyclerView?.adapter) {
- is RankCollectionAdapter -> (recyclerView.adapter as RankCollectionAdapter).notifyChildItem()
- is GameVerticalAdapter -> (recyclerView.adapter as GameVerticalAdapter).notifyChildItem(packageName)
+ when (val adapter = recyclerView?.adapter) {
+ is RankCollectionAdapter -> adapter.notifyChildItem()
+ is GameVerticalAdapter -> adapter.notifyChildItem(packageName)
+ is GameHorizontalAdapter -> adapter.notifyChildItem(packageName)
+ is GameHorizontalSlideAdapter -> adapter.notifyChildItem(packageName)
else -> recyclerView?.adapter?.notifyDataSetChanged()
}
} else {
@@ -440,7 +462,7 @@ class HomeFragmentAdapter(
fun getGameEntityByPackage(packageName: String): List {
val positionList = ArrayList()
- val positionMap = viewModel.positionAndPackageMap
+ val positionMap = viewModel.positionAndPackageMap.value ?: return positionList
for (key in positionMap.keys) {
if (key.contains(packageName)) {
val position = positionMap[key]!!
@@ -465,7 +487,9 @@ class HomeFragmentAdapter(
}
val attachGame = itemData.attachGame?.linkGame
- if (attachGame != null) {
+ val recentVGame = itemData.recentVGame
+
+ if (attachGame != null || recentVGame != null) {
positionList.add(GameAndPosition(attachGame, position))
continue
}
@@ -510,5 +534,6 @@ class HomeFragmentAdapter(
const val UNKNOWN_ITEM: Int = 111
const val COMMON_ITEM: Int = 115
const val GAME_COLLECTION_ITEM: Int = 116
+ const val RECENT_V_GAME: Int = 117
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/home/HomeGameItemViewHolder.kt b/app/src/main/java/com/gh/gamecenter/home/HomeGameItemViewHolder.kt
index e902dc5892..a163d4af31 100644
--- a/app/src/main/java/com/gh/gamecenter/home/HomeGameItemViewHolder.kt
+++ b/app/src/main/java/com/gh/gamecenter/home/HomeGameItemViewHolder.kt
@@ -4,23 +4,29 @@ import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.GradientDrawable
import android.view.View
+import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
-import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
-import com.gh.gamecenter.core.utils.RandomUtils
+import androidx.recyclerview.widget.RecyclerView
+import com.gh.common.util.DownloadItemUtils
import com.gh.gamecenter.R
+import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.common.utils.*
+import com.gh.gamecenter.core.utils.RandomUtils
import com.gh.gamecenter.databinding.HomeGameItemBinding
-import com.gh.gamecenter.entity.GameEntity
class HomeGameItemViewHolder(val binding: HomeGameItemBinding) : BaseRecyclerViewHolder(binding.root) {
- fun bindGame(game: GameEntity) {
+ fun bindGame(homeItemData: HomeItemData, adapter: RecyclerView.Adapter, position: Int) {
+ val game = homeItemData.attachGame?.linkGame!!
binding.gameIcon.displayGameIcon(game)
binding.gameName.text = game.name
binding.gameName.setTextColor(R.color.text_title.toColor(binding.root.context))
binding.gameBrief.setTextColor(R.color.text_title.toColor(binding.root.context))
- binding.gameRating.goneIf(!(game.showComment && game.commentCount >= 3 && game.star >= 7))
binding.gameRating.text = game.star.toString()
+ binding.gameRating2.text = game.star.toString()
+ val drawable = R.drawable.home_game_rating.toDrawable(binding.root.context)
+ drawable?.setBounds(0, 0, 12F.dip2px(), 12F.dip2px())
+ binding.gameRating.setCompoundDrawables(drawable, null, null, null)
ImageUtils.display(binding.gameImage, game.homeSetting.image)
binding.gameTags.postDelayed({
binding.gameTags.visibility = if (game.tagStyle.isNotEmpty()) {
@@ -47,8 +53,8 @@ class HomeGameItemViewHolder(val binding: HomeGameItemBinding) : BaseRecyclerVie
}
}
}
- binding.gameTags.post {
- binding.gameSubtitleTv.maxWidth = binding.gameTags.width + 24F.dip2px()
+ binding.ratingAndTagContainer.post {
+ binding.gameSubtitleTv.maxWidth = binding.ratingAndTagContainer.width + 32F.dip2px()
}
}
if (game.advanceDownload) {
@@ -61,7 +67,12 @@ class HomeGameItemViewHolder(val binding: HomeGameItemBinding) : BaseRecyclerVie
}
ConstraintSet().apply {
clone(binding.root)
- connect(R.id.game_name, ConstraintSet.END, if (game.serverLabel != null && !game.advanceDownload) R.id.recent_played_tag else R.id.gameSubtitleTv, ConstraintSet.START)
+ connect(
+ R.id.game_name,
+ ConstraintSet.END,
+ if (game.serverLabel != null && !game.advanceDownload) R.id.recent_played_tag else R.id.gameSubtitleTv,
+ ConstraintSet.START
+ )
}.applyTo(binding.root)
val hierarchy = binding.gameImage.hierarchy
@@ -70,5 +81,33 @@ class HomeGameItemViewHolder(val binding: HomeGameItemBinding) : BaseRecyclerVie
} catch (ignore: Throwable) {
hierarchy.setPlaceholderImage(RandomUtils.getRandomPlaceholderColor())
}
+
+ DownloadItemUtils.setOnClickListener(
+ binding.root.context,
+ binding.downloadBtn,
+ game,
+ position,
+ adapter,
+ "新首页",
+ "",
+ homeItemData.exposureEvent
+ )
+ DownloadItemUtils.updateDownloadButton(binding.root.context, binding.downloadBtn, game)
+ binding.downloadBtn.goneIf(game.homeSetting.downloadBtnSwitch != "on")
+ binding.gameRating.goneIf(!(game.showComment && game.commentCount >= 3 && game.star >= 7 && game.homeSetting.downloadBtnSwitch == "on"))
+ binding.gameRating2.goneIf(!(game.showComment && game.commentCount >= 3 && game.star >= 7 && game.homeSetting.downloadBtnSwitch != "on"))
+ ConstraintSet().apply {
+ clone(binding.gameSubtitleTv.parent as ConstraintLayout)
+ clear(binding.gameSubtitleTv.id, ConstraintSet.END)
+ if (binding.downloadBtn.visibility == View.VISIBLE) {
+ connect(binding.gameSubtitleTv.id, ConstraintSet.END, binding.downloadBtn.id, ConstraintSet.START)
+ } else if (binding.gameRating2.visibility == View.VISIBLE) {
+ connect(binding.gameSubtitleTv.id, ConstraintSet.END, binding.gameRating2.id, ConstraintSet.START)
+ } else {
+ connect(binding.gameSubtitleTv.id, ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END)
+ }
+ setMargin(binding.gameSubtitleTv.id, ConstraintSet.END, 8F.dip2px())
+ applyTo(binding.gameSubtitleTv.parent as ConstraintLayout)
+ }
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/home/HomeItemData.kt b/app/src/main/java/com/gh/gamecenter/home/HomeItemData.kt
index 6c35cae520..89717b960a 100644
--- a/app/src/main/java/com/gh/gamecenter/home/HomeItemData.kt
+++ b/app/src/main/java/com/gh/gamecenter/home/HomeItemData.kt
@@ -1,12 +1,17 @@
package com.gh.gamecenter.home
-import com.gh.gamecenter.entity.*
+import com.gh.gamecenter.entity.AmwayCommentEntity
+import com.gh.gamecenter.entity.HomeContent
+import com.gh.gamecenter.entity.HomeRecommend
+import com.gh.gamecenter.entity.HomeSlide
import com.gh.gamecenter.gamecollection.square.GameCollectionListItemData
+import com.gh.vspace.VGameItemData
data class HomeItemData(var slides: List? = null,
var recommends: List? = null,
var amway: List? = null,
var gameCollection: List? = null,
var attachGame: HomeContent? = null,
+ var recentVGame: ArrayList? = null,
var lineDivider: Float? = null,
var unknownData: Any? = null) : LegacyHomeItemData()
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/home/HomeViewModel.kt b/app/src/main/java/com/gh/gamecenter/home/HomeViewModel.kt
index 531e7c418f..12c17cd528 100644
--- a/app/src/main/java/com/gh/gamecenter/home/HomeViewModel.kt
+++ b/app/src/main/java/com/gh/gamecenter/home/HomeViewModel.kt
@@ -15,8 +15,10 @@ import com.gh.common.util.HomePluggableHelper
import com.gh.download.DownloadManager
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.baselist.LoadStatus
+import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.retrofit.Response
+import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.utils.RandomUtils
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.entity.*
@@ -24,8 +26,11 @@ import com.gh.gamecenter.game.rank.RankCollectionAdapter
import com.gh.gamecenter.gamecollection.square.GameCollectionListItemData
import com.gh.gamecenter.packagehelper.PackageRepository
import com.gh.gamecenter.retrofit.RetrofitManager
+import com.gh.vspace.VGameItemData
+import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.halo.assistant.fragment.SettingsFragment
+import com.lightgame.download.DownloadEntity
import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
@@ -44,6 +49,7 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
private var mHomeContents = ArrayList()
private var mPluginList: List? = null // 插件化
private var mSmartSubject: SubjectEntity? = null // 智能推荐专题
+ private var mVGameList: ArrayList? = null // 最近的畅玩游戏
private var mContentPage = 1 // 专题分页
private var mIsLoading = false
@@ -56,32 +62,136 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
var homeOnlyWithoutOtherTab = false
var itemDataList: MediatorLiveData> = MediatorLiveData()
- var positionAndPackageMap = HashMap() // key: packageName + position, value: position
+ private var mPositionAndPackageMap = HashMap() // key: packageName + position, value: position
+ var positionAndPackageMap = MutableLiveData>()
val loadStatus = MutableLiveData()
init {
itemDataList.addSource(PackageRepository.gameUpdateLiveData) {
initPlugin(it)
+ refreshRecentVGameIfNeeded()
+ }
+ itemDataList.addSource(DownloadManager.getInstance().downloadEntityLiveData) {
+ refreshRecentVGameIfNeeded()
}
loadStatus.postValue(LoadStatus.INIT_LOADING)
- initData()
}
- fun initData() {
+ fun initData(homeDataEntity: HomeDataEntity?) {
mHomeSlides = arrayListOf()
mHomeRecommends = arrayListOf()
mHomeContents = arrayListOf()
mSubjectGameIdList = hashSetOf()
+ homeDataEntity?.let {
+ mHomeSlides.addAll(it.homeSlide)
+ mHomeRecommends.addAll(it.homeRecommend)
+ mHomeContents.addAll(it.homeContent)
+ transformationItemData()
+ mContentPage = 2
+ loadStatus.postValue(LoadStatus.INIT_LOADED)
+ }
+
// 触发列表刷新行为时亦刷新内存中的备用游戏库列表
GameSubstituteRepositoryHelper.refreshRepositoryFromLocal()
- getHomeSlides()
if (SPUtils.getBoolean(SettingsFragment.PERSONAL_RECOMMEND_SP_KEY, true)) {
getSmartColumn()
}
+
+ refreshRecentVGameIfNeeded()
+ }
+
+ fun refreshRecentVGameIfNeeded() {
+ if (VHelper.isVGameOn()
+ && SPUtils.getBoolean(Constants.SP_HOME_VGAME_AREA_ENABLED, true)
+ ) {
+ val entityList = getSortedVEntityList()
+
+ if (entityList.isNotEmpty()) {
+ mVGameList = ArrayList(entityList)
+
+ if (mHomeSlides.isNotEmpty() || mHomeRecommends.isNotEmpty()) {
+ transformationItemData()
+ }
+ } else {
+ mVGameList?.clear()
+ transformationItemData()
+ }
+ } else {
+ mVGameList?.clear()
+ transformationItemData()
+ }
+ }
+
+ /**
+ * 获取排好序的最近在玩列表
+ *
+ * 首位:固定展示最近一次点击过下载\启动的游戏
+ * 后续位置-优先级:完成下载但未启动过的游戏 > 完成下载且已启动过的游戏
+ * 完成下载但未启动过的游戏:按照点击下载的时间倒序排列
+ * 完成下载且已启动过的游戏:按照游戏的畅玩时长从左(长)向右(短)排列
+ */
+ private fun getSortedVEntityList(): List {
+ val rawDownloadEntityList = DownloadManager.getInstance().allVDownloadTaskSnapshots
+ val rawInstalledEntityList = VHelper.getAllVGameSnapshots()
+ val rawEntityList = arrayListOf()
+
+ var fixedTopEntity: VGameItemData? = null
+ val unplayedEntityList = arrayListOf()
+ val playedEntityList = arrayListOf()
+ val sortedEntityList = arrayListOf()
+
+ val distinctIdSet = hashSetOf()
+ // 将下载任务的实体放进待排序列表里
+ for (rawDownloadEntity in rawDownloadEntityList) {
+ distinctIdSet.add(rawDownloadEntity.gameId)
+ rawEntityList.add(rawDownloadEntity)
+ }
+ // 将已安装任务的实体放进待排序列表里
+ for (rawInstalledEntity in rawInstalledEntityList) {
+ if (distinctIdSet.contains(rawInstalledEntity.downloadEntity.gameId)) {
+ continue
+ }
+ rawEntityList.add(rawInstalledEntity.downloadEntity)
+ }
+ distinctIdSet.clear()
+
+ for (rawEntity in rawEntityList) {
+ val lastPlayedTime = VHelper.getLastPlayedTime(rawEntity)
+ val latestModifiedTime = maxOf(rawEntity.start, VHelper.getLastPlayedTime(rawEntity))
+
+ if (fixedTopEntity == null) {
+ fixedTopEntity = VGameItemData.from(rawEntity)
+ } else {
+ val fixedTopLatestModifiedTime = maxOf(fixedTopEntity.downloadEntity.start, VHelper.getLastPlayedTime(fixedTopEntity.downloadEntity))
+ if (latestModifiedTime > fixedTopLatestModifiedTime) {
+ fixedTopEntity = VGameItemData.from(rawEntity)
+ }
+ }
+
+ if (lastPlayedTime == 0L) {
+ unplayedEntityList.add(VGameItemData.from(rawEntity))
+ } else {
+ playedEntityList.add(VGameItemData.from(rawEntity))
+ }
+ }
+
+ fixedTopEntity?.let {
+ sortedEntityList.add(it)
+ unplayedEntityList.removeAll { entity ->
+ entity.downloadEntity.packageName == fixedTopEntity.downloadEntity.packageName
+ }
+ playedEntityList.removeAll { entity ->
+ entity.downloadEntity.packageName == fixedTopEntity.downloadEntity.packageName
+ }
+ }
+ sortedEntityList.addAll(unplayedEntityList.sortedByDescending { it.downloadEntity.start })
+ sortedEntityList.addAll(playedEntityList.sortedByDescending { VHelper.getTotalPlayedTime(it.downloadEntity.packageName) })
+
+ return sortedEntityList.take(8)
}
private fun initPlugin(updateList: List?) {
@@ -101,7 +211,7 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
}
// 下载7天排序
- list.sortWith(Comparator { o1, o2 -> o2.download - o1.download })
+ list.sortWith { o1, o2 -> o2.download - o1.download }
mPluginList = list
if (mHomeSlides.isNotEmpty() || mHomeRecommends.isNotEmpty()) {
@@ -109,40 +219,6 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
}
}
- @SuppressLint("CheckResult")
- private fun getHomeSlides() {
- mApi.getHomeSlides(HaloApp.getInstance().channel, BuildConfig.VERSION_NAME)
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(object : BiResponse>() {
- override fun onSuccess(data: List) {
- mHomeSlides.addAll(data)
- getHomeRecommends()
- }
-
- override fun onFailure(exception: Exception) {
- getHomeRecommends()
- }
- })
- }
-
- @SuppressLint("CheckResult")
- private fun getHomeRecommends() {
- mApi.getHomeRecommends(HaloApp.getInstance().channel, BuildConfig.VERSION_NAME)
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(object : BiResponse>() {
- override fun onSuccess(data: List) {
- mHomeRecommends.addAll(data)
- getHomeContent(true)
- }
-
- override fun onFailure(exception: Exception) {
- getHomeContent(true)
- }
- })
- }
-
@SuppressLint("CheckResult")
fun getHomeContent(initData: Boolean) {
if (mIsLoading && !initData || loadStatus.value == LoadStatus.LIST_OVER) return
@@ -241,7 +317,7 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
private fun initRandomGame(subjectId: String, sourceList: List?) {
var rawList: MutableList? = null
for (entity in mHomeContents) {
- if (entity.linkColumn?.id == subjectId) rawList = entity.linkColumn?.data
+ if (entity.linkColumn?.id == subjectId) rawList = entity.linkColumn.data
}
if (rawList == null) return
@@ -273,185 +349,231 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
}
fun transformationItemData() {
- mSnapshotItemList.clear()
+ runOnIoThread(true) {
+ mSnapshotItemList.clear()
- // 是否使用带特别高的带分割线的 item
- var useUltraHeightDivider = false
- var shouldShowDivider = false
+ // 是否使用带特别高的带分割线的 item
+ var useUltraHeightDivider = false
+ var shouldShowDivider = false
- val iterator = mHomeContents.iterator()
- while (iterator.hasNext()) {
- val item = iterator.next()
- // 裁剪排行榜数据数量
- if (item.linkType == "column_collection" && item.linkColumn?.style == "top") {
- item.linkColumn.columns.let { columns ->
- for (column in columns) {
- column.data = ArrayList(column.data?.take(RankCollectionAdapter.MAX_RANK_ITEM_COUNT) ?: listOf())
- }
- }
- }
- }
-
- if (mSmartSubject != null && mHomeContents.size > mSmartSubject!!.sort) {
- val element = HomeContent(
- linkType = "smart_subject",
- linkId = mSmartSubject?.id ?: "",
- linkText = mSmartSubject?.name ?: "",
- linkColumn = mSmartSubject
- )
- mHomeContents.add(mSmartSubject!!.sort, element)
- mSmartSubject = null // 防止重复插入
- }
-
- if (mHomeSlides.isNotEmpty()) {
- val slideItem = HomeItemData()
- slideItem.slides = mHomeSlides
- mSnapshotItemList.add(slideItem)
- }
-
- if (mHomeRecommends.isNotEmpty()) {
- val recommend = HomeItemData()
- recommend.recommends = mHomeRecommends
- mSnapshotItemList.add(recommend)
- }
-
- // 插件化
- if (mPluginList != null && mPluginList!!.isNotEmpty()) {
- val plugin = HomeItemData()
- plugin.pluginList = mPluginList
- mSnapshotItemList.add(plugin)
-
- for (entity in mPluginList!!) {
- addGamePositionAndPackage(entity)
- }
- }
-
- for (i in 0 until mHomeContents.size) {
- val homeContent = mHomeContents[i]
- val linkType = homeContent.linkType
- val linkStyle = homeContent.linkColumn?.style ?: ""
-
- if (i + 1 < mHomeContents.size) {
- val nextItem = mHomeContents[i + 1]
- shouldShowDivider = nextItem.linkType == "game" || nextItem.linkType == "video"
- }
-
- if (linkType == "game" || linkType == "video") {
- val attachGame = HomeItemData()
- attachGame.blockPosition = i
- attachGame.attachGame = homeContent
- attachGame.attachGame?.linkGame?.outerSequence = attachGame.blockPosition
- attachGame.attachGame?.linkGame?.sequence = attachGame.blockPosition
- mSnapshotItemList.add(attachGame)
- } else if (linkType == "top_game_comment") {
- val head = HomeItemData()
- head.columnHead = SubjectEntity(type = linkType, name = "安利墙")
- mSnapshotItemList.add(LegacyHomeSubjectTransformer.getBlankSpacingItem(HomeItemData()) as HomeItemData)
- mSnapshotItemList.add(head)
-
- val amway = HomeItemData()
- amway.blockPosition = i
- amway.amway = homeContent.linkTopGameComment?.apply {
- for ((index, amwayEntity) in this.withIndex()) {
- amwayEntity.game.sequence = index
- amwayEntity.game.outerSequence = i
- }
- }
- mSnapshotItemList.add(amway)
- } else if (linkType == "column"
- || linkType == "column_collection" && linkStyle != "top"
- || linkType == "smart_subject"
- || linkType == "column_test"
- ) {
-
- homeContent.linkColumn?.data = RegionSettingHelper.filterGame(homeContent.linkColumn?.data)
-
- homeContent.linkColumn?.let { subjectEntity ->
- subjectEntity.data?.let { data ->
- // 这个 for 循环主要功能是用来标识替换已安装的游戏
- for (game in data) {
- mSubjectGameIdList.add(game.id)
- // 应用专题是否显示游戏名后缀的配置
- game.shouldShowNameSuffix = subjectEntity.showSuffix
- }
-
- subjectEntity.relatedColumnId?.let {
- GameSubstituteRepositoryHelper.replaceGames(data, mSubjectGameIdList, it, mShouldLogReplaceEvent)
- mShouldLogReplaceEvent = false
+ val iterator = mHomeContents.iterator()
+ while (iterator.hasNext()) {
+ val item = iterator.next()
+ // 裁剪排行榜数据数量
+ if (item.linkType == "column_collection" && item.linkColumn?.style == "top") {
+ item.linkColumn.columns.let { columns ->
+ for (column in columns) {
+ column.data = ArrayList(column.data?.take(RankCollectionAdapter.MAX_RANK_ITEM_COUNT) ?: listOf())
}
}
}
- // 仅普通纵向专题需要特别高的分割线
- useUltraHeightDivider = homeContent.linkColumn?.type == "game_vertical"
+ // 双列卡片专题过滤掉无封面图游戏
+ if (item.linkType == "column" && item.linkColumn?.type == "game_double_card") {
+ item.linkColumn.data = item.linkColumn.data?.filter { it.columnImage.isNotBlank() }?.toMutableList()
+ // 游戏数量小于2个不显示专题,所以直接去掉
+ if ((item.linkColumn.data?.size ?: 0) < 2) {
+ iterator.remove()
+ }
+ }
+ }
- LegacyHomeSubjectTransformer.transform(
- mSnapshotItemList as ArrayList,
- homeContent.linkColumn,
- i,
- { HomeItemData() },
- { addGamePositionAndPackage(it) }
+ if (mSmartSubject != null && mHomeContents.size > mSmartSubject!!.sort) {
+ val element = HomeContent(
+ linkType = "smart_subject",
+ linkId = mSmartSubject?.id ?: "",
+ linkText = mSmartSubject?.name ?: "",
+ linkColumn = mSmartSubject
)
- } else if (linkType == "column_collection" && linkStyle == "top") {
- val rankItem = HomeItemData().apply {
- blockPosition = i
- rankCollection = homeContent.linkColumn
- }
- mSnapshotItemList.add(rankItem)
- appendAdditionalInfoToRankSubjectGame(homeContent.linkColumn, i)
- } else if (linkType == "common_collection") {
- val commonCollectionItem = HomeItemData()
- val subjectEntity = SubjectEntity().apply {
- type = homeContent.linkType
- id = homeContent.linkId
- name = homeContent.linkText
- style = homeContent.commonCollection?.style
- commonCollectionList = homeContent.commonCollection?.collectionList
- }
- val head = HomeItemData()
- head.columnHead = subjectEntity
- mSnapshotItemList.add(LegacyHomeSubjectTransformer.getBlankSpacingItem(HomeItemData()) as HomeItemData)
- mSnapshotItemList.add(head)
- commonCollectionItem.commonCollection = subjectEntity
- commonCollectionItem.blockPosition = i
- mSnapshotItemList.add(commonCollectionItem)
- } else if (linkType == "game_list_collection") {
- val head = HomeItemData()
- head.columnHead = SubjectEntity(type = linkType, name = homeContent.linkText)
- mSnapshotItemList.add(LegacyHomeSubjectTransformer.getBlankSpacingItem(HomeItemData()) as HomeItemData)
- mSnapshotItemList.add(head)
+ mHomeContents.add(mSmartSubject!!.sort, element)
+ mSmartSubject = null // 防止重复插入
+ }
- val gameCollection = HomeItemData()
- gameCollection.blockPosition = i
- val itemDataList = arrayListOf().apply {
- if (!homeContent.linkGameCollection.isNullOrEmpty()) {
- var position = 0
- for (item in homeContent.linkGameCollection) {
- add(GameCollectionListItemData(gameCollectionItem = item, gameStartPosition = position))
- position += if (item.count?.game!! > 2) 3 else if (item.games?.size == 0) 0 else item.count?.game ?: 0
+ if (mHomeSlides.isNotEmpty()) {
+ val slideItem = HomeItemData()
+ slideItem.slides = mHomeSlides
+ mSnapshotItemList.add(slideItem)
+ }
+
+ if (mHomeRecommends.isNotEmpty()) {
+ val recommend = HomeItemData()
+ recommend.recommends = mHomeRecommends
+ mSnapshotItemList.add(recommend)
+ }
+
+ // 最近在玩的畅玩游戏
+ if (mVGameList != null && !mVGameList.isNullOrEmpty()) {
+ val item = HomeItemData()
+ item.recentVGame = mVGameList
+ mSnapshotItemList.add(item)
+
+ for (entity in mVGameList!!) {
+ val packageName = entity.downloadEntity.packageName
+ mPositionAndPackageMap[packageName + (mSnapshotItemList.size - 1)] = mSnapshotItemList.size - 1
+ }
+ }
+
+ // 插件化
+ if (mPluginList != null && mPluginList!!.isNotEmpty()) {
+ val plugin = HomeItemData()
+ plugin.pluginList = mPluginList
+ mSnapshotItemList.add(plugin)
+
+ for (entity in mPluginList!!) {
+ addGamePositionAndPackage(entity)
+ }
+ }
+
+ for (i in 0 until mHomeContents.size) {
+ val homeContent = mHomeContents[i]
+ val linkType = homeContent.linkType
+ val linkStyle = homeContent.linkColumn?.style ?: ""
+
+ if (i + 1 < mHomeContents.size) {
+ val nextItem = mHomeContents[i + 1]
+ shouldShowDivider = nextItem.linkType == "game" || nextItem.linkType == "video"
+ }
+
+ if (linkType == "game" || linkType == "video") {
+ val attachGame = HomeItemData()
+ attachGame.blockPosition = i
+ attachGame.attachGame = homeContent
+ attachGame.attachGame?.linkGame?.outerSequence = attachGame.blockPosition
+ attachGame.attachGame?.linkGame?.sequence = attachGame.blockPosition
+ mSnapshotItemList.add(attachGame)
+ homeContent.linkGame?.let {
+ addGamePositionAndPackage(it)
+ }
+ } else if (linkType == "top_game_comment") {
+ val head = HomeItemData()
+ head.columnHead = SubjectEntity(type = linkType, name = "安利墙")
+ mSnapshotItemList.add(LegacyHomeSubjectTransformer.getBlankSpacingItem(HomeItemData()) as HomeItemData)
+ mSnapshotItemList.add(head)
+
+ val amway = HomeItemData()
+ amway.blockPosition = i
+ amway.amway = homeContent.linkTopGameComment?.apply {
+ for ((index, amwayEntity) in this.withIndex()) {
+ amwayEntity.game.sequence = index
+ amwayEntity.game.outerSequence = i
}
}
- }
- gameCollection.gameCollection = itemDataList
- mSnapshotItemList.add(gameCollection)
- } else {
- val unknown = HomeItemData()
- unknown.blockPosition = i + 1
- unknown.unknownData = ""
- mSnapshotItemList.add(unknown)
- }
+ mSnapshotItemList.add(amway)
+ } else if (linkType == "column"
+ || linkType == "column_collection" && linkStyle != "top"
+ || linkType == "smart_subject"
+ || linkType == "column_test"
+ ) {
- if (i != 0 && shouldShowDivider) {
- if (useUltraHeightDivider) {
- useUltraHeightDivider = false
- mSnapshotItemList.add(HomeItemData(lineDivider = ULTRA_HEIGHT_DIVIDER))
+ homeContent.linkColumn?.data = RegionSettingHelper.filterGame(homeContent.linkColumn?.data)
+
+ homeContent.linkColumn?.let { subjectEntity ->
+ subjectEntity.data?.let { data ->
+ // 这个 for 循环主要功能是用来标识替换已安装的游戏
+ for (game in data) {
+ mSubjectGameIdList.add(game.id)
+ // 应用专题是否显示游戏名后缀的配置
+ game.shouldShowNameSuffix = subjectEntity.showSuffix
+ }
+
+ subjectEntity.relatedColumnId?.let {
+ GameSubstituteRepositoryHelper.replaceGames(data, mSubjectGameIdList, it, mShouldLogReplaceEvent)
+ mShouldLogReplaceEvent = false
+ }
+ }
+ }
+
+ // 仅普通纵向专题需要特别高的分割线
+ useUltraHeightDivider = homeContent.linkColumn?.type == "game_vertical"
+
+ LegacyHomeSubjectTransformer.transform(
+ mSnapshotItemList as ArrayList,
+ homeContent.linkColumn,
+ i,
+ { HomeItemData() },
+ { addGamePositionAndPackage(it) }
+ )
+ } else if (linkType == "column_collection" && linkStyle == "top") {
+ val rankItem = HomeItemData().apply {
+ blockPosition = i
+ rankCollection = homeContent.linkColumn
+ }
+ mSnapshotItemList.add(rankItem)
+ appendAdditionalInfoToRankSubjectGame(homeContent.linkColumn, i)
+ } else if (linkType == "common_collection") {
+ val commonCollectionItem = HomeItemData()
+ val subjectEntity = SubjectEntity().apply {
+ type = homeContent.linkType
+ id = homeContent.linkId
+ name = homeContent.linkText
+ style = homeContent.commonCollection?.style
+ commonCollectionList = homeContent.commonCollection?.collectionList
+ }
+ val head = HomeItemData()
+ head.columnHead = subjectEntity
+ mSnapshotItemList.add(LegacyHomeSubjectTransformer.getBlankSpacingItem(HomeItemData()) as HomeItemData)
+ mSnapshotItemList.add(head)
+ commonCollectionItem.commonCollection = subjectEntity
+ commonCollectionItem.blockPosition = i
+ mSnapshotItemList.add(commonCollectionItem)
+ } else if (linkType == "game_list_collection") {
+ val head = HomeItemData()
+ head.columnHead = SubjectEntity(type = linkType, name = homeContent.linkText)
+ mSnapshotItemList.add(LegacyHomeSubjectTransformer.getBlankSpacingItem(HomeItemData()) as HomeItemData)
+ mSnapshotItemList.add(head)
+
+ val gameCollection = HomeItemData()
+ gameCollection.blockPosition = i
+ val itemDataList = arrayListOf().apply {
+ if (!homeContent.linkGameCollection.isNullOrEmpty()) {
+ var position = 0
+ for (item in homeContent.linkGameCollection) {
+ add(GameCollectionListItemData(gameCollectionItem = item, gameStartPosition = position))
+ position += if (item.count?.game!! > 2) 3 else if (item.games?.size == 0) 0 else item.count?.game ?: 0
+ }
+ }
+ }
+ gameCollection.gameCollection = itemDataList
+ mSnapshotItemList.add(gameCollection)
+ } else if (linkType == "community_article"
+ || linkType == "question"
+ || linkType == "bbs_video"
+ || linkType == "news"
+ ) {
+ val homeItemData = HomeItemData().apply {
+ blockPosition = i
+ bigImageRecommend = SubjectEntity(
+ id = homeContent.linkId,
+ type = homeContent.linkType,
+ image = homeContent.image,
+ firstLineRecommend = homeContent.firstLineRecommend,
+ secondLineRecommend = homeContent.secondLineRecommend,
+ recommendTag = homeContent.recommendTag,
+ columnName = homeContent.linkText
+ )
+ }
+ mSnapshotItemList.add(LegacyHomeSubjectTransformer.getBlankSpacingItem(HomeItemData()) as HomeItemData)
+ mSnapshotItemList.add(homeItemData)
} else {
- mSnapshotItemList.add(HomeItemData(lineDivider = DEFAULT_DIVIDER))
+ val unknown = HomeItemData()
+ unknown.blockPosition = i + 1
+ unknown.unknownData = ""
+ mSnapshotItemList.add(unknown)
+ }
+
+ if (i != 0 && shouldShowDivider) {
+ if (useUltraHeightDivider) {
+ useUltraHeightDivider = false
+ mSnapshotItemList.add(HomeItemData(lineDivider = ULTRA_HEIGHT_DIVIDER))
+ } else {
+ mSnapshotItemList.add(HomeItemData(lineDivider = DEFAULT_DIVIDER))
+ }
+ shouldShowDivider = false
}
- shouldShowDivider = false
}
+ positionAndPackageMap.postValue(HashMap(mPositionAndPackageMap))
+ itemDataList.postValue(ArrayList(mSnapshotItemList))
}
- itemDataList.postValue(mSnapshotItemList)
}
private fun addGamePositionAndPackage(game: GameEntity) {
@@ -459,7 +581,7 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
for (apkEntity in game.getApk()) {
packages += apkEntity.packageName
}
- positionAndPackageMap[packages + (mSnapshotItemList.size - 1)] = mSnapshotItemList.size - 1
+ mPositionAndPackageMap[packages + (mSnapshotItemList.size - 1)] = mSnapshotItemList.size - 1
game.gameLocation = GameEntity.GameLocation.INDEX
game.setEntryMap(DownloadManager.getInstance().getEntryMap(game.name))
}
diff --git a/app/src/main/java/com/gh/gamecenter/home/LegacyHomeFragmentAdapterAssistant.kt b/app/src/main/java/com/gh/gamecenter/home/LegacyHomeFragmentAdapterAssistant.kt
index bd5ec69a75..043923d254 100644
--- a/app/src/main/java/com/gh/gamecenter/home/LegacyHomeFragmentAdapterAssistant.kt
+++ b/app/src/main/java/com/gh/gamecenter/home/LegacyHomeFragmentAdapterAssistant.kt
@@ -31,9 +31,11 @@ import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.entity.LinkEntity
import com.gh.gamecenter.game.GameAndPosition
import com.gh.gamecenter.game.GameItemViewHolder
+import com.gh.gamecenter.game.bigimagerecommend.BigImageRecommendViewHolder
import com.gh.gamecenter.game.columncollection.GameColumnCollectionViewHolder
import com.gh.gamecenter.game.commoncollection.CommonCollectionViewHolder
import com.gh.gamecenter.game.commoncollection.detail.CommonCollectionDetailActivity
+import com.gh.gamecenter.game.doublecard.DoubleCardListViewHolder
import com.gh.gamecenter.game.gallery.GameGallerySlideViewHolder
import com.gh.gamecenter.game.gallery.GameGalleryViewHolder
import com.gh.gamecenter.game.horizontal.GameHorizontalListViewHolder
@@ -81,6 +83,8 @@ class LegacyHomeFragmentAdapterAssistant(
if (itemData.blankDivider != null) return ItemViewType.BLANK_DIVIDER
if (itemData.commonCollection != null) return ItemViewType.COMMON_LINK_COLLECTION
if (itemData.rankCollection != null) return ItemViewType.RANK_COLLECTION
+ if (itemData.doubleCardColumn != null) return ItemViewType.DOUBLE_CARD_COLUMN
+ if (itemData.bigImageRecommend != null) return ItemViewType.BIG_IMAGE_RECOMMEND
return 0
}
@@ -103,6 +107,8 @@ class LegacyHomeFragmentAdapterAssistant(
ItemViewType.BLANK_DIVIDER -> BlankDividerViewHolder(parent.toBinding())
ItemViewType.COMMON_LINK_COLLECTION -> CommonCollectionViewHolder(parent.toBinding())
ItemViewType.RANK_COLLECTION -> RankCollectionViewHolder(parent.toBinding())
+ ItemViewType.DOUBLE_CARD_COLUMN -> DoubleCardListViewHolder(parent.toBinding())
+ ItemViewType.BIG_IMAGE_RECOMMEND -> BigImageRecommendViewHolder(parent.toBinding())
else -> throw NullPointerException()
}
@@ -131,6 +137,8 @@ class LegacyHomeFragmentAdapterAssistant(
)
is CommonCollectionViewHolder -> bindCommonCollection(holder, item)
is RankCollectionViewHolder -> bindRankCollection(holder, item)
+ is DoubleCardListViewHolder -> bindGameDoubleCardList(holder, item)
+ is BigImageRecommendViewHolder -> bindBigImageRecommend(holder, item)
}
}
@@ -158,7 +166,29 @@ class LegacyHomeFragmentAdapterAssistant(
val horizontalColumn = itemData.horizontalColumn
if (horizontalColumn != null) {
- positionList.add(GameAndPosition(null, position))
+ for (i in horizontalColumn.data!!.indices) {
+ val entity = horizontalColumn.data!![i]
+ if (!entity.image.isNullOrEmpty()) continue
+ for (apkEntity in entity.getApk()) {
+ if (apkEntity.packageName == packageName) {
+ positionList.add(GameAndPosition(entity, position))
+ }
+ }
+ }
+ return
+ }
+
+ val horizontalSlide = itemData.horizontalSlide
+ if (horizontalSlide != null) {
+ for (i in horizontalSlide.data!!.indices) {
+ val entity = horizontalSlide.data!![i]
+ if (!entity.image.isNullOrEmpty()) continue
+ for (apkEntity in entity.getApk()) {
+ if (apkEntity.packageName == packageName) {
+ positionList.add(GameAndPosition(entity, position))
+ }
+ }
+ }
return
}
@@ -372,7 +402,7 @@ class LegacyHomeFragmentAdapterAssistant(
val subjectAdapter = holder.bindHorizontalList(subjectEntity!!)
if (mOuterType == OuterType.AMWAY) {
- holder.binding.horizontalRv.isNestedScrollingEnabled = false
+ holder.binding.recyclerView.isNestedScrollingEnabled = false
}
val exposureEventList = arrayListOf()
@@ -404,7 +434,7 @@ class LegacyHomeFragmentAdapterAssistant(
val subjectAdapter = holder.bindHorizontalSlideList(subjectEntity!!, this)
if (mOuterType == OuterType.AMWAY) {
- holder.binding.horizontalRv.isNestedScrollingEnabled = false
+ holder.binding.recyclerView.isNestedScrollingEnabled = false
}
val exposureEventList = arrayListOf()
@@ -434,7 +464,7 @@ class LegacyHomeFragmentAdapterAssistant(
}
if (subjectEntity.type != "game_horizontal") {
- holder.binding.horizontalRv.doOnScrolledSpecificDistance(distanceX = DisplayUtils.dip2px(24f), singleTimeEvent = true) {
+ holder.binding.recyclerView.doOnScrolledSpecificDistance(distanceX = DisplayUtils.dip2px(24f), singleTimeEvent = true) {
if (mOuterType == OuterType.NEW_HOME) {
MtaHelper.onEvent("游戏专题", "新首页专题滑动", "内容" + item.blockPosition + "_" + subjectEntity.name)
} else {
@@ -839,6 +869,38 @@ class LegacyHomeFragmentAdapterAssistant(
}
}
+ private fun bindGameDoubleCardList(holder: DoubleCardListViewHolder, item: LegacyHomeItemData) {
+ item.doubleCardColumn?.data?.run {
+ val subjectEntity = item.doubleCardColumn!!
+ val subjectAdapter = holder.bindDoubleCardList(subjectEntity)
+
+ val exposureEventList = arrayListOf()
+ runOnIoThread(true) {
+ for (i in 0 until subjectAdapter.itemCount) {
+ if (i >= size) break
+
+ get(i).sequence = i
+ val event = ExposureEvent.createEventWithSourceConcat(
+ gameEntity = get(i),
+ basicSource = mBasicExposureSources,
+ source = listOf(ExposureSource("专题", subjectEntity.name ?: ""))
+ )
+ exposureEventList.add(event)
+ }
+ }
+ item.exposureEventList = exposureEventList
+ subjectAdapter.exposureEventList = exposureEventList
+ }
+ }
+
+ private fun bindBigImageRecommend(holder: BigImageRecommendViewHolder, item: LegacyHomeItemData) {
+ item.bigImageRecommend?.run {
+ holder.bindBigImageRecommend(this, "新首页") {
+ NewFlatLogUtils.logHomeGameContentCardClick(it.type ?: "", it.link ?: "", it.linkText ?: "")
+ }
+ }
+ }
+
private fun setPageSwitchData() {
PageSwitchDataHelper.pushCurrentPageData(
hashMapOf(
diff --git a/app/src/main/java/com/gh/gamecenter/home/LegacyHomeItemData.kt b/app/src/main/java/com/gh/gamecenter/home/LegacyHomeItemData.kt
index 7a1bcb222e..5b96ea2ad1 100644
--- a/app/src/main/java/com/gh/gamecenter/home/LegacyHomeItemData.kt
+++ b/app/src/main/java/com/gh/gamecenter/home/LegacyHomeItemData.kt
@@ -28,5 +28,7 @@ open class LegacyHomeItemData(
var columnCollection: SubjectEntity? = null,
var commonCollection: SubjectEntity? = null,
var rankCollection: SubjectEntity? = null, // 排行榜样式专题合集
+ var doubleCardColumn: SubjectEntity? = null, // 双列卡片专题
+ var bigImageRecommend: SubjectEntity? = null, //提问、帖子、视频帖、文章
var blankDivider: Float? = null // 空白填充内容
)
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/home/LegacyHomeSubjectTransformer.kt b/app/src/main/java/com/gh/gamecenter/home/LegacyHomeSubjectTransformer.kt
index 9b11983b2a..3f1203dd1f 100644
--- a/app/src/main/java/com/gh/gamecenter/home/LegacyHomeSubjectTransformer.kt
+++ b/app/src/main/java/com/gh/gamecenter/home/LegacyHomeSubjectTransformer.kt
@@ -115,13 +115,32 @@ object LegacyHomeSubjectTransformer {
val itemHorizontalSlide = newItemInstance()
itemHorizontalSlide.blockPosition = blockPosition + 1
itemHorizontalSlide.horizontalSlide = subjectEntity
- appendAdditionalInfoToSubjectGame(subjectEntity, blockPosition)
-
if (subjectEntity.indexRightTop == "all") {
subjectEntity.indexRightTopLink = LinkEntity(text = subjectEntity.name, link = subjectEntity.id, type = "column_test")
}
-
itemList.add(itemHorizontalSlide)
+
+ if (!subjectEntity.showDownload) {
+ appendAdditionalInfoToSubjectGame(subjectEntity, blockPosition)
+ } else {
+ for (i in 0 until data.size) {
+ val game = data[i]
+ if (!game.image.isNullOrEmpty()) continue
+ game.subjectData = GameSubjectData(
+ id = subjectEntity.id,
+ name = subjectEntity.name,
+ tag = subjectEntity.tag,
+ position = i + if (data[0].image.isNullOrEmpty()) 1 else 0,
+ isOrder = subjectEntity.isOrder,
+ briefStyle = subjectEntity.briefStyle,
+ isShowSuffix = subjectEntity.showSuffix
+ )
+ game.outerSequence = blockPosition
+ game.sequence = i
+
+ addGamePositionAndPackage(game)
+ }
+ }
return
}
@@ -129,8 +148,29 @@ object LegacyHomeSubjectTransformer {
val itemDataSubject = newItemInstance()
itemDataSubject.blockPosition = blockPosition + 1
itemDataSubject.horizontalColumn = subjectEntity
- appendAdditionalInfoToSubjectGame(subjectEntity, blockPosition)
itemList.add(itemDataSubject)
+
+ if (!subjectEntity.showDownload) {
+ appendAdditionalInfoToSubjectGame(subjectEntity, blockPosition)
+ } else {
+ for (i in 0 until data.size) {
+ val game = data[i]
+ if (!game.image.isNullOrEmpty()) continue
+ game.subjectData = GameSubjectData(
+ id = subjectEntity.id,
+ name = subjectEntity.name,
+ tag = subjectEntity.tag,
+ position = i + if (data[0].image.isNullOrEmpty()) 1 else 0,
+ isOrder = subjectEntity.isOrder,
+ briefStyle = subjectEntity.briefStyle,
+ isShowSuffix = subjectEntity.showSuffix
+ )
+ game.outerSequence = blockPosition
+ game.sequence = i
+
+ addGamePositionAndPackage(game)
+ }
+ }
return
}
@@ -166,6 +206,15 @@ object LegacyHomeSubjectTransformer {
return
}
+ if (subjectEntity.type == "game_double_card") {
+ val itemDataSubject = newItemInstance()
+ itemDataSubject.blockPosition = blockPosition + 1
+ itemDataSubject.doubleCardColumn = subjectEntity
+ appendAdditionalInfoToSubjectGame(subjectEntity, blockPosition)
+ itemList.add(itemDataSubject)
+ return
+ }
+
for (i in 0 until data.size) {
val game = data[i]
game.sequence = i
diff --git a/app/src/main/java/com/gh/gamecenter/manager/DataCollectionManager.java b/app/src/main/java/com/gh/gamecenter/manager/DataCollectionManager.java
index d9fef20e7c..613262c8b8 100644
--- a/app/src/main/java/com/gh/gamecenter/manager/DataCollectionManager.java
+++ b/app/src/main/java/com/gh/gamecenter/manager/DataCollectionManager.java
@@ -36,7 +36,7 @@ public class DataCollectionManager {
}
public static void onEvent(Context context, String type, Map map, boolean isUpload) {
- AppExecutor.getLogExecutor().execute(() -> {
+ AppExecutor.getIoExecutor().execute(() -> {
map.put("createdOn", Utils.getTime(context));
if (isUpload) {
DataCollectionManager.getInstance().realTimeUpload(type, map);
@@ -183,7 +183,7 @@ public class DataCollectionManager {
* 统计点击数据
*/
public void statClickData() {
- AppExecutor.getLogExecutor().execute(() -> {
+ AppExecutor.getIoExecutor().execute(() -> {
List list = dao.getClickData();
if (list != null && !list.isEmpty()) {
List ids = new ArrayList<>();
@@ -207,7 +207,7 @@ public class DataCollectionManager {
}
public static void onEvent(Context context, String type, Map map) {
- AppExecutor.getLogExecutor().execute(() -> {
+ AppExecutor.getIoExecutor().execute(() -> {
map.put("createdOn", Utils.getTime(context));
if ("news".equals(type) || "download".equals(type) || "search".equals(type)) {
DataCollectionManager.getInstance().realTimeUpload(type, map);
diff --git a/app/src/main/java/com/gh/gamecenter/manager/PackagesManager.kt b/app/src/main/java/com/gh/gamecenter/manager/PackagesManager.kt
index ede57e2cb8..95bc5e6402 100644
--- a/app/src/main/java/com/gh/gamecenter/manager/PackagesManager.kt
+++ b/app/src/main/java/com/gh/gamecenter/manager/PackagesManager.kt
@@ -2,11 +2,11 @@ package com.gh.gamecenter.manager
import android.text.TextUtils
import com.gh.common.constant.Config
+import com.gh.common.util.PackageUtils
import com.gh.gamecenter.entity.GameInstall
import com.gh.gamecenter.entity.GameUpdateEntity
+import com.halo.assistant.HaloApp
import java.util.*
-import kotlin.collections.ArrayList
-import kotlin.collections.HashMap
/**
* todo 整理部分与[PackageUtils]冲突的方法
@@ -109,7 +109,7 @@ object PackagesManager {
// TODO 检查为什么 4.3.0 以后 arrayList.contains 也会触发 outOfBounds 异常,而以前不会,因为 kotlin 版本更新?
// 先简单改成 SynchronizedList
- return installedPkgList.contains(packageName)
+ return installedPkgList.contains(packageName) && PackageUtils.isInstalled(HaloApp.getInstance(), packageName)
}
/**
diff --git a/app/src/main/java/com/gh/gamecenter/manager/UpdateManager.java b/app/src/main/java/com/gh/gamecenter/manager/UpdateManager.java
index 488465bb49..0b0403e01c 100644
--- a/app/src/main/java/com/gh/gamecenter/manager/UpdateManager.java
+++ b/app/src/main/java/com/gh/gamecenter/manager/UpdateManager.java
@@ -144,7 +144,7 @@ public class UpdateManager {
}
if (DownloadStatus.done.equals(downloadEntity.getStatus())) {
- DownloadManager.getInstance().cancel(downloadEntity.getUrl(), false, true);
+ DownloadManager.getInstance().cancel(downloadEntity.getUrl(), false, true, false);
if (downloadDialog != null) {
try {
downloadDialog.dismiss();
@@ -517,7 +517,7 @@ public class UpdateManager {
}
downloadEntity.setPackageName(mApplicationContext.getPackageName());
- DownloadManager.getInstance().cancel(appEntity.getUrl(), true, true);
+ DownloadManager.getInstance().cancel(appEntity.getUrl(), true, true, false);
DownloadManager.getInstance().pauseAll();
AppExecutor.getUiExecutor().executeWithDelay(() -> {
diff --git a/app/src/main/java/com/gh/gamecenter/manager/UserManager.java b/app/src/main/java/com/gh/gamecenter/manager/UserManager.java
index 051a08c94e..e2b4e6bc15 100644
--- a/app/src/main/java/com/gh/gamecenter/manager/UserManager.java
+++ b/app/src/main/java/com/gh/gamecenter/manager/UserManager.java
@@ -7,10 +7,14 @@ import android.text.TextUtils;
import androidx.annotation.Nullable;
+import com.gh.common.repository.ReservationRepository;
+import com.gh.common.util.ErrorHelper;
import com.gh.gamecenter.common.base.activity.BaseActivity;
import com.gh.gamecenter.common.constant.Constants;
+import com.gh.gamecenter.common.eventbus.EBShowDialog;
import com.gh.gamecenter.common.exposure.meta.MetaUtil;
-import com.gh.common.repository.ReservationRepository;
+import com.gh.gamecenter.common.retrofit.BiResponse;
+import com.gh.gamecenter.common.retrofit.Response;
import com.gh.gamecenter.common.utils.DeviceUtils;
import com.gh.gamecenter.common.utils.EnvHelper;
import com.gh.gamecenter.core.utils.GsonUtils;
@@ -19,9 +23,6 @@ import com.gh.gamecenter.entity.CommunityEntity;
import com.gh.gamecenter.entity.LoginTokenEntity;
import com.gh.gamecenter.entity.TokenEntity;
import com.gh.gamecenter.entity.UserInfoEntity;
-import com.gh.gamecenter.common.eventbus.EBShowDialog;
-import com.gh.gamecenter.common.retrofit.BiResponse;
-import com.gh.gamecenter.common.retrofit.Response;
import com.gh.gamecenter.retrofit.RetrofitManager;
import com.gh.gamecenter.retrofit.service.ApiService;
import com.gh.gamecenter.user.UserRepository;
@@ -187,7 +188,7 @@ public class UserManager {
public void onFailure(HttpException e) {
super.onFailure(e);
String errorMessage = "null";
- if (e != null && (e.code() == 401 || e.code() == 400)) {
+ if (e != null && (e.code() == 401 || e.code() == 403 || e.code() == 400)) {
int code = -1;
try {
errorMessage = e.response().errorBody().string();
@@ -200,6 +201,11 @@ public class UserManager {
if (code == 400401 || code == 400802) { // 自动注销
UserRepository.getInstance().logout();
}
+
+ if (code == 403401) {
+ UserRepository.getInstance().logout();
+ ErrorHelper.handleLoginError(HaloApp.getInstance().getApplicationContext(), e);
+ }
} catch (Exception e1) {
e1.printStackTrace();
}
diff --git a/app/src/main/java/com/gh/gamecenter/message/MessageDetailFragment.java b/app/src/main/java/com/gh/gamecenter/message/MessageDetailFragment.java
index 77e0f634ee..cba0cf2ac1 100644
--- a/app/src/main/java/com/gh/gamecenter/message/MessageDetailFragment.java
+++ b/app/src/main/java/com/gh/gamecenter/message/MessageDetailFragment.java
@@ -21,6 +21,7 @@ import androidx.recyclerview.widget.RecyclerView;
import com.gh.common.constant.Config;
import com.gh.common.util.CheckLoginUtils;
import com.gh.common.util.DialogUtils;
+import com.gh.gamecenter.common.callback.ConfirmListener;
import com.gh.gamecenter.core.utils.DisplayUtils;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.common.util.ErrorHelper;
@@ -399,7 +400,7 @@ public class MessageDetailFragment extends ToolbarFragment implements OnCommentC
e1.printStackTrace();
}
}
- ErrorHelper.handleError(requireContext(), errorString, false);
+ ErrorHelper.handleError(requireContext(), errorString, false, () -> mBinding.pieceCommentTypingContainer.answerCommentSendBtn.performClick());
}
});
});
diff --git a/app/src/main/java/com/gh/gamecenter/mygame/PlayedGameAdapter.kt b/app/src/main/java/com/gh/gamecenter/mygame/PlayedGameAdapter.kt
index 6ea5d76125..7010c26614 100644
--- a/app/src/main/java/com/gh/gamecenter/mygame/PlayedGameAdapter.kt
+++ b/app/src/main/java/com/gh/gamecenter/mygame/PlayedGameAdapter.kt
@@ -33,7 +33,7 @@ import com.gh.gamecenter.common.callback.ConfirmListener
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.databinding.ItemPlayedGameBinding
-import com.gh.gamecenter.databinding.ItemUsageStatsBinding
+import com.gh.gamecenter.databinding.ViewSimpleToggleBinding
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.lightgame.download.DownloadEntity
@@ -340,7 +340,7 @@ open class PlayedGameAdapter(
}
}
- class UsageStatsViewHolder(var binding: ItemUsageStatsBinding) : RecyclerView.ViewHolder(binding.root)
+ class UsageStatsViewHolder(var binding: ViewSimpleToggleBinding) : RecyclerView.ViewHolder(binding.root)
fun resetListData() {
if (!hasHeader()) EnergyTaskHelper.postEnergyTask("open_game_time")
diff --git a/app/src/main/java/com/gh/gamecenter/packagehelper/PackageRepository.kt b/app/src/main/java/com/gh/gamecenter/packagehelper/PackageRepository.kt
index 072ed61789..56025baaf3 100644
--- a/app/src/main/java/com/gh/gamecenter/packagehelper/PackageRepository.kt
+++ b/app/src/main/java/com/gh/gamecenter/packagehelper/PackageRepository.kt
@@ -3,23 +3,25 @@ package com.gh.gamecenter.packagehelper
import android.annotation.SuppressLint
import android.text.TextUtils
import androidx.lifecycle.MutableLiveData
-import com.gh.gamecenter.common.exposure.meta.MetaUtil
import com.gh.common.filter.RegionSettingHelper
-import com.gh.gamecenter.common.loghub.LoghubUtils
-import com.gh.common.util.*
+import com.gh.common.util.ApkActiveUtils
+import com.gh.common.util.GameUtils
+import com.gh.common.util.PackageUtils
import com.gh.gamecenter.R
-import com.gh.gamecenter.core.runOnIoThread
-import com.gh.gamecenter.core.utils.SPUtils
+import com.gh.gamecenter.common.exposure.meta.MetaUtil
+import com.gh.gamecenter.common.loghub.LoghubUtils
+import com.gh.gamecenter.common.retrofit.BiResponse
+import com.gh.gamecenter.common.retrofit.ObservableUtil
+import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.secondOrNull
import com.gh.gamecenter.common.utils.tryCatchInRelease
+import com.gh.gamecenter.core.runOnIoThread
+import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.manager.PackagesManager
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.packagehelper.PackageRepository.gameInstalled
import com.gh.gamecenter.packagehelper.PackageRepository.gameUpdate
-import com.gh.gamecenter.common.retrofit.BiResponse
-import com.gh.gamecenter.common.retrofit.ObservableUtil
-import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
@@ -53,6 +55,9 @@ object PackageRepository {
val gameUpdateLiveData = MutableLiveData>()
val gameInstalledLiveData = MutableLiveData>()
+ val installedGameListLiveData = MutableLiveData>() // 已安装的游戏列表 (信息比 GameInstall 更全)
+
+ private val mInstalledGameList = Collections.synchronizedList(ArrayList())
val gameInstalled = Collections.synchronizedList(ArrayList())
val gameUpdate = ArrayList()
@@ -61,11 +66,11 @@ object PackageRepository {
/**
* 预留方法,如果想手动初始化可以调用
*/
- // TODO 在获取到页面数据以后刷新
@JvmStatic
fun initData() {
runOnIoThread {
if (gameInstalled.isNotEmpty()) gameInstalled.clear()
+ if (mInstalledGameList.isNotEmpty()) mInstalledGameList.clear()
if (gameUpdate.isNotEmpty()) gameUpdate.clear()
if (mInstalledPkgList.isNotEmpty()) mInstalledPkgList.clear()
@@ -169,11 +174,14 @@ object PackageRepository {
* 如果有数据变动会调用[gameUpdateLiveData] [gameInstalledLiveData]实现相关页面刷新
*
* @param filteredList 已安装的游戏包名集合 (仅已收录部分)
+ * @param onWorkerThreadOnly 是否在工作线程执行
+ * @param matchSmoothGameOnly 是否仅匹配畅玩游戏
*/
@SuppressLint("CheckResult")
private fun loadInstalledGameDigestAndNotifyData(
filteredList: ArrayList,
- onWorkerThreadOnly: Boolean = false
+ onWorkerThreadOnly: Boolean = false,
+ matchSmoothGameOnly: Boolean = false,
) {
var isNotifyUpdate = false
val maxPageCount = (filteredList.size / PAGE_SIZE) + 1
@@ -207,13 +215,16 @@ object PackageRepository {
}
for (game in validGames) {
+ // 仅匹配畅玩游戏时,非畅玩游戏直接跳过
+ if (matchSmoothGameOnly && !game.isVGame()) {
+ continue
+ }
+
if (gh_id == null || gh_id == game.id) {
gameInstalled.add(
- GameInstall.transformGameInstall(
- game,
- pkgName
- )
+ GameInstall.transformGameInstall(game, pkgName)
)
+ mInstalledGameList.add(game)
val isCanPluggable = checkGamePlugin(game, pkgName)
val isCanUpdate = checkGameUpdate(game)
addCurrentlyInstalledVersionIfValid(game)
@@ -247,7 +258,12 @@ object PackageRepository {
addUpdateOrPluggable(updateEntity)
}
return true
+ } else if (game.isVGame()) {
+ // 畅玩游戏移除更新,避免死循环更新
+ removeUpdate(game.id, false)
+ return true
}
+
return false
}
@@ -340,11 +356,22 @@ object PackageRepository {
if (!isExist) gameUpdate.add(data)
}
+ /**
+ * 移除更新
+ * @param gameId 游戏 ID
+ */
+ fun removeUpdate(gameId: String, notifyUpdate: Boolean) {
+ gameUpdate.removeAll { it.id == gameId }
+ if (notifyUpdate) {
+ notifyGameUpdateData()
+ }
+ }
+
/**
* 新增已安装的游戏
* @param pkgName 已安装的游戏包名
*/
- fun installedGame(pkgName: String) {
+ fun addInstalledGame(pkgName: String) {
mInstalledPkgList.add(pkgName)
notifyInstallPkgData()
@@ -355,11 +382,24 @@ object PackageRepository {
}
}
+ /**
+ * 批量新增已安装的游戏数量
+ * @param pkgNameList 数组列表
+ */
+ fun addInstalledGames(pkgNameList: ArrayList, isVGameOnly: Boolean = false) {
+ mInstalledPkgList.addAll(pkgNameList)
+ notifyInstallPkgData()
+
+ updateFilterPackage(pkgNameList) {
+ loadInstalledGameDigestAndNotifyData(pkgNameList, true, isVGameOnly)
+ }
+ }
+
/**
* 新增卸载游戏
* @param pkgName 已安装的游戏包名
*/
- fun uninstalledGame(pkgName: String) {
+ fun addUninstalledGame(pkgName: String) {
// TODO 检查为什么会有两个相同的包名添加到 mInstalledPkgList 里
mInstalledPkgList.removeAll { it == pkgName }
// 尝试从临时的当前版本列表里移除已卸载的条目
@@ -389,8 +429,10 @@ object PackageRepository {
var i = 0
while (i < gameInstalled.size) {
val game = gameInstalled[i]
+ val gameEntity = mInstalledGameList[i]
if (game.packageName == pkgName) {
gameInstalled.remove(game)
+ mInstalledGameList.remove(gameEntity)
} else {
i++
}
@@ -401,6 +443,7 @@ object PackageRepository {
private fun notifyGameInstallData() {
PackagesManager.initGameInstall(ArrayList(gameInstalled))
gameInstalledLiveData.postValue(ArrayList(gameInstalled))
+ installedGameListLiveData.postValue(ArrayList(mInstalledGameList))
}
private fun notifyGameUpdateData() {
diff --git a/app/src/main/java/com/gh/gamecenter/packagehelper/PackageViewModel.kt b/app/src/main/java/com/gh/gamecenter/packagehelper/PackageViewModel.kt
index 8acf514491..fa72d37602 100644
--- a/app/src/main/java/com/gh/gamecenter/packagehelper/PackageViewModel.kt
+++ b/app/src/main/java/com/gh/gamecenter/packagehelper/PackageViewModel.kt
@@ -65,7 +65,7 @@ class PackageViewModel(application: Application,
* 只在收到安装广播时调用,不建议手动调用
*/
fun addInstalledGame(pkgName: String?) {
- if (!TextUtils.isEmpty(pkgName)) mRepository.installedGame(pkgName!!)
+ if (!TextUtils.isEmpty(pkgName)) mRepository.addInstalledGame(pkgName!!)
}
/**
@@ -73,7 +73,7 @@ class PackageViewModel(application: Application,
* 只在收到卸载广播时调用,不建议手动调用
*/
fun addUninstalledGame(pkgName: String?) {
- if (!TextUtils.isEmpty(pkgName)) mRepository.uninstalledGame(pkgName!!)
+ if (!TextUtils.isEmpty(pkgName)) mRepository.addUninstalledGame(pkgName!!)
}
/**
diff --git a/app/src/main/java/com/gh/gamecenter/personal/PersonalFragment.kt b/app/src/main/java/com/gh/gamecenter/personal/PersonalFragment.kt
index f5604262ef..33064af33c 100644
--- a/app/src/main/java/com/gh/gamecenter/personal/PersonalFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/personal/PersonalFragment.kt
@@ -222,7 +222,7 @@ class PersonalFragment : BaseLazyFragment() {
.decorView
.findViewById(android.R.id.content)
.findViewById(BaseActivity.ID_ROOT_INDICATOR)
- indicator.setOnClickListener {
+ indicator?.setOnClickListener {
requireContext().startActivity(
getIntent(requireContext())
)
diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeFragment.kt b/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeFragment.kt
index 9146c4feee..a20dc06167 100644
--- a/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeFragment.kt
@@ -1,10 +1,12 @@
package com.gh.gamecenter.personalhome
+import android.annotation.SuppressLint
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
+import android.view.MotionEvent
import android.view.View
import android.widget.CheckedTextView
import android.widget.LinearLayout
@@ -44,6 +46,7 @@ import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.appbar.AppBarLayout.OnOffsetChangedListener
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
+import io.reactivex.disposables.Disposable
import kotlin.math.abs
class UserHomeFragment : ToolbarFragment() {
@@ -661,30 +664,13 @@ class UserHomeFragment : ToolbarFragment() {
}
}
-// userBadge.setOnClickListener {
-// MtaHelper.onEvent("个人主页详情", "个人主页详情", if (mUserHomeViewModel.userId == UserManager.getInstance().userId) "我的徽章" else "TA的徽章")
-// MtaHelper.onEvent("进入徽章墙_用户记录", if (mUserHomeViewModel.userId == UserManager.getInstance().userId) "个人主页-我的徽章" else "个人主页-Ta的徽章",
-// "${mUserHomeViewModel.userInfo.value?.name}(${mUserHomeViewModel.userId})")
-// MtaHelper.onEvent("徽章中心", "进入徽章中心", if (mUserHomeViewModel.userId == UserManager.getInstance().userId) "个人主页-我的徽章" else "个人主页-Ta的徽章")
-// directToBadgeWall(requireContext(),
-// mUserHomeViewModel.userId, mUserHomeViewModel.userInfo.value?.name
-// ?: "", mUserHomeViewModel.userInfo.value?.icon ?: "")
-// }
+ userName.setOnLongClickListener {
+ userName.text.toString().copyTextAndToast("用户昵称已复制~")
+ return@setOnLongClickListener true
+ }
}
}
-// private fun updateUserBadge(badges: List) {
-// mHomeBinding?.userBadgeList?.removeAllViews()
-// for (badge in badges.take(6)) {
-// val badgeView = SimpleDraweeView(context)
-// val params = LinearLayout.LayoutParams(24F.dip2px(), 24F.dip2px())
-// params.setMargins(2F.dip2px(), 0, 2F.dip2px(), 0)
-// badgeView.layoutParams = params
-// ImageUtils.display(badgeView, badge.icon)
-// mHomeBinding?.userBadgeList?.addView(badgeView)
-// }
-// }
-
override fun onClick(v: View) {
super.onClick(v)
when (v.id) {
diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/background/BackgroundPreviewFragment.kt b/app/src/main/java/com/gh/gamecenter/personalhome/background/BackgroundPreviewFragment.kt
index 1096c623ec..4bdf9ab1de 100644
--- a/app/src/main/java/com/gh/gamecenter/personalhome/background/BackgroundPreviewFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/personalhome/background/BackgroundPreviewFragment.kt
@@ -11,10 +11,12 @@ import android.view.View
import androidx.annotation.RequiresApi
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
-import com.gh.gamecenter.common.base.fragment.WaitingDialogFragment
-import com.gh.common.util.*
+import com.gh.common.util.EnergyTaskHelper
+import com.gh.common.util.GhMatisseFilter
import com.gh.gamecenter.CropImageActivity
import com.gh.gamecenter.R
+import com.gh.gamecenter.common.base.fragment.ToolbarFragment
+import com.gh.gamecenter.common.base.fragment.WaitingDialogFragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.*
@@ -22,7 +24,6 @@ import com.gh.gamecenter.databinding.FragmentBackgroundPreviewBinding
import com.gh.gamecenter.entity.BackgroundImageEntity
import com.gh.gamecenter.entity.ErrorEntity
import com.gh.gamecenter.manager.UserManager
-import com.gh.gamecenter.common.base.fragment.ToolbarFragment
import com.gh.gamecenter.user.UserViewModel
import com.halo.assistant.HaloApp
import com.zhihu.matisse.Matisse
@@ -43,8 +44,6 @@ class BackgroundPreviewFragment : ToolbarFragment() {
private var mLocalPath: String = ""
private var backgroundImageEntity: BackgroundImageEntity? = null//如果为空,则是本地选择的
- private var mIsTheFirstTimeUserChangeBlurriness = true // 用户是否进入页面来第一次更改模糊度
-
private lateinit var mUserViewModel: UserViewModel
override fun getLayoutId(): Int = 0
@@ -176,10 +175,6 @@ class BackgroundPreviewFragment : ToolbarFragment() {
}, {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
changeAmbiguity()
- if (mIsTheFirstTimeUserChangeBlurriness) {
- SentryHelper.onEvent("USER_CHANGE_BLURRINESS", "isEmulator", "${HaloApp.getInstance().isEmulator}")
- mIsTheFirstTimeUserChangeBlurriness = false
- }
} else {
ToastUtils.showToast("系统版本太低")
}
@@ -214,13 +209,18 @@ class BackgroundPreviewFragment : ToolbarFragment() {
private fun changeAmbiguity() {
if (mOriginBitmap == null) return
val progress = mBinding.blurSeek.progress
- mTempBitmap = if (progress == 0) {
- Bitmap.createBitmap(mOriginBitmap!!)
- } else {
- BitmapUtils.getBlurBitmap(requireContext(), mOriginBitmap, progress)
+
+ try {
+ mTempBitmap = if (progress == 0) {
+ Bitmap.createBitmap(mOriginBitmap!!)
+ } else {
+ BitmapUtils.getBlurBitmap(requireContext(), mOriginBitmap, progress)
+ }
+ mBinding.mineGhIv.setImageBitmap(mTempBitmap)
+ mBinding.personalHomeIv.setImageBitmap(mTempBitmap)
+ } catch (t: Throwable) {
+ ToastUtils.toast("您的设备暂不支持调整模糊度")
}
- mBinding.mineGhIv.setImageBitmap(mTempBitmap)
- mBinding.personalHomeIv.setImageBitmap(mTempBitmap)
}
private fun changeCommitButton() {
diff --git a/app/src/main/java/com/gh/gamecenter/provider/GhContentProvider.kt b/app/src/main/java/com/gh/gamecenter/provider/GhContentProvider.kt
index 91129dcc8b..006c56e97a 100644
--- a/app/src/main/java/com/gh/gamecenter/provider/GhContentProvider.kt
+++ b/app/src/main/java/com/gh/gamecenter/provider/GhContentProvider.kt
@@ -28,6 +28,7 @@ class GhContentProvider : ContentProvider() {
}
private fun initProviderSqliteHelper(context: Context?){
+
val helper: SQLiteOpenHelper =
object : SQLiteOpenHelper(context, CERTIFICATION_DATABASE_NAME, null, 1) {
override fun onCreate(db: SQLiteDatabase) {
@@ -94,22 +95,22 @@ class GhContentProvider : ContentProvider() {
- fun localInsert(context: Context,values: ContentValues?){
- initProviderSqliteHelper(context)
- try {
- values?.put(KEY_PRIMARY_KEY, 1)
- // 如果已存在则直接替换
- mSqLiteDatabase?.insertWithOnConflict(
- CERTIFICATION_TABLE_NAME,
- null,
- values,
- SQLiteDatabase.CONFLICT_REPLACE
- )
-
- } catch (e: SQLiteFullException) {
- Utils.toast(context,"数据库内存已满,无法同步")
- }
- }
+// fun localInsert(context: Context,values: ContentValues?){
+// initProviderSqliteHelper(context)
+// try {
+// values?.put(KEY_PRIMARY_KEY, 1)
+// // 如果已存在则直接替换
+// mSqLiteDatabase?.insertWithOnConflict(
+// CERTIFICATION_TABLE_NAME,
+// null,
+// values,
+// SQLiteDatabase.CONFLICT_REPLACE
+// )
+//
+// } catch (e: SQLiteFullException) {
+// Utils.toast(context,"数据库内存已满,无法同步")
+// }
+// }
override fun insert(uri: Uri, values: ContentValues?): Uri? {
val context = context ?: return null
diff --git a/app/src/main/java/com/gh/gamecenter/qa/answer/BaseAnswerOrArticleItemViewHolder.kt b/app/src/main/java/com/gh/gamecenter/qa/answer/BaseAnswerOrArticleItemViewHolder.kt
index 42c5ff3e9d..2e84e8ca0d 100644
--- a/app/src/main/java/com/gh/gamecenter/qa/answer/BaseAnswerOrArticleItemViewHolder.kt
+++ b/app/src/main/java/com/gh/gamecenter/qa/answer/BaseAnswerOrArticleItemViewHolder.kt
@@ -60,28 +60,38 @@ open class BaseAnswerOrArticleItemViewHolder(itemView: View) : BaseRecyclerViewH
when (entity.type) {
"community_article" -> {
val communityId = if (!entity.communityId.isNullOrEmpty()) entity.communityId
- ?: "" else entity.bbs.id
- val intent = ArticleDetailActivity.getCommentIntent(itemView.context,
- CommunityEntity(communityId, entity.communityName ?: ""),
- entity.id ?: "", entrance, "")
+ ?: "" else entity.bbs.id
+ val intent = ArticleDetailActivity.getCommentIntent(
+ itemView.context,
+ CommunityEntity(communityId, entity.communityName ?: ""),
+ entity.id ?: "", entrance, ""
+ )
itemView.context.startActivity(intent)
}
"video" -> {
val communityId = if (!entity.communityId.isNullOrEmpty()) entity.communityId
?: "" else entity.bbs.id
- itemView.context.startActivity(ForumVideoDetailActivity.getIntent(itemView.context, entity.id
- ?: "", communityId, true))
+ itemView.context.startActivity(
+ ForumVideoDetailActivity.getIntent(
+ itemView.context, entity.id
+ ?: "", communityId, true
+ )
+ )
}
"answer" -> {
- val intent = CommentActivity.getAnswerCommentIntent(itemView.context,
- entity.id ?: "",
- entity.count.comment,
- false)
+ val intent = CommentActivity.getAnswerCommentIntent(
+ itemView.context,
+ entity.id ?: "",
+ entity.count.comment,
+ false
+ )
itemView.context.startActivity(intent)
}
else -> {
- val intent = NewQuestionDetailActivity.getCommentIntent(itemView.context, entity.id
- ?: "", entrance, "")
+ val intent = NewQuestionDetailActivity.getCommentIntent(
+ itemView.context, entity.id
+ ?: "", entrance, ""
+ )
itemView.context.startActivity(intent)
}
}
@@ -156,10 +166,15 @@ open class BaseAnswerOrArticleItemViewHolder(itemView: View) : BaseRecyclerViewH
id = entity.id,
title = entity.title,
images = entity.images,
- description = entity.brief)
- it.context.startActivity(QuestionsInviteActivity.getIntent(it.context,
- questionsDetailEntity,
- entrance))
+ description = entity.brief
+ )
+ it.context.startActivity(
+ QuestionsInviteActivity.getIntent(
+ it.context,
+ questionsDetailEntity,
+ entrance
+ )
+ )
}
}
@@ -173,7 +188,16 @@ open class BaseAnswerOrArticleItemViewHolder(itemView: View) : BaseRecyclerViewH
"video" -> "视频帖评论"
else -> "提问帖评论"
}
- NewLogUtils.logRecommendFeedContentClick("click_for_you_comment", contentType, id, (position + 1), bbs.id, bbsType, user.id ?: "", commentType)
+ NewLogUtils.logRecommendFeedContentClick(
+ "click_for_you_comment",
+ contentType,
+ id,
+ (position + 1),
+ bbs.id,
+ bbsType,
+ user.id ?: "",
+ commentType
+ )
}
}
@@ -192,10 +216,12 @@ open class BaseAnswerOrArticleItemViewHolder(itemView: View) : BaseRecyclerViewH
else -> {
val communityId = if (entity.community.id.isNotEmpty()) entity.community.id
else UserManager.getInstance().community.id
- val intent = ArticleDetailActivity.getCommentIntent(itemView.context,
- CommunityEntity(communityId, entity.community.name),
- entity.id,
- entrance, "")
+ val intent = ArticleDetailActivity.getCommentIntent(
+ itemView.context,
+ CommunityEntity(communityId, entity.community.name),
+ entity.id,
+ entrance, ""
+ )
itemView.context.startActivity(intent)
MtaHelper.onEvent(getEventId(entrance), getKey(entrance), "评论图标")
}
@@ -209,7 +235,15 @@ open class BaseAnswerOrArticleItemViewHolder(itemView: View) : BaseRecyclerViewH
CheckLoginUtils.checkLogin(itemView.context, entrance) {
if (entrance == "社区+(推荐)" && position != null) {
entity.run {
- NewLogUtils.logRecommendFeedContentClick("click_for_you_like", contentType, id, position + 1, bbs.id, bbsType, user.id ?: "")
+ NewLogUtils.logRecommendFeedContentClick(
+ "click_for_you_like",
+ contentType,
+ id,
+ position + 1,
+ bbs.id,
+ bbsType,
+ user.id ?: ""
+ )
}
}
@@ -281,75 +315,72 @@ open class BaseAnswerOrArticleItemViewHolder(itemView: View) : BaseRecyclerViewH
}
if (entity.type == "video") {
RetrofitManager.getInstance()
- .api.voteVideo(entity.id)
- .subscribeOn(Schedulers.io())
- .subscribe(object : BiResponse