Compare commits

..

14 Commits

Author SHA1 Message Date
45b5277138 chore: 版本更新至 5.9.2-536 2022-06-20 14:44:33 +08:00
db39ea77d5 Merge branch 'hotfix-v5.9.2-535-community_home_bitmap_crash' into 'legacy-release'
fix:修复社区首页获取顶部背景宽高为0的问题

See merge request halo/android/assistant-android!270
2022-06-20 10:53:10 +08:00
lyr
e5388560e0 fix:修复社区首页获取顶部背景宽高为0的问题 2022-06-20 10:49:13 +08:00
9b58bf3890 Merge remote-tracking branch 'origin/legacy-release' into legacy-release 2022-06-17 17:53:36 +08:00
42a7c4918f feat: 添加实名认证页面跳转 scheme 2022-06-17 17:52:48 +08:00
565c3ec8e2 chore: 版本更新到 5.9.2-535 2022-06-16 09:55:23 +08:00
a03c673ae7 Merge branch 'hotfix-v5.9.2-534-community_home_ui' into 'legacy-release'
fix:V5.9.2UI问题(3) https://git.shanqu.cc/pm/halo/halo-app-issues/-/issues/1922

See merge request halo/android/assistant-android!266
2022-06-15 17:51:48 +08:00
lyr
0e06f998f3 fix:V5.9.2UI问题(3) https://git.shanqu.cc/pm/halo/halo-app-issues/-/issues/1922 2022-06-15 17:49:23 +08:00
288e71d34c Merge branch 'hotfix-v5.9.2-534-community_home_ui' into 'legacy-release'
1.V5.9.2UI问题 https://git.shanqu.cc/pm/halo/halo-app-issues/-/issues/1922; 2.fix:修复社区-论坛滑动轮播图闪退问题

See merge request halo/android/assistant-android!265
2022-06-15 17:22:34 +08:00
lyr
e305a90748 1.V5.9.2UI问题 https://git.shanqu.cc/pm/halo/halo-app-issues/-/issues/1922;
2.fix:修复社区-论坛滑动轮播图闪退问题
2022-06-15 17:19:54 +08:00
b752cdaeb8 chore: 版本更新至 5.9.2-534 2022-06-14 16:22:39 +08:00
5e5f0360dd fix: 修复 OAID 获取异常造成推广包接口失效问题 2022-06-14 16:21:50 +08:00
e0ed6da7ae Merge branch 'feature-issues1865_content_provider_sync_certification' into 'legacy-release'
feat: 实名认证功能 https://git.shanqu.cc/pm/halo-plugin-issues/-/issues/221

See merge request halo/android/assistant-android!264
2022-06-14 16:17:09 +08:00
2940d11943 feat: 实名认证功能 https://git.shanqu.cc/pm/halo-plugin-issues/-/issues/221 2022-06-14 16:17:09 +08:00
5787 changed files with 116981 additions and 251674 deletions

View File

@ -1,555 +0,0 @@
[*]
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

View File

@ -1,155 +1,44 @@
# commit_sha 文件记录上一次成功流水线的commit sha用于定时计划检测是否有新代码提交有就执行流水线没有就终止流水线
cache:
# 不同的分支采用不同的 cache防止分支之间相互影响
key: "${CI_COMMIT_REF_SLUG}_commit_sha"
paths:
- commit_sha
policy: pull
# 将打包&发送apk包邮件job 和代码分析job 并行执行
stages:
- build&analyze
- oss-upload&send-email
- ci_sonar_mail
- analysis
- sendmail
# 阻止了 合并请求 或 push分支和标签的流水线。 最后的 when: always 规则运行所有其他流水线类型,包括定时计划流水线。
workflow:
rules:
- if: '$CI_PIPELINE_SOURCE == "push"'
when: always
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: never
- when: always
before_script:
# 检查是否存在 commit_sha 文件
- if [ -f commit_sha ]; then cat commit_sha; else echo "0000000" > commit_sha; fi
- export BEFORE_COMMIT_SHA=$(cat commit_sha)
# 比较commit sha ,若与上一次成功流水线的commit sha 相同,则退出流水线
- if [ "$CI_COMMIT_SHA" == "$BEFORE_COMMIT_SHA" ] && [ "$CI_PIPELINE_SOURCE" != "web" ]; then exit 137; fi
# 使用 .post 阶段使作业在流水线的末尾运行。.post 始终是流水线的最后阶段。
change_commit:
tags:
- offline-test
stage: .post
# 此job 跳过拉取git代码
variables:
GIT_STRATEGY: none
script:
# 更新 commit_sha
- if [ "$CI_COMMIT_SHA" != "$BEFORE_COMMIT_SHA" ]; then echo $CI_COMMIT_SHA > commit_sha; fi
cache:
# 不同的分支采用不同的 cache防止分支之间相互影响
key: "${CI_COMMIT_REF_SLUG}_commit_sha"
paths:
- commit_sha
policy: pull-push
allow_failure:
exit_codes: 137
android_build:
## 代码检查
sonarqube_analysis:
tags:
# - local-runner
- offline-test
stage: build&analyze
image: hub.shanqu.cc/library/ci-android:jdk11-sdk31-33
resource_group: android_build
variables:
GIT_SUBMODULE_STRATEGY: recursive
KUBERNETES_CPU_LIMIT: "10"
stage: analysis
image: sonarsource/sonar-scanner-cli:latest
dependencies: [] #禁止传递来的artifact
script:
- export GRADLE_USER_HOME=/home/gitlab-runner/ci-build-cache/$CI_PROJECT_PATH/.gradle
- chmod +x ./gradlew
- ./scripts/jenkins_build.sh $CI_COMMIT_REF_NAME $BEFORE_COMMIT_SHA $CI_COMMIT_SHA
#设置打包后的产物用于job之间共享
artifacts:
paths:
- app/build/tmp/*.apk
expire_in: 48 hrs # 指定附件上载后保存的时间24h默认永久在Gitlab保存
allow_failure:
exit_codes: 137
## 获取项目的一级组和二级组和项目名作为projectKey例如projectKey=platform-backend-eci-monitor
- group=`echo $CI_PROJECT_PATH | sed 's#/#-#g'`
- sonar-scanner
-Dsonar.host.url=http://sonarqube-server.sonarqube:9000/
-Dsonar.login=be43de7264ce4c4766eb0c020373c3e74e6df257
-Dsonar.jacoco.reportPaths=target/jacoco.exec
-Dsonar.projectKey=$group
-Dsonar.projectName=$CI_PROJECT_PATH
-Dsonar.sourceEncoding=UTF-8
-Dsonar.exclusions=**/vendor/**,**/errcode/**
-Dsonar.gitlab.project_id=$CI_PROJECT_ID
-Dsonar.gitlab.commit_sha=$CI_COMMIT_SHA
-Dsonar.gitlab.ref_name=$CI_COMMIT_REF_NAME
-Dsonar.gitlab.ci_merge_request_iid=$CI_MERGE_REQUEST_IID
-Dsonar.gitlab.merge_request_discussion=true
-Dsonar.java.binaries=. # 如果不使用Maven或Gradle进行分析则必须手动提供测试二进制文件
only:
- dev
- feat/GHZSCY-5250
# 代码检查
sonarqube_analysis:
tags:
- offline-test
stage: build&analyze
image: sonarsource/sonar-scanner-cli:latest
dependencies: [] #禁止传递来的artifact
script:
## 获取项目的一级组和二级组和项目名作为projectKey例如projectKey=platform-backend-eci-monitor
- group=`echo $CI_PROJECT_PATH | sed 's#/#-#g'`
- sonar-scanner
-Dsonar.host.url=http://sonarqube-server.sonarqube:9000/
-Dsonar.login=be43de7264ce4c4766eb0c020373c3e74e6df257
-Dsonar.jacoco.reportPaths=target/jacoco.exec
-Dsonar.projectKey=$group
-Dsonar.projectName=$CI_PROJECT_PATH
-Dsonar.sourceEncoding=UTF-8
-Dsonar.exclusions=**/vendor/**,**/errcode/**
-Dsonar.gitlab.project_id=$CI_PROJECT_ID
-Dsonar.gitlab.commit_sha=$CI_COMMIT_SHA
-Dsonar.gitlab.ref_name=$CI_COMMIT_REF_NAME
-Dsonar.gitlab.ci_merge_request_iid=$CI_MERGE_REQUEST_IID
-Dsonar.gitlab.merge_request_discussion=true
-Dsonar.java.binaries=.
-Dsonar.branch.name=$CI_COMMIT_REF_NAME
allow_failure:
exit_codes: 137
only:
- dev
- release
## 发送简易检测结果报告
send_sonar_report:
tags:
- offline-test
stage: ci_sonar_mail
image: hub.shanqu.cc/library/docker:latest
# 此job 跳过拉取git代码
variables:
GIT_STRATEGY: none
script:
- group=`echo $CI_PROJECT_PATH | sed 's#/#-#g'`
- docker run -e PROJECTKEY=$group -e EMAIL=$GITLAB_USER_EMAIL -e BRANCH=$CI_COMMIT_REF_NAME --name send-email --rm hub.shanqu.cc/platform/send-sonar-report:latest
allow_failure:
exit_codes: 137
only:
- dev
- release
oss-upload&send-email:
tags:
- sysadm-devops
stage: oss-upload&send-email
image: hub.shanqu.cc/devops/android-apk-oss-upload:latest
variables:
GIT_STRATEGY: none
VAULT_ADDR: https://vault.shanqu.cc # 固定值
VAULT_SECRET_PATH: prod/devops/android-apk-oss-upload # 固定值
VAULT_ROLE: android-apk-oss-upload # 固定值
ENDPOINT: "tos-cn-guangzhou.ivolces.com" # 固定值
BUCKET: "sysadm-public" # 固定值
FILE_PATH: "app/build/tmp/" # APK 存放路径
Email_To_List: $EMAIL_TO_LIST # 邮件接受人列表
Email_Title: "光环助手 $CI_COMMIT_BRANCH" # 邮件标题
PIPELINE_ID: $CI_PIPELINE_ID # 流水线id
COMMIT_BRANCH: $CI_COMMIT_BRANCH # 提交分支
MAIL_MESSAGE: "[$CI_COMMIT_AUTHOR] $CI_COMMIT_MESSAGE"
needs:
- job: android_build
artifacts: true
script:
### 绑定上传参数 ###
- export OSS_PATH="release/dev/${CI_PROJECT_NAME}/$(date "+%Y/%m/%d")"
### 开启上传 ###
- /usr/local/bin/python /upload.py
### 发送邮件
- /usr/local/bin/python /ci-android-mail-jira-comment.py
only:
- dev
- feat/GHZSCY-5250
tags:
- offline-test
stage: sendmail
image: hub.shanqu.cc/library/docker:latest
dependencies: [] #禁止传递来的artifact
script:
- group=`echo $CI_PROJECT_PATH | sed 's#/#-#g'`
- docker login -u "${HARBOR_REGISTRY_USERNAME}" -p "${HARBOR_REGISTRY_PASSWORD}" "${HARBOR_REGISTRY}"
- docker run -e PROJECTKEY=$group -e EMAIL=$GITLAB_USER_EMAIL --name send-email --rm hub.shanqu.cc/platform/send-sonar-report:latest
only:
- dev

11
.gitmodules vendored
View File

@ -1,10 +1,7 @@
[submodule "libraries/LGLibrary"]
path = libraries/LGLibrary
url = ../../../android/common-library.git
url = git@git.shanqu.cc:android/common-library.git
branch = master
[submodule "vspace-bridge"]
path = vspace-bridge
url = ../../../cwzs/android/vspace-bridge.git
[submodule "ndownload"]
path = ndownload
url = ../../../android/ndownload.git
[submodule "assistant_flutter"]
path = assistant_flutter
url = git@git.shanqu.cc:halo/android/flutter-module.git

View File

@ -1,15 +0,0 @@
FROM openjdk:11-jdk
WORKDIR /project
SHELL ["/bin/bash", "-c"]
#配置SDK环境变量
ENV ANDROID_SDK_ROOT /usr/lib/sdk
ENV ANDROID_HOME /usr/lib/sdk
ENV PATH $ANDROID_SDK_ROOT:$PATH
ENV PATH=$PATH:${ANDROID_HOME}/cmdline-tools/cmdline-tools/bin/
ENV GRADLE_USER_HOME /project/.gradle
RUN source ~/.bashrc
RUN sed -i "s@http://\(deb\|security\).debian.org@https://mirrors.aliyun.com@g" /etc/apt/sources.list \
&& apt-get --quiet update --yes \
&& apt-get --quiet install --yes lib32stdc++6 lib32z1 libncurses5 util-linux bash tzdata librdkafka-dev pkgconf \
&& rm -rf /var/lib/apt/lists/*
COPY .gradle /project/.gradle

View File

@ -12,13 +12,12 @@
2. 尽量使 View 在被销毁之后仍能恢复状态,处理方式可参考 [保存界面状态](https://developer.android.com/topic/libraries/architecture/saving-states)
3. 尽量参考原有文件结构及命名规范,即以 大模块 - 小模块 的形式生成包关系
4. 遵循最小改动原则,在提交代码前务必先检查变动的代码,尽量以可控的变动规模来构成一个 commit ,以便日后追踪问题
5. Commit message 提交规范可参考 [Conventional Commits](https://www.conventionalcommits.org/zh-hans/v1.0.0/)
6. 代码规范可参考 [AOSP Java 风格](https://source.android.com/setup/contribute/code-style)
7. 尽量使用 Kotlin 来写新文件
8. 不要使用 DataBinding
9. Commit 前请确保不带入非项目必须文件,可手动修改 [.gitignore](https://stackoverflow.com/questions/8527597/how-do-i-ignore-files-in-a-directory-in-git) 文件忽略
10. 优先使用 ViewBinding 获取 View 对象
11. No AsyncTask!
5. 代码规范可参考 [AOSP Java 风格](https://source.android.com/setup/contribute/code-style)
6. 尽量使用 Kotlin 来写新文件
7. 尽量不要使用 DataBinding
8. Commit 前请确保不带入非项目必须文件,可手动修改 [.gitignore](https://stackoverflow.com/questions/8527597/how-do-i-ignore-files-in-a-directory-in-git) 文件忽略
9. 优先使用 ViewBinding 获取 View 对象
10. No AsyncTask!
### 公用部分
@ -30,7 +29,14 @@
### git 版本管理
本项目使用简化版的 git flow 来管理分支,细节请看 [光环安卓简单 git 规范](https://git.shanqu.cc/halo/android/assistant-android/-/wikis/%E5%85%89%E7%8E%AF%E5%AE%89%E5%8D%93%E7%AE%80%E5%8D%95-git-%E8%A7%84%E8%8C%83)
本项目使用简化版的 git flow 来管理分支,细节请看 [光环安卓简单 git 规范](https://git.ghzs.com/halo/android/assistant-android/-/wikis/%E5%85%89%E7%8E%AF%E5%AE%89%E5%8D%93%E7%AE%80%E5%8D%95-git-%E8%A7%84%E8%8C%83)
### API 环境配置
本项目使用 Build Variants 来切换 API 环境
* internal 为测试环境
* publish 为正式环境
### 图片资源配置
@ -46,3 +52,14 @@
* 本项目使用了微信的 [AndResGuard](https://github.com/shwenzhang/AndResGuard) 作为资源混淆压缩方案,新增需要使用 `getIdentifier` 获取的资源文件时需要添加至白名单
* 本项目默认使用 R8 作为混淆工具,往 proguard-rules.txt 添加 proguard 新配置项时请检查可用性(如语法等)
### APK打包配置
> 打内部测试包:`./scripts/test_build.sh`
> 打邮件测试包:`./scripts/jenkins_build.sh`
### TODO
* 把原有 EventBus 的消息 Type 统一到一个文件内
* 将实现细节从 View(Fragment、Activity) 剥离并以 MVVM 结构改造
* 重构 MainActivity

View File

@ -9,22 +9,12 @@ import groovy.xml.XmlUtil
android {
String CONFIG_ID = ""
String FIRST_LAUNCH = ""
String SDK_VERSION = ""
String SDK_APP_ID = ""
String SDK_APP_NAME = ""
boolean USE_DEFAULT_CHANNEL_SDK = true
int ACTIVATE_REPORTING_RATIO = 100
buildFeatures {
viewBinding true
dataBinding true
}
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
@ -53,14 +43,22 @@ android {
}
defaultConfig {
vectorDrawables.useSupportLibrary = true
multiDexEnabled true
javaCompileOptions {
annotationProcessorOptions {
arguments = [eventBusIndex: 'com.gh.EventBusIndex']
}
}
ndk {
// x86 本来是为了模拟器用户使用 RenderScript 用的,但是其实用到 RenderScript 的人本来就不多 (一天不到 100),用模拟器的人就更少了
// 加了 x86 反而会导致用户没法使用微博登录,因为微博没有提供 x86 的 SO ...
// 还会增大 APK 体积,所以还是去掉吧。数据可见 https://sentry.shanqu.cc/organizations/lightgame/issues/144232/?project=22
abiFilters "armeabi-v7a", "arm64-v8a"
// 如果不添加 `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 为例,明明设备是骁龙 615ARMv8-64 bit 的设备却不支持 arm64 的 abi限制了只使用 java 后还是报错,只有 5.05.1 设备无法复现 : (
// 惊了
abiFilters "armeabi-v7a", "arm64-v8a", "x86"
}
renderscriptTargetApi 18
@ -77,35 +75,24 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt', 'proguard-fresco.txt'
String CORE_EVENT_GAME_CATEGORY = ""
// 推广用的关键事件游戏类型
buildConfigField "String", "CORE_EVENT_GAME_CATEGORY", "\"${CORE_EVENT_GAME_CATEGORY}\""
// 推广用的配置 id
buildConfigField "String", "CONFIG_ID", "\"${CONFIG_ID}\""
// 推广用的 SDK 版本 (仅记录使用)
buildConfigField "String", "SDK_VERSION", "\"${SDK_VERSION}\""
buildConfigField "String", "SDK_APP_ID", "\"${SDK_APP_ID}\""
buildConfigField "String", "SDK_APP_NAME", "\"${SDK_APP_NAME}\""
buildConfigField "boolean", "USE_DEFAULT_CHANNEL_SDK", "${USE_DEFAULT_CHANNEL_SDK}"
// 首次启动的跳转配置
buildConfigField "String", "FIRST_LAUNCH", "\"${FIRST_LAUNCH}\""
buildConfigField "int", "ACTIVATE_REPORTING_RATIO", "${ACTIVATE_REPORTING_RATIO}"
// All third-party appid/appkey
buildConfigField "boolean", "IS_GAT_APP", "false"
/**
* All third-party appid/appkey
*/
buildConfigField "String", "API_HOST", "\"${API_HOST}\""
buildConfigField "String", "NEW_API_HOST", "\"${NEW_API_HOST}\""
buildConfigField "String", "LOG_HUB_PROJECT", "\"${LOG_HUB_PROJECT}\""
buildConfigField "String", "VAPI_HOST", "\"${VAPI_HOST}\""
buildConfigField "String", "WECHAT_APPID", "\"${WECHAT_APPID}\""
buildConfigField "String", "WECHAT_SECRET", "\"${WECHAT_SECRET}\""
buildConfigField "String", "TENCENT_APPID", "\"${TENCENT_APPID}\""
buildConfigField "String", "WEIBO_APPKEY", "\"${WEIBO_APPKEY}\""
buildConfigField "String", "QUICK_LOGIN_APPID", "\"${QUICK_LOGIN_APPID}\""
buildConfigField "String", "QUICK_LOGIN_APPKEY", "\"${QUICK_LOGIN_APPKEY}\""
/**
* Build Time 供区分 jenkins 打包时间用
* IS_NIGHT_MODE_ON 供区分夜间模式功能是否启用
*/
buildConfigField "long", "BUILD_TIME", "0"
buildConfigField "boolean", "IS_NIGHT_MODE_ON", "true"
}
// gradle 2.2以上默认同时启用v1和v2优先用于Android N
@ -120,12 +107,6 @@ android {
}
}
kapt {
arguments {
arg("AROUTER_MODULE_NAME", project.name)
}
}
buildTypes {
debug {
debuggable true
@ -156,66 +137,41 @@ android {
variantFilter { variant ->
def names = variant.flavors*.name
def isDebugType = variant.buildType.name == "debug"
if ((names.contains("tea") || name.contains("kuaishou") || name.contains("gdt")) && isDebugType) {
if ((names.contains("tea")) && isDebugType) {
setIgnore(true)
}
}
flavorDimensions("env", "region")
flavorDimensions("env")
sourceSets {
publish {
java.srcDirs = ['src/main/java', "src/default/java"]
java.srcDirs = ['src/main/java']
}
internal {
java.srcDirs = ['src/main/java', "src/default/java"]
java.srcDirs = ['src/main/java']
}
tea {
java.srcDirs = ['src/main/java', 'src/tea/java']
}
kuaishou {
java.srcDirs = ['src/main/java', 'src/kuaishou/java']
}
gdt {
java.srcDirs = ['src/main/java', 'src/gdt/java']
}
gat {
java.srcDirs = ['src/main/java', 'src/gat/java']
}
cn {
java.srcDirs = ['src/main/java', 'src/cn/java']
}
sm {
java.srcDirs = ['src/main/java', 'src/sm/java']
}
}
productFlavors {
// internal 内部测试包使用的 flavor接口包含包括测试和正式环境
// internal test dev host
internal {
dimension "env"
versionNameSuffix "-debug"
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}\""
buildConfigField "String", "QUICK_LOGIN_APPID", "\"${DEV_QUICK_LOGIN_APPID}\""
buildConfigField "String", "QUICK_LOGIN_APPKEY", "\"${DEV_QUICK_LOGIN_APPKEY}\""
buildConfigField "String", "DEV_CSJ_APPID", "\"${DEV_CSJ_APPID}\""
buildConfigField "String", "CSJ_APPID", "\"${CSJ_APPID}\""
}
// publish 发布时候使用的 flavor接口仅包含正式环境
// 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}\""
buildConfigField "String", "QUICK_LOGIN_APPID", "\"${QUICK_LOGIN_APPID}\""
buildConfigField "String", "QUICK_LOGIN_APPKEY", "\"${QUICK_LOGIN_APPKEY}\""
buildConfigField "String", "DEV_CSJ_APPID", "\"${CSJ_APPID}\""
buildConfigField "String", "CSJ_APPID", "\"${CSJ_APPID}\""
}
tea {
@ -223,69 +179,14 @@ android {
buildConfigField "String", "DEV_API_HOST", "\"${API_HOST}\""
buildConfigField "String", "NEW_DEV_API_HOST", "\"${NEW_API_HOST}\""
buildConfigField "String", "DEV_VAPI_HOST", "\"${VAPI_HOST}\""
buildConfigField "String", "QUICK_LOGIN_APPID", "\"${QUICK_LOGIN_APPID}\""
buildConfigField "String", "QUICK_LOGIN_APPKEY", "\"${QUICK_LOGIN_APPKEY}\""
buildConfigField "String", "DEV_CSJ_APPID", "\"${CSJ_APPID}\""
buildConfigField "String", "CSJ_APPID", "\"${CSJ_APPID}\""
manifestPlaceholders.put("APPLOG_SCHEME", "rangersapplog.byAx6uYt".toLowerCase())
}
}
kuaishou {
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}\""
buildConfigField "String", "QUICK_LOGIN_APPID", "\"${QUICK_LOGIN_APPID}\""
buildConfigField "String", "QUICK_LOGIN_APPKEY", "\"${QUICK_LOGIN_APPKEY}\""
buildConfigField "String", "DEV_CSJ_APPID", "\"${CSJ_APPID}\""
buildConfigField "String", "CSJ_APPID", "\"${CSJ_APPID}\""
}
gdt {
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}\""
buildConfigField "String", "QUICK_LOGIN_APPID", "\"${QUICK_LOGIN_APPID}\""
buildConfigField "String", "QUICK_LOGIN_APPKEY", "\"${QUICK_LOGIN_APPKEY}\""
buildConfigField "String", "DEV_CSJ_APPID", "\"${CSJ_APPID}\""
buildConfigField "String", "CSJ_APPID", "\"${CSJ_APPID}\""
}
sm {
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}\""
buildConfigField "String", "QUICK_LOGIN_APPID", "\"${QUICK_LOGIN_APPID}\""
buildConfigField "String", "QUICK_LOGIN_APPKEY", "\"${QUICK_LOGIN_APPKEY}\""
buildConfigField "String", "DEV_CSJ_APPID", "\"${CSJ_APPID}\""
buildConfigField "String", "CSJ_APPID", "\"${CSJ_APPID}\""
}
// 港澳台
gat {
dimension "region"
applicationId rootProject.ext.applicationIdGat
// 支持繁体
resConfigs "zh", "zh-rTW"
buildConfigField "boolean", "IS_GAT_APP", "true"
buildConfigField "String", "LOG_HUB_PROJECT", "\"${LOG_HUB_PROJECT_GAT}\""
buildConfigField "String", "API_HOST", "\"${API_HOST_GAT}\""
buildConfigField "String", "NEW_API_HOST", "\"${NEW_API_HOST_GAT}\""
}
cn {
dimension "region"
}
lintOptions {
// For flutter release build, see https://github.com/flutter/flutter/issues/58247
checkReleaseBuilds false
}
}
@ -299,45 +200,86 @@ dependencies {
implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs')
teaImplementation fileTree(include: ['*.jar', '*.aar'], dir: 'src/tea/libs')
kuaishouImplementation fileTree(include: ['*.jar', '*.aar'], dir: 'src/kuaishou/libs')
gdtImplementation fileTree(include: ['*.jar', '*.aar'], dir: 'src/gdt/libs')
smImplementation fileTree(include: ['*.jar', '*.aar'], dir: 'src/sm/libs')
testImplementation 'junit:junit:4.12'
debugImplementation "com.squareup.leakcanary:leakcanary-android:${leakcanary}"
debugImplementation "com.squareup.leakcanary:leakcanary-android-process:${leakcanary}"
debugImplementation "com.squareup.okhttp3:logging-interceptor:${okHttp}"
// debugImplementation "com.gu.android:toolargetool:${toolargetool}" // 需要使用调试时才启用
debugImplementation "com.github.nichbar:WhatTheStack:${whatTheStack}"
debugImplementation "io.github.didi.dokit:dokitx:${dokit}"
implementation "androidx.multidex:multidex:${multiDex}"
implementation "androidx.core:core-ktx:${core}"
implementation "androidx.fragment:fragment-ktx:${fragment}"
implementation "androidx.multidex:multidex:${multiDex}"
implementation "androidx.appcompat:appcompat:${appCompat}"
implementation "androidx.cardview:cardview:${cardView}"
implementation "androidx.annotation:annotation:${annotation}"
implementation "androidx.constraintlayout:constraintlayout:${constraintLayout}"
implementation "androidx.recyclerview:recyclerview:${recyclerView}"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifeCycle"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifeCycle"
implementation "androidx.lifecycle:lifecycle-common-java8:$lifeCycle"
implementation "androidx.lifecycle:lifecycle-extensions:$lifeCycleExtensions"
implementation "androidx.room:room-runtime:${room}"
implementation "androidx.room:room-rxjava2:${room}"
implementation "androidx.core:core-ktx:${ktx}"
implementation "androidx.viewpager2:viewpager2:${viewpager2}"
implementation "androidx.webkit:webkit:${webkit}"
kapt "androidx.room:room-compiler:${room}"
implementation "com.google.android.material:material:${material}"
implementation "com.kyleduo.switchbutton:library:${switchButton}"
implementation "com.tencent.vasdolly:helper:${apkChannelPackage}"
implementation "com.tencent.vasdolly:writer:${apkChannelPackage}"
implementation "com.facebook.fresco:fresco:${fresco}"
implementation "com.facebook.fresco:animated-gif-lite:${fresco}"
implementation "com.facebook.fresco:animated-drawable:${fresco}"
implementation "com.facebook.fresco:animated-webp:${fresco}"
implementation "com.facebook.fresco:webpsupport:${fresco}"
implementation "com.squareup.okhttp3:okhttp:${okHttp}"
implementation "com.leon.channel:helper:${apkChannelPackage}"
implementation "com.squareup.retrofit2:retrofit:${retrofit}"
implementation "com.squareup.retrofit2:converter-gson:${retrofit}" // include gson 2.7
implementation "com.squareup.retrofit2:adapter-rxjava2:${retrofit}"
implementation "com.j256.ormlite:ormlite-android:${ormlite}"
implementation "com.j256.ormlite:ormlite-core:${ormlite}"
implementation "org.jetbrains.kotlin:kotlin-stdlib:${kotlin_version}"
implementation "org.greenrobot:eventbus:${eventbus}"
kapt "org.greenrobot:eventbus-annotation-processor:${eventbusApt}"
implementation "io.reactivex.rxjava2:rxjava:${rxJava2}"
implementation "io.reactivex.rxjava2:rxandroid:${rxAndroid2}"
implementation "com.jakewharton.rxbinding2:rxbinding:${rxBinding2}"
implementation "com.google.zxing:core:${zxing}"
implementation "com.google.zxing:android-core:${zxing}"
implementation "com.daimajia.swipelayout:library:${swipeLayout}"
implementation "com.google.android:flexbox:${flexbox}"
implementation "pub.devrel:easypermissions:${easypermissions}"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "com.contrarywind:Android-PickerView:${pickerView}"
implementation "com.scwang.smartrefresh:SmartRefreshLayout:${smartRefreshLayout}"
implementation "net.cachapa.expandablelayout:expandablelayout:${expandableLayout}"
// 用于比较 versionName 是大于小于或等于
implementation "com.g00fy2:versioncompare:${versioncompare}"
implementation "top.zibin:Luban:${luban}"
implementation "com.squareup.picasso:picasso:${picasso}"
// for video streaming
implementation("com.github.CarGuo.GSYVideoPlayer:gsyVideoPlayer-java:$gsyVideo", {
exclude module: "gsyvideoplayer-androidvideocache"
@ -345,78 +287,60 @@ dependencies {
})
implementation "com.github.CarGuo.GSYVideoPlayer:gsyVideoPlayer-exo_player2:$gsyVideo"
implementation "androidx.work:work-runtime:${workManager}"
implementation "com.llew.huawei:verifier:${verifier}"
implementation "com.github.tbruyelle:rxpermissions:${rxPermissions}"
implementation "com.lg:skeleton:${skeleton}"
implementation "com.tencent.mm.opensdk:wechat-sdk-android-without-mta:${mta}"
implementation "com.github.nichbar:AndroidRomChecker:${romChecker}"
debugImplementation "com.github.nichbar.chucker:library:${chucker}"
releaseImplementation "com.github.nichbar.chucker:library-no-op:${chucker}"
teaImplementation "com.bytedance.applog:RangersAppLog-Lite-cn:${bytedanceApplog}"
teaImplementation "com.bytedance.applog:RangersAppLog-All-convert:${bytedanceApplog}"
implementation "com.aliyun.dpa:oss-android-sdk:${oss}"
implementation "com.airbnb.android:lottie:${lottie}"
implementation "net.lingala.zip4j:zip4j:${zip4j}"
implementation "io.sentry:sentry-android:4.3.0"
implementation("com.github.piasy:BigImageViewer:${bigImageViewer}", {
exclude group: 'com.squareup.okhttp3'
exclude group: 'androidx.swiperefreshlayout'
exclude group: 'com.github.bumptech.glide'
exclude group: 'com.facebook.fresco'
})
implementation "com.github.PhilJay:MPAndroidChart:${chart}"
implementation "com.lahm.library:easy-protector-release:${easyProtector}"
implementation "com.github.hsiafan:apk-parser:${apkParser}"
implementation "org.nanohttpd:nanohttpd:${nanohttpd}"
implementation "com.aliyun.openservices:aliyun-log-android-sdk:${aliyunLog}"
implementation "com.lg:easyfloat:${easyFloat}"
implementation "io.github.florent37:shapeofview:${shapeOfView}"
implementation "io.github.sinaweibosdk:core:${weiboSDK}"
implementation "com.lg:apksig:${apksig}"
implementation "com.lg:gid:${gid}"
implementation "com.lg:shortcut:${shortcut}"
implementation "com.louiscad.splitties:splitties-fun-pack-android-base-with-views-dsl:${splitties}"
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:${desugarJdkLibs}"
compileOnly "com.github.axen1314.lancet:lancet-base:${lancet_version}"
kapt "com.alibaba:arouter-compiler:$arouterVersion"
implementation project(':ndownload')
implementation project(':vspace-bridge:vspace')
implementation (project(':module_common')) {
exclude group: 'androidx.swiperefreshlayout'
}
implementation(project(':module_login')) {
exclude group: 'androidx.swiperefreshlayout'
}
implementation(project(':module_setting')) {
exclude group: 'androidx.swiperefreshlayout'
}
// implementation(project(':module_setting_compose')) {
// exclude group: 'androidx.swiperefreshlayout'
// }
implementation(project(':module_core_feature')) {
exclude group: 'androidx.swiperefreshlayout'
}
// implementation(project(':module_feedback')) {
// exclude group: 'androidx.swiperefreshlayout'
// }
implementation(project(':feature:new_feedback',)) {
exclude group: 'androidx.swiperefreshlayout'
}
implementation(project(':module_sensors_data')) {
exclude group: 'androidx.swiperefreshlayout'
}
implementation(project(':module_message')) {
exclude group: 'androidx.swiperefreshlayout'
}
// implementation(project(':feature:vpn'))
implementation(project(':feature:pkg'))
implementation(project(':feature:oaid'))
implementation(project(':feature:floating-window'))
implementation(project(':feature:csj_ad'))
// implementation(project(':feature:beizi_startup_ad'))
implementation(project(':feature:xapk-installer'))
implementation(project(':feature:qq_game')) {
exclude group: 'androidx.swiperefreshlayout'
}
internalImplementation(project(':module_internal_test'))
// 根据BUILD_PUSH_TYPE决定使用哪个推送SDK目前默认使用阿里云推送
def pushProject = findProperty('BUILD_PUSH_TYPE') == 'jg'
? project(':feature:jg_push') : project(':feature:acloud_push')
implementation(pushProject) {
exclude group: 'androidx.swiperefreshlayout'
}
implementation project(':libraries:LGLibrary')
implementation project(':libraries:QQShare')
implementation project(':libraries:Matisse')
}
File propFile = file('sign.properties')
if (propFile.exists()) {
Properties props = new Properties()
@ -485,13 +409,6 @@ andResGuard {
// 打开这个开关会合并所有哈希值相同的资源,但请不要过度依赖这个功能去除去冗余资源
mergeDuplicatedRes = true
whiteList = [
"R.xml.jpush*",
"R.drawable.jpush*",
"R.layout.jpush*",
"R.layout.push*",
"R.string.jg*",
"R.style.MyDialogStyle",
"R.style.JPushTheme",
"R.drawable.icon",
"R.drawable.ic_bar_back",
"R.drawable.toolbar_search_icon",
@ -513,14 +430,36 @@ andResGuard {
"R.drawable.bg_notification_reserve_game_style_2",
"R.drawable.bg_notification_video_style_1",
"R.drawable.bg_notification_video_style_2",
"R.drawable.ic_search_no_1",
"R.drawable.ic_search_no_2",
"R.drawable.ic_search_no_3",
"R.drawable.ic_search_no_4",
"R.drawable.ic_search_no_5",
"R.drawable.ic_search_no_6",
"R.drawable.ic_search_no_7",
"R.drawable.ic_search_no_8",
"R.drawable.ic_search_no_9",
"R.drawable.ic_search_no_10",
"R.drawable.ic_search_no_11",
"R.drawable.ic_search_no_12",
"R.drawable.ic_search_no_13",
"R.drawable.ic_search_no_14",
"R.drawable.ic_search_no_15",
"R.drawable.ic_search_no_16",
"R.drawable.ic_search_no_17",
"R.drawable.ic_search_no_18",
"R.drawable.ic_search_no_19",
"R.drawable.ic_search_no_20",
"R.drawable.ic_recommend_activity",
"R.drawable.ic_recommend_discount",
"R.drawable.ic_recommend_function",
"R.drawable.ic_recommend_gift",
"R.drawable.ic_recommend_role",
"R.drawable.download_button_normal_style",
"R.drawable.ic_selector_selected",
"R.drawable.ic_selector_default",
"R.drawable.login_btn_bg",
"R.drawable.ic_quick_login_check",
"R.drawable.ic_quick_login_uncheck",
"R.anim.anim_auth_in",
"R.anim.anim_auth_out",
"R.id.download_speed",
"R.id.download_percentage",
"R.id.comment",
@ -531,9 +470,6 @@ 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",
@ -542,6 +478,7 @@ andResGuard {
"R.drawable.suggest_type_function_suggest",
"R.drawable.suggest_type_article_collect",
"R.drawable.suggest_type_copyright",
"R.drawable.help_result_empty",
"R.drawable.news_comment_detail_read",
"R.drawable.news_comment_detail_comment",
"R.drawable.news_comment_detail_share",
@ -563,12 +500,7 @@ andResGuard {
"R.drawable.suggest_add_pic_icon",
"R.drawable.icon_pic_add",
"R.drawable.ask_search_input_delete",
"R.drawable.suggest_pic_delete",
"R.id.cardIv",
"R.id.cardMask",
"R.id.cardGradientMask",
"R.id.gameIconIv",
"R.id.titleContainer"
"R.drawable.suggest_pic_delete"
]
compressFilePattern = [
"*.png",
@ -577,7 +509,7 @@ andResGuard {
"*.gif",
]
sevenzip {
artifact = 'io.github.leon406:SevenZip:1.2.22.5'
artifact = 'com.tencent.mm:SevenZip:1.2.20'
}
}
@ -663,4 +595,4 @@ project.afterEvaluate {
}
}
}
}
}

Binary file not shown.

View File

@ -0,0 +1,266 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\Android\sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
#--------- remove logs start ----------------
-assumenosideeffects class com.lightgame.config.CommonDebug {
private static String getLogTag(...);
private static String getMethodName();
public static void logMethodName(...);
public static void logParams(...);
public static void logFields(...);
public static void logMethodWithParams(...);
}
#-assumenosideeffects class com.lightgame.config.CommonDebug {*;}
#-dontoptimize
#--------- remove logs end ----------------
-keepattributes *Annotation*,Signature,InnerClasses,EnclosingMethod
-dontwarn InnerClasses
# OrmLite uses reflection
-keep class com.j256.**
-keepclassmembers class com.j256.** { *; }
-keep enum com.j256.**
-keepclassmembers enum com.j256.** { *; }
-keep interface com.j256.**
-keepclassmembers interface com.j256.** { *; }
-dontwarn com.j256.**
#okhttp3
-dontwarn com.squareup.okhttp3.**
-dontwarn okio.**
-keep class com.squareup.okhttp3.** { *;}
# stetho
-keep class com.facebook.stetho.** { *; }
-dontwarn com.facebook.stetho.**
# Retrofit 2.2
# Platform calls Class.forName on types which do not exist on Android to determine platform.
-dontnote retrofit2.Platform
# Platform used when running on Java 8 VMs. Will not be used at runtime.
-dontwarn retrofit2.Platform$Java8
# Retain generic type information for use by reflection by converters and adapters.
-keepattributes Signature
# Retain declared checked exceptions for use by a Proxy instance.
-keepattributes Exceptions
# Retrofit 2.X
## https://square.github.io/retrofit/ ##
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
-keepclasseswithmembers class * {
@retrofit2.http.* <methods>;
}
# rxjava
-keep class rx.schedulers.Schedulers {
public static <methods>;
}
-keep class rx.schedulers.ImmediateScheduler {
public <methods>;
}
-keep class rx.schedulers.TestScheduler {
public <methods>;
}
-keep class rx.schedulers.Schedulers {
public static ** test();
}
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
long producerIndex;
long consumerIndex;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
long producerNode;
long consumerNode;
}
-dontwarn rx.internal.util.**
## AutoScrollViewPager
-keep class cn.trinea.android.** { *; }
-keepclassmembers class cn.trinea.android.** { *; }
-dontwarn cn.trinea.android.**
## butterknife
# Retain generated class which implement Unbinder.
#-keep public class * implements butterknife.Unbinder { public <init>(**, android.view.View); }
#
## Prevent obfuscation of types which use ButterKnife annotations since the simple name
## is used to reflectively look up the generated ViewBinding.
#-keep class butterknife.*
#-keepclasseswithmembernames class * { @butterknife.* <methods>; }
#-keepclasseswithmembernames class * { @butterknife.* <fields>; }
-dontwarn butterknife.internal.**
-keep class **$$ViewInjector { *; }
-keepnames class * { @butterknife.InjectView *;}
-dontwarn butterknife.Views$InjectViewProcessor
-dontwarn com.gc.materialdesign.views.**
# eventbus
-keepattributes *Annotation*
-keepclassmembers class ** {
@org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
# Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
<init>(java.lang.Throwable);
}
# weiboSdk
-keep class com.sina.weibo.sdk.** { *; }
-dontwarn android.webkit.WebView
-dontwarn android.webkit.WebViewClient
# app models
-keep class com.gh.common.view.** {*;}
-keep class com.gh.gamecenter.db.info.** {*;}
-keep class com.gh.gamecenter.entity.** {*;}
-keep class com.gh.gamecenter.qa.entity.** {*;}
-keep class com.gh.gamecenter.retrofit.** {*;}
-keep class com.gh.gamecenter.eventbus.** {*;}
-keep class com.gh.gamecenter.video.detail.** {*;}
-keep class * extends rx.Subscriber
#---------------------------------webview------------------------------------
-keepclassmembers class * extends android.webkit.WebViewClient {
public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
public boolean *(android.webkit.WebView, java.lang.String);
}
-keepclassmembers class * extends android.webkit.WebViewClient {
public void *(android.webkit.WebView, java.lang.String);
}
#----------------------------------------------------------------------------
##---------------Begin: proguard configuration for Gson ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# For using GSON @Expose annotation
-keepattributes *Annotation*
# Gson specific classes
-keep class sun.misc.Unsafe { *; }
#-keep class com.google.gson.stream.** { *; }
# Prevent proguard from stripping interface information from TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
-keepclassmembers enum * { *; }
##---------------End: proguard configuration for Gson ----------
# ------ bugly ---------
-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;}
# easypermission
-keepclassmembers class * {
@pub.devrel.easypermissions.AfterPermissionGranted <methods>;
}
# 重命名文件为SourceFile再配合mapping符号表可以拿到真实的类名
-renamesourcefileattribute SourceFile
# 保留源文件行号
-keepattributes SourceFile,LineNumberTable
-ignorewarnings
-keep @androidx.annotation.Keep class *
-keepclassmembers class ** {
@androidx.annotation.Keep *;
}
-keep class com.gh.loghub.** { *; }
### greenDAO 3
-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
public static java.lang.String TABLENAME;
}
-keep class **$Properties
-keep class org.greenrobot.greendao.** { *; }
# If you do not use SQLCipher:
-dontwarn org.greenrobot.greendao.database.**
# If you do not use RxJava:
-dontwarn rx.**
-dontwarn org.greenrobot.greendao.rx.**
-dontwarn org.greenrobot.greendao.**
### fastJson
-dontwarn com.alibaba.fastjson.**
-keep class com.alibaba.fastjson.** { *; }
-keepattributes Signature
-keepattributes Annotation
### AndroidX
-keep class androidx.core.app.CoreComponentFactory { *; }
#阿里云上传
-keep class com.alibaba.sdk.android.oss.** { *; }
-dontwarn okio.**
-dontwarn org.apache.commons.codec.binary.**
#视频相关
-keep class com.shuyu.gsyvideoplayer.video.** { *; }
-dontwarn com.shuyu.gsyvideoplayer.video.**
-keep class com.shuyu.gsyvideoplayer.video.base.** { *; }
-dontwarn com.shuyu.gsyvideoplayer.video.base.**
-keep class com.shuyu.gsyvideoplayer.utils.** { *; }
-dontwarn com.shuyu.gsyvideoplayer.utils.**
-keep class tv.danmaku.ijk.** { *; }
-dontwarn tv.danmaku.ijk.**
-keep public class * extends android.view.View{
*** get*();
void set*(***);
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
#穿山甲
-keep class com.bytedance.sdk.openadsdk.** { *; }
-keep public interface com.bytedance.sdk.openadsdk.downloadnew.** {*;}
-keep class com.pgl.sys.ces.* {*;}
-keep class com.gyf.immersionbar.* {*;}
-dontwarn com.gyf.immersionbar.**
-keep class com.taobao.securityjni.**{*;}
-keep class com.taobao.wireless.security.**{*;}
-keep class com.ut.secbody.**{*;}
-keep class com.taobao.dp.**{*;}
-keep class com.alibaba.wireless.security.**{*;}
-keep class com.alibaba.sdk.android.**{*;}
-keep class com.ut.**{*;}
-keep class com.ta.**{*;}
-keep class com.gh.gamecenter.TeaHelper { *; }

View File

@ -1,6 +1,26 @@
# inline getter method
-allowaccessmodification
#--------- remove logs start ----------------
-assumenosideeffects class com.lightgame.config.CommonDebug {
private static String getLogTag(...);
private static String getMethodName();
public static void logMethodName(...);
public static void logParams(...);
public static void logFields(...);
public static void logMethodWithParams(...);
}
-assumenosideeffects class com.lightgame.utils.Utils {
public static void log(...);
}
#--------- remove logs end ----------------
#--------- remove useless mtahelper class --------
-assumenosideeffects class com.gh.common.util.MtaHelper {
public static void onEvent(...);
public static void onEventWithTime(...);
public static void onEventWithBasicDeviceInfo(...);
}
#--------- remove useless mta class end ----
# TODO Dicard sourceFile in final release build but remain in internal build.
-renamesourcefileattribute SourceFile
@ -16,37 +36,69 @@
-keepclassmembers interface com.j256.* { *; }
-dontwarn com.j256.**
### app models
-keep class com.gh.gamecenter.db.info.* {*;}
-keep class com.gh.gamecenter.entity.** {<fields>;}
-keep class com.gh.gamecenter.qa.entity.** {<fields>;}
-keep class com.gh.download.DownloadDataSimpleEntity {<fields>;}
-keep class com.gh.gamecenter.floatingwindow.FloatingWindowEntity {<fields>;}
-keep class com.gh.gamecenter.BR
-keep class com.gh.gamecenter.retrofit.* {*;}
-keep class com.gh.gamecenter.eventbus.* {*;}
-keep class com.gh.gamecenter.home.gamecollection.carousel.GameCollectionStackLayout {*;}
-keep class com.gh.gamecenter.home.gamecollection.carousel.GameCollectionStackAnimation {*;}
### AutoScrollViewPager
-keep class cn.trinea.android.* { *; }
-keepclassmembers class cn.trinea.android.* { *; }
-dontwarn cn.trinea.android.**
# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
### eventbus
-keepclassmembers class * {
@org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
### Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
<init>(java.lang.Throwable);
}
# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * extends com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
### weiboSdk
-keep class com.sina.weibo.sdk.** { *; }
-dontwarn android.webkit.WebView
-dontwarn android.webkit.WebViewClient
# Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher.
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken
### wechatSdk
### TODO 这里用 com.tencent.*{*;} 不起效?但其它地方可以?
-keep class com.tencent.**{*;}
### app models
-keep class com.gh.common.view.* {*;}
-keep class com.gh.gamecenter.db.info.* {*;}
-keep class com.gh.gamecenter.entity.* {*;}
-keep class com.gh.gamecenter.qa.entity.* {*;}
-keep class com.gh.gamecenter.retrofit.* {*;}
-keep class com.gh.gamecenter.eventbus.* {*;}
-keep class com.gh.gamecenter.video.detail.* {*;}
-keep class com.gh.gamecenter.home.gamecollection.* {*;}
###
-keepclassmembers class * extends android.webkit.WebViewClient {
public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
public boolean *(android.webkit.WebView, java.lang.String);
}
-keepclassmembers class * extends android.webkit.WebViewClient {
public void *(android.webkit.WebView, java.lang.String);
}
### easypermission
-keepclassmembers class * {
@pub.devrel.easypermissions.AfterPermissionGranted <methods>;
}
# TODO What's this ?
-ignorewarnings
### Keep Annotation
-keep @androidx.annotation.Keep class *
-keepclassmembers class * {
@androidx.annotation.Keep *;
}
### 阿里云上传
-keep class com.alibaba.sdk.android.oss.* { *; }
-dontwarn okio.**
-dontwarn org.apache.commons.codec.binary.**
### 视频相关
-keep class com.shuyu.gsyvideoplayer.video.* { *; }
-dontwarn com.shuyu.gsyvideoplayer.video.**
@ -56,7 +108,7 @@
-dontwarn com.shuyu.gsyvideoplayer.utils.**
-keep class tv.danmaku.ijk.* { *; }
-dontwarn tv.danmaku.ijk.**
-keep public class * extends android.view.View {
-keep public class * extends android.view.View{
*** get*();
void set*(***);
public <init>(android.content.Context);
@ -64,35 +116,42 @@
public <init>(android.content.Context, android.util.AttributeSet, int);
}
### RecyclerView.jumpToPositionForSmoothScroller
-keep class androidx.recyclerview.widget.RecyclerView {
void jumpToPositionForSmoothScroller(int);
}
### ViewBinding 反射相关
-keep class * implements androidx.viewbinding.ViewBinding {
public static *** inflate(android.view.LayoutInflater, android.view.ViewGroup, boolean);
}
-keep class com.alibaba.sdk.android.*{*;}
-keep class com.ut.*{*;}
-keep class com.ta.*{*;}
### TEA
-keep class com.gh.gamecenter.TeaHelper { *; }
### 阿里云日志
-keep class com.aliyun.sls.android.producer.* { *; }
-keep interface com.aliyun.sls.android.producer.* { *; }
### 中国移动一键登录
-dontwarn com.cmic.sso.sdk.**
-keep class com.cmic.sso.sdk.* { *; }
### EasyFloat
-keep class com.lzf.easyfloat.* {*;}
### 广点通SDK
-dontwarn com.qq.gdt.action.**
-keep class com.qq.gdt.action.** {*;}
-keep public class com.tencent.turingfd.sdk.**
### 神马 SDK
-dontwarn com.gism.**
-keepclasseswithmembers class * {
native <methods>;
### 避免 WebChromeClient 被混淆
-keepclassmembers class * extends android.webkit.WebChromeClient{
public void openFileChooser(...);
}
-keepclassmembernames class com.contrarywind.view.WheelView {
private int itemsVisible;
### emoji4j
-keep class emoji4j.* {*;}
### dokit
-keep class com.didichuxing.** {*;}
# Flutter模块
-keep class com.gh.common.util.DirectUtils {
public static void directToQa(...);
public static void directToQaCollection(...);
public static void directToGift(...);
public static void directToConcernInfo(...);
public static void directToFeedback(...);
public static void directToSuggestion(...);
}

View File

@ -0,0 +1,32 @@
package com.gh.gamecenter;
import android.app.Application;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
/**
* @author CsHeng
* @Date 03/09/2017
* @Time 4:34 PM
*/
public class Injection {
public static boolean appInit(Application application) {
// 监控Bundle大小,预防溢出(需要调试的时候再开启吧!)
// TooLargeTool.startLogging(application);
return true;
}
public static OkHttpClient.Builder provideRetrofitBuilder() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
builder.addNetworkInterceptor(interceptor);
return builder;
}
}

View File

@ -1,40 +0,0 @@
package com.gh.gamecenter.provider
import android.app.Activity
import android.app.Application
import android.text.TextUtils
import com.gh.gamecenter.common.constant.Config
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.PackageFlavorHelper
import com.gh.gamecenter.core.provider.IFlavorProvider
import com.gh.gamecenter.core.utils.SPUtils
import com.tencent.vasdolly.helper.ChannelReaderUtil
class FlavorProviderImp : IFlavorProvider {
override fun getChannelStr(application: Application): String {
var channel = ChannelReaderUtil.getChannel(application)
if (channel == null || TextUtils.isEmpty(channel.trim())) {
channel = if (PackageFlavorHelper.IS_TEST_FLAVOR) {
Config.DEFAULT_CHANNEL
} else {
Config.DEFAULT_CHANNEL_FOR_RELEASE
}
}
if (PackageFlavorHelper.IS_TEST_FLAVOR) {
channel = SPUtils.getString(Constants.SP_TEST_FLAVOR_CHANNEL, channel)
}
return channel
}
override fun init(application: Application, activity: Activity, activateRatio: Int) {
// do nothing
}
override fun logEvent(content: String) {
// do nothing
}
override fun logCoreEvent() {
// do nothing
}
}

View File

@ -1,44 +0,0 @@
package com.gh.gamecenter
import android.app.Application
import com.lightgame.utils.Utils
import com.qq.gdt.action.ActionParam
import com.qq.gdt.action.ActionType
import com.qq.gdt.action.GDTAction
import com.qq.gdt.action.PrivateController
import org.json.JSONObject
object GdtHelper {
private const val USER_ACTION_SET_ID = "1201041887"
private const val APP_SECRET_ID = "c29cc5c48cf540c43b4b97363bb09216"
private const val KS_USER_ACTION_SET_ID = "1201032128"
private const val KS_APP_SECRET_ID = "9bdbbb81d4e0bd333a2a581f9ee36986"
@JvmStatic
fun init(application: Application, channel: String) {
GDTAction.setPrivateController(object : PrivateController() {
override fun isCanUsePhoneState(): Boolean {
return false
}
})
if (channel == "KS_GDT_GHZS_MC01") {
GDTAction.init(application, KS_USER_ACTION_SET_ID, KS_APP_SECRET_ID, channel)
} else {
GDTAction.init(application, USER_ACTION_SET_ID, APP_SECRET_ID, channel)
}
Utils.log("init GdtHelper")
}
@JvmStatic
fun logAction(type: String) {
when (type) {
"EVENT_ACTIVE" -> GDTAction.logAction(ActionType.START_APP)
"active_register" -> GDTAction.logAction(ActionType.REGISTER)
"EVENT_NEXTDAY_STAY" -> GDTAction.logAction(ActionType.START_APP, JSONObject().apply {
put(ActionParam.Key.LENGTH_OF_STAY, 1)
})
}
}
}

View File

@ -1,52 +0,0 @@
package com.gh.gamecenter.provider
import android.app.Activity
import android.app.Application
import android.text.TextUtils
import com.gh.gamecenter.GdtHelper
import com.gh.gamecenter.core.provider.IFlavorProvider
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.TimeUtils
import com.halo.assistant.HaloApp
import com.tencent.vasdolly.helper.ChannelReaderUtil
class FlavorProviderImp : IFlavorProvider {
override fun init(application: Application, activity: Activity, activateRatio: Int) {
GdtHelper.init(application, getChannelStr(application))
if (HaloApp.getInstance().isBrandNewInstall) {
logEvent("EVENT_ACTIVE")
SPUtils.setLong("TIME_OF_BRAND_NEW_INSTALL", System.currentTimeMillis() / 1000)
} else {
val shouldSendRetentionLogEvent =
SPUtils.getBoolean("SHOULD_SEND_RETENTION_EVENT", true)
val installTimeNotToday =
!TimeUtils.isToday(SPUtils.getLong("TIME_OF_BRAND_NEW_INSTALL", System.currentTimeMillis() / 1000))
if (shouldSendRetentionLogEvent && installTimeNotToday) {
logEvent("EVENT_NEXTDAY_STAY")
SPUtils.setBoolean("SHOULD_SEND_RETENTION_EVENT", false)
}
}
}
override fun getChannelStr(application: Application): String {
var channel = ChannelReaderUtil.getChannel(application)
if (channel == null || TextUtils.isEmpty(channel.trim())) {
channel = GDT_DEFAULT_CHANNEL
}
return channel
}
override fun logEvent(content: String) {
GdtHelper.logAction(content)
}
override fun logCoreEvent() {
// do nothing
}
companion object {
private const val GDT_DEFAULT_CHANNEL = "GDT_GHZS_01"
}
}

View File

@ -1,32 +0,0 @@
package com.gh.vspace
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.Keep
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.LayoutPersonalOtherItemBinding
import com.gh.vspace.installexternalgames.InstallExternalGameActivity
@Keep
class ExternalGameUsage : IExternalGamesUsage {
override fun addInstallExternalGameButton(viewParent: ViewGroup) {
val context = viewParent.context
viewParent.findViewById<View>(R.id.install_game_from_external) ?: run {
val binding = LayoutPersonalOtherItemBinding.inflate(LayoutInflater.from(context)).apply {
root.id = R.id.install_game_from_external
titleTv.text = context.getString(R.string.title_install_external_game)
iconIv.setImageResource(R.drawable.ic_personal_my_game)
root.setOnClickListener {
VHelper.connectService {
context.startActivity(
InstallExternalGameActivity.getIntent(context)
.apply { flags = flags or Intent.FLAG_ACTIVITY_NEW_TASK })
}
}
}
viewParent.addView(binding.root, 0)
}
}
}

View File

@ -1,5 +0,0 @@
package com.gh.vspace.installexternalgames;
public class Constants {
public static final String TAG = "从SD卡安装";
}

View File

@ -1,47 +0,0 @@
package com.gh.vspace.installexternalgames
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.common.utils.toBinding
class ExternalGameAdapter(private val games: List<ExternalGameUiState>, private val onItemClickListener: OnItemClickListener) :
RecyclerView.Adapter<ExternalGameViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ExternalGameViewHolder {
return ExternalGameViewHolder(parent.toBinding())
}
override fun getItemCount(): Int {
return games.size
}
override fun onBindViewHolder(holder: ExternalGameViewHolder, position: Int) {
val item = games[position]
holder.apkInfo.text = item.externalGameEntity.let { item ->
"""
应用程序名:${item.appName}
版本号:${item.apkVersion}
包名: ${item.apkPackageName}
路径:${item.apkPath}
""".trimIndent()
}
holder.install.goneIf(item.isInstalled) {
holder.install.setOnClickListener {
onItemClickListener.onItemClick(item, OnItemClickListener.ClickType.CLICK_INSTALL)
}
}
holder.uninstall.goneIf(!item.isInstalled) {
holder.uninstall.setOnClickListener {
onItemClickListener.onItemClick(
item,
OnItemClickListener.ClickType.CLICK_UNINSTALL
)
}
}
holder.start.goneIf(!item.isInstalled) {
holder.start.setOnClickListener {
onItemClickListener.onItemClick(item, OnItemClickListener.ClickType.CLICK_START)
}
}
}
}

View File

@ -1,11 +0,0 @@
package com.gh.vspace.installexternalgames
data class ExternalGameEntity(
val cpuAbi: Set<String>,
val apkPath: String,
val apkFileName: String,
val appName: String,
val apkVersion: String,
val apkPackageName: String,
val lastModified: Long,
)

View File

@ -1,6 +0,0 @@
package com.gh.vspace.installexternalgames
data class ExternalGameUiState(
val externalGameEntity: ExternalGameEntity,
val isInstalled: Boolean
)

View File

@ -1,11 +0,0 @@
package com.gh.vspace.installexternalgames
import androidx.recyclerview.widget.RecyclerView
import com.gh.gamecenter.databinding.LayoutExternalGameItemBinding
class ExternalGameViewHolder(binding: LayoutExternalGameItemBinding) : RecyclerView.ViewHolder(binding.root) {
val apkInfo = binding.apkFileInfo
val install = binding.btnInstall
val uninstall = binding.btnUninstall
val start = binding.btnStart
}

View File

@ -1,14 +0,0 @@
package com.gh.vspace.installexternalgames
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.gh.gamecenter.common.base.activity.ToolBarActivity
class InstallExternalGameActivity : ToolBarActivity() {
companion object {
fun getIntent(context: Context): Intent {
return getTargetIntent(context, InstallExternalGameActivity::class.java, InstallExternalGameFragment::class.java, Bundle())
}
}
}

View File

@ -1,153 +0,0 @@
package com.gh.vspace.installexternalgames
import android.app.Dialog
import android.os.Bundle
import androidx.recyclerview.widget.LinearLayoutManager
import com.gh.common.util.DialogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.fragment.ToolbarFragment
import com.gh.gamecenter.common.exposure.meta.MetaUtil
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.common.view.divider.HorizontalDividerItemDecoration
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.databinding.FragmentInstallExternalGamesBinding
import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.lg.vspace.VirtualAppManager
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
class InstallExternalGameFragment : ToolbarFragment(), OnItemClickListener {
private val mViewModel: InstallExternalGameViewModel by lazy { viewModelProvider() }
private lateinit var mBinding: FragmentInstallExternalGamesBinding
private val games = mutableListOf<ExternalGameUiState>()
private var adapter = ExternalGameAdapter(games, this)
private var uninstallDisposable: Disposable? = null
override fun getLayoutId() = 0
override fun getInflatedLayout() =
FragmentInstallExternalGamesBinding.inflate(layoutInflater).apply { mBinding = this }.root
private lateinit var dialog: Dialog
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setNavigationTitle(getString(com.gh.gamecenter.R.string.title_install_external_game))
initView()
mViewModel.gamesList.observe(this) {
if (dialog.isShowing) {
dialog.dismiss()
}
games.clear()
games.addAll(
it.map {
ExternalGameUiState(it, VHelper.isInstalled(it.apkPackageName))
}
)
adapter.notifyDataSetChanged()
}
mViewModel.scanPaths()
}
private fun initView() {
dialog = DialogUtils.showWaitDialog(requireContext(), "")
mBinding.externalGamesList.let {
it.adapter = adapter
it.layoutManager = LinearLayoutManager(requireContext())
val itemDecoration = HorizontalDividerItemDecoration.Builder(requireContext())
.size(2F.dip2px())
.color(R.color.ui_divider.toColor(requireContext()))
.build()
if (it.itemDecorationCount != 0) {
it.removeItemDecorationAt(0)
}
it.addItemDecoration(itemDecoration)
}
}
override fun onDestroy() {
super.onDestroy()
if (dialog.isShowing) {
dialog.dismiss()
}
if (uninstallDisposable?.isDisposed != true) {
uninstallDisposable?.dispose()
}
}
override fun onItemClick(externalGameUiState: ExternalGameUiState, clickType: OnItemClickListener.ClickType) {
when (clickType) {
OnItemClickListener.ClickType.CLICK_INSTALL -> {
install(externalGameUiState)
}
OnItemClickListener.ClickType.CLICK_UNINSTALL -> {
uninstall(externalGameUiState)
}
OnItemClickListener.ClickType.CLICK_START -> {
start(externalGameUiState)
}
}
}
private fun install(externalGameUiState: ExternalGameUiState) {
val bit =
externalGameUiState.externalGameEntity.cpuAbi.let { if (it.size == 1 && it.contains("armeabi-v7a")) "32" else "64" }
if (VHelper.showDialogIfVSpaceIsNeeded(
requireContext(),
"",
externalGameUiState.externalGameEntity.appName,
"",
bit = bit
)
) return
dialog.show()
externalGameUiState.externalGameEntity.let {
val intent = VirtualAppManager.getInstallIntent(context, it.apkPath, it.apkPackageName)
requireActivity().startActivity(intent)
}
}
private fun uninstall(externalGameUiState: ExternalGameUiState) {
dialog.show()
uninstallDisposable = Single.create<Void> {
VHelper.uninstall(externalGameUiState.externalGameEntity.apkPackageName)
}.subscribeOn(Schedulers.from(AppExecutor.lightWeightIoExecutor)).observeOn(AndroidSchedulers.mainThread())
.subscribe { t1, t2 ->
if (dialog.isShowing) {
dialog.dismiss()
}
}
}
private fun start(externalGameUiState: ExternalGameUiState) {
val intent = VirtualAppManager.get().getStartGameIntent(
externalGameUiState.externalGameEntity.apkPackageName,
"",
externalGameUiState.externalGameEntity.appName,
"",
MetaUtil.getBase64EncodedAndroidId(),
HaloApp.getInstance().gid,
com.gh.gamecenter.BuildConfig.VERSION_NAME,
HaloApp.getInstance().channel,
"",
""
)
requireActivity().startActivity(intent)
}
}

View File

@ -1,64 +0,0 @@
package com.gh.vspace.installexternalgames
import android.app.Application
import android.content.pm.PackageManager
import android.os.Environment
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.gh.gamecenter.core.runOnIoThread
import com.gh.vspace.VHelper
import com.lg.vspace.helper.compat.NativeLibraryHelperCompat
import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
class InstallExternalGameViewModel(application: Application) : AndroidViewModel(application) {
private val _gamesList = MutableLiveData<List<ExternalGameEntity>>(listOf())
val gamesList: LiveData<List<ExternalGameEntity>> = _gamesList
private val pkgManger = getApplication<Application>().packageManager
private var disposable: Disposable = VHelper.callSite.observeOn(AndroidSchedulers.mainThread()).subscribe {
scanPaths()
}
fun scanPaths() {
runOnIoThread {
_gamesList.postValue(Environment.getExternalStorageDirectory().walk().maxDepth(1)
.filter { it.isHidden.not() }
.filter { it.isFile }
.onEach {
Utils.log(Constants.TAG, "获得文件: ${it.name}")
}
.filter { it.extension == "apk" }
.map {
val packageInfo = pkgManger.getPackageArchiveInfo(
it.absolutePath,
PackageManager.GET_META_DATA or PackageManager.GET_ACTIVITIES
)
packageInfo?.let { packageInfo ->
val applicationInfo = packageInfo.applicationInfo
applicationInfo.publicSourceDir = it.absolutePath
applicationInfo.sourceDir = it.absolutePath
ExternalGameEntity(
cpuAbi = NativeLibraryHelperCompat.getPackageAbiList(it.absolutePath),
apkPath = it.absolutePath,
apkFileName = it.name,
apkPackageName = packageInfo.packageName,
apkVersion = packageInfo.versionName,
appName = pkgManger.getApplicationLabel(applicationInfo).toString(),
lastModified = it.lastModified()
)
}
}.filterNotNull()
.toList().sortedByDescending { it.lastModified }
)
}
}
override fun onCleared() {
super.onCleared()
disposable.dispose()
}
}

View File

@ -1,11 +0,0 @@
package com.gh.vspace.installexternalgames
interface OnItemClickListener {
enum class ClickType {
CLICK_INSTALL, CLICK_UNINSTALL, CLICK_START
}
fun onItemClick(externalGameUiState: ExternalGameUiState, clickType: ClickType)
}

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/external_games_list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,43 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/apk_file_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
tools:text="文件名:\n路径" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/btn_install"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text_install"
android:visibility="gone"
tools:visibility="visible" />
<Button
android:id="@+id/btn_uninstall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text_uninstall"
android:visibility="gone"
tools:visibility="visible" />
<Button
android:id="@+id/btn_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text_start"
android:visibility="gone"
tools:visibility="visible" />
</LinearLayout>
</LinearLayout>

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="title_install_external_game">從SD卡安裝</string>
<string name="text_install">安裝</string>
<string name="text_uninstall">卸載</string>
<string name="text_start">啟動</string>
</resources>

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="install_game_from_external" type="id" />
</resources>

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="title_install_external_game">从SD卡安装</string>
<string name="text_install">安装</string>
<string name="text_uninstall">卸载</string>
<string name="text_start">启动</string>
</resources>

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<!-- Trust user added CAs while debuggable only -->
<certificates src="user" />
<certificates src="system" />
</trust-anchors>
</base-config>
</network-security-config>

View File

@ -1,30 +0,0 @@
package com.gh.gamecenter
import android.content.Context
import com.kwai.monitor.log.TurboAgent
import com.kwai.monitor.log.TurboConfig
object KuaishouHelper {
private val mAppId by lazy { BuildConfig.SDK_APP_ID.ifEmpty { "81537" } }
private val mAppName by lazy { BuildConfig.SDK_APP_NAME.ifEmpty { "guanghuanzhushou_1" } }
@JvmStatic
fun init(context: Context, channel: String) {
TurboAgent.init(
TurboConfig.TurboConfigBuilder.create(context)
.setAppId(mAppId)
.setAppName(mAppName)
.setAppChannel(channel)
.build()
)
}
@JvmStatic
fun onEvent(type: String) {
when (type) {
"EVENT_ACTIVE" -> TurboAgent.onAppActive()
"active_register" -> TurboAgent.onRegister()
"EVENT_NEXTDAY_STAY" -> TurboAgent.onNextDayStay()
}
}
}

View File

@ -1,65 +0,0 @@
package com.gh.gamecenter.provider
import android.app.Activity
import android.app.Application
import android.text.TextUtils
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.KuaishouHelper
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.provider.IFlavorProvider
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.TimeUtils
import com.gh.gamecenter.core.utils.ToastUtils
import com.halo.assistant.HaloApp
import com.kwai.monitor.payload.TurboHelper
import com.tencent.vasdolly.helper.ChannelReaderUtil
class FlavorProviderImp : IFlavorProvider {
override fun init(application: Application, activity: Activity, activateRatio: Int) {
KuaishouHelper.init(application, getChannelStr(application))
if (HaloApp.getInstance().isBrandNewInstall) {
logEvent("EVENT_ACTIVE")
SPUtils.setLong("TIME_OF_BRAND_NEW_INSTALL", System.currentTimeMillis() / 1000)
} else {
val shouldSendRetentionLogEvent =
SPUtils.getBoolean("SHOULD_SEND_RETENTION_EVENT", true)
val installTimeNotToday =
!TimeUtils.isToday(SPUtils.getLong("TIME_OF_BRAND_NEW_INSTALL", System.currentTimeMillis() / 1000))
if (shouldSendRetentionLogEvent && installTimeNotToday) {
logEvent("EVENT_NEXTDAY_STAY")
SPUtils.setBoolean("SHOULD_SEND_RETENTION_EVENT", false)
}
}
}
override fun getChannelStr(application: Application): String {
var channel = if (BuildConfig.USE_DEFAULT_CHANNEL_SDK) {
ChannelReaderUtil.getChannel(application)
} else {
TurboHelper.getChannel(application)
}
if (channel == null || TextUtils.isEmpty(channel.trim())) {
channel = KUAISHOU_CHANNEL
}
return channel
}
override fun logEvent(content: String) {
KuaishouHelper.onEvent(content)
}
override fun logCoreEvent() {
logEvent("EVENT_KEY_PATH_OPTIMIZATION")
if (BuildConfig.ACTIVATE_REPORTING_RATIO == 1) {
AppExecutor.uiExecutor.executeWithDelay({
ToastUtils.toast("关键行为 EVENT_KEY_PATH_OPTIMIZATION")
}, 500)
}
}
companion object {
private const val KUAISHOU_CHANNEL = "KS-GHZS-01"
}
}

View File

@ -3,22 +3,6 @@
xmlns:tools="http://schemas.android.com/tools"
package="com.gh.gamecenter">
<queries>
<package android:name="com.gh.gamecenter" />
</queries>
<queries>
<package android:name="com.lg.vspace" />
</queries>
<!-- 华为/荣耀角标 -->
<uses-permission android:name="com.huawei.android.launcher.permission.CHANGE_BADGE "/>
<uses-permission android:name="com.hihonor.android.launcher.permission.CHANGE_BADGE" />
<!-- vivo角标 -->
<uses-permission android:name="com.vivo.notification.permission.BADGE_ICON" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
<!-- 允许应用程序访问网络连接 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 允许应用程序写入外部存储如SD卡上写文件 -->
@ -29,6 +13,10 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 允许应用程序获取网络信息状态 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 允许应用程序读取电话状态 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- 允许应用程序获取当前或最近运行的应用 -->
<uses-permission android:name="android.permission.GET_TASKS" />
<!-- 允许访问振动设备 -->
<uses-permission android:name="android.permission.VIBRATE" />
<!-- 允许应用程序改变Wi-Fi连接状态 -->
@ -37,11 +25,8 @@
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<!-- 允许应用程序快捷方式 -->
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<!-- 应用安装相关 -->
<uses-permission android:name="com.android.permission.GET_INSTALLED_APPS" />
<!-- 前台服务权限-->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission
android:name="android.permission.PACKAGE_USAGE_STATS"
@ -54,8 +39,7 @@
<!-- 如果有视频相关的广告且使用textureView播放请务必添加否则黑屏 -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-sdk tools:overrideLibrary="
com.shuyu.gsyvideoplayer,
<uses-sdk tools:overrideLibrary="com.shuyu.gsyvideoplayer,
com.shuyu.gsyvideoplayer.lib,
com.haroldadmin.whatthestack,
com.shuyu.gsyvideoplayer.armv7a,
@ -65,52 +49,13 @@
com.google.android.exoplayer2,
tv.danmaku.ijk.media.exo2,
pl.droidsonroids.gif,
com.lzf.easyfloat,
com.airbnb.lottie.compose,
androidx.compose.ui.platform,
androidx.compose.material.icons,
androidx.activity.compose,
androidx.compose.ui.tooling,
androidx.compose.ui.tooling.data,
androidx.compose.material.ripple,
androidx.compose.foundation,
androidx.compose.animation,
androidx.compose.foundation.layout,
androidx.compose.ui.text,
androidx.compose.ui.graphics,
androidx.compose.ui.unit,
androidx.compose.ui.util,
androidx.compose.ui.geometry,
androidx.compose.runtime.saveable,
androidx.compose.animation.core,
androidx.constraintlayout.compose,
androidx.compose.ui.test.manifest,
com.bytedance.sdk.openadsdk,
com.bykv.vk.openvk,
com.bytedance.tools,
androidx.compose.ui.tooling.preview,
com.tencent.qqmini,
com.tencent.qqmini.minigame.external,
com.tencent.qqmini.minigame.opensdk,
com.tencent.qqmini.union.ad" />
com.lzf.easyfloat" />
<!-- 去掉 SDK 一些流氓权限 -->
<uses-permission
android:name="android.permission.READ_CONTACTS"
tools:node="remove" />
<uses-permission
android:name="android.permission.READ_PHONE_STATE"
tools:node="remove" />
<uses-permission
android:name="android.permission.GET_TASKS"
tools:node="remove" />
<uses-permission
android:name="android.permission.ACCESS_COARSE_LOCATION"
tools:node="remove" />
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
@ -126,16 +71,10 @@
android:label="@string/app_name"
android:largeHeap="true"
android:networkSecurityConfig="@xml/network_security_config"
android:preserveLegacyExternalStorage="true"
android:requestLegacyExternalStorage="true"
android:resizeableActivity="true"
android:theme="@style/AppCompatTheme.APP"
tools:replace="android:name,android:allowBackup"
tools:targetApi="r">
<meta-data
android:name="EasyGoClient"
android:value="true" />
tools:targetApi="n">
<meta-data
android:name="io.sentry.auto-init"
@ -146,8 +85,6 @@
android:name="io.sentry.breadcrumbs.system-events"
android:value="false" />
<service android:name="com.gh.ndownload.NDownloadService" />
<activity
android:name="com.gh.gamecenter.SplashScreenActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
@ -164,15 +101,10 @@
<activity
android:name="com.gh.gamecenter.MainActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:exported="true"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:theme="@style/AppCompatTheme.APP"
android:windowSoftInputMode="stateAlwaysHidden|adjustResize">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
</intent-filter>
</activity>
android:windowSoftInputMode="stateAlwaysHidden|adjustResize" />
<activity
android:name="com.gh.gamecenter.DownloadManagerActivity"
@ -204,7 +136,11 @@
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.newsdetail.NewsDetailActivity"
android:name="com.gh.gamecenter.NewsDetailActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.SettingActivity"
android:screenOrientation="portrait" />
<activity
@ -230,7 +166,7 @@
<activity
android:name="com.gh.gamecenter.WebActivity"
android:screenOrientation="portrait" />
android:screenOrientation="portrait"/>
<activity
android:name="com.gh.gamecenter.SingletonWebActivity"
@ -259,7 +195,7 @@
android:windowSoftInputMode="stateHidden" />
<activity
android:name="com.gh.gamecenter.libao.LibaoDetailActivity"
android:name="com.gh.gamecenter.LibaoDetailActivity"
android:screenOrientation="portrait" />
<activity
@ -274,6 +210,18 @@
android:name="com.gh.gamecenter.SelectUserIconActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.AboutActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.security.SecurityActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.security.BindPhoneActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.CommentDetailActivity"
android:screenOrientation="portrait"
@ -288,10 +236,13 @@
android:configChanges="orientation|screenSize|keyboardHidden"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.SuggestionActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.VoteActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateAlwaysHidden|adjustPan" />
android:windowSoftInputMode="stateAlwaysHidden|adjustResize" />
<activity
android:name="com.gh.gamecenter.WeiBoShareActivity"
@ -306,6 +257,11 @@
android:name=".category.CategoryListActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.LoginActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateHidden" />
<activity
android:name="com.gh.gamecenter.UserInfoActivity"
android:screenOrientation="portrait" />
@ -318,19 +274,55 @@
android:name="com.gh.gamecenter.CollectionActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.MessageActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.UserInfoEditActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateHidden" />
<activity
android:name="com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity"
android:screenOrientation="portrait" />
<activity
android:name=".qa.answer.fold.AnswerFoldActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.qa.answer.edit.AnswerEditActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.ConcernInfoActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.InfoActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.MessageKeFuActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.MessageInviteActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.MessageVoteActivity"
android:screenOrientation="portrait" />
<activity
android:name=".qa.questions.invite.QuestionsInviteActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.qa.myqa.MyAskActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.qa.questions.edit.QuestionEditActivity"
android:screenOrientation="portrait" />
@ -352,6 +344,10 @@
android:name="com.gh.gamecenter.amway.AmwayActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.NetworkDiagnosisActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.personalhome.fans.FansActivity"
android:screenOrientation="portrait" />
@ -368,6 +364,10 @@
android:name="com.gh.gamecenter.qa.article.edit.ArticleEditActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.qa.article.MyArticleActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.qa.article.draft.ArticleDraftActivity"
android:screenOrientation="portrait" />
@ -376,6 +376,10 @@
android:name="com.gh.gamecenter.qa.article.detail.ArticleDetailActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.qa.article.detail.comment.ArticleDetailCommentActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.qa.draft.CommunityDraftWrapperActivity"
android:screenOrientation="portrait" />
@ -406,6 +410,10 @@
android:name="com.gh.gamecenter.history.HistoryActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.personalhome.rating.RatingActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.gamedetail.rating.logs.CommentLogsActivity"
android:screenOrientation="portrait" />
@ -431,6 +439,10 @@
android:name="com.gh.gamecenter.qa.editor.LocalMediaActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.mygame.PlayedGameActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.servers.GameServersActivity"
android:screenOrientation="portrait" />
@ -447,6 +459,15 @@
android:name="com.halo.assistant.fragment.user.UserPortraitCropImageActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.HelpAndFeedbackActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateHidden" />
<activity
android:name="com.gh.gamecenter.help.HelpDetailActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.qa.comment.CommentActivity"
android:theme="@style/Theme.Transparent"
@ -471,13 +492,12 @@
android:screenOrientation="portrait" />
<activity
android:name=".gamedetail.fuli.kaifu.ServersCalendarManagementActivity"
android:name="com.gh.gamecenter.QaActivity"
android:screenOrientation="portrait" />
<activity
android:name=".gamedetail.fuli.kaifu.ServersSubscribedGameListActivity"
android:name=".qa.answer.draft.AnswerDraftActivity"
android:screenOrientation="portrait" />
<activity
android:name=".gamedetail.rating.RatingFoldActivity"
android:screenOrientation="portrait" />
@ -489,6 +509,14 @@
android:name=".video.poster.PosterEditActivity"
android:screenOrientation="portrait" />
<activity
android:name=".video.poster.PosterClipActivity"
android:screenOrientation="portrait" />
<activity
android:name=".forum.select.ForumSelectActivity"
android:screenOrientation="portrait" />
<activity
android:name=".forum.detail.ForumDetailActivity"
android:screenOrientation="portrait" />
@ -542,6 +570,19 @@
android:name=".forum.search.ForumOrUserSearchActivity"
android:screenOrientation="portrait" />
<activity
android:name=".energy.EnergyCenterActivity"
android:launchMode="singleTask"
android:screenOrientation="portrait" />
<activity
android:name=".energy.EnergyHouseActivity"
android:screenOrientation="portrait" />
<activity
android:name=".personal.NewPersonalActivity"
android:screenOrientation="portrait" />
<activity
android:name=".qa.questions.draft.QuestionDraftActivity"
android:screenOrientation="portrait" />
@ -566,6 +607,14 @@
android:name=".qa.video.publish.VideoPublishActivity"
android:screenOrientation="portrait" />
<activity
android:name=".setting.GameDownloadSettingActivity"
android:screenOrientation="portrait" />
<activity
android:name=".setting.VideoSettingActivity"
android:screenOrientation="portrait" />
<activity
android:name=".qa.video.detail.ForumVideoDetailActivity"
android:screenOrientation="portrait" />
@ -594,10 +643,6 @@
android:name=".game.commoncollection.detail.CommonCollectionDetailActivity"
android:screenOrientation="portrait" />
<activity
android:name=".game.commoncollection.detail.CustomCommonCollectionDetailActivity"
android:screenOrientation="portrait" />
<activity
android:name=".gamecollection.detail.GameCollectionDetailActivity"
android:screenOrientation="portrait" />
@ -606,6 +651,14 @@
android:name=".gamecollection.detail.GameCollectionPosterActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.cmic.sso.sdk.activity.LoginAuthActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:theme="@android:style/Theme.Dialog" />
<activity
android:name=".home.skip.PackageSkipActivity"
android:screenOrientation="portrait" />
@ -618,8 +671,8 @@
<!-- android:theme="@android:style/Theme.Translucent" />-->
<activity
android:name="com.gh.gamecenter.SkipActivity"
android:exported="true"
android:name="com.gh.gamecenter.SkipActivity"
android:theme="@style/Theme.AppCompat.Light.Fullscreen.Transparent">
<intent-filter>
<data android:scheme="ghzhushou" />
@ -638,19 +691,6 @@
</intent-filter>
</activity>
<!-- 光环助手授权登陆页面 -->
<activity
android:name=".authorization.AuthorizationActivity"
android:exported="true"
android:launchMode="singleTask"
android:screenOrientation="portrait">
<intent-filter>
<data android:scheme="ghzhushou_authorization" />
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.VIEW" />
</intent-filter>
</activity>
<activity
android:name="com.gh.gamecenter.teenagermode.TeenagerModeActivity"
android:screenOrientation="portrait" />
@ -689,17 +729,7 @@
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.toolbox.ToolBoxActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.vspace.VDownloadManagerActivity"
android:launchMode="singleTask"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.vspace.VSpaceLoadingActivity"
android:launchMode="singleTask"
android:name="com.gh.gamecenter.toolbox.ToolBoxBlockActivity"
android:screenOrientation="portrait" />
<activity
@ -707,71 +737,11 @@
android:screenOrientation="portrait" />
<activity
android:name=".qa.comment.NewCommentDetailActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.mypost.MyPostActivity"
android:screenOrientation="portrait" />
<activity
android:name=".VerifyPhoneActivity"
android:screenOrientation="portrait" />
<activity
android:name=".BbsCertificationActivity"
android:screenOrientation="portrait" />
<activity
android:name=".discovery.DiscoveryActivity"
android:screenOrientation="portrait" />
<activity
android:name=".cloudarchive.CloudArchiveManagerActivity"
android:screenOrientation="portrait" />
<activity
android:name=".savegame.GameArchiveListActivity"
android:screenOrientation="portrait" />
<activity
android:name=".discovery.interestedgame.InterestedGameActivity"
android:screenOrientation="portrait" />
<activity
android:name=".servers.gametest2.GameServerTestV2Activity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.gamecollection.hotlist.GameCollectionHotListActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.qgame.QGameHomeWrapperActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.qgame.QGameSearchActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.gamecollection.hotlist.GameCollectionListDetailActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.UserAuthActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.SplashAdActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.gh.gamecenter.wrapper.ToolbarWrapperActivity"
android:screenOrientation="portrait" />
<activity android:name=".forum.home.CommunityActivity"
android:screenOrientation="portrait"/>
android:name="${applicationId}.wxapi.WXEntryActivity"
android:exported="true"
android:label="@string/app_name"
android:launchMode="singleTop"
android:theme="@android:style/Theme.Translucent.NoTitleBar"></activity>
<!-- <activity-->
<!-- android:name="${applicationId}.douyinapi.DouYinEntryActivity"-->
@ -793,42 +763,20 @@
android:name="com.gh.gamecenter.provider.GhContentProvider"
android:authorities="${applicationId}.provider"
android:enabled="true"
android:exported="true" />
android:exported="true"/>
<provider
android:name="com.gh.vspace.VFileProvider"
android:authorities="${applicationId}.virtual_file_provider"
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
android:grantUriPermissions="true">
tools:node="merge">
<!-- If you are using androidx.startup to initialize other components -->
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup"
tools:node="remove" />
</provider>
<service
android:name=".aidl.CommunicationService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.gh.gamecenter.aidl.CommunicationService" />
</intent-filter>
</service>
<!-- <provider-->
<!-- android:name="androidx.startup.InitializationProvider"-->
<!-- android:authorities="${applicationId}.androidx-startup"-->
<!-- android:exported="false"-->
<!-- tools:node="merge">-->
<!-- &lt;!&ndash; If you are using androidx.startup to initialize other components &ndash;&gt;-->
<!-- <meta-data-->
<!-- android:name="androidx.work.WorkManagerInitializer"-->
<!-- android:value="androidx.startup"-->
<!-- tools:node="remove" />-->
<!-- </provider>-->
<service android:name="com.gh.gamecenter.install.InstallService" />
<receiver
android:name="com.gh.gamecenter.receiver.DownloadReceiver"
android:exported="false">
@ -844,11 +792,6 @@
</intent-filter>
</receiver>
<activity
android:name="com.gh.common.xapk.XapkInstallReceiver"
android:exported="false"
android:theme="@style/Theme.Transparent" />
<receiver
android:name="com.gh.gamecenter.receiver.ActivitySkipReceiver"
android:exported="true">
@ -856,6 +799,40 @@
<action android:name="com.gh.gamecenter.ACTIVITYSKIP" />
</intent-filter>
</receiver>
<!-- 梦工厂配置 开始 -->
<!--<meta-data
android:name="MGC_APPID"
android:value="1001276" />
<provider
android:name="com.leto.game.base.provider.LetoFileProvider"
android:authorities="${applicationId}.leto.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/leto_file_path"
tools:replace="android:resource" />
</provider>-->
<!-- 梦工厂配置 结束 -->
<!-- 穿山甲配置 开始 -->
<!--<provider
android:name="com.bytedance.sdk.openadsdk.TTFileProvider"
android:authorities="${applicationId}.TTFileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<provider
android:name="com.bytedance.sdk.openadsdk.multipro.TTMultiProvider"
android:authorities="${applicationId}.TTMultiProvider"
android:exported="false" />-->
<!-- 穿山甲配置 结束 -->
</application>
</manifest>

View File

@ -1,27 +0,0 @@
{
"easyGoVersion": "1.0",
"client": "com.gh.gamecenter",
"logicEntities": [
{
"head": {
"function": "magicwindow",
"required": "true"
},
"body": {
"mode":"1",
"activityPairs":[
{"from":"com.gh.gamecenter.MainActivity","to":"*"}
],
"defaultDualActivities": {
"mainPages": "com.gh.gamecenter.MainActivity"
},
"UX": {
"supportRotationUxCompat": "false",
"isDraggable": "true"
},
"transActivities":[
]
}
}
]
}

View File

@ -6,6 +6,8 @@
<link rel="stylesheet" type="text/css" href="normalize.css">
<link rel="stylesheet" type="text/css" href="style.css">
<link rel="stylesheet" type="text/css" href="video-js.min.css">
<!-- <link rel="stylesheet" href="https://static-web.ghzs.com/website-static/lib/video-js.min.css">--> <!--在web页面播放视频-->
<!--<link rel="stylesheet" type="text/css" href="https://resource.ghzs.com/css/halo_app.css">-->
</head>
<body style="overflow-x: hidden; word-break: break-all;">
@ -13,5 +15,8 @@
<script type="text/javascript" src="zepto.min.js"></script>
<script type="text/javascript" src="rich_editor.js"></script>
<script type="text/javascript" src="video.min.js"></script>
<!--<script src="https://static-web.ghzs.com/website-static/lib/video.min.js"></script>--> <!--在web页面播放视频-->
<!--<script type="text/javascript" src="content.js"></script>-->
<!--<script type="text/javascript" src="https://resource.ghzs.com/js/halo_app.js"></script>-->
</body>
</html>

View File

@ -0,0 +1 @@
{"v":"5.5.9","fr":60,"ip":0,"op":90,"w":1080,"h":202,"nm":"click","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"椭圆形","sr":1,"ks":{"o":{"a":0,"k":20,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[204,1455,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":[24,24],"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":120,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"椭圆形","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":63,"s":[10]},{"t":70,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[204,1455,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":39,"s":[100,100,100]},{"t":49,"s":[110,110,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[36,36],"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":120,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"圆环","refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.531],"y":[0]},"t":28,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":38,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.526],"y":[0]},"t":48,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.446],"y":[0]},"t":63,"s":[50]},{"t":82,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[125.951,79.658,0],"ix":2},"a":{"a":0,"k":[205.951,1458.658,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.601,0.601,0.333],"y":[0,0,0]},"t":28,"s":[50,50,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.528,0.528,0.333],"y":[0,0,0]},"t":38,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.526,0.526,0.333],"y":[0,0,0]},"t":48,"s":[120,120,100]},{"t":63,"s":[100,100,100]}],"ix":6}},"ao":0,"w":1080,"h":1920,"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"点击手","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.596],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":10,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.515],"y":[0]},"t":63,"s":[100]},{"t":83,"s":[0]}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.507],"y":[0]},"t":10,"s":[6]},{"t":30,"s":[2]}],"ix":10},"p":{"a":0,"k":[178.982,123.325,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.489,0.489,0.333],"y":[0,0,0]},"t":10,"s":[100,100,100]},{"t":30,"s":[90,90,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-5.33,-8.3],[3.89,0.27],[-4.4,-1.68],[-4.33,-0.67],[-4.08,9.32],[3.33,5.44],[3.39,4.6],[0.87,-3.7],[3.6,-0.86],[1.03,-0.21],[2.34,-0.53],[0.96,1.15],[4.22,5.48],[-1.18,-4.56]],"o":[[1.11,1.71],[-3.89,-0.27],[6.42,2.5],[4.33,0.66],[1.63,-5.32],[-3.34,-5.45],[-1.68,-2.1],[-0.71,3.14],[-3.43,0.95],[-0.57,0.08],[-3.86,1.12],[-3.23,-3.94],[-1.89,-2.28],[2.42,4.64]],"v":[[-5.387,9.698],[-10.717,8.498],[-12.327,15.628],[5.813,21.748],[23.313,11.778],[20.273,-1.202],[11.563,-13.962],[5.393,-12.362],[1.083,-13.722],[-2.087,-9.742],[-5.707,-11.752],[-8.777,-7.572],[-18.297,-20.542],[-23.827,-17.832]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","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":"路径备份 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0}],"markers":[]}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
{"v":"5.6.4","fr":25,"ip":0,"op":35,"w":1080,"h":214,"nm":"点赞","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"椭圆形 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.588],"y":[0]},"t":17,"s":[15]},{"t":20,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[468.04,73.68,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.659,0.659,0.333],"y":[0,0,0]},"t":10,"s":[50,50,100]},{"t":19,"s":[150,150,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[24,24],"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":10,"op":1510,"st":10,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"椭圆形 3","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.588],"y":[0]},"t":27,"s":[15]},{"t":30,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[468.04,73.68,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.659,0.659,0.333],"y":[0,0,0]},"t":20,"s":[50,50,100]},{"t":28,"s":[140,140,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[24,24],"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":20,"op":1520,"st":20,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"路径备份 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.602],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":5,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.663],"y":[0]},"t":24,"s":[100]},{"t":29,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[531.02,129.675,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.514,0.514,0.333],"y":[0,0,0]},"t":5,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.533,0.533,0.333],"y":[0,0,0]},"t":10,"s":[90,90,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.586,0.586,0.333],"y":[0,0,0]},"t":15,"s":[95,95,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.499,0.499,0.333],"y":[0,0,0]},"t":19,"s":[90,90,100]},{"t":24,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-5.33,-8.3],[3.89,0.27],[-4.4,-1.68],[-4.33,-0.67],[-4.08,9.32],[3.33,5.44],[3.39,4.6],[0.87,-3.7],[3.6,-0.86],[1.03,-0.21],[2.34,-0.53],[0.96,1.15],[4.22,5.48],[-1.18,-4.56]],"o":[[1.11,1.71],[-3.89,-0.27],[6.42,2.5],[4.33,0.66],[1.63,-5.32],[-3.34,-5.45],[-1.68,-2.1],[-0.71,3.14],[-3.43,0.95],[-0.57,0.08],[-3.86,1.12],[-3.23,-3.94],[-1.89,-2.28],[2.42,4.64]],"v":[[-5.387,9.698],[-10.717,8.498],[-12.327,15.628],[5.813,21.748],[23.313,11.778],[20.273,-1.202],[11.563,-13.962],[5.393,-12.362],[1.083,-13.722],[-2.087,-9.742],[-5.707,-11.752],[-8.777,-7.572],[-18.297,-20.542],[-23.827,-17.832]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","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":"路径备份 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1500,"st":0,"bm":0}],"markers":[]}

View File

@ -1 +0,0 @@
{"v":"5.9.1","fr":60,"ip":0,"op":100,"w":64,"h":64,"nm":"多版本下载提示_dark","ddd":0,"assets":[{"id":"comp_0","nm":"arrow 合成_dark","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"arrow","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.333],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":24,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":76,"s":[100]},{"t":100,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.333,"y":1},"o":{"x":0.364,"y":0},"t":0,"s":[28,-12,0],"to":[0,6.382,0],"ti":[0,-0.284,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":24,"s":[28,28,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.667,"y":0},"t":76,"s":[28,28,0],"to":[0,6.667,0],"ti":[0,-6.667,0]},{"t":100,"s":[28,68,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":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,2],[0,-2]],"c":false},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2,0],[0,2]],"c":false},"ix":2},"nm":"路径 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[2,0],[0,2]],"c":false},"ix":2},"nm":"路径 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.333,0.333],"y":[1,1]},"o":{"x":[0.333,0.333],"y":[0,0]},"t":0,"s":[80,120]},{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.667,0.667],"y":[0,0]},"t":24,"s":[100,100]},{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.667,0.667],"y":[0,0]},"t":76,"s":[100,100]},{"t":100,"s":[80,120]}],"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":"组 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.156862750649,0.533333361149,0.878431379795,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"stroke","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":[400,400],"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":"Vector 97","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":100,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"arrow 合成_dark","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[32,32,0],"ix":2,"l":2},"a":{"a":0,"k":[28,28,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":56,"h":56,"ip":0,"op":100,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"base","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[32,32,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":[15,15],"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.156862750649,0.533333361149,0.878431379795,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"stroke","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.137254908681,0.137254908681,0.137254908681,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,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[400,400],"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":"Ellipse 44","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":100,"st":0,"bm":0}],"markers":[]}

View File

@ -1 +0,0 @@
{"v":"5.9.1","fr":60,"ip":0,"op":100,"w":64,"h":64,"nm":"多版本下载提示_light","ddd":0,"assets":[{"id":"comp_0","nm":"arrow 合成_light","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"arrow","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.333],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":24,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.667],"y":[0]},"t":76,"s":[100]},{"t":100,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.333,"y":1},"o":{"x":0.364,"y":0},"t":0,"s":[28,-12,0],"to":[0,6.382,0],"ti":[0,-0.284,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":24,"s":[28,28,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.667,"y":0},"t":76,"s":[28,28,0],"to":[0,6.667,0],"ti":[0,-6.667,0]},{"t":100,"s":[28,68,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":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,2],[0,-2]],"c":false},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2,0],[0,2]],"c":false},"ix":2},"nm":"路径 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[2,0],[0,2]],"c":false},"ix":2},"nm":"路径 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.333,0.333],"y":[1,1]},"o":{"x":[0.333,0.333],"y":[0,0]},"t":0,"s":[80,120]},{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.667,0.667],"y":[0,0]},"t":24,"s":[100,100]},{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.667,0.667],"y":[0,0]},"t":76,"s":[100,100]},{"t":100,"s":[80,120]}],"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":"组 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.141176477075,0.588235318661,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"stroke","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":[400,400],"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":"Vector 97","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":100,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"arrow 合成_light","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[32,32,0],"ix":2,"l":2},"a":{"a":0,"k":[28,28,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":56,"h":56,"ip":0,"op":100,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"base","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[32,32,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":[15,15],"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.141176477075,0.588235318661,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"stroke","mn":"ADBE Vector Graphic - Stroke","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":"filling","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":[400,400],"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":"Ellipse 44","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":100,"st":0,"bm":0}],"markers":[]}

View File

@ -1 +0,0 @@
{"v":"5.9.1","fr":60,"ip":0,"op":60,"w":144,"h":144,"nm":"icon_change","ddd":0,"assets":[{"id":"comp_0","nm":"icon_change_detail","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"stroke1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[37.04,52.994,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":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.533,-0.143],[0.143,-0.533],[1.487,-1.304],[1.961,-0.258],[1.774,0.875],[0.709,0.661],[0,0],[0,0.445],[0,0],[-0.276,0],[0,0],[-0.013,0],[0,0],[0.315,-0.315],[0,0],[-0.682,-0.336],[-1.569,0.207],[-1.19,1.043],[-0.41,1.528]],"o":[[0.533,0.143],[-0.512,1.91],[-1.487,1.304],[-1.961,0.258],[-0.879,-0.433],[0,0],[-0.315,0.315],[0,0],[0,-0.276],[0,0],[0.013,0],[0,0],[0.445,0],[0,0],[0.555,0.508],[1.419,0.7],[1.569,-0.207],[1.19,-1.043],[0.143,-0.533]],"v":[[8.605,-4.301],[9.312,-3.076],[6.247,1.854],[0.958,4.25],[-4.77,3.304],[-7.163,1.652],[-8.493,2.982],[-9.347,2.628],[-9.347,-1.665],[-8.847,-2.165],[-8.161,-2.165],[-8.122,-2.165],[-4.554,-2.165],[-4.2,-1.311],[-5.748,0.237],[-3.885,1.51],[0.697,2.267],[4.928,0.35],[7.381,-3.594]],"c":true},"ix":2},"nm":"stroke1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,1,1,1,0.5,1,1,1,1,1,1,1,0,1,0.5,0.8,1,0.6],"ix":9}},"s":{"a":0,"k":[-5.347,-4.665],"ix":5},"e":{"a":0,"k":[8.653,-4.665],"ix":6},"t":1,"nm":"color1","mn":"ADBE Vector Graphic - G-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":"stroke1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"stroke2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[34.96,19.006,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":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.961,0.258],[-1.774,-0.875],[-0.709,-0.661],[0,0],[0,-0.445],[0,0],[0.276,0],[0,0],[0.012,0],[0,0],[-0.315,0.315],[0,0],[0.682,0.336],[1.569,-0.207],[1.19,-1.043],[0.41,-1.528],[0.533,0.143],[-0.143,0.533],[-1.487,1.304]],"o":[[1.961,-0.258],[0.879,0.433],[0,0],[0.315,-0.315],[0,0],[0,0.276],[0,0],[-0.012,0],[0,0],[-0.445,0],[0,0],[-0.555,-0.508],[-1.419,-0.7],[-1.569,0.207],[-1.19,1.043],[-0.143,0.533],[-0.533,-0.143],[0.512,-1.91],[1.487,-1.304]],"v":[[-0.958,-4.25],[4.77,-3.304],[7.163,-1.652],[8.493,-2.982],[9.347,-2.628],[9.347,1.665],[8.847,2.165],[8.16,2.165],[8.123,2.165],[4.554,2.165],[4.2,1.311],[5.748,-0.237],[3.885,-1.51],[-0.697,-2.267],[-4.928,-0.35],[-7.381,3.594],[-8.605,4.301],[-9.312,3.076],[-6.247,-1.854]],"c":true},"ix":2},"nm":"stroke2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,1,1,1,0.5,1,1,1,1,1,1,1,0,1,0.5,0.8,1,0.6],"ix":9}},"s":{"a":0,"k":[5.347,4.665],"ix":5},"e":{"a":0,"k":[-8.653,4.665],"ix":6},"t":1,"nm":"color2","mn":"ADBE Vector Graphic - G-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":"stroke2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":300,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"icon_change_detail","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.5],"y":[1]},"o":{"x":[0.5],"y":[0]},"t":0,"s":[0]},{"t":36,"s":[360]}],"ix":10},"p":{"a":0,"k":[72,72,0],"ix":2,"l":2},"a":{"a":0,"k":[36,36,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":72,"h":72,"ip":0,"op":300,"st":0,"bm":0}],"markers":[]}

View File

@ -1 +0,0 @@
{"v":"5.9.1","fr":60,"ip":0,"op":60,"w":72,"h":72,"nm":"icon_title_change","ddd":0,"assets":[{"id":"comp_0","nm":"arrow","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"arrow_e_dark","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[29.25,30,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":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.701,0.456],[-1.627,-0.674],[-0.705,-0.667],[0,0],[-0.552,0],[0,-0.552],[0,0],[0.552,0],[0,0],[0.012,0],[0,0],[0,0.552],[-0.552,0],[0,0],[0.615,0.255],[1.276,-0.342],[0.804,-1.048],[0,-1.321],[-0.804,-1.048],[-1.276,-0.342],[-1.22,0.505],[-0.66,1.144],[-0.478,-0.276],[0.276,-0.478],[1.627,-0.674],[1.701,0.456],[1.072,1.397],[0,1.761],[-1.072,1.397]],"o":[[1.701,-0.456],[0.909,0.376],[0,0],[0,-0.552],[0.552,0],[0,0],[0,0.552],[0,0],[-0.012,0],[0,0],[-0.552,0],[0,-0.552],[0,0],[-0.493,-0.435],[-1.22,-0.505],[-1.276,0.342],[-0.804,1.048],[0,1.321],[0.804,1.048],[1.276,0.342],[1.22,-0.505],[0.276,-0.478],[0.478,0.276],[-0.881,1.525],[-1.627,0.674],[-1.701,-0.456],[-1.072,-1.397],[0,-1.761],[1.072,-1.397]],"v":[[-1.821,-7.727],[3.311,-7.391],[5.75,-5.809],[5.75,-6.5],[6.75,-7.5],[7.75,-6.5],[7.75,-3.5],[6.75,-2.5],[6.331,-2.5],[6.295,-2.5],[3.75,-2.5],[2.75,-3.5],[3.75,-4.5],[4.219,-4.5],[2.546,-5.543],[-1.303,-5.796],[-4.51,-3.653],[-5.75,0],[-4.51,3.653],[-1.303,5.796],[2.546,5.543],[5.446,3],[6.812,2.634],[7.178,4],[3.311,7.391],[-1.821,7.727],[-6.097,4.87],[-7.75,0],[-6.097,-4.87]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.158117651939,0.532358944416,0.878431379795,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":"arrow_e_dark","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":300,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"arrow","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.5],"y":[1]},"o":{"x":[0.5],"y":[0]},"t":0,"s":[0]},{"t":36,"s":[360]}],"ix":10},"p":{"a":0,"k":[36,36,0],"ix":2,"l":2},"a":{"a":0,"k":[30,30,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":60,"h":60,"ip":0,"op":300,"st":0,"bm":0}],"markers":[]}

View File

@ -1 +0,0 @@
{"v":"5.9.1","fr":60,"ip":0,"op":60,"w":72,"h":72,"nm":"icon_title_change","ddd":0,"assets":[{"id":"comp_0","nm":"arrow","fr":60,"layers":[{"ddd":0,"ind":2,"ty":4,"nm":"arrow_e_light","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[29.25,30,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":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.701,0.456],[-1.627,-0.674],[-0.705,-0.667],[0,0],[-0.552,0],[0,-0.552],[0,0],[0.552,0],[0,0],[0.012,0],[0,0],[0,0.552],[-0.552,0],[0,0],[0.615,0.255],[1.276,-0.342],[0.804,-1.048],[0,-1.321],[-0.804,-1.048],[-1.276,-0.342],[-1.22,0.505],[-0.66,1.144],[-0.478,-0.276],[0.276,-0.478],[1.627,-0.674],[1.701,0.456],[1.072,1.397],[0,1.761],[-1.072,1.397]],"o":[[1.701,-0.456],[0.909,0.376],[0,0],[0,-0.552],[0.552,0],[0,0],[0,0.552],[0,0],[-0.012,0],[0,0],[-0.552,0],[0,-0.552],[0,0],[-0.493,-0.435],[-1.22,-0.505],[-1.276,0.342],[-0.804,1.048],[0,1.321],[0.804,1.048],[1.276,0.342],[1.22,-0.505],[0.276,-0.478],[0.478,0.276],[-0.881,1.525],[-1.627,0.674],[-1.701,-0.456],[-1.072,-1.397],[0,-1.761],[1.072,-1.397]],"v":[[-1.821,-7.727],[3.311,-7.391],[5.75,-5.809],[5.75,-6.5],[6.75,-7.5],[7.75,-6.5],[7.75,-3.5],[6.75,-2.5],[6.331,-2.5],[6.295,-2.5],[3.75,-2.5],[2.75,-3.5],[3.75,-4.5],[4.219,-4.5],[2.546,-5.543],[-1.303,-5.796],[-4.51,-3.653],[-5.75,0],[-4.51,3.653],[-1.303,5.796],[2.546,5.543],[5.446,3],[6.812,2.634],[7.178,4],[3.311,7.391],[-1.821,7.727],[-6.097,4.87],[-7.75,0],[-6.097,-4.87]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.141176477075,0.588235318661,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":"arrow_e_light","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":300,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"arrow","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.5],"y":[1]},"o":{"x":[0.5],"y":[0]},"t":0,"s":[0]},{"t":36,"s":[360]}],"ix":10},"p":{"a":0,"k":[36,36,0],"ix":2,"l":2},"a":{"a":0,"k":[30,30,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":60,"h":60,"ip":0,"op":300,"st":0,"bm":0}],"markers":[]}

View File

@ -0,0 +1 @@
{"v":"5.5.9","fr":60,"ip":0,"op":120,"w":1080,"h":586,"nm":"上滑","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":2,"ty":4,"nm":"手","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.642],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":6,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.558],"y":[0]},"t":60,"s":[100]},{"t":71,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.479,"y":0},"t":3,"s":[611,475,0],"to":[0,-62.75,0],"ti":[0,62.75,0]},{"t":40,"s":[611,98.5,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[90,90,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-7.78,-12.06],[5.68,0.39],[-6.42,-2.45],[-6.32,-0.97],[-5.95,13.55],[4.87,7.91],[4.94,6.69],[1.26,-5.37],[5.25,-1.25],[1.5,-0.3],[3.4,-0.77],[1.4,1.68],[6.15,7.98],[-1.73,-6.64]],"o":[[1.62,2.49],[-5.68,-0.39],[9.37,3.63],[6.31,0.98],[2.39,-7.74],[-4.87,-7.92],[-2.45,-3.05],[-1.05,4.57],[-4.99,1.39],[-0.83,0.13],[-5.63,1.63],[-4.71,-5.72],[-2.75,-3.31],[3.52,6.76]],"v":[[-7.86,14.26],[-15.64,12.52],[-17.99,22.89],[8.47,31.78],[33.98,17.29],[29.55,-1.59],[16.85,-20.15],[7.86,-17.83],[1.56,-19.8],[-3.05,-14.02],[-8.33,-16.94],[-12.44,-11.045],[-26.761,-30.19],[-34.75,-25.78]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","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":120,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"矩形","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.715],"y":[0]},"t":57,"s":[100]},{"t":67,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[525,228.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.491,"y":0},"t":3,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[24.328,180.5],[-22,180.5],[-22,204.5],[24.328,204.5]],"c":true}]},{"t":40,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[24.328,-207.5],[-22,-207.5],[-22,204.5],[24.328,204.5]],"c":true}]}],"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"蒙版 1"}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[6,137],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":2,"ix":4},"nm":"矩形路径 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,1,1,1,0.5,1,1,1,1,1,1,1,0,1,0.5,0.5,1,0],"ix":9}},"s":{"a":0,"k":[0,-68.5],"ix":5},"e":{"a":0,"k":[0,68.5],"ix":6},"t":1,"nm":"Gradient Fill 1","mn":"ADBE Vector Graphic - G-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},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":33,"ix":3},"m":1,"ix":2,"nm":"修剪路径 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":3,"op":123,"st":3,"bm":0}],"markers":[]}

View File

@ -0,0 +1 @@
{"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":[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},"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":[100]},{"t":18,"s":[0]}],"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":[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":[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,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},"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.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":[]}

View File

@ -0,0 +1 @@
{"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":[]}

View File

@ -1 +0,0 @@
{"v":"5.12.2","fr":60,"ip":0,"op":40,"w":66,"h":66,"nm":"icon_tab_my","ddd":0,"assets":[{"id":"comp_0","nm":"icon","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"highlight","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33.134,34.5,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":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":0.733},"o":{"x":0.333,"y":0},"t":0,"s":[{"i":[[0,-0.004],[0.493,0],[0,0.004],[-0.493,0]],"o":[[0,0.004],[-0.493,0],[0,-0.004],[0.493,0]],"v":[[0.893,1.488],[0,1.496],[-0.893,1.488],[0,1.483]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0.267},"t":10,"s":[{"i":[[0,-1.018],[1.793,0],[0,1.018],[-1.793,0]],"o":[[0,1.018],[-1.793,0],[0,-1.018],[1.793,0]],"v":[[2.914,-0.344],[0,1.5],[-2.914,-0.344],[0,-1.5]],"c":true}]},{"i":{"x":0.333,"y":1},"o":{"x":0.667,"y":0},"t":18,"s":[{"i":[[0,-1.181],[1.407,0],[0,1.181],[-1.407,0]],"o":[[0,1.181],[-1.407,0],[0,-1.181],[1.407,0]],"v":[[2.226,-0.341],[0,1.74],[-2.211,-0.341],[0,-1.74]],"c":true}]},{"i":{"x":0.333,"y":1},"o":{"x":0.667,"y":0},"t":26,"s":[{"i":[[0,-0.905],[1.381,0],[0,0.905],[-1.381,0]],"o":[[0,0.905],[-1.381,0],[0,-0.905],[1.381,0]],"v":[[2.5,-0.306],[0,1.333],[-2.5,-0.306],[0,-1.333]],"c":true}]},{"t":32,"s":[{"i":[[0,-1.018],[1.381,0],[0,1.018],[-1.381,0]],"o":[[0,1.018],[-1.381,0],[0,-1.018],[1.381,0]],"v":[[2.5,-0.344],[0,1.5],[-2.5,-0.344],[0,-1.5]],"c":true}]}],"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","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":"color","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":60,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"body","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[33,34.204,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":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.866,0],[0,3.866],[3.866,0],[0,-3.866]],"o":[[3.866,0],[0,-3.866],[-3.866,0],[0,3.866]],"v":[[0,4.599],[7,-2.401],[0,-9.401],[-7,-2.401]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0.207,0.359],[2.438,0],[1.189,-2.104],[-0.361,-0.204],[-0.204,0.361],[-1.915,0],[-0.932,-1.613],[-0.359,0.207]],"o":[[-1.198,-2.072],[-2.462,0],[-0.204,0.361],[0.361,0.204],[0.925,-1.638],[1.897,0],[0.207,0.359],[0.359,-0.207]],"v":[[5.848,8.225],[0,4.849],[-5.88,8.282],[-5.596,9.304],[-4.574,9.02],[0,6.349],[4.549,8.976],[5.574,9.25]],"c":true},"ix":2},"nm":"路径 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"bm":0,"g":{"p":3,"k":{"a":0,"k":[0,0.267,0.639,1,0.5,0.241,0.596,1,1,0.216,0.553,1],"ix":9}},"s":{"a":0,"k":[-3.812,-4.384],"ix":5},"e":{"a":0,"k":[6.345,8.129],"ix":6},"t":1,"nm":"color","mn":"ADBE Vector Graphic - G-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":"Union","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"icon","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":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":[33,33,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":0,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":8,"s":[70,70,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":18,"s":[110,110,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":26,"s":[90,90,100]},{"t":32,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"w":66,"h":66,"ip":0,"op":60,"st":0,"bm":0}],"markers":[],"props":{}}

File diff suppressed because one or more lines are too long

View File

@ -34,18 +34,18 @@ try {
var script = document.createElement("script")
document.body.appendChild(script)
if (isDebug) {
script.src = "https://dev-and-static.ghzs66.com/web/js/halo.js" + "?timestamp=" + Math.round(new Date().getTime() / 1000)
script.src = "https://resource.ghzs.com/js/halo_app_test.js" + "?timestamp=" + Math.round(new Date().getTime() / 1000)
} else {
script.src = "https://and-static.ghzs66.com/web/js/halo.js" + "?timestamp=" + Math.round(new Date().getTime() / 1000 / 1000)
script.src = "https://resource.ghzs.com/js/halo.js" + "?timestamp=" + Math.round(new Date().getTime() / 1000 / 1000)
}
var style = document.createElement("link")
style.rel = "stylesheet"
style.type = "text/css"
if (isDebug) {
style.href = "https://dev-and-static.ghzs66.com/web/css/halo.css" + "?timestamp=" + Math.round(new Date().getTime() / 1000)
style.href = "https://resource.ghzs.com/css/halo_app_test.css" + "?timestamp=" + Math.round(new Date().getTime() / 1000)
} else {
style.href = "https://and-static.ghzs66.com/web/css/halo.css" + "?timestamp=" + Math.round(new Date().getTime() / 1000 / 1000)
style.href = "https://resource.ghzs.com/css/halo.css" + "?timestamp=" + Math.round(new Date().getTime() / 1000 / 1000)
}
document.head.appendChild(style)
@ -205,17 +205,14 @@ RE.setOutdent = function() {
RE.setJustifyLeft = function() {
document.execCommand('justifyLeft', false, null);
RE.enabledEditingItems()
}
RE.setJustifyCenter = function() {
document.execCommand('justifyCenter', false, null);
RE.enabledEditingItems()
}
RE.setJustifyRight = function() {
document.execCommand('justifyRight', false, null);
RE.enabledEditingItems()
}
RE.setBlockquote = function() {
@ -230,16 +227,6 @@ RE.insertImage = function(url) {
RE.insertHTML(html);
}
// 设置分割线
RE.insertHorizontalRule = function() {
document.execCommand('insertHorizontalRule', false, null);
}
// 设置编辑器默认换行符
RE.setDefaultParagraphSeparator = function(separator) {
document.execCommand('defaultParagraphSeparator', false, separator);
}
// 替换成缩略图
RE.replaceTbImage = function(imgRuleFlag, gifRuleFlag) {
var imgs = document.getElementsByTagName("img");
@ -587,10 +574,6 @@ document.addEventListener("selectionchange", function(e) {
RE.sendElementNameToNative()
});
document.addEventListener("selectionchange", function(e) {
RE.enabledEditingItems(e)
});
RE.recursion = function(dom) {
var parenDom = dom.parentElement
if (parenDom && parenDom instanceof Element &&
@ -633,6 +616,7 @@ RE.sendElementNameToNative = function() {
// android function to open link
function customLinkgo(self) {
var datas = self.dataset.datas
// console.log(datas)
window.OnLinkClickListener.onClick(datas)
}

View File

@ -30,6 +30,7 @@ body {
}
#editor {
display: table-cell;
outline: 0px solid transparent;
background-repeat: no-repeat;
background-position: center;

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -151,7 +151,7 @@ class CircleImageView extends ImageView {
private void updateRadialGradient(int diameter) {
mRadialGradient = new RadialGradient(diameter / 2, diameter / 2,
mShadowRadius, new int[]{FILL_SHADOW_COLOR, Color.TRANSPARENT},
mShadowRadius, new int[] { FILL_SHADOW_COLOR, Color.TRANSPARENT },
null, Shader.TileMode.CLAMP);
mShadowPaint.setShader(mRadialGradient);
}

View File

@ -44,9 +44,8 @@ import androidx.annotation.RestrictTo;
import androidx.core.util.Preconditions;
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
import com.gh.gamecenter.common.R;
import com.gh.gamecenter.core.HaloApp;
import com.gh.gamecenter.R;
import com.halo.assistant.HaloApp;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@ -812,7 +811,7 @@ public class CircularProgressDrawable extends Drawable implements Animatable {
void drawImageToRing(Canvas canvas, Rect bounds, Animator animator) {
Bitmap bitmap;
Resources resources = HaloApp.getInstance().getResources();
Resources resources = HaloApp.getInstance().getApplication().getResources();
int offset = (int) (mInterpolatedTime * 100) / 2;
if (!animator.isRunning()) {

View File

@ -137,8 +137,8 @@ public class SwipeRefreshLayout extends ViewGroup implements NestedScrollingPare
// refresh was triggered.
private boolean mReturningToStart;
private final DecelerateInterpolator mDecelerateInterpolator;
private static final int[] LAYOUT_ATTRS = new int[]{
android.R.attr.enabled
private static final int[] LAYOUT_ATTRS = new int[] {
android.R.attr.enabled
};
CircleImageView mCircleView;
@ -250,9 +250,9 @@ public class SwipeRefreshLayout extends ViewGroup implements NestedScrollingPare
* up rather than clipped.
* @param start The offset in pixels from the top of this view at which the
* progress spinner should appear.
* @param end The offset in pixels from the top of this view at which the
* progress spinner should come to rest after a successful swipe
* gesture.
* @param end The offset in pixels from the top of this view at which the
* progress spinner should come to rest after a successful swipe
* gesture.
*/
public void setProgressViewOffset(boolean scale, int start, int end) {
mScale = scale;
@ -265,7 +265,7 @@ public class SwipeRefreshLayout extends ViewGroup implements NestedScrollingPare
/**
* @return The offset in pixels from the top of this view at which the progress spinner should
* appear.
* appear.
*/
public int getProgressViewStartOffset() {
return mOriginalOffsetTop;
@ -273,7 +273,7 @@ public class SwipeRefreshLayout extends ViewGroup implements NestedScrollingPare
/**
* @return The offset in pixels from the top of this view at which the progress spinner should
* come to rest after a successful swipe gesture.
* come to rest after a successful swipe gesture.
*/
public int getProgressViewEndOffset() {
return mSpinnerOffsetEnd;
@ -288,9 +288,9 @@ public class SwipeRefreshLayout extends ViewGroup implements NestedScrollingPare
* @param scale Set to true if there is no view at a higher z-order than where the progress
* spinner is set to appear. Setting it to true will cause indicator to be scaled
* up rather than clipped.
* @param end The offset in pixels from the top of this view at which the
* progress spinner should come to rest after a successful swipe
* gesture.
* @param end The offset in pixels from the top of this view at which the
* progress spinner should come to rest after a successful swipe
* gesture.
*/
public void setProgressViewEndTarget(boolean scale, int end) {
mSpinnerOffsetEnd = end;
@ -304,6 +304,7 @@ public class SwipeRefreshLayout extends ViewGroup implements NestedScrollingPare
* @param slingshotDistance The distance in pixels that the refresh indicator can be pulled
* beyond its resting position. Use
* {@link #DEFAULT_SLINGSHOT_DISTANCE} to reset to the default value.
*
*/
public void setSlingshotDistance(@Px int slingshotDistance) {
mCustomSlingshotDistance = slingshotDistance;
@ -453,7 +454,6 @@ public class SwipeRefreshLayout extends ViewGroup implements NestedScrollingPare
/**
* Pre API 11, this does an alpha animation.
*
* @param progress
*/
void setAnimationProgress(float progress) {
@ -575,7 +575,7 @@ public class SwipeRefreshLayout extends ViewGroup implements NestedScrollingPare
/**
* @return Whether the SwipeRefreshWidget is actively showing refresh
* progress.
* progress.
*/
public boolean isRefreshing() {
return mRefreshing;
@ -666,7 +666,7 @@ public class SwipeRefreshLayout extends ViewGroup implements NestedScrollingPare
/**
* @return Whether it is possible for the child view of this layout to
* scroll up. Override this if the child view is a custom view.
* scroll up. Override this if the child view is a custom view.
*/
public boolean canChildScrollUp() {
if (mChildScrollUpCallback != null) {
@ -681,7 +681,6 @@ public class SwipeRefreshLayout extends ViewGroup implements NestedScrollingPare
/**
* Set a callback to override {@link SwipeRefreshLayout#canChildScrollUp()} method. Non-null
* callback will return the value provided by the callback and ignore all internal logic.
*
* @param callback Callback that should be called when canChildScrollUp() is called.
*/
public void setOnChildScrollUpCallback(@Nullable OnChildScrollUpCallback callback) {
@ -830,7 +829,7 @@ public class SwipeRefreshLayout extends ViewGroup implements NestedScrollingPare
@Override
public void onNestedScroll(final View target, final int dxConsumed, final int dyConsumed,
final int dxUnconsumed, final int dyUnconsumed) {
final int dxUnconsumed, final int dyUnconsumed) {
// Dispatch up to the nested parent first
dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
mParentOffsetInWindow);
@ -876,7 +875,7 @@ public class SwipeRefreshLayout extends ViewGroup implements NestedScrollingPare
@Override
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed,
int dyUnconsumed, int[] offsetInWindow) {
int dyUnconsumed, int[] offsetInWindow) {
return mNestedScrollingChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed,
dxUnconsumed, dyUnconsumed, offsetInWindow);
}
@ -889,13 +888,13 @@ public class SwipeRefreshLayout extends ViewGroup implements NestedScrollingPare
@Override
public boolean onNestedPreFling(View target, float velocityX,
float velocityY) {
float velocityY) {
return dispatchNestedPreFling(velocityX, velocityY);
}
@Override
public boolean onNestedFling(View target, float velocityX, float velocityY,
boolean consumed) {
boolean consumed) {
return dispatchNestedFling(velocityX, velocityY, consumed);
}
@ -923,8 +922,8 @@ public class SwipeRefreshLayout extends ViewGroup implements NestedScrollingPare
float slingshotDist = mCustomSlingshotDistance > 0
? mCustomSlingshotDistance
: (mUsingCustomStart
? mSpinnerOffsetEnd - mOriginalOffsetTop
: mSpinnerOffsetEnd);
? mSpinnerOffsetEnd - mOriginalOffsetTop
: mSpinnerOffsetEnd);
float tensionSlingshotPercent = Math.max(0, Math.min(extraOS, slingshotDist * 2)
/ slingshotDist);
float tensionPercent = (float) ((tensionSlingshotPercent / 4) - Math.pow(
@ -1147,13 +1146,13 @@ public class SwipeRefreshLayout extends ViewGroup implements NestedScrollingPare
};
private void startScaleDownReturnToStartAnimation(int from,
AnimationListener listener) {
AnimationListener listener) {
mFrom = from;
mStartingScale = mCircleView.getScaleX();
mScaleDownToStartAnimation = new Animation() {
@Override
public void applyTransformation(float interpolatedTime, Transformation t) {
float targetScale = (mStartingScale + (-mStartingScale * interpolatedTime));
float targetScale = (mStartingScale + (-mStartingScale * interpolatedTime));
setAnimationProgress(targetScale);
moveToStart(interpolatedTime);
}
@ -1204,7 +1203,8 @@ public class SwipeRefreshLayout extends ViewGroup implements NestedScrollingPare
* is called to allow the implementer to override its behavior.
*
* @param parent SwipeRefreshLayout that this callback is overriding.
* @param child The child view of SwipeRefreshLayout.
* @param child The child view of SwipeRefreshLayout.
*
* @return Whether it is possible for the child view of parent layout to scroll up.
*/
boolean canChildScrollUp(@NonNull SwipeRefreshLayout parent, @Nullable View child);

View File

@ -31,7 +31,7 @@ public class ViewPagerSwipeRefreshLayout extends SwipeRefreshLayout {
break;
case MotionEvent.ACTION_MOVE:
// 如果viewpager正在拖拽中那么不拦截它的事件直接return false
if (mIsVpDragger) {
if(mIsVpDragger) {
return false;
}
@ -41,7 +41,7 @@ public class ViewPagerSwipeRefreshLayout extends SwipeRefreshLayout {
float distanceX = Math.abs(endX - startX);
float distanceY = Math.abs(endY - startY);
// 如果X轴位移大于Y轴位移那么将事件交给viewPager处理
if (distanceX > mTouchSlop && distanceX > distanceY) {
if(distanceX > mTouchSlop && distanceX > distanceY) {
mIsVpDragger = true;
return false;
}

View File

@ -1,683 +0,0 @@
package com.gh.ad
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.SharedPreferences
import android.os.Message
import android.text.TextUtils
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.TextView
import androidx.appcompat.content.res.AppCompatResources
import androidx.fragment.app.Fragment
import com.alibaba.android.arouter.launcher.ARouter
import com.facebook.drawee.view.SimpleDraweeView
import com.gh.common.exposure.ExposureManager
import com.gh.common.util.DirectUtils.directToLinkPage
import com.gh.common.util.LogUtils
import com.gh.common.util.NewFlatLogUtils.logOpenScreenAdSkip
import com.gh.common.util.PackageUtils
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.MainActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.provider.IBeiziAdProvider
import com.gh.gamecenter.core.provider.ICsjAdProvider
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.TimeUtils.getToday
import com.gh.gamecenter.entity.AdConfig
import com.gh.gamecenter.entity.StartupAdEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent.Companion.createEvent
import com.gh.gamecenter.feature.exposure.ExposureType
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import io.reactivex.schedulers.Schedulers
/**
* 广告实现代理类
*
* 由它来分发功能实现到具体的实现
*
* 以最复杂的开屏广告为例有三种实现1. 自有的广告实现 2. 穿山甲的开屏广告实现 3. Beizi 的开屏广告实现)
*
* 由于两个广告 SDK 有可能在一次启动中都被使用,所以会根据获取到的广告配置 config 来决定是否需要出是很好两个 SDK
*/
object AdDelegateHelper {
private var mCsjAdImpl: ICsjAdProvider? = null
private var mBeiziAdImpl: IBeiziAdProvider? = null
private val mAdConfigList: ArrayList<AdConfig> by lazy { arrayListOf() }
private var mSplashAd: AdConfig? = null
private var mDownloadManagerAd: AdConfig? = null
private val mGameSearchAdList: ArrayList<AdConfig> by lazy { arrayListOf() }
private var mVGameLaunchAd: AdConfig? = null
val vGameLaunchAd: AdConfig?
get() = mVGameLaunchAd
private const val AD_SDK_CSJ = "穿山甲"
private const val AD_SDK_BEIZI = "倍孜"
const val AD_TYPE_SDK = "third_party_ads" // 第三方 SDK 广告
const val AD_TYPE_OWNER = "owner_ads" // 自有广告
private const val KEY_CACHE_CONFIG = "cache_config" // 放在 SP 里的广告缓存(避免接口加载问题)
private val mAdConfigSp: SharedPreferences by lazy {
HaloApp.getInstance().getSharedPreferences("AdConfig", Context.MODE_PRIVATE)
}
var isShowingSplashAd = false // 是否正在显示开屏广告
var gameSearchKeyword = ""
fun initAdSdk(context: Context) {
// 初始化 Beizi
if (mBeiziAdImpl == null) {
mBeiziAdImpl =
ARouter.getInstance().build(RouteConsts.provider.beiziAd).navigation() as? IBeiziAdProvider
mBeiziAdImpl?.initSDK(context)
}
// 初始化穿山甲
if (mCsjAdImpl == null) {
mCsjAdImpl =
ARouter.getInstance().build(RouteConsts.provider.csjAd).navigation() as? ICsjAdProvider
val csjAppId = if (EnvHelper.isDevEnv) BuildConfig.DEV_CSJ_APPID else BuildConfig.CSJ_APPID
mCsjAdImpl?.initSDK(context, csjAppId, HaloApp.getInstance().oaid)
// 监听亮色/暗色模式切换
DarkModeUtils.registerModeChangeListener {
val topActivity = CurrentActivityHolder.getCurrentActivity() ?: return@registerModeChangeListener
updateThemeStatus(context, DarkModeUtils.isDarkModeOn(topActivity))
}
}
}
/**
* 请求接口获取广告相关配置
*/
@SuppressLint("CheckResult")
fun requestAdConfig(isFromRetry: Boolean, keyword: String = "", callback: (() -> Unit)? = null) {
// mAdConfigList 不为空不需要重试
if (isFromRetry && mAdConfigList.isNotEmpty()) {
return
}
val paramsMap = if (keyword.isNotEmpty()) mapOf("keyword" to keyword) else mapOf()
RetrofitManager.getInstance()
.newApi
.getAdConfig(paramsMap)
.subscribeOn(Schedulers.io())
.subscribe(object : BiResponse<List<AdConfig>>() {
override fun onSuccess(data: List<AdConfig>) {
gameSearchKeyword = keyword
handleAdConfig(data)
callback?.invoke()
// 缓存数据到 SP 供接口请求失败用
SPUtils.setString(mAdConfigSp, KEY_CACHE_CONFIG, data.toJson())
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
// 若接口请求失败时,从 SP 里获取上次缓存的数据
val cachedConfig: List<AdConfig>? = SPUtils.getString(mAdConfigSp, KEY_CACHE_CONFIG).toObject()
if (cachedConfig != null && mAdConfigList.isEmpty()) {
handleAdConfig(cachedConfig)
}
callback?.invoke()
}
})
}
/**
* 获取搜索页的广告列表
*/
fun getGameSearchAdList(): ArrayList<AdConfig> {
return mGameSearchAdList
}
/**
* 获取下载管理页的广告
*/
fun getDownloadManagerAd(): AdConfig? {
return mDownloadManagerAd
}
/**
* 处理广告配置
*/
fun handleAdConfig(configList: List<AdConfig>) {
mAdConfigList.clear()
mGameSearchAdList.clear()
mSplashAd = null
mDownloadManagerAd = null
mVGameLaunchAd = null
for (config in configList) {
mAdConfigList.add(config)
// 处理返回的数据
when (config.location) {
"halo_launch" -> {
config.ownerAd?.startAd?.let { it.id = config.ownerAd.id }
mSplashAd = config
}
"download_manager" -> mDownloadManagerAd = config
"game_search" -> config.let { mGameSearchAdList.add(it) }
"helper_launch" -> mVGameLaunchAd = config
}
}
}
/**
* 是否需要显示开屏广告
* @param isHotLaunch 是否为热启动
*/
fun shouldShowStartUpAd(isHotLaunch: Boolean): Boolean {
return mSplashAd != null
&& !isShowingSplashAd
&& (!isHotLaunch || shouldShowStartUpAdWhenHotLaunch())
&& !isMatchAdFreeRule(mSplashAd)
&& isMatchStartUpAdDisplayRule()
}
/**
* 热启动是否需要显示开屏广告
*/
private fun shouldShowStartUpAdWhenHotLaunch() =
mSplashAd?.displayRule?.hotStartSplashAd?.type == AD_TYPE_SDK && mSplashAd?.hotStartThirdPartyAd != null
/**
* 是否需要显示下载管理广告
*/
fun shouldShowDownloadManagerAd(): Boolean {
return mDownloadManagerAd != null && !isMatchAdFreeRule(mDownloadManagerAd) && isMatchDownloadManagerAdDisplayRule()
}
/**
* 是否需要显示游戏搜索广告
*/
fun shouldShowGameSearchAd(adConfig: AdConfig): Boolean {
return !isMatchAdFreeRule(adConfig) && isMatchGameSearchAdDisplayRule(adConfig)
}
/**
* 是否在免广告时长内
*/
private fun isMatchAdFreeRule(adConfig: AdConfig?): Boolean {
adConfig?.displayRule?.run {
if (adFreeDuration > 0) {
val ghInstalledDurationInHours = (System.currentTimeMillis() - PackageUtils.getInstalledTime(
HaloApp.getInstance(),
BuildConfig.APPLICATION_ID
)).toFloat() / 1000 / 3600
return ghInstalledDurationInHours < adFreeDuration
} else {
return false
}
}
return false
}
/**
* 是否大于开屏广告展示间隔时长
*/
private fun isMatchStartUpAdDisplayRule(): Boolean {
mSplashAd?.displayRule?.run {
if (adDisplayInterval > 0) {
val lastShowTime = SPUtils.getLong(Constants.SP_LAST_SPLASH_AD_SHOW_TIME, 0L)
val durationInMinutes = (System.currentTimeMillis() - lastShowTime).toFloat() / 1000 / 60
return durationInMinutes > adDisplayInterval
} else {
return true
}
}
return true
}
/**
* 是否大于广告管理展示间隔时长
*/
private fun isMatchDownloadManagerAdDisplayRule(): Boolean {
mDownloadManagerAd?.displayRule?.run {
if (adDisplayInterval > 0) {
val lastShowTime = SPUtils.getLong(Constants.SP_LAST_DOWNLOAD_MANAGER_AD_SHOW_TIME, 0L)
val durationInMinutes = (System.currentTimeMillis() - lastShowTime).toFloat() / 1000 / 60
return durationInMinutes > adDisplayInterval
} else {
return true
}
}
return true
}
/**
* 是否大于游戏搜索展示间隔时长
*/
private fun isMatchGameSearchAdDisplayRule(adConfig: AdConfig?): Boolean {
adConfig?.displayRule?.run {
if (adDisplayInterval > 0) {
val lastShowTime = SPUtils.getLong(Constants.SP_LAST_GAME_SEARCH_AD_SHOW_TIME + adConfig.position, 0L)
val durationInMinutes = (System.currentTimeMillis() - lastShowTime).toFloat() / 1000 / 60
return durationInMinutes > adDisplayInterval
} else {
return true
}
}
return true
}
/**
* 更新主题样式
*/
private fun updateThemeStatus(context: Context, isDarkMode: Boolean) {
mCsjAdImpl?.updateThemeStatus(context, isDarkMode)
}
/**
* 请求开屏广告
*/
@JvmStatic
fun requestSplashAd(
activity: Activity,
adViewWidthInPx: Int,
adViewHeightInPx: Int,
adViewWidthInDp: Float,
adViewHeightInDp: Float,
startAdContainer: ViewGroup,
sdkStartAdContainer: ViewGroup,
adsViewGroup: FrameLayout,
handler: BaseActivity.BaseHandler,
isHotLaunch: Boolean,
hideAction: () -> Unit
) {
val hideCallback = {
isShowingSplashAd = false
hideAction.invoke()
}
if (mSplashAd != null) {
when (if (isHotLaunch) mSplashAd!!.displayRule.hotStartSplashAd?.type else mSplashAd!!.displayRule.adSource) {
AD_TYPE_SDK -> {
isShowingSplashAd = true
requestThirdPartySplashAd(
activity,
adViewWidthInPx,
adViewHeightInPx,
adViewWidthInDp,
adViewHeightInDp,
startAdContainer,
sdkStartAdContainer,
adsViewGroup,
handler,
isHotLaunch,
hideCallback
)
}
AD_TYPE_OWNER -> {
isShowingSplashAd = true
requestStandardSplashAd(
activity,
adViewWidthInPx,
adViewHeightInPx,
adViewWidthInDp,
adViewHeightInDp,
startAdContainer,
sdkStartAdContainer,
adsViewGroup,
handler,
isHotLaunch,
hideCallback
)
}
}
} else {
hideCallback.invoke()
}
}
/**
* 获取第三方开屏广告
*/
private fun requestThirdPartySplashAd(
activity: Activity,
adViewWidthInPx: Int,
adViewHeightInPx: Int,
adViewWidthInDp: Float,
adViewHeightInDp: Float,
startAdContainer: ViewGroup,
sdkStartAdContainer: ViewGroup,
adsViewGroup: FrameLayout,
handler: BaseActivity.BaseHandler,
isHotLaunch: Boolean,
hideCallback: () -> Unit
) {
// 第三方开屏广告回调,失败时根据接口配置选项决定是否显示自有开屏广告
val sdkSplashCallback: (isSuccess: Boolean) -> Unit = { isSuccess ->
if (isSuccess) {
hideCallback.invoke()
SPUtils.setLong(Constants.SP_LAST_SPLASH_AD_SHOW_TIME, System.currentTimeMillis())
} else {
if (mSplashAd?.displayRule?.adSource == AD_TYPE_SDK && mSplashAd?.displayRule?.onFailedAction == "show" && !isHotLaunch) {
sdkStartAdContainer.visibility = View.GONE
requestStandardSplashAd(
activity,
adViewWidthInPx,
adViewHeightInPx,
adViewWidthInDp,
adViewHeightInDp,
startAdContainer,
sdkStartAdContainer,
adsViewGroup,
handler,
isHotLaunch,
hideCallback
)
} else {
hideCallback.invoke()
}
}
}
val thirdPartyAd = if (isHotLaunch) mSplashAd?.hotStartThirdPartyAd else mSplashAd?.thirdPartyAd
// 第三方广告的数据为空,按加载失败处理
if (mSplashAd == null || thirdPartyAd == null) {
sdkSplashCallback.invoke(false)
return
}
val timeout = if (isHotLaunch) {
((mSplashAd?.displayRule?.hotStartSplashAd?.timeout ?: 3.5F) * 1000).toInt()
} else {
((mSplashAd?.displayRule?.timeout ?: 3.5F) * 1000).toInt()
}
if (thirdPartyAd.sourceName == AD_SDK_BEIZI) {
sdkStartAdContainer.visibility = View.VISIBLE
requestBeiziSplashAd(sdkStartAdContainer, adsViewGroup, adViewWidthInPx, adViewHeightInPx, timeout.toLong(), sdkSplashCallback)
} else if (thirdPartyAd.sourceName == AD_SDK_CSJ) {
sdkStartAdContainer.visibility = View.VISIBLE
requestCsjSplashAd(
activity,
thirdPartyAd.slotId,
adViewWidthInPx,
adViewHeightInPx,
adViewWidthInDp,
adViewHeightInDp,
sdkStartAdContainer,
timeout,
sdkSplashCallback
)
}
}
/**
* 获取穿山甲的开屏广告
*/
private fun requestCsjSplashAd(
activity: Activity,
slotId: String,
adViewWidthInPx: Int,
adViewHeightInPx: Int,
adViewWidthInDp: Float,
adViewHeightInDp: Float,
startAdContainer: ViewGroup,
timeout: Int,
callback: (isSuccess: Boolean) -> Unit,
) {
if (mCsjAdImpl == null) {
callback.invoke(false)
} else {
mCsjAdImpl?.requestSplashAd(
activity,
slotId,
adViewWidthInPx,
adViewHeightInPx,
adViewWidthInDp,
adViewHeightInDp,
startAdContainer,
timeout,
callback,
)
}
}
/**
* 获取 Beizi 的开屏广告
*/
private fun requestBeiziSplashAd(
startAdContainer: View,
adsFl: FrameLayout,
adViewWidthInPx: Int,
adViewHeightInPx: Int,
timeout: Long,
callback: (isSuccess: Boolean) -> Unit,
) {
if (mBeiziAdImpl == null) {
callback.invoke(false)
} else {
mBeiziAdImpl?.requestSplashAd(startAdContainer, adsFl, adViewWidthInPx, adViewHeightInPx, timeout, callback)
}
}
/**
* 显示自有的开屏广告
*/
private fun requestStandardSplashAd(
activity: Activity,
adViewWidthInPx: Int,
adViewHeightInPx: Int,
adViewWidthInDp: Float,
adViewHeightInDp: Float,
startAdContainer: ViewGroup,
sdkStartAdContainer: ViewGroup,
adsViewGroup: FrameLayout,
handler: BaseActivity.BaseHandler,
isHotLaunch: Boolean,
hideCallback: () -> Unit
) {
val splashAd = mSplashAd?.ownerAd?.startAd
val onEmptyCallback = {
if (mSplashAd?.displayRule?.adSource == AD_TYPE_OWNER && mSplashAd?.displayRule?.onFailedAction == "show" && mSplashAd?.thirdPartyAd != null) {
// 自有广告为空时,显示第三方广告
requestThirdPartySplashAd(
activity,
adViewWidthInPx,
adViewHeightInPx,
adViewWidthInDp,
adViewHeightInDp,
startAdContainer,
sdkStartAdContainer,
adsViewGroup,
handler,
isHotLaunch,
hideCallback
)
} else {
hideCallback.invoke()
}
}
if (splashAd == null) {
onEmptyCallback.invoke()
return
}
if (!TextUtils.isEmpty(splashAd.img)) {
val showedTodayTimestamp = SPUtils.getString(Constants.SP_STARTUP_AD_TIMESTAMP, "") ?: ""
when (splashAd.rule) {
"each" -> showStandardSplashAd(splashAd, startAdContainer, handler, hideCallback)
"once" -> if (TextUtils.isEmpty(showedTodayTimestamp)
|| !showedTodayTimestamp.contains(splashAd.id)
) {
showStandardSplashAd(splashAd, startAdContainer, handler, hideCallback)
} else {
onEmptyCallback.invoke()
}
"everyday" -> {
val today = getToday()
if (TextUtils.isEmpty(showedTodayTimestamp)
|| !showedTodayTimestamp.contains(today)
|| !showedTodayTimestamp.contains(splashAd.id)
) {
showStandardSplashAd(splashAd, startAdContainer, handler, hideCallback)
} else {
onEmptyCallback.invoke()
}
}
else -> hideCallback.invoke()
}
SPUtils.setString(Constants.SP_STARTUP_AD_TIMESTAMP, splashAd.id + getToday())
} else {
hideCallback.invoke()
}
}
private fun showStandardSplashAd(
ad: StartupAdEntity,
startAdContainer: ViewGroup,
handler: BaseActivity.BaseHandler,
hideCallback: () -> Unit
) {
val jumpBtn: View = startAdContainer.findViewById(R.id.jumpBtn)
val jumpDetailBtn: TextView = startAdContainer.findViewById(R.id.jumpDetailBtn)
val adImage: SimpleDraweeView = startAdContainer.findViewById(R.id.adImage)
val icpContainer: View? = startAdContainer.findViewById(R.id.startAdIcpContainer)
startAdContainer.visibility = View.VISIBLE
icpContainer?.visibility = View.VISIBLE
jumpDetailBtn.text = ad.desc
jumpDetailBtn.setDrawableEnd(
AppCompatResources.getDrawable(
startAdContainer.context,
R.drawable.ic_startup_ad_arrow
), null, null
)
ImageUtils.display(adImage, ad.img)
startAdContainer.setOnClickListener {
// 拦截点击事件传递
}
jumpBtn.setOnClickListener {
handler.removeMessages(MainActivity.COUNTDOWN_AD)
hideCallback.invoke()
val linkEntity = ad.jump
logOpenScreenAdSkip(
ad.id,
(if (linkEntity.text != null) linkEntity.text else "")!!,
(if (linkEntity.type != null) linkEntity.type else "")!!,
(if (linkEntity.link != null) linkEntity.link else "")!!
)
SensorsBridge.trackEvent(
"SplashAdOwnSkip",
"splash_ad_id",
ad.id,
"link_type",
linkEntity.type ?: "",
"link_id",
linkEntity.link ?: "",
"link_text",
linkEntity.text ?: ""
)
}
val sources: MutableList<ExposureSource> = ArrayList()
sources.add(ExposureSource("开屏广告", ad.id))
val event = createEvent(null, sources, null, ExposureType.EXPOSURE)
ExposureManager.log(event)
if (ad.button) {
jumpDetailBtn.setOnClickListener { v: View ->
val linkEntity = ad.jump
directToLinkPage(v.context, linkEntity, "(启动广告)", "", event)
SensorsBridge.trackEvent(
"SplashAdOwnClick",
"splash_ad_id",
ad.id,
"link_type",
linkEntity.type ?: "",
"link_id",
linkEntity.link ?: "",
"link_text",
linkEntity.text ?: ""
)
v.postDelayed({
handler.removeMessages(MainActivity.COUNTDOWN_AD)
hideCallback.invoke()
}, 1000)
}
jumpDetailBtn.visibility = View.VISIBLE
LogUtils.logStartAd("watch_start_ads", ad)
} else {
LogUtils.logStartAd("start_ads", ad)
}
SPUtils.setLong(Constants.SP_LAST_SPLASH_AD_SHOW_TIME, System.currentTimeMillis())
val msg = Message.obtain()
msg.what = MainActivity.COUNTDOWN_AD
msg.obj = ad
handler.sendMessageDelayed(msg, 1000)
}
/**
* 获取第三方信息流广告
*/
fun requestThirdPartyFlowAd(
fragment: Fragment,
slotId: String,
adContainerView: ViewGroup,
expressViewWidth: Float,
callback: (isSuccess: Boolean) -> Unit,
) {
mCsjAdImpl?.requestFlowAd(fragment, adContainerView, slotId, expressViewWidth, callback)
}
/**
* 获取第三方 Banner 广告
*/
fun requestThirdPartyBannerAd(
fragment: Fragment,
containerView: ViewGroup,
ad: AdConfig.ThirdPartyAd,
expressViewWidthInDp: Float,
callback: (isSuccess: Boolean) -> Unit
) {
val slotId = ad.slotId
val displayRatio: Float = if (ad.displaySize.isEmpty()) {
2F
} else {
val array = ad.displaySize.split("*")
if (array.size == 2) {
array[0].toFloat() / array[1].toFloat()
} else {
2F
}
}
val expressViewHeightInDp = expressViewWidthInDp / displayRatio
mCsjAdImpl?.requestBannerAd(
fragment,
containerView,
slotId,
expressViewWidthInDp,
expressViewHeightInDp,
callback
)
}
/**
* 取消开屏广告
*/
fun cancelSplashAd(context: Context) {
mBeiziAdImpl?.cancelSplashAd(context)
mCsjAdImpl?.cancelSplashAd(context)
}
}

View File

@ -0,0 +1,134 @@
package com.gh.base;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Looper;
import android.preference.PreferenceManager;
import android.util.Log;
import com.gh.common.constant.Config;
import com.gh.common.util.DataCollectionUtils;
import com.gh.common.util.DataUtils;
import com.gh.gamecenter.SplashScreenActivity;
import com.lightgame.config.CommonDebug;
import com.lightgame.download.FileUtils;
import com.lightgame.utils.AppManager;
import com.lightgame.utils.Utils;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.Thread.UncaughtExceptionHandler;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.TimeoutException;
import io.sentry.Sentry;
public class AppUncaughtHandler implements UncaughtExceptionHandler {
private Context mContext;
public AppUncaughtHandler(Context context) {
// 获取系统默认的UncaughtException处理器
mContext = context;
}
@Override
public void uncaughtException(Thread t, Throwable e) {
if (("FinalizerWatchdogDaemon").equals(t.getName())
&& e instanceof TimeoutException) {
// ignore timeoutException
// detail can be found in this didi tech blog post https://mp.weixin.qq.com/s?__biz=MzU1ODEzNjI2NA==&mid=2247487185&idx=2&sn=cf2d9e10053f625bde0f61d246f14870&source=41#wechat_redirect
} else {
new Thread(() -> {
Looper.prepare();
Utils.toast(mContext.getApplicationContext(), "\"光环助手\"发生错误");
Looper.loop();
});
saveLocalLog(mContext, e);
restart(mContext);
Sentry.captureException(e);
}
}
public static void restart(final Context context) {
// S450 这机器会无限重启循环 : (
if ("S450".equals(Build.MODEL)) return;
// 防止重复奔溃导致助手一直重启20秒内不做处理
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
long curTime = System.currentTimeMillis();
long time = sp.getLong("last_restart_time", 0);
if (curTime - time > 20 * 1000) {
sp.edit().putLong("last_restart_time", curTime).apply();
Intent intent = new Intent(context, SplashScreenActivity.class);
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
PendingIntent restartIntent = PendingIntent.getActivity(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
// 退出程序并重启
AlarmManager mgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, curTime + 3000, restartIntent); // 1秒钟后重启应用
}
//error restart
// System.exit(2);
AppManager.getInstance().finishAllActivity();
}
// 保存log到本地
public static void saveLocalLog(Context context, Throwable ex) {
String errorMsg = Log.getStackTraceString(ex);
Config.setExceptionMsg(errorMsg);
// 保存到本地
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.getDefault());
File file = new File(FileUtils.getLogPath(context.getApplicationContext(),
format.format(new Date()) + "_gh_assist" + ".log"));
FileWriter writer = null;
try {
file.createNewFile();
writer = new FileWriter(file);
writer.write(errorMsg);
writer.flush();
} catch (IOException e1) {
e1.printStackTrace();
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 下次应用启动再上报
*
* @param context
* @param throwable
*/
public static void reportException(Context context, Throwable throwable) {
CommonDebug.logMethodWithParams(context, "ERRMSG", throwable);
// 上传错误数据
try {
DataCollectionUtils.uploadError(context, Log.getStackTraceString(throwable));
} catch (Exception e) {
}
DataUtils.onError(context, throwable);
}
}

View File

@ -0,0 +1,629 @@
package com.gh.base;
import static com.gh.common.util.EntranceUtils.KEY_ENTRANCE;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Parcel;
import android.os.TransactionTooLargeException;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.content.ContextCompat;
import androidx.core.view.LayoutInflaterCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Lifecycle;
import com.gh.base.fragment.BaseFragment;
import com.gh.common.constant.Constants;
import com.gh.common.tracker.IBusiness;
import com.gh.common.util.DialogHelper;
import com.gh.common.util.DialogUtils;
import com.gh.common.util.DisplayUtils;
import com.gh.common.util.EntranceUtils;
import com.gh.common.util.EnvHelper;
import com.gh.common.util.ExtensionsKt;
import com.gh.common.util.MtaHelper;
import com.gh.common.util.NetworkUtils;
import com.gh.common.util.NightModeUtils;
import com.gh.common.util.PackageFlavorHelper;
import com.gh.common.util.PackageInstaller;
import com.gh.common.util.QuickLoginHelper;
import com.gh.common.util.RunningUtils;
import com.gh.common.util.SPUtils;
import com.gh.common.util.ShareUtils;
import com.gh.common.util.StringUtils;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.LoginActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.SplashScreenActivity;
import com.gh.gamecenter.eventbus.EBShowDialog;
import com.lightgame.BaseAppCompatActivity;
import com.lightgame.download.DownloadEntity;
import com.lightgame.download.FileUtils;
import com.lightgame.utils.Utils;
import com.tencent.tauth.Tencent;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.json.JSONObject;
import java.lang.ref.WeakReference;
import java.util.List;
import kotlin.Pair;
import pub.devrel.easypermissions.EasyPermissions;
/**
* 只提供基础的服务(EventBus/Share/GlobalDialog/Permissions)
* <p>
* 需要工具栏的页面请继承{@link ToolBarActivity}
*/
public abstract class BaseActivity extends BaseAppCompatActivity implements EasyPermissions.PermissionCallbacks, IBusiness {
// global dialog key
public final static String DOWNLOAD_HIJACK = "hijack";
public final static String LOGIN_EXCEPTION = "loginException";
public final static String PLUGGABLE = "plugin";
public final static String SIGNATURE_CONFLICT = "signature_conflict";
public final static int ID_ROOT_INDICATOR = 999;
public final static int ID_NIGHT_INDICATOR = 998;
public final int MAX_BUNDLE_SIZE = 300;
@NonNull
protected String mEntrance;
private boolean mIsExistLogoutDialog;
protected boolean mNightMode;
public long startPageTime = 0;
protected final Handler mBaseHandler = new BaseHandler(this);
protected static class BaseHandler extends Handler {
private final WeakReference<BaseActivity> mActivityWeakReference;
BaseHandler(BaseActivity activity) {
mActivityWeakReference = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
BaseActivity activity = mActivityWeakReference.get();
if (activity != null) activity.handleMessage(msg);
}
}
protected void handleMessage(Message msg) {
}
//接收QQ或者QQ空间分享回调
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
ExtensionsKt.tryCatchInRelease(() -> {
if (requestCode == com.tencent.connect.common.Constants.REQUEST_QQ_SHARE
|| requestCode == com.tencent.connect.common.Constants.REQUEST_QZONE_SHARE) {
Tencent.onActivityResultData(requestCode, resultCode, data, ShareUtils.getInstance(this).QqShareListener);
}
return null;
});
}
@Override
protected void onCreate(Bundle savedInstanceState) {
if (PackageFlavorHelper.IS_TEST_FLAVOR && isAutoResetViewBackgroundEnabled()) {
LayoutInflaterCompat.setFactory2(getLayoutInflater(), new CustomLayoutInflaterFactory(this));
}
super.onCreate(savedInstanceState);
if (useEventBus()) EventBus.getDefault().register(this);
mEntrance = getIntent().getStringExtra(KEY_ENTRANCE);
if (TextUtils.isEmpty(mEntrance)) {
mEntrance = Constants.ENTRANCE_UNKNOWN;
}
if (BuildConfig.DEBUG) {
Utils.log("ACTIVITY_ENTRANCE -> " + mEntrance);
}
disableAutofill();
if (savedInstanceState != null) {
String xapkUnzipActivity = SPUtils.getString(Constants.SP_XAPK_UNZIP_ACTIVITY);
String xapkUrl = SPUtils.getString(Constants.SP_XAPK_URL);
Utils.log("页面重建了--" + xapkUnzipActivity + "--" + xapkUrl);
if (this.getClass().isAssignableFrom(SplashScreenActivity.class)) {
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, "");
SPUtils.setString(Constants.SP_XAPK_URL, "");
return;
}
if (this.getClass().getName().equals(xapkUnzipActivity) && !TextUtils.isEmpty(xapkUrl)) {
DownloadEntity downloadEntity = DownloadManager.getInstance().getDownloadEntityByUrl(xapkUrl);
if (downloadEntity != null) {
PackageInstaller.install(this, downloadEntity, false);
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, "");
SPUtils.setString(Constants.SP_XAPK_URL, "");
}
}
}
mNightMode = NightModeUtils.INSTANCE.isNightMode(this);
}
@Override
protected void onResume() {
super.onResume();
startPageTime = System.currentTimeMillis();
if (BuildConfig.IS_NIGHT_MODE_ON
&& !NightModeUtils.INSTANCE.getSystemMode()
&& mNightMode != NightModeUtils.INSTANCE.isNightMode(this)) {
onNightModeChange();
}
}
@SuppressWarnings("ConstantConditions")
@Override
public void setContentView(View view) {
if (!(this instanceof SplashScreenActivity) && PackageFlavorHelper.IS_TEST_FLAVOR) {
view = getRootViewWithEnvIndicator(view);
}
super.setContentView(view);
}
@Override
protected void onDestroy() {
if (useEventBus()) EventBus.getDefault().unregister(this);
mBaseHandler.removeCallbacksAndMessages(null);
super.onDestroy();
}
public void toast(String msg) {
Utils.toast(this, msg);
}
public void toast(int msg) {
toast(getString(msg));
}
public void showShare(String url,
String icon,
String shareTitle,
String shareSummary,
ShareUtils.ShareEntrance shareEntrance, String id) {
ShareUtils.getInstance(this).showShareWindows(this,
getWindow().getDecorView(),
url,
icon,
shareTitle,
shareSummary,
shareEntrance, id);
if (shareEntrance == ShareUtils.ShareEntrance.game || shareEntrance == ShareUtils.ShareEntrance.plugin) {
MtaHelper.onEvent("内容分享", "内容分享", shareTitle + shareSummary);
} else {
MtaHelper.onEvent("内容分享", "内容分享", shareTitle);
}
}
/**
* 关闭 editText 自动填充帐号 (我们也用不上),开启的时候有小概率出发 TimeoutException
*/
private void disableAutofill() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
getWindow().getDecorView().setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS);
}
}
private View getRootViewWithEnvIndicator(View view) {
RelativeLayout screenRootView = new RelativeLayout(this);
screenRootView.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));
LinearLayout ll = new LinearLayout(this);
TextView tv = new TextView(this);
String envText = "正式环境";
tv.setBackground(ContextCompat.getDrawable(this, R.color.theme));
if (EnvHelper.isDevEnv()) {
envText = "测试环境";
tv.setBackground(ContextCompat.getDrawable(this, R.color.theme_red));
}
tv.setText(envText);
tv.setGravity(Gravity.CENTER);
tv.setTextColor(Color.WHITE);
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13);
tv.measure(0, 0);
tv.setAlpha(0.15F);
tv.setId(ID_ROOT_INDICATOR);
int height = tv.getMeasuredHeight();
int width = tv.getMeasuredWidth();
tv.setPadding(DisplayUtils.dip2px(20), 0, DisplayUtils.dip2px(20), 0);
ll.setTranslationX(DisplayUtils.dip2px(20));
ll.setRotation(45);
ll.addView(tv);
ll.setPadding(0, (width - height) / 2, 0, (width - height) / 2);
if (BuildConfig.DEBUG) {
tv.setOnLongClickListener(v -> {
EntranceUtils.saveShortcut(this.getClass().getName(), getIntent().getExtras());
return true;
});
}
screenRootView.addView(view);
screenRootView.addView(ll);
if (BuildConfig.IS_NIGHT_MODE_ON) {
screenRootView.addView(getNightModeIndicatorView());
}
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) ll.getLayoutParams();
lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
view.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));
return screenRootView;
}
private View getNightModeIndicatorView() {
LinearLayout ll = new LinearLayout(this);
TextView tv = new TextView(this);
String envText = NightModeUtils.INSTANCE.isNightMode(this) ? "夜间模式" : "日间模式";
tv.setBackground(ContextCompat.getDrawable(this, R.color.theme));
tv.setText(envText);
tv.setGravity(Gravity.CENTER);
tv.setTextColor(Color.WHITE);
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13);
tv.measure(0, 0);
tv.setAlpha(NightModeUtils.INSTANCE.isNightMode(this) ? 0.8F : 0.15F);
tv.setId(ID_NIGHT_INDICATOR);
int height = tv.getMeasuredHeight();
int width = tv.getMeasuredWidth();
tv.setPadding(DisplayUtils.dip2px(20), 0, DisplayUtils.dip2px(20), 0);
ll.setTranslationX(DisplayUtils.dip2px(-20));
ll.setRotation(-45);
ll.addView(tv);
ll.setPadding(0, (width - height) / 2, 0, (width - height) / 2);
if (PackageFlavorHelper.IS_TEST_FLAVOR) {
tv.setOnClickListener(v -> {
//切换深色模式
String mode;
String positive;
String negative;
if (NightModeUtils.INSTANCE.getSystemMode()) {
mode = "跟随系统模式";
positive = "普通模式";
negative = "深色模式";
} else if (NightModeUtils.INSTANCE.getNightMode()) {
mode = "深色模式";
positive = "跟随系统模式";
negative = "普通模式";
} else {
mode = "普通模式";
positive = "跟随系统模式";
negative = "深色模式";
}
DialogHelper.showCenterDialog(this, "选择模式", "当前为 " + mode, positive, negative, () -> {
if (NightModeUtils.INSTANCE.getSystemMode()) {
NightModeUtils.INSTANCE.setNightMode(false);
NightModeUtils.INSTANCE.setSystemMode(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_NO);
}
} else {
NightModeUtils.INSTANCE.setSystemMode(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
}
}
NightModeUtils.INSTANCE.initNightMode();
}, () -> {
if (NightModeUtils.INSTANCE.getSystemMode()) {
NightModeUtils.INSTANCE.setNightMode(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES);
}
} else {
boolean nightMode = NightModeUtils.INSTANCE.getNightMode();
NightModeUtils.INSTANCE.setNightMode(!NightModeUtils.INSTANCE.getNightMode());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
getDelegate().setLocalNightMode(nightMode ? AppCompatDelegate.MODE_NIGHT_NO : AppCompatDelegate.MODE_NIGHT_YES);
}
}
NightModeUtils.INSTANCE.setSystemMode(false);
NightModeUtils.INSTANCE.initNightMode();
});
});
}
return ll;
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(final EBShowDialog showDialog) {
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)
&& this.getClass().getName().equals(RunningUtils.getTopActivity(this))) {
if (DOWNLOAD_HIJACK.equals(showDialog.getType())) {
DialogUtils.showQqSessionDialog(this);// 建议用户联系客服
} else if (PLUGGABLE.equals(showDialog.getType())) {
DialogHelper.showPluginDialog(this, () -> {
if (FileUtils.isEmptyFile(showDialog.getPath())) {
toast(R.string.install_failure_hint);
} else {
PackageInstaller.uninstall(BaseActivity.this, showDialog.getPath());
}
return null;
});
} else if (SIGNATURE_CONFLICT.equals(showDialog.getType())) {
DialogHelper.showSignatureConflictDialog(this, () -> {
PackageInstaller.uninstall(BaseActivity.this, showDialog.getPath());
return null;
});
} else if (LOGIN_EXCEPTION.equals(showDialog.getType())) {
if (mIsExistLogoutDialog) return;
mIsExistLogoutDialog = true;
try {
JSONObject object = new JSONObject(showDialog.getPath());
JSONObject device = object.getJSONObject("device");
String model = device.getString("model");
DialogHelper.showCenterDialog(this, "你的账号已在另外一台设备登录"
, StringUtils.buildString("", model, "")
, "知道了", "重新登录"
, () -> {
}
, () -> {
if (SPUtils.getBoolean(Constants.SP_HAS_GET_PHONE_INFO) || NetworkUtils.isOpenMobileData(BaseActivity.this)) {
QuickLoginHelper.startLogin(BaseActivity.this, "你的账号已在另外一台设备登录多设备-重新登录");
} else {
startActivity(LoginActivity.getIntent(BaseActivity.this,
"你的账号已在另外一台设备登录多设备-重新登录"));
}
}
);
mBaseHandler.postDelayed(() -> mIsExistLogoutDialog = false, 5000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
@Override
protected void onPause() {
super.onPause();
if (isFinishing()) {
onFinish();
for (Fragment fragment : getSupportFragmentManager().getFragments()) {
if (fragment.isAdded() && fragment instanceof BaseFragment) {
((BaseFragment) fragment).onParentActivityFinish();
}
}
}
}
/**
* 此回调可用于确认当前 activity 已经执行了 finish() 方法并处于 isFinishing 状态
*/
protected void onFinish() {
}
@Override
public void onRequestPermissionsResult(int requestCode,
@NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
}
@Override
public void onPermissionsDenied(int requestCode, List<String> perms) {
}
@Override
public void onPermissionsGranted(int requestCode, List<String> perms) {
}
protected void setStatusBarColor(int color) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.setStatusBarColor(color);
}
}
/**
* 提供当前 activity 的中文名 (不重载的话为类名)
*/
public String getActivityNameInChinese() {
return getClass().getSimpleName();
}
/**
* @param entrance 上一个页面的链式入口名称
* @param path 当前页面名称
* @return 完整的链式入口名称
*/
public static String mergeEntranceAndPath(String entrance, String path) {
if (TextUtils.isEmpty(entrance) && TextUtils.isEmpty(path)) return "";
if (TextUtils.isEmpty(entrance) && !TextUtils.isEmpty(path)) {
return StringUtils.buildString("(", path, ")");
}
if (!TextUtils.isEmpty(entrance) && TextUtils.isEmpty(path)) {
return entrance;
}
return StringUtils.buildString(entrance, "+(", path, ")");
}
protected boolean useEventBus() {
return true;
}
@Override
public Resources getResources() {
Resources resources = super.getResources();
if (resources.getConfiguration().fontScale != 1.0f) {
Configuration configuration = resources.getConfiguration();
configuration.fontScale = 1.0f;
resources.updateConfiguration(configuration, resources.getDisplayMetrics());
}
return resources;
}
/**
* ActivityThread每次调用onSaveInstanceState时outState大小都会累加最终会导致{@link TransactionTooLargeException}异常
* 解决方案判断每次获取到的outState大小当达到300k时手动clear掉
*/
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
if (preventRecreateFragmentByFragmentManager()) {
outState = discardFragmentFromSaveInstanceState(outState);
}
long bundleSize = getBundleSize(outState);
if (bundleSize > MAX_BUNDLE_SIZE * 1024) {
outState.clear();
}
}
/**
* 是否停用 Activity 重建时 FragmentManager 根据 saveState 自动重建保存的 Fragment 的功能
*/
protected boolean preventRecreateFragmentByFragmentManager() {
return false;
}
private Bundle discardFragmentFromSaveInstanceState(Bundle outState) {
if (outState != null) {
outState.remove("android:support:fragments");
}
return outState;
}
private long getBundleSize(Bundle bundle) {
long dataSize;
Parcel obtain = Parcel.obtain();
try {
obtain.writeBundle(bundle);
dataSize = obtain.dataSize();
} finally {
obtain.recycle();
}
return dataSize;
}
@Override
public Pair<String, String> getBusinessId() {
return null;
}
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
onNightModeChange();
}
protected void onNightModeChange() {
if (BuildConfig.IS_NIGHT_MODE_ON) {
mNightMode = NightModeUtils.INSTANCE.isNightMode(this);
TextView tv = findViewById(ID_NIGHT_INDICATOR);
if (tv != null) {
tv.setText(NightModeUtils.INSTANCE.isNightMode(this) ? "夜间模式" : "日间模式");
tv.setAlpha(NightModeUtils.INSTANCE.isNightMode(this) ? 0.8F : 0.15F);
}
if (isAutoResetViewBackgroundEnabled()) {
updateStaticViewBackground(getWindow().getDecorView());
}
}
}
protected boolean isAutoResetViewBackgroundEnabled() {
return false;
}
/**
* 自动重置部分 view 的背景颜色/资源
*
* @param view 父 view
*/
private void updateStaticViewBackground(View view) {
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
View child = ((ViewGroup) view).getChildAt(i);
updateStaticViewBackground(child);
}
}
String backgroundString = (String) view.getTag(CustomLayoutInflaterFactory.TAG_BACKGROUND_ID);
String textColorString = (String) view.getTag(CustomLayoutInflaterFactory.TAG_TEXT_COLOR_ID);
if (backgroundString != null) {
if (backgroundString.startsWith("#")) return;
int backgroundId = Integer.parseInt(
backgroundString
.replace("@", "")
.replace("?", "")
);
if (backgroundId != 0) {
try {
TypedValue value = new TypedValue();
getResources().getValue(backgroundId, value, true);
if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
view.setBackgroundColor(ExtensionsKt.toColor(backgroundId, this));
} else {
view.setBackground(ExtensionsKt.toDrawable(backgroundId, this));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
if (textColorString != null && view instanceof TextView) {
if (textColorString.startsWith("#")) return;
int textColorId = Integer.parseInt(
textColorString
.replace("@", "")
.replace("?", "")
);
if (textColorId != 0) {
try {
final ColorStateList colorStateList = ContextCompat.getColorStateList(this, textColorId);
((TextView) view).setTextColor(colorStateList);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}

View File

@ -1,25 +1,24 @@
package com.gh.gamecenter.common.base.activity;
package com.gh.base;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.gh.gamecenter.common.R;
import com.gh.gamecenter.common.base.adapter.FragmentAdapter;
import com.gh.gamecenter.common.base.fragment.BaseFragment_TabLayout;
import com.gh.gamecenter.common.view.TabIndicatorView;
import com.gh.base.adapter.FragmentAdapter;
import com.gh.base.fragment.BaseFragment_TabLayout;
import com.gh.common.view.TabIndicatorView;
import com.gh.gamecenter.R;
import com.google.android.material.tabs.TabLayout;
import com.lightgame.view.NoScrollableViewPager;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.ViewPager;
/**
* Created by khy on 15/03/18.
*/
@ -87,7 +86,7 @@ public abstract class BaseActivity_TabLayout extends ToolBarActivity implements
mViewPager.setOffscreenPageLimit(mFragmentsList.size());
mViewPager.addOnPageChangeListener(this);
mViewPager.setAdapter(provideAdapter());
mViewPager.setAdapter(new FragmentAdapter(getSupportFragmentManager(), mFragmentsList, mTabTitleList));
mViewPager.setCurrentItem(mCheckedIndex);
mTabLayout.setupWithViewPager(mViewPager);
mTabIndicatorView.setupWithTabLayout(mTabLayout);
@ -104,21 +103,9 @@ public abstract class BaseActivity_TabLayout extends ToolBarActivity implements
tab.setCustomView(tabView);
}
initTabStyle();
}
protected PagerAdapter provideAdapter() {
return new FragmentAdapter(getSupportFragmentManager(), mFragmentsList, mTabTitleList);
}
protected void initTabStyle() {
BaseFragment_TabLayout.initTabStyle(mTabLayout, mCheckedIndex);
}
protected void updateTabStyle(TabLayout.Tab tab, boolean isChecked) {
BaseFragment_TabLayout.updateTabStyle(tab, isChecked);
}
private ArrayList<Fragment> restoreFragments() {
String tag = "android:switcher:" + mViewPager.getId() + ":";
ArrayList<Fragment> fragments = new ArrayList<>();
@ -149,20 +136,20 @@ public abstract class BaseActivity_TabLayout extends ToolBarActivity implements
}
@Override
protected void onDarkModeChanged() {
super.onDarkModeChanged();
protected void onNightModeChange() {
super.onNightModeChange();
View container = findViewById(R.id.activity_tab_container);
if (container != null) {
container.setBackgroundColor(ContextCompat.getColor(this, R.color.ui_surface));
container.setBackgroundColor(ContextCompat.getColor(this, R.color.background_white));
for (int i = 0; i < mTabLayout.getTabCount(); i++) {
TabLayout.Tab tab = mTabLayout.getTabAt(i);
if (tab != null) {
updateTabStyle(tab, tab.isSelected());
BaseFragment_TabLayout.updateTabStyle(tab, tab.isSelected());
}
}
}
if (mDividerLineView != null) {
mDividerLineView.setBackgroundColor(ContextCompat.getColor(this, R.color.ui_divider));
mDividerLineView.setBackgroundColor(ContextCompat.getColor(this, R.color.divider));
}
}
}

View File

@ -1,10 +1,7 @@
package com.gh.gamecenter.common.base;
import android.view.View;
package com.gh.base;
import androidx.recyclerview.widget.RecyclerView;
import com.gh.gamecenter.common.callback.OnListClickListener;
import android.view.View;
/**
* 目前仅提供butterknife bind方法

View File

@ -6,7 +6,6 @@ import android.app.Activity
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.os.Bundle
import android.text.TextUtils
import android.view.View
@ -15,21 +14,16 @@ import android.widget.CheckBox
import android.widget.FrameLayout
import android.widget.TextView
import androidx.lifecycle.Observer
import com.gh.common.util.DialogUtils
import com.gh.common.util.NewLogUtils
import com.gh.common.AppExecutor
import com.gh.common.runOnIoThread
import com.gh.common.util.*
import com.gh.common.view.RichEditor
import com.gh.gamecenter.CropImageActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.activity.ToolBarActivity
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.qa.editor.*
import com.gh.gamecenter.feature.entity.AnswerEntity
import com.gh.gamecenter.feature.entity.ArticleEntity
import com.gh.gamecenter.qa.entity.AnswerEntity
import com.gh.gamecenter.qa.entity.ArticleEntity
import com.gh.gamecenter.qa.entity.EditorInsertEntity
import com.gh.gamecenter.video.poster.PosterEditActivity
import com.gh.gamecenter.video.upload.UploadManager
@ -43,8 +37,7 @@ import org.json.JSONArray
import org.json.JSONObject
import java.io.File
// TODO: 移动到module_bbs模块
abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor() : ToolBarActivity(),
abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> : ToolBarActivity(),
KeyboardHeightObserver, UploadVideoListener {
lateinit var mRichEditor: RichEditor
@ -57,16 +50,11 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
private lateinit var mEditorFontItalic: CheckableImageView
private lateinit var mEditorFontStrikeThrough: CheckableImageView
private lateinit var mEditorFontUnderline: CheckableImageView
private lateinit var mEditorParagraphDivider: CheckableImageView
private lateinit var mEditorParagraphH1: CheckableImageView
private lateinit var mEditorParagraphH2: CheckableImageView
private lateinit var mEditorParagraphH3: CheckableImageView
private lateinit var mEditorParagraphH4: CheckableImageView
private lateinit var mEditorParagraphQuote: CheckableImageView
private lateinit var mEditorAlignLeft: CheckableImageView
private lateinit var mEditorAlignCenter: CheckableImageView
private lateinit var mEditorAlignRight: CheckableImageView
private lateinit var mEditorAlignContainer: View
private lateinit var mEditorFontContainer: View
private lateinit var mEditorParagraphContainer: View
private lateinit var mEditorLinkContainer: View
@ -102,7 +90,6 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
mRichEditor.insertCustomStyleLink(insertData)
}
}
INSERT_ARTICLE_CODE -> {
val article =
data?.getParcelableExtra<ArticleEntity>(ArticleEntity::class.java.simpleName)
@ -112,7 +99,6 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
mRichEditor.insertCustomStyleLink(insertData)
}
}
INSERT_GAME_CODE -> {
val game = data?.getParcelableExtra<GameEntity>(GameEntity::class.java.simpleName)
if (game != null) {
@ -121,38 +107,30 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
mRichEditor.insertCustomStyleLink(insertData)
}
}
INSERT_GAME_COLLECTION_CODE -> {
val gameCollectionEntity =
data?.getParcelableExtra<GamesCollectionEntity>(GamesCollectionEntity::class.java.simpleName)
val gameCollectionEntity = data?.getParcelableExtra<GamesCollectionEntity>(GamesCollectionEntity::class.java.simpleName)
if (gameCollectionEntity != null) {
mRichEditor.focusEditor()
insertData = EditorInsertEntity.transform(gameCollectionEntity)
mRichEditor.insertCustomStyleLink(insertData)
}
}
REQUEST_CODE_IMAGE -> {
if (data != null) mViewModel.uploadPic(data)
}
INSERT_MEDIA_VIDEO_CODE -> {
val localVideoList =
data?.getParcelableArrayListExtra<LocalVideoEntity>(LocalVideoEntity::class.java.name)
?: arrayListOf()
val localVideoList = data?.getParcelableArrayListExtra<LocalVideoEntity>(LocalVideoEntity::class.java.name) ?: arrayListOf()
if (localVideoList.isNotEmpty()) {
mRichEditor.focusEditor()
uploadVideo(localVideoList)
}
}
REQUEST_CODE_IMAGE_CROP -> {
val imagePath = data?.getStringExtra(CropImageActivity.RESULT_CLIP_PATH)
if (!imagePath.isNullOrEmpty()) {
mViewModel.uploadPoster(imagePath)
}
}
INSERT_VIDEO_CODE -> {
val videoEntity = data?.getParcelableExtra<MyVideoEntity>(MyVideoEntity::class.java.simpleName)
if (videoEntity != null) {
@ -206,12 +184,7 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
mEditorParagraphH2 = findViewById(R.id.editor_paragraph_h2)
mEditorParagraphH3 = findViewById(R.id.editor_paragraph_h3)
mEditorParagraphH4 = findViewById(R.id.editor_paragraph_h4)
mEditorParagraphDivider = findViewById(R.id.editor_paragraph_divider)
mEditorParagraphQuote = findViewById(R.id.editor_paragraph_quote)
mEditorAlignLeft = findViewById(R.id.editor_align_left)
mEditorAlignCenter = findViewById(R.id.editor_align_center)
mEditorAlignRight = findViewById(R.id.editor_align_right)
mEditorAlignContainer = findViewById(R.id.editor_align_container)
mEditorFontContainer = findViewById(R.id.editor_font_container)
mEditorParagraphContainer = findViewById(R.id.editor_paragraph_container)
mEditorLinkContainer = findViewById(R.id.editor_link_container)
@ -232,9 +205,6 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
mViewModel.setUploadVideoListener(this)
mKeyboardHeightProvider = KeyboardHeightProvider(this)
mRichEditor.post { mKeyboardHeightProvider?.start() }
mRichEditor.enableForceDark(DarkModeUtils.isDarkModeOn(this))
mRichEditor.setEditorBackgroundColor(R.color.ui_surface.toColor(this))
mRichEditor.setEditorFontColor(if (mIsDarkModeOn) Color.parseColor("#C2C2C2") else Color.parseColor("#4A4A4A"))
// 防止个别手机在Js里无法获取粘贴内容
mRichEditor.addJavascriptInterface(OnPasteListener(), "onPasteListener")
mRichEditor.addJavascriptInterface(OnCursorChangeListener(), "OnCursorChangeListener")
@ -258,13 +228,6 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
mRichEditor.hasFocus()
} else false
}
mRichEditor.setOnDecorationChangeListener { _, types ->
mEditorAlignLeft.isChecked = types.contains(RichEditor.Type.JUSTIFYLEFT)
mEditorAlignCenter.isChecked = types.contains(RichEditor.Type.JUSTIFYCENTER)
mEditorAlignRight.isChecked = types.contains(RichEditor.Type.JUSTIFYRIGHT)
}
mOriginalCb.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
mOriginalTipsContainer.alpha = 0f
@ -349,9 +312,6 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
MtaHelper.onEvent(mtaEventName(), "文字样式", "文字样式-下滑线")
}
}
mEditorParagraphDivider.setOnClickListener {
mRichEditor.insertDivider()
}
mEditorParagraphH1.setOnClickListener {
if (mEditorParagraphH1.isChecked) {
mRichEditor.formatBlock()
@ -397,27 +357,6 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
}
mEditorParagraphQuote.isChecked = !mEditorParagraphQuote.isChecked
}
mEditorAlignLeft.setOnClickListener {
if (!mEditorAlignLeft.isChecked) {
mRichEditor.setAlignLeft()
MtaHelper.onEvent(mtaEventName(), "文本对齐选项", "文本对齐选项-靠左")
mEditorAlignLeft.isChecked = !mEditorAlignLeft.isChecked
}
}
mEditorAlignCenter.setOnClickListener {
if (!mEditorAlignCenter.isChecked) {
mRichEditor.setAlignCenter()
MtaHelper.onEvent(mtaEventName(), "文本对齐选项", "文本对齐选项-靠中")
mEditorAlignCenter.isChecked = !mEditorAlignCenter.isChecked
}
}
mEditorAlignRight.setOnClickListener {
if (!mEditorAlignRight.isChecked) {
mRichEditor.setAlignRight()
MtaHelper.onEvent(mtaEventName(), "文本对齐选项", "文本对齐选项-靠右")
mEditorAlignRight.isChecked = !mEditorAlignRight.isChecked
}
}
findViewById<View>(R.id.editor_link_answer).setOnClickListener {
MtaHelper.onEvent(mtaEventName(), "插入链接", "插入链接-回答")
startActivityForResult(
@ -497,22 +436,25 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
return
}
try {
PermissionHelper.checkStoragePermissionBeforeAction(this) {
val maxChooseCount = if (videoCount + 3 <= MAX_MEDIA_COUNT) 3 else MAX_MEDIA_COUNT - videoCount
startActivityForResult(
LocalMediaActivity.getIntent(
this@BaseRichEditorActivity,
LocalMediaActivity.ChooseType.VIDEO,
maxChooseCount,
if (mtaEventName() == "提问帖") "发提问帖" else "发帖子"
), INSERT_MEDIA_VIDEO_CODE
)
NewLogUtils.logChooseMedia(
"view_media",
if (mtaEventName() == "提问帖") "提问帖" else "帖子",
"视频"
)
}
PermissionHelper.checkStoragePermissionBeforeAction(this,
object : EmptyCallback {
override fun onCallback() {
val maxChooseCount = if (videoCount + 3 <= MAX_MEDIA_COUNT) 3 else MAX_MEDIA_COUNT - videoCount
startActivityForResult(
LocalMediaActivity.getIntent(
this@BaseRichEditorActivity,
LocalMediaActivity.ChooseType.VIDEO,
maxChooseCount,
if (mtaEventName() == "提问帖") "发提问帖" else "发帖子"
), INSERT_MEDIA_VIDEO_CODE
)
NewLogUtils.logChooseMedia(
"view_media",
if (mtaEventName() == "提问帖") "提问帖" else "帖子",
"视频"
)
}
})
} catch (e: Exception) {
toast(R.string.media_image_hint)
e.printStackTrace()
@ -522,21 +464,23 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
private fun chooseImage() {
MtaHelper.onEvent(mtaEventName(), "插入图片", "插入图片")
val imageCount = mViewModel.quoteCountEntity.imageCount
if (imageCount >= MAX_IMAGE_COUNT) {
if (imageCount >= MAX_MEDIA_COUNT) {
toast(R.string.answer_edit_max_img_hint)
return
}
try {
PermissionHelper.checkStoragePermissionBeforeAction(this) {
val maxChooseCount = if (imageCount + 10 <= MAX_IMAGE_COUNT) 10 else MAX_IMAGE_COUNT - imageCount
val intent = LocalMediaActivity.getIntent(
this@BaseRichEditorActivity,
LocalMediaActivity.ChooseType.IMAGE,
maxChooseCount,
if (mtaEventName() == "提问帖") "发提问帖" else "发帖子"
)
startActivityForResult(intent, REQUEST_CODE_IMAGE)
}
PermissionHelper.checkStoragePermissionBeforeAction(this, object : EmptyCallback {
override fun onCallback() {
val maxChooseCount = if (imageCount + 10 <= MAX_MEDIA_COUNT) 10 else MAX_MEDIA_COUNT - imageCount
val intent = LocalMediaActivity.getIntent(
this@BaseRichEditorActivity,
LocalMediaActivity.ChooseType.IMAGE,
maxChooseCount,
if (mtaEventName() == "提问帖") "发提问帖" else "发帖子"
)
startActivityForResult(intent, REQUEST_CODE_IMAGE)
}
})
} catch (e: Exception) {
toast(R.string.media_image_hint)
e.printStackTrace()
@ -559,7 +503,6 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
mEditorFontContainer.visibility = if (mEditorFont.isChecked) View.VISIBLE else View.GONE
mEditorParagraphContainer.visibility =
if (mEditorFont.isChecked) View.VISIBLE else View.GONE
mEditorAlignContainer.visibility = if (mEditorFont.isChecked) View.VISIBLE else View.GONE
mEditorLinkContainer.visibility = View.GONE
mTagsContainer.visibility = View.GONE
mIsExtendedKeyboardShow = mEditorFont.isChecked
@ -581,7 +524,6 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
if (mEditorLink.isChecked) View.VISIBLE else View.GONE
mEditorLinkContainer.visibility = if (mEditorLink.isChecked) View.VISIBLE else View.GONE
mEditorFontContainer.visibility = View.GONE
mEditorAlignContainer.visibility = View.GONE
mEditorParagraphContainer.visibility = View.GONE
mTagsContainer.visibility = View.GONE
mIsExtendedKeyboardShow = mEditorLink.isChecked
@ -793,16 +735,6 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
abstract fun provideViewModel(): VM
abstract fun getVideoGuideKey(): String
override fun isAutoResetViewBackgroundEnabled(): Boolean = true
override fun onDarkModeChanged() {
super.onDarkModeChanged()
updateStatusBarColor(R.color.ui_surface, R.color.ui_surface)
mRichEditor.enableForceDark(DarkModeUtils.isDarkModeOn(this))
mRichEditor.setEditorBackgroundColor(R.color.ui_surface.toColor(this))
mRichEditor.setEditorFontColor(if (mIsDarkModeOn) Color.parseColor("#C2C2C2") else Color.parseColor("#4A4A4A"))
}
companion object {
const val ELEMENT_NAME_BOLD = " b "
const val ELEMENT_NAME_ITALIC = " i "
@ -821,7 +753,6 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
const val INSERT_VIDEO_CODE = 415
const val MAX_INPUT_TEXT_NUM = 10000
const val MAX_MEDIA_COUNT = 20
const val MAX_IMAGE_COUNT = 70
const val REQUEST_CODE_IMAGE = 120
const val INSERT_MEDIA_VIDEO_CODE = 121

View File

@ -1,6 +1,5 @@
package com.gh.base
import android.annotation.SuppressLint
import android.app.Application
import android.content.Intent
import android.graphics.Bitmap
@ -10,19 +9,15 @@ import android.text.TextUtils
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import com.gh.base.fragment.WaitingDialogFragment
import com.gh.common.runOnUiThread
import com.gh.common.util.*
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.fragment.WaitingDialogFragment
import com.gh.gamecenter.common.entity.ErrorEntity
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.core.utils.MD5Utils
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.entity.ForumDetailEntity
import com.gh.gamecenter.entity.ErrorEntity
import com.gh.gamecenter.entity.LocalVideoEntity
import com.gh.gamecenter.entity.QuoteCountEntity
import com.gh.gamecenter.qa.BbsType
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.retrofit.service.ApiService
import com.gh.gamecenter.video.upload.OnUploadListener
@ -31,24 +26,24 @@ import com.google.gson.JsonObject
import com.lightgame.utils.Utils
import com.zhihu.matisse.Matisse
import com.zhihu.matisse.internal.utils.PathUtils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import retrofit2.HttpException
import java.io.File
import java.io.FileOutputStream
import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
import kotlin.collections.LinkedHashMap
import kotlin.collections.List
import kotlin.collections.Map
import kotlin.collections.find
import kotlin.collections.forEach
import kotlin.collections.set
// TODO: 移动到module_bbs模块
abstract class BaseRichEditorViewModel(application: Application) : AndroidViewModel(application) {
val mApi: ApiService = RetrofitManager.getInstance().api
val mNewApi: ApiService = RetrofitManager.getInstance().newApi
val processDialog = MediatorLiveData<WaitingDialogFragment.WaitingDialogData>()
val uploadingImage = ArrayList<LinkedHashMap<String, String>>()
val chooseImagesUpload = MutableLiveData<LinkedHashMap<String, String>>()
val chooseImagesUploadSuccess = MutableLiveData<LinkedHashMap<String, String>>()
var uploadImageSubscription: Disposable? = null
@ -61,11 +56,10 @@ abstract class BaseRichEditorViewModel(application: Application) : AndroidViewMo
val TITLE_MIN_LENGTH = 6
val MIN_TEXT_LENGTH = 6
val MAX_TEXT_LENGTH = 10000
val FILE_HOST = "file:///"
var id = ""//视频标记
var videoId = ""//更改封面视频id
val quoteCountEntity = QuoteCountEntity()//数据上报用
val sectionListLiveData = MutableLiveData<List<ForumDetailEntity.Section>>()
var isModerator = false
fun setUploadVideoListener(uploadVideoListener: UploadVideoListener) {
this.mUploadVideoListener = uploadVideoListener
@ -74,10 +68,7 @@ abstract class BaseRichEditorViewModel(application: Application) : AndroidViewMo
//检查图片是否符合规则并上传图片
fun uploadPic(data: Intent) {
val uris = Matisse.obtainResult(data)
val rawImgUrlList = ArrayList<String>() // 需要上传图片的原始地址列表
val uploadingImgList = ArrayList<String>() // 正在上传图片的地址列表(已压缩处理)
val compressedImgUrlList = ArrayList<String>() // 压缩处理后图片的地址列表
val pictureList = ArrayList<String>()
for (uri in uris) {
val picturePath = PathUtils.getPath(getApplication(), uri)
if (picturePath != null) {
@ -91,12 +82,12 @@ abstract class BaseRichEditorViewModel(application: Application) : AndroidViewMo
continue
}
Utils.log("picturePath = $picturePath")
rawImgUrlList.add(picturePath)
pictureList.add(picturePath)
} else {
Utils.log("picturePath is null")
}
}
if (rawImgUrlList.size == 0) return
if (pictureList.size == 0) return
val imageType = when (getRichType()) {
RichType.ARTICLE -> UploadImageUtils.UploadType.community_article
RichType.QUESTION -> UploadImageUtils.UploadType.question
@ -104,7 +95,7 @@ abstract class BaseRichEditorViewModel(application: Application) : AndroidViewMo
}
uploadImageSubscription = UploadImageUtils.compressAndUploadImageList(
imageType,
rawImgUrlList,
pictureList,
false,
object : UploadImageUtils.OnUploadImageListListener {
override fun onProgress(total: Long, progress: Long) {}
@ -114,120 +105,91 @@ abstract class BaseRichEditorViewModel(application: Application) : AndroidViewMo
imageUrls.forEach {
chooseImageMd5Map[MD5Utils.getUrlMD5(it)] = ""
}
uploadingImgList.addAll(imageUrls)
compressedImgUrlList.addAll(imageUrls)
uploadingImage.add(chooseImageMd5Map)
chooseImagesUpload.postValue(chooseImageMd5Map)
}
override fun onSingleSuccess(imageUrlMap: Map<String, String>) {
imageUrlMap.forEach {
if (uploadingImgList.contains(it.key)) {
uploadingImgList.remove(it.key)
}
}
override fun onSingleSuccess(imageUrl: Map<String, String>) {
val map = LinkedHashMap<String, String>()
for (key in imageUrlMap.keys) {
// 文件格式为 HEIC 时,使用经 OSS 转码的图片作为预览图片
if (FileUtils.getFileMimeType(getApplication(), key.decodeURI())?.lowercase(Locale.CHINA)?.contains("heic") == true) {
val transformedImgUrl = ImageUtils.getIdealImageUrl(imageUrlMap[key], 5000) ?: ""
map[MD5Utils.getUrlMD5(key)] = transformedImgUrl
mapImages[transformedImgUrl.decodeURI()] = imageUrlMap[key] ?: ""
} else {
map[MD5Utils.getUrlMD5(key)] = imageUrlMap[key] ?: ""
mapImages[TextUtils.htmlEncode(key).decodeURI()] = imageUrlMap[key] ?: ""
}
for (key in imageUrl.keys) {
map[MD5Utils.getUrlMD5(key)] = FILE_HOST + key.decodeURI()
mapImages[TextUtils.htmlEncode(key).decodeURI()] = imageUrl[key] ?: ""
}
chooseImagesUploadSuccess.value = map
chooseImagesUploadSuccess.postValue(map)
}
override fun onSuccess(imageUrlMap: LinkedHashMap<String, String>, errorMap: Map<String, Exception>) {
imageUrlMap.forEach {
if (uploadingImgList.contains(it.key)) {
uploadingImgList.remove(it.key)
}
override fun onSuccess(
imageUrl: LinkedHashMap<String, String>,
errorMap: Map<String, Exception>
) {
val uploadMap = uploadingImage.find {
it.containsKey(
MD5Utils.getUrlMD5(
imageUrl.entries.iterator().next().key
)
)
}
uploadMap?.let {
uploadingImage.remove(uploadMap)
}
var errorSize = compressedImgUrlList.size - imageUrlMap.size
if (errorSize > 0 || uploadingImgList.isNotEmpty()) {
val errorImageMap = LinkedHashMap<String, String>()
val errorSize = pictureList.size - imageUrl.size
if (errorSize > 0) {
val map = LinkedHashMap<String, String>()
for (key in errorMap.keys) {
errorImageMap[MD5Utils.getUrlMD5(key)] = ""
map[MD5Utils.getUrlMD5(key)] = ""
}
//value为空会删除PlaceholderImage
chooseImagesUploadSuccess.postValue(map)
for (rawImgUrl in compressedImgUrlList) {
if (!imageUrlMap.containsKey(rawImgUrl)) {
errorImageMap[MD5Utils.getUrlMD5(rawImgUrl)] = ""
for (error in errorMap.values) {
if (error is HttpException && error.code() == 403) {
Utils.toast(getApplication(), errorSize.toString() + "张违规图片上传失败")
return
}
}
errorSize = if (errorMap.isEmpty()) {
errorImageMap.size
} else {
errorMap.size + errorImageMap.size
}
// value为空会删除PlaceholderImage
chooseImagesUploadSuccess.value = errorImageMap
if (handleUploadError(errorSize, errorMap)) return
if (errorSize > 0) {
ToastUtils.showToast(errorSize.toString() + "张图片上传失败")
}
Utils.toast(getApplication(), errorSize.toString() + "张图片上传失败")
}
}
override fun onError(errorMap: Map<String, Exception>) {
val errorSize = uploadingImgList.size
if (uploadingImgList.size > 0) {
val errorSize = errorMap.size
if (errorSize > 0) {
val map = LinkedHashMap<String, String>()
for (key in uploadingImgList) {
for (key in errorMap.keys) {
map[MD5Utils.getUrlMD5(key)] = ""
}
// value为空会删除PlaceholderImage
chooseImagesUploadSuccess.value = map
//value为空会删除PlaceholderImage
chooseImagesUploadSuccess.postValue(map)
}
if (handleUploadError(errorSize, errorMap)) return
if (errorSize == 0) return
for (error in errorMap.values) {
if (error is HttpException && error.code() == 403) {
val e = error.response()?.errorBody()?.string()?.toObject<ErrorEntity>()
if (e != null && e.code == 403017) {
Utils.toast(
getApplication(),
errorSize.toString() + "张图片的宽或高超过限制,请裁剪后上传"
)
} else {
Utils.toast(getApplication(), errorSize.toString() + "张违规图片上传失败")
}
return
}
}
if (errorSize == 1) {
ToastUtils.showToast("图片上传失败")
Utils.toast(getApplication(), "图片上传失败")
} else {
ToastUtils.showToast(errorSize.toString() + "张图片上传失败")
Utils.toast(getApplication(), errorSize.toString() + "张图片上传失败")
}
}
})
}
/**
* 处理上传错误 (包括超时 cancel 的异常)
* @return 如果 toast 过了就返回 true
*/
private fun handleUploadError(
errorSize: Int,
errorMap: Map<String, Exception>
): Boolean {
for (error in errorMap.values) {
if (error is HttpException && error.code() == 403) {
val e = error.response()?.errorBody()?.string()?.toObject<ErrorEntity>()
if (e != null && e.code == 403017) {
ToastUtils.showToast(errorSize.toString() + "张图片的宽或高超过限制,请裁剪后上传")
} else {
ToastUtils.showToast(errorSize.toString() + "张违规图片上传失败")
}
return true
}
}
return false
}
fun uploadPoster(picturePath: String) {
processDialog.postValue(WaitingDialogFragment.WaitingDialogData("封面上传中...", true))
uploadImageSubscription =
UploadImageUtils.compressAndUploadImage(
UploadImageUtils.UploadType.poster,
UploadImageUtils.compressAndUploadImage(UploadImageUtils.UploadType.poster,
picturePath,
false,
object : UploadImageUtils.OnUploadImageListener {
@ -346,8 +308,7 @@ abstract class BaseRichEditorViewModel(application: Application) : AndroidViewMo
return
}
uploadImageSubscription =
UploadImageUtils.compressAndUploadImage(
UploadImageUtils.UploadType.poster,
UploadImageUtils.compressAndUploadImage(UploadImageUtils.UploadType.poster,
localVideoPoster,
false,
object : UploadImageUtils.OnUploadImageListener {
@ -426,30 +387,6 @@ abstract class BaseRichEditorViewModel(application: Application) : AndroidViewMo
return true
}
fun getForumSections(bbsId: String) {
mNewApi.getForumSections(bbsId)
.compose(observableToMain())
.subscribe(object : Response<List<ForumDetailEntity.Section>>() {
override fun onResponse(response: List<ForumDetailEntity.Section>?) {
response?.run {
sectionListLiveData.postValue(this)
}
}
})
}
@SuppressLint("CheckResult")
fun getModeratorsInfo(bbsId: String) {
mApi.getModeratorsInfo(bbsId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<JsonObject>() {
override fun onSuccess(data: JsonObject) {
isModerator = data["is_moderators"].asBoolean
}
})
}
private fun getVideoType(): String {
return when (type) {
BbsType.GAME_BBS.value -> {

View File

@ -1,9 +1,9 @@
package com.gh.gamecenter.common.base
package com.gh.base
import android.content.Context
import android.content.SharedPreferences
import com.gh.gamecenter.common.HaloApp
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.common.util.SPUtils
import com.halo.assistant.HaloApp
/**
* SP 实现的简单列表持久化结构
@ -12,7 +12,7 @@ abstract class BaseSimpleDao {
// 使用独有的 SP 文件
private val mSp: SharedPreferences by lazy {
HaloApp.getInstance().getSharedPreferences("SimpleDao", Context.MODE_PRIVATE)
HaloApp.getInstance().application.getSharedPreferences("SimpleDao", Context.MODE_PRIVATE)
}
fun add(key: String) {

View File

@ -1,11 +1,11 @@
package com.gh.gamecenter.core.utils
package com.gh.base
import android.app.Activity
object CurrentActivityHolder {
@JvmStatic
val activitySet by lazy { HashSet<Activity>() }
val activitySet = HashSet<Activity>()
@JvmStatic
fun getCurrentActivity(): Activity? {

View File

@ -0,0 +1,53 @@
package com.gh.base
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.gh.gamecenter.R
class CustomLayoutInflaterFactory(
private val mAppCompatActivity: AppCompatActivity
) : LayoutInflater.Factory2 {
override fun onCreateView(
parent: View?,
name: String,
context: Context,
attrs: AttributeSet
): View? {
val view: View?
try {
view = mAppCompatActivity.delegate.createView(parent, name, context, attrs)
?: mAppCompatActivity.onCreateView(parent, name, context, attrs)
?: mAppCompatActivity.layoutInflater.createView(name, null, attrs)
} catch (e: Exception) {
return null
}
val n = attrs.attributeCount
for (i in 0 until n) {
val attributeName = attrs.getAttributeName(i).toString()
if (attributeName.contains("background")) {
view?.setTag(TAG_BACKGROUND_ID, attrs.getAttributeValue(i))
} else if (attributeName.contains("textColor")) {
view?.setTag(TAG_TEXT_COLOR_ID, attrs.getAttributeValue(i))
}
}
return view
}
override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? {
return mAppCompatActivity.onCreateView(name, context, attrs)
}
companion object {
const val TAG_BACKGROUND_ID = R.string.background_id
const val TAG_TEXT_COLOR_ID = R.string.text_color_id
}
}

View File

@ -1,86 +0,0 @@
package com.gh.base
import android.view.Gravity
import androidx.appcompat.app.AppCompatActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.DarkModeUtils
import com.gh.gamecenter.common.utils.DialogHelper
import com.gh.gamecenter.common.utils.PackageFlavorHelper
import com.gh.gamecenter.common.utils.dip2px
import com.lzf.easyfloat.EasyFloat
import com.lzf.easyfloat.enums.ShowPattern
import com.lzf.easyfloat.enums.SidePattern
object DarkModeSwitchHelper {
fun showDarkModeSwitchFloatingView(activity: AppCompatActivity) {
if (PackageFlavorHelper.IS_TEST_FLAVOR) {
EasyFloat.with(activity)
.setLayout(R.layout.layout_day_mode_night_mode_switch)
.setTag("night_mode_switch_floating_view")
.setAnimator(null)
.setGravity(Gravity.TOP.xor(Gravity.END), 0, 114F.dip2px())
.setSidePattern(SidePattern.RESULT_SIDE)
.setDragEnable(true)
.setShowPattern(ShowPattern.CURRENT_ACTIVITY)
.registerCallback {
createResult { _, _, view ->
view?.setOnClickListener {
showDarkModeSwitchDialog(activity)
}
}
}
.show()
}
}
fun dismissDarkModeSwitchFloatingView() {
if (PackageFlavorHelper.IS_TEST_FLAVOR) {
EasyFloat.dismiss("night_mode_switch_floating_view")
}
}
private fun showDarkModeSwitchDialog(activity: AppCompatActivity) {
if (PackageFlavorHelper.IS_TEST_FLAVOR) {
//切换深色模式
var mode = "普通模式"
var positive = "跟随系统模式"
var negative = "深色模式"
if (DarkModeUtils.isFollowSystemDarkModeFromSp()) {
mode = "跟随系统模式"
positive = "普通模式"
negative = "深色模式"
} else if (DarkModeUtils.isAppDarkModeEnabledFromSp()) {
mode = "深色模式"
positive = "跟随系统模式"
negative = "普通模式"
}
DialogHelper.showDialog(
context = activity,
title = "选择模式",
content = "当前为 $mode",
confirmText = positive,
cancelText = negative,
confirmClickCallback = {
if (DarkModeUtils.isFollowSystemDarkModeFromSp()) {
DarkModeUtils.updateAppDarkModeStatusToSp(false)
DarkModeUtils.updateFollowSystemDarkModeToSp(false)
} else {
DarkModeUtils.updateFollowSystemDarkModeToSp(true)
}
DarkModeUtils.initDarkMode()
},
cancelClickCallback = {
if (DarkModeUtils.isFollowSystemDarkModeFromSp()) {
DarkModeUtils.updateAppDarkModeStatusToSp(true)
} else {
DarkModeUtils.updateAppDarkModeStatusToSp(!DarkModeUtils.isAppDarkModeEnabledFromSp())
}
DarkModeUtils.updateFollowSystemDarkModeToSp(false)
DarkModeUtils.initDarkMode()
},
extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
)
}
}
}

View File

@ -1,123 +0,0 @@
package com.gh.base
import android.graphics.Typeface
import android.os.Bundle
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import com.gh.download.DownloadManager
import com.gh.gamecenter.DownloadManagerActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.activity.ToolBarActivity
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.core.utils.SPUtils.getBoolean
import com.gh.gamecenter.entity.GameUpdateEntity
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.packagehelper.PackageViewModel
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
// TODO:移动到module_download模块中
abstract class DownloadToolbarActivity : ToolBarActivity() {
private var mDownloadCountHint: TextView? = null
private var mPackageViewModel: PackageViewModel? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (!getBoolean(Constants.SP_TEENAGER_MODE) && showDownloadMenu()) {
mPackageViewModel = viewModelProvider(PackageViewModel.Factory())
mPackageViewModel?.filterSameUpdateLiveData?.observe(this) { updateList: List<GameUpdateEntity> ->
updateDownloadCountHint(updateList)
}
}
}
override fun setToolbarMenu(res: Int) {
// 青少年模式下要隐藏下载按钮
if (getBoolean(Constants.SP_TEENAGER_MODE) && res == R.menu.menu_download) return
super.setToolbarMenu(res)
}
override fun inflateMenu(res: Int) {
super.inflateMenu(res)
if (!getBoolean(Constants.SP_TEENAGER_MODE) && showDownloadMenu()) {
createDownloadMenu(res)
}
}
private fun createDownloadMenu(res: Int) {
if (res != R.menu.menu_download) {
menuInflater.inflate(R.menu.menu_download, mActionMenuView.menu)
}
if (mPackageViewModel != null) {
updateDownloadCountHint(mPackageViewModel?.filterSameUpdateLiveData?.value)
}
val downloadMenuView = mActionMenuView.menu.findItem(R.id.menu_download).actionView
mDownloadCountHint = downloadMenuView?.findViewById(R.id.menu_download_count_hint)
mDownloadCountHint?.typeface = Typeface.createFromAsset(assets, Constants.DIN_FONT_PATH)
}
override fun onMenuItemClick(item: MenuItem?): Boolean {
if (item!!.itemId == R.id.menu_download) {
// MtaHelper.onEvent("下载管理", "下载管理入口", getActivityNameInChinese());
val intent = DownloadManagerActivity.getDownloadMangerIntent(this, mEntrance)
startActivity(intent)
return true
}
return super.onMenuItemClick(item)
}
private fun updateDownloadCountHint(updateList: List<GameUpdateEntity>?) {
if (mDownloadCountHint == null) return
val count = DownloadManager.getInstance().getDownloadOrUpdateCount(updateList)
if (count != null) {
mDownloadCountHint?.visibility = View.VISIBLE
mDownloadCountHint?.text = count
val params = mDownloadCountHint?.layoutParams
params?.width = if (count.isEmpty()) 6F.dip2px() else ConstraintLayout.LayoutParams.WRAP_CONTENT
params?.height = if (count.isEmpty()) 6F.dip2px() else 14F.dip2px()
(params as? ViewGroup.MarginLayoutParams)?.setMargins(
0,
if (count.isEmpty()) 0 else (-4F).dip2px(),
if (count.isEmpty()) (-4F).dip2px() else (-8F).dip2px(),
0
)
mDownloadCountHint?.setPadding(
if (count.isEmpty()) 0 else 4F.dip2px(),
0,
if (count.isEmpty()) 0 else 4F.dip2px(),
0
)
mDownloadCountHint?.minWidth = if (count.isEmpty()) 0 else 14F.dip2px()
mDownloadCountHint?.layoutParams = params
} else {
mDownloadCountHint?.visibility = View.GONE
}
}
protected open fun showDownloadMenu(): Boolean {
return false
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(status: EBDownloadStatus?) {
if (!getBoolean(Constants.SP_TEENAGER_MODE) && showDownloadMenu() && mPackageViewModel != null) {
updateDownloadCountHint(mPackageViewModel?.filterSameUpdateLiveData?.value)
}
}
override fun onDarkModeChanged() {
super.onDarkModeChanged()
if (showDownloadMenu() && getMenuItem(R.id.menu_download) != null) {
(getMenuItem(R.id.menu_download).actionView?.findViewById(R.id.menu_download_iv) as ImageView).setImageResource(
R.drawable.toolbar_download
)
}
}
}

View File

@ -1,4 +1,4 @@
package com.gh.gamecenter.core
package com.gh.base
import java.util.concurrent.ThreadFactory
import java.util.concurrent.atomic.AtomicInteger

View File

@ -0,0 +1,229 @@
//package com.gh.base
//
//import android.app.Notification
//import android.app.NotificationChannel
//import android.app.NotificationManager
//import android.app.PendingIntent
//import android.content.Context
//import android.content.Intent
//import android.os.Build
//import android.os.Bundle
//import android.preference.PreferenceManager
//import android.text.TextUtils
//import android.view.View
//import androidx.core.app.NotificationCompat
//import androidx.core.text.htmlEncode
//import com.gh.common.notifier.Notifier
//import com.gh.common.util.*
//import com.gh.gamecenter.R
//import com.gh.gamecenter.entity.PushEntity
//import com.gh.gamecenter.entity.PushMessageEntity
//import com.gh.gamecenter.entity.PushMessageUnreadEntity
//import com.gh.gamecenter.entity.PushNotificationEntity
//import com.gh.gamecenter.manager.UserManager
//import com.gh.gamecenter.message.MessageUnreadRepository
//import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity
//import com.gh.gamecenter.receiver.UmengMessageReceiver
//import com.gh.gamecenter.receiver.UmengMessageReceiver.Companion.TYPE_CLICK
//import com.gh.gamecenter.receiver.UmengMessageReceiver.Companion.TYPE_REMOVE
//import com.gh.gamecenter.retrofit.Response
//import com.gh.gamecenter.retrofit.RetrofitManager
//import com.google.gson.Gson
//import com.umeng.message.UmengMessageService
//import io.reactivex.android.schedulers.AndroidSchedulers
//import io.reactivex.schedulers.Schedulers
//import okhttp3.MediaType
//import okhttp3.RequestBody
//import okhttp3.ResponseBody
//import org.android.agoo.common.AgooConstants
//import org.json.JSONObject
//import retrofit2.HttpException
//import java.util.*
//
//class GHUmengNotificationService : UmengMessageService() {
//
// companion object {
// const val ACTION_UMENG = "com.gh.gamecenter.UMENG"
// const val MESSAGE_FROM_SYSTEM = "message_from_system"
// const val HALO_MESSAGE_DIALOG = "HALO_MESSAGE_DIALOG"
// const val HALO_MESSAGE_CENTER = "HALO_MESSAGE_CENTER"
// const val ANSWER = "answer"
// const val FOLLOW_QUESTION = "follow_question"
// const val NOTIFICATION_ID = 2015
// const val DISPLAY_TYPE_NOTIFICATION = "notification"
// const val DISPLAY_TYPE_CUSTOM = "custom"
// const val MESSAGE_ID = "message_id"
// const val NOTIFICATION_MESSAGE_ID = "notification_message_id" // 通知中心消息 ID
// const val PUSH_ID = "push_id"
// }
//
// val notificationTags = arrayOf("GH_UMENG_TAG_1", "GH_UMENG_TAG_2", "GH_UMENG_TAG_3")
// val gson = Gson()
//
// override fun onMessage(context: Context, intent: Intent) {
// val message = intent.getStringExtra(AgooConstants.MESSAGE_BODY)
// val isMessageFromSystem = intent.getBooleanExtra(MESSAGE_FROM_SYSTEM, false)
//
// try {
// val pushData = message.toObject<PushEntity>()
// pushData?.let { handlePushData(context, it, message, isMessageFromSystem) }
// } catch (e: Exception) {
// e.printStackTrace()
// }
// }
//
// private fun handlePushData(context: Context, pushData: PushEntity, message: String, isMessageFromSystem: Boolean) {
// val notificationManager = context.applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
//
// if (pushData.displayType == DISPLAY_TYPE_NOTIFICATION) {
// // 其它类型的透传信息
// // 显示到通知栏
// val msg = message.toObject<PushNotificationEntity>()
// val data = msg?.extra?.data
//
// // 系统推送(非自定义信息),直接处理跳转
// if (isMessageFromSystem) {
// val intent = Intent()
// intent.setClass(context, UmengMessageReceiver::class.java)
// intent.putExtra(EntranceUtils.KEY_DATA, data?.link)
// intent.putExtra(EntranceUtils.KEY_TYPE, UmengMessageReceiver.DIRECT_ONLY)
// intent.putExtra(EntranceUtils.KEY_MESSAGE, message)
// intent.putExtra(NOTIFICATION_MESSAGE_ID, data?.messageId)
// context.sendBroadcast(intent)
// return
// }
//
// // 用户未登录的情况下不生成消息中心通知,避免用户掉登录了还收到跳转至消息中心的通知
// if (data != null
// && data.link?.link == "system"
// && !UserManager.getInstance().isLoggedIn) {
// return
// }
//
// val clickIntent = Intent()
// val removeIntent = Intent()
//
// clickIntent.setClass(context, UmengMessageReceiver::class.java)
// clickIntent.putExtra(EntranceUtils.KEY_DATA, data?.link)
// clickIntent.putExtra(EntranceUtils.KEY_MESSAGE, message)
// clickIntent.putExtra(MESSAGE_ID, msg?.msgId)
// clickIntent.putExtra(PUSH_ID, data?.pushId)
// clickIntent.putExtra(NOTIFICATION_MESSAGE_ID, data?.messageId)
// clickIntent.putExtra(EntranceUtils.KEY_TYPE, TYPE_CLICK)
//
// removeIntent.setClass(context, UmengMessageReceiver::class.java)
// removeIntent.putExtra(EntranceUtils.KEY_TYPE, TYPE_REMOVE)
// removeIntent.putExtra(EntranceUtils.KEY_MESSAGE, message)
//
// val clickPendingIntent = PendingIntent.getBroadcast(context, System.currentTimeMillis().toInt(),
// clickIntent, PendingIntent.FLAG_UPDATE_CURRENT)
//
// val deletePendingIntent = PendingIntent.getBroadcast(context, System.currentTimeMillis().toInt() + 1,
// removeIntent, PendingIntent.FLAG_UPDATE_CURRENT)
//
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// val channel = NotificationChannel("Halo_Push", "Halo_Push", NotificationManager.IMPORTANCE_DEFAULT)
// notificationManager.createNotificationChannel(channel)
// }
//
// val notification = NotificationCompat.Builder(context, "Halo_Push")
// .setSmallIcon(R.drawable.ic_notification)
// .setTicker(pushData.body?.ticker)
// .setContentTitle(pushData.body?.title)
// .setContentText(pushData.body?.text?.fromHtml())
// .setContentIntent(clickPendingIntent)
// .setDeleteIntent(deletePendingIntent)
// .build()
// notification.flags = notification.flags or Notification.FLAG_AUTO_CANCEL
//
// notificationManager.notify(getNotificationTag(context), NOTIFICATION_ID, notification)
// } else {
// if (UserManager.getInstance().isLoggedIn &&
// HALO_MESSAGE_DIALOG == pushData.body?.custom &&
// MessageUnreadRepository.unreadLiveData.value != null) {
// // 回答了问题或者关注了问题的消息
// val msg = gson.fromJson(message, PushMessageEntity::class.java)
// val data = msg?.extra?.data
//
// val type = if (ANSWER == data?.type) {
// "回答了你的问题"
// } else {
// "回答了你关注的问题"
// }
//
// val userName = StringUtils.shrinkStringWithDot(data?.userEntity?.name, 8)
// val displayText = userName + type
//
// if (Notifier.isActivityValid(CurrentActivityHolder.getCurrentActivity()) &&
// Notifier.shouldShowNotifier(data?.answer?.id + displayText)) {
// Notifier.create(CurrentActivityHolder.getCurrentActivity())
// .setText(displayText)
// .setDuration(5000)
// .setIcon(data?.userEntity?.icon)
// .setOnClickListener(View.OnClickListener {
// val bundle = Bundle()
// bundle.putString(EntranceUtils.KEY_ANSWER_ID, data?.answer?.id)
// bundle.putString(EntranceUtils.KEY_ENTRANCE, EntranceUtils.ENTRANCE_UMENG)
// bundle.putString(EntranceUtils.KEY_TO, AnswerDetailActivity::class.java.name)
// EntranceUtils.jumpActivity(context, bundle)
//
// MtaHelper.onEvent("消息弹窗", type, "Does not contains any parameter.")
//
// // 标记已读
// val jsonObject = JSONObject()
// jsonObject.put("type", type)
// val body = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())
//
// RetrofitManager.getInstance().api.postMessageRead(UserManager.getInstance().userId, data?.id, body)
// .subscribeOn(Schedulers.io())
// .observeOn(AndroidSchedulers.mainThread())
// .subscribe(object : Response<ResponseBody>() {
// override fun onResponse(response: ResponseBody?) {
// super.onResponse(response)
// MessageUnreadRepository.loadMessageUnreadData()
// }
//
// override fun onFailure(e: HttpException?) {
// e?.printStackTrace()
// }
// })
// Notifier.hide()
// })
// .show(false)
// Notifier.tagNotifierAsShowed(data?.answer?.id + displayText)
// }
// } else if (HALO_MESSAGE_CENTER == pushData.body?.custom) {
// // 消息中心逻辑
// val msg = gson.fromJson(message, PushMessageUnreadEntity::class.java)
// val data = msg?.extra?.data
// data?.let { MessageUnreadRepository.loadMessageUnreadData() }
// }
// }
// }
//
// /**
// * 规则:最多三条消息,以旧换新
// *
// * @return NotificationTag
// */
// private fun getNotificationTag(context: Context): String {
// val sp = PreferenceManager.getDefaultSharedPreferences(context)
// val edit = sp.edit()
//
// val timeTagMap = HashMap<Long, String>()
// for (tag in notificationTags) {
// val time = sp.getLong(tag, 0)
// if (time == 0L) {
// edit.putLong(tag, System.currentTimeMillis()).apply()
// return tag
// } else {
// timeTagMap[time] = tag
// }
// }
//
// val minTime = Collections.min(timeTagMap.keys)
// val tag = timeTagMap[minTime]
// edit.putLong(tag, System.currentTimeMillis()).apply()
// return if (TextUtils.isEmpty(tag)) notificationTags[0] else tag!!
// }
//}

View File

@ -3,54 +3,41 @@ package com.gh.base
import android.app.Activity
import android.app.Application
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.alibaba.android.arouter.launcher.ARouter
import com.gh.ad.AdDelegateHelper
import com.gh.common.notifier.Notifier
import com.gh.common.util.DataUtils
import com.gh.common.util.FloatingBackViewManager
import com.gh.common.xapk.XapkInstaller
import com.gh.download.DownloadManager
import com.gh.gamecenter.SingletonWebActivity
import com.gh.gamecenter.SkipActivity
import com.gh.gamecenter.SplashAdActivity
import com.gh.gamecenter.MainActivity
import com.gh.gamecenter.SplashScreenActivity
import com.gh.gamecenter.authorization.AuthorizationActivity
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.utils.PackageFlavorHelper
import com.gh.gamecenter.core.provider.IPushProvider
import com.gh.vspace.VHelper
import com.gh.gamecenter.energy.EnergyCenterActivity
import com.gh.gamecenter.forum.detail.ForumDetailActivity
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.halo.assistant.HaloApp
import com.lightgame.utils.AppManager
// TODO移动到对应的模块
class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
private var isFromBackgroundToForeground = false // 是否后台回到前台
private var activityCount = 0
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
// do nothing
AppManager.getInstance().addActivity(activity)
}
override fun onActivityStarted(activity: Activity) {
GlobalActivityManager.currentActivity = activity
activityCount ++
if (activityCount == 1 && isFromBackgroundToForeground) {
if (AdDelegateHelper.shouldShowStartUpAd(true)
&& !HaloApp.getInstance().isSkippingThirdParty
&& activity !is SplashScreenActivity
&& activity !is SkipActivity
&& activity !is AuthorizationActivity
&& activity !is SplashAdActivity
) {
activity.startActivity(SplashAdActivity.getIntent(activity))
}
isFromBackgroundToForeground = false
}
}
override fun onActivityResumed(activity: Activity) {
CurrentActivityHolder.activitySet.add(activity)
// 判断是否需要显示或隐藏返回小浮窗
if (FloatingBackViewManager.getType().isNotEmpty()) {
if (activity is SingletonWebActivity
if (activity is EnergyCenterActivity
&& FloatingBackViewManager.getType() == FloatingBackViewManager.TYPE_TASK
) {
FloatingBackViewManager.disableBackView()
} else if (!shouldShowActivityBackView(activity)
&& FloatingBackViewManager.getType() == FloatingBackViewManager.TYPE_ACTIVITY
) {
FloatingBackViewManager.disableBackView()
@ -60,6 +47,7 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
}
if (HaloApp.isUserAcceptPrivacyPolicy(activity)) {
DataUtils.onResume(activity)
// FIXME 这里应该只是部分Activity需要
try {
// 初始化gameMap
@ -70,44 +58,40 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
e.printStackTrace()
}
}
}
if (PackageFlavorHelper.IS_TEST_FLAVOR && activity is AppCompatActivity) {
DarkModeSwitchHelper.showDarkModeSwitchFloatingView(activity)
}
if (activity is AppCompatActivity
&& activity !is SplashScreenActivity
&& activity !is SkipActivity
&& activity !is AuthorizationActivity
) {
VHelper.showFeedbackDialogIfLastSuccessfulLaunchedGameExitUnexpectedly(activity)
}
XapkInstaller.updateCurrentInstallStatus()
// 清除桌面角标
val pushProvider = ARouter.getInstance().build(RouteConsts.provider.push).navigation() as? IPushProvider
pushProvider?.cleanBadgeNumber(activity.applicationContext)
private fun shouldShowActivityBackView(activity: Activity): Boolean {
return (activity is MainActivity
|| activity is ArticleDetailActivity
|| activity is ForumVideoDetailActivity
|| activity is ForumDetailActivity
|| activity is ForumListActivity
|| activity is NewQuestionDetailActivity)
}
override fun onActivityPaused(activity: Activity) {
CurrentActivityHolder.activitySet.remove(activity)
FloatingBackViewManager.dismissBackView()
if (PackageFlavorHelper.IS_TEST_FLAVOR && activity is AppCompatActivity) {
DarkModeSwitchHelper.dismissDarkModeSwitchFloatingView()
if (HaloApp.isUserAcceptPrivacyPolicy(activity)) {
DataUtils.onPause(activity)
}
if (activity.isFinishing) {
AppManager.getInstance().finishActivity(activity)
}
}
override fun onActivityStopped(activity: Activity) {
activityCount --
isFromBackgroundToForeground = activityCount <= 0
Notifier.hide()
}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
// do nothing
}
override fun onActivityDestroyed(activity: Activity) {
// do nothing
AppManager.getInstance().finishActivity(activity)
}
}

View File

@ -1,4 +1,4 @@
package com.gh.gamecenter.common.callback;
package com.gh.base;
import android.content.Context;
import android.view.GestureDetector;

View File

@ -0,0 +1,19 @@
package com.gh.base;
import android.view.View;
/**
* Created by khy on 26/09/17.
*/
public interface OnListClickListener {
/**
*
* @param view
* @param position list position
* @param data list data (直接强转 如果列表传入不同数据类型 请做好判断)
* @param <T>
*/
<T> void onListClick(View view, int position, T data);
}

View File

@ -0,0 +1,20 @@
package com.gh.base;
/**
* Created by Administrator on 2016/9/8.
*
* 逐步移除
*/
@Deprecated
public interface OnRequestCallBackListener<T> {
void loadDone();
void loadDone(T obj);
void loadError();
void loadEmpty();
}

View File

@ -0,0 +1,7 @@
package com.gh.base;
import android.view.View;
public interface OnViewClickListener<T> {
void onClick(View v, T data);
}

View File

@ -1,4 +1,4 @@
package com.gh.gamecenter.core.iinterface;
package com.gh.base;
import java.util.ArrayList;

View File

@ -0,0 +1,336 @@
package com.gh.base;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.DrawableRes;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.appcompat.widget.ActionMenuView;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProviders;
import com.facebook.drawee.view.SimpleDraweeView;
import com.gh.common.constant.Constants;
import com.gh.common.util.DisplayUtils;
import com.gh.common.util.ImageUtils;
import com.gh.common.util.SPUtils;
import com.gh.common.view.GameIconView;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.DownloadManagerActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.entity.GameUpdateEntity;
import com.gh.gamecenter.eventbus.EBDownloadStatus;
import com.gh.gamecenter.normal.ToolbarController;
import com.gh.gamecenter.packagehelper.PackageViewModel;
import com.lightgame.OnTitleClickListener;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
/**
* 需要用到工具栏的页面使用
* <p>
* 特殊页面请参考{@link BaseActivity}
*/
public abstract class ToolBarActivity extends BaseActivity implements ToolbarController, ActionMenuView.OnMenuItemClickListener {
@Nullable
private PackageViewModel mPackageViewModel;
protected View mToolbarContainer;
protected Toolbar mToolbar;
protected TextView mTitleTv;
protected LinearLayout mTitleContainer;
protected LinearLayout mIconTitleContainer;
protected FrameLayout mBackContainer;
protected ActionMenuView mActionMenuView;
protected View mBackBtn;
protected GameIconView mGameIconView;
protected SimpleDraweeView mUserAvatarIv;
protected TextView mIconTitle;
@Nullable
private TextView mDownloadCountHint;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStatusBarDarkMode(true, this);
initToolbar();
if (!SPUtils.getBoolean(Constants.SP_TEENAGER_MODE) && showDownloadMenu()) {
mPackageViewModel = ViewModelProviders.of(this, new PackageViewModel.Factory()).get(PackageViewModel.class);
mPackageViewModel.getFilterSameUpdateLiveData().observe(this, this::updateDownloadCountHint);
}
}
// 小米沉浸式黑色字体
@SuppressLint("PrivateApi")
public void setStatusBarDarkMode(boolean darkmode, Activity activity) {
Class<? extends Window> clazz = activity.getWindow().getClass();
try {
Class<?> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
int darkModeFlag = field.getInt(layoutParams);
Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
extraFlagField.invoke(activity.getWindow(), darkmode ? darkModeFlag : 0, darkModeFlag);
} catch (Exception ignore) {
}
}
private void initToolbar() {
mToolbarContainer = findViewById(R.id.normal_toolbar_container);
mToolbar = findViewById(R.id.normal_toolbar);
mTitleTv = findViewById(R.id.normal_title);
mActionMenuView = findViewById(R.id.actionMenuView);
mTitleContainer = findViewById(R.id.titleContainer);
mIconTitleContainer = findViewById(R.id.iconTitleContainer);
mBackContainer = findViewById(R.id.backContainer);
mBackBtn = findViewById(R.id.backBtn);
mGameIconView = findViewById(R.id.gameIv);
mUserAvatarIv = findViewById(R.id.userAvatar);
mIconTitle = findViewById(R.id.iconTitle);
if (mToolbar != null) {
// setSupportActionBar(mToolbar); // 替换actionBar后 toolBar无法控制
// mToolbar.setNavigationIcon(provideNavigationIcon());
// mToolbar.setNavigationOnClickListener(provideNavigationItemClickListener());
if (mBackBtn != null) mBackBtn.setOnClickListener(provideNavigationItemClickListener());
if (mBackContainer != null) mBackContainer.setOnClickListener(provideNavigationItemClickListener());
if (mTitleTv != null) {
mTitleTv.setOnClickListener(view -> {
final List<Fragment> fragmentList = getSupportFragmentManager().getFragments();
for (Fragment fragment : fragmentList) {
if (fragment instanceof OnTitleClickListener) {
((OnTitleClickListener) fragment).onTitleClick();
}
}
});
}
}
}
@DrawableRes
public int provideNavigationIcon() {
return R.drawable.ic_bar_back; // default navigation icon
}
@Override
public void setNavigationTitle(String title) {
if (mTitleTv != null) mTitleTv.setText(title);
if (mIconTitle != null) mIconTitle.setText(title);
}
@Override
public void setNavigationTitle(@StringRes int res) {
setNavigationTitle(getString(res));
}
/**
* 重写此方法以将标题靠左显示
*/
public boolean showToolbarAtLeft() {
return false;
}
@Override
public void setToolbarMenu(int res) {
if (mActionMenuView == null) return;
// 青少年模式下要隐藏下载按钮
if (SPUtils.getBoolean(Constants.SP_TEENAGER_MODE) && res == R.menu.menu_download) return;
// mToolbar.inflateMenu(res);
// mToolbar.setOnMenuItemClickListener(this);
getMenuInflater().inflate(res, mActionMenuView.getMenu());
mActionMenuView.setOnMenuItemClickListener(this);
if (showDownloadMenu()) {
createDownloadMenu(res);
}
Menu menu = mActionMenuView.getMenu();
for (int i = 0; i < menu.size(); i++) {
MenuItem menuItem = menu.getItem(i);
// menu设置actionLayout后无法捕捉点击事件以icon为tag如果icon is null 手动设置menuItem点击事件
if (menuItem != null && menuItem.getIcon() == null) {
if (menuItem.getActionView() != null) {
menuItem.getActionView().setOnClickListener((v) -> this.onMenuItemClick(menuItem));
}
}
}
if (showToolbarAtLeft() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && mTitleTv != null) {
mTitleTv.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_START);
}
setTitleCenter();
}
@Override
protected void onResume() {
super.onResume();
setTitleCenter();
}
// 设置标题居中
public void setTitleCenter() {
if (mActionMenuView != null && mTitleContainer != null && mBackContainer != null && !showToolbarAtLeft()) {
mActionMenuView.post(() -> {
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mTitleContainer.getLayoutParams();
params.setMargins(mActionMenuView.getWidth() - mBackContainer.getWidth(), 0, 0, 0);
mTitleContainer.setLayoutParams(params);
});
}
}
public void setGameIconToolbar(String icon, String iconSubscript) {
mTitleContainer.setVisibility(View.GONE);
mGameIconView.displayGameIcon(icon, iconSubscript);
mGameIconView.setVisibility(View.VISIBLE);
mIconTitleContainer.setVisibility(View.VISIBLE);
}
public void setUserAvatarIconToolbar(String icon) {
mTitleContainer.setVisibility(View.GONE);
ImageUtils.display(mUserAvatarIv, icon);
mUserAvatarIv.setVisibility(View.VISIBLE);
mIconTitleContainer.setVisibility(View.VISIBLE);
}
private void createDownloadMenu(int res) {
if (res != R.menu.menu_download) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_download, mActionMenuView.getMenu());
}
if (mPackageViewModel != null) {
updateDownloadCountHint(mPackageViewModel.getFilterSameUpdateLiveData().getValue());
}
View downloadMenuView = mActionMenuView.getMenu().findItem(R.id.menu_download).getActionView();
mDownloadCountHint = downloadMenuView.findViewById(R.id.menu_download_count_hint);
}
private void updateDownloadCountHint(List<GameUpdateEntity> updateList) {
if (mDownloadCountHint == null) return;
String count = DownloadManager.getInstance().getDownloadOrUpdateCount(updateList);
if (count != null) {
mDownloadCountHint.setVisibility(View.VISIBLE);
mDownloadCountHint.setText(count);
ViewGroup.LayoutParams params = mDownloadCountHint.getLayoutParams();
if (TextUtils.isEmpty(count)) {
params.width = DisplayUtils.dip2px(6);
params.height = DisplayUtils.dip2px(6);
} else {
params.width = DisplayUtils.dip2px(12);
params.height = DisplayUtils.dip2px(12);
}
mDownloadCountHint.setLayoutParams(params);
} else {
mDownloadCountHint.setVisibility(View.GONE);
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(EBDownloadStatus status) {
if (!SPUtils.getBoolean(Constants.SP_TEENAGER_MODE) && showDownloadMenu() && mPackageViewModel != null) {
updateDownloadCountHint(mPackageViewModel.getFilterSameUpdateLiveData().getValue());
}
}
@Override
public MenuItem getMenuItem(int res) {
if (mToolbar == null) return null; //后续页面做好判断
return mActionMenuView.getMenu().findItem(res);
}
public void clearMenu() {
if (mToolbar != null) {
mActionMenuView.getMenu().clear();
setTitleCenter();
}
}
public Menu getMenu() {
return mActionMenuView.getMenu();
}
@Override
public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == R.id.menu_download) {
// MtaHelper.onEvent("下载管理", "下载管理入口", getActivityNameInChinese());
Intent intent = DownloadManagerActivity.getDownloadMangerIntent(this, mEntrance);
startActivity(intent);
}
return false;
}
protected View.OnClickListener provideNavigationItemClickListener() {
return view -> onBackPressed();
}
protected boolean showDownloadMenu() {
return false;
}
@Override
public void hideToolbar(boolean isHide) {
if (mToolbarContainer != null) {
mToolbarContainer.setVisibility(isHide ? View.GONE : View.VISIBLE);
}
}
@Override
protected void onNightModeChange() {
super.onNightModeChange();
if (mToolbar != null) {
mToolbar.setBackgroundColor(ContextCompat.getColor(this, R.color.background_white));
}
if (mBackBtn != null) {
if (mBackBtn instanceof ImageView) {
((ImageView) mBackBtn).setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_bar_back));
} else if (mBackBtn instanceof TextView) {
((TextView) mBackBtn).setTextColor(ContextCompat.getColor(this, R.color.text_subtitle));
}
}
if (mTitleTv != null) {
mTitleTv.setTextColor(ContextCompat.getColor(this, R.color.text_black));
}
if (showDownloadMenu() && getMenuItem(R.id.menu_download) != null) {
((ImageView) getMenuItem(R.id.menu_download).getActionView().findViewById(R.id.menu_download_iv)).setImageDrawable(ContextCompat.getDrawable(this, R.drawable.toolbar_download));
}
}
}

View File

@ -1,4 +1,4 @@
package com.gh.gamecenter.common.base.adapter;
package com.gh.base.adapter;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
@ -18,12 +18,12 @@ public class FragmentAdapter extends FragmentPagerAdapter {
private List<String> mTitleList;
public FragmentAdapter(FragmentManager fm, List<Fragment> fragmentList) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
super(fm);
this.mFragmentList = fragmentList;
}
public FragmentAdapter(FragmentManager fm, List<Fragment> fragmentList, List<String> titleList) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
super(fm);
this.mFragmentList = fragmentList;
this.mTitleList = titleList;
}

View File

@ -0,0 +1,31 @@
package com.gh.base.adapter;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import java.util.List;
/**
* Created by khy on 7/12/28.
*/
public class FragmentStateAdapter extends FragmentStatePagerAdapter {
private List<Fragment> mFragmentList;
public FragmentStateAdapter(FragmentManager fm, List<Fragment> fragmentList) {
super(fm);
this.mFragmentList = fragmentList;
}
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
@Override
public int getCount() {
return mFragmentList.size();
}
}

View File

@ -1,10 +1,18 @@
package com.gh.gamecenter.common.base.fragment;
package com.gh.base.fragment;
import android.app.Dialog;
import android.content.res.Configuration;
import android.os.Bundle;
import android.view.KeyEvent;
import com.gh.common.util.ClickUtils;
import com.gh.common.util.NightModeUtils;
import com.gh.gamecenter.R;
import com.lightgame.utils.RuntimeUtils;
import com.lightgame.utils.Utils;
import java.lang.reflect.Field;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
@ -14,14 +22,6 @@ import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.Lifecycle;
import com.gh.gamecenter.common.R;
import com.gh.gamecenter.common.utils.DarkModeUtils;
import com.gh.gamecenter.core.utils.ClickUtils;
import com.lightgame.utils.RuntimeUtils;
import com.lightgame.utils.Utils;
import java.lang.reflect.Field;
/**
* @author CsHeng
* @Date 17/05/2017
@ -30,12 +30,12 @@ import java.lang.reflect.Field;
public class BaseDialogFragment extends DialogFragment {
protected boolean mIsDarkModeOn;
protected boolean mNightMode;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mIsDarkModeOn = DarkModeUtils.INSTANCE.isDarkModeOn(requireContext());
mNightMode = NightModeUtils.INSTANCE.isNightMode(requireContext());
}
@NonNull
@ -109,13 +109,11 @@ public class BaseDialogFragment extends DialogFragment {
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mIsDarkModeOn = DarkModeUtils.INSTANCE.isDarkModeOn(requireContext());
onDarkModeChanged();
onNightModeChange();
}
protected void onDarkModeChanged() {
protected void onNightModeChange() {
mNightMode = NightModeUtils.INSTANCE.isNightMode(requireContext());
}
}

View File

@ -1,18 +1,16 @@
package com.gh.gamecenter.common.base.fragment;
package com.gh.base.fragment;
import android.app.Dialog;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.gh.gamecenter.common.R;
import com.gh.gamecenter.R;
/**
* Wrap another fragment with dialog fragment.

View File

@ -1,6 +1,4 @@
package com.gh.gamecenter.common.base.fragment;
import static com.gh.gamecenter.common.constant.EntranceConsts.KEY_ENTRANCE;
package com.gh.base.fragment;
import android.content.Intent;
import android.content.res.Configuration;
@ -11,6 +9,7 @@ import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
@ -20,17 +19,16 @@ import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import androidx.recyclerview.widget.RecyclerView;
import com.gh.gamecenter.common.BuildConfig;
import com.gh.gamecenter.common.R;
import com.gh.gamecenter.common.callback.OnListClickListener;
import com.gh.gamecenter.common.callback.OnRequestCallBackListener;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.eventbus.EBMiPush;
import com.gh.gamecenter.common.syncpage.ISyncAdapterHandler;
import com.gh.gamecenter.common.syncpage.SyncDataEntity;
import com.gh.gamecenter.common.syncpage.SyncPageRepository;
import com.gh.gamecenter.common.utils.DarkModeUtils;
import com.gh.base.OnListClickListener;
import com.gh.base.OnRequestCallBackListener;
import com.gh.common.constant.Constants;
import com.gh.common.syncpage.ISyncAdapterHandler;
import com.gh.common.syncpage.SyncDataEntity;
import com.gh.common.syncpage.SyncPageRepository;
import com.gh.common.util.NightModeUtils;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.R;
import com.gh.gamecenter.eventbus.EBMiPush;
import com.lightgame.OnTitleClickListener;
import com.lightgame.utils.RuntimeUtils;
import com.lightgame.utils.Utils;
@ -48,6 +46,8 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import kotlin.Pair;
import static com.gh.common.util.EntranceUtils.KEY_ENTRANCE;
/**
* Created by LGT on 2016/9/4.
* Fragment 基类
@ -61,19 +61,16 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
protected boolean isEverPause;
protected boolean mIsDarkModeOn;
protected boolean mNightMode;
@NonNull
protected String mEntrance = "";
protected boolean mIsFromMainWrapper = false;
protected boolean mIsFromTabWrapper = false;
public long startPageTime = 0;
protected final Handler mBaseHandler = new BaseFragment.BaseHandler(this);
public static class BaseHandler extends Handler {
protected static class BaseHandler extends Handler {
private final WeakReference<BaseFragment> mFragmentWeakReference;
BaseHandler(BaseFragment fragment) {
@ -140,12 +137,8 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
super.onCreate(savedInstanceState);
final Intent intent = getActivity().getIntent();
mEntrance = intent.getStringExtra(KEY_ENTRANCE);
if (getArguments() != null) {
if (TextUtils.isEmpty(mEntrance)) {
mEntrance = getArguments().getString(KEY_ENTRANCE);
}
mIsFromMainWrapper = getArguments().getBoolean(EntranceConsts.KEY_IS_FROM_MAIN_WRAPPER, false);
mIsFromTabWrapper = getArguments().getBoolean(EntranceConsts.KEY_IS_FROM_TAB_WRAPPER, false);
if (TextUtils.isEmpty(mEntrance) && getArguments() != null) {
mEntrance = getArguments().getString(KEY_ENTRANCE);
}
if (TextUtils.isEmpty(mEntrance)) {
@ -170,7 +163,12 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
if (addSyncPageObserver()) {
initSyncPageObserver();
}
mIsDarkModeOn = DarkModeUtils.INSTANCE.isDarkModeOn(requireContext());
if (BuildConfig.IS_NIGHT_MODE_ON) {
mNightMode = NightModeUtils.INSTANCE.isNightMode(requireContext());
} else {
mNightMode = false;
}
}
private void initSyncPageObserver() {
@ -244,9 +242,10 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
isEverPause = false;
startPageTime = System.currentTimeMillis();
if (!DarkModeUtils.INSTANCE.isFollowSystemDarkModeFromSp()
&& mIsDarkModeOn != DarkModeUtils.INSTANCE.isDarkModeOn(requireContext())) {
onDarkModeChanged();
if (BuildConfig.IS_NIGHT_MODE_ON
&& !NightModeUtils.INSTANCE.getSystemMode()
&& mNightMode != NightModeUtils.INSTANCE.isNightMode(requireContext())) {
onNightModeChange();
}
}
@ -286,27 +285,22 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
@Override
public void loadDone() {
// do nothing
}
@Override
public void loadDone(T obj) {
// do nothing
}
@Override
public void loadError() {
// do nothing
}
@Override
public void loadEmpty() {
// do nothing
}
@Override
public void loadNotFound() {
// do nothing
}
@Override
@ -360,14 +354,12 @@ public abstract class BaseFragment<T> extends Fragment implements OnRequestCallB
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (mIsDarkModeOn != DarkModeUtils.INSTANCE.isDarkModeOn(requireContext())) {
mIsDarkModeOn = DarkModeUtils.INSTANCE.isDarkModeOn(requireContext());
onDarkModeChanged();
if (BuildConfig.IS_NIGHT_MODE_ON) {
onNightModeChange();
}
}
protected void onDarkModeChanged() {
protected void onNightModeChange() {
mNightMode = NightModeUtils.INSTANCE.isNightMode(requireContext());
}
}

View File

@ -1,4 +1,4 @@
package com.gh.gamecenter.common.base.fragment;
package com.gh.base.fragment;
import android.content.Context;
import android.content.Intent;
@ -15,10 +15,12 @@ import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.ViewPager;
import com.gh.gamecenter.common.R;
import com.gh.gamecenter.common.base.adapter.FragmentAdapter;
import com.gh.gamecenter.common.view.TabIndicatorView;
import com.gh.base.adapter.FragmentAdapter;
import com.gh.common.view.TabIndicatorView;
import com.gh.gamecenter.R;
import com.gh.gamecenter.normal.NormalFragment;
import com.google.android.material.tabs.TabLayout;
import com.halo.assistant.HaloApp;
import com.lightgame.utils.Utils;
import com.lightgame.view.NoScrollableViewPager;
@ -29,7 +31,7 @@ import java.util.List;
* Created by khy on 15/03/18.
*/
public abstract class BaseFragment_TabLayout extends ToolbarFragment implements ViewPager.OnPageChangeListener {
public abstract class BaseFragment_TabLayout extends NormalFragment implements ViewPager.OnPageChangeListener {
public static final String PAGE_INDEX = "PAGE_INDEX";
@ -171,7 +173,7 @@ public abstract class BaseFragment_TabLayout extends ToolbarFragment implements
return;
}
tabTitle.setTypeface(isChecked ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT);
tabTitle.setTextColor(ContextCompat.getColor(tabTitle.getContext(), isChecked ? R.color.text_theme : R.color.text_secondary));
tabTitle.setTextColor(ContextCompat.getColorStateList(tabTitle.getContext(), R.color.text_tabbar_style));
}
// 如果不设置View的话无法动态设置字体样式
@ -201,11 +203,11 @@ public abstract class BaseFragment_TabLayout extends ToolbarFragment implements
}
@Override
protected void onDarkModeChanged() {
super.onDarkModeChanged();
protected void onNightModeChange() {
super.onNightModeChange();
View container = requireView().findViewById(R.id.fragment_tab_container);
if (container != null) {
container.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.ui_surface));
container.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.background_white));
for (int i = 0; i < mTabLayout.getTabCount(); i++) {
TabLayout.Tab tab = mTabLayout.getTabAt(i);
if (tab != null) {
@ -214,7 +216,7 @@ public abstract class BaseFragment_TabLayout extends ToolbarFragment implements
}
}
if (mDividerLineView != null) {
mDividerLineView.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.ui_divider));
mDividerLineView.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.divider));
}
}
}

View File

@ -7,11 +7,10 @@
* 2013-3-6 CsHeng
*/
package com.gh.gamecenter.common.base.fragment;
package com.gh.base.fragment;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.IdRes;
import androidx.annotation.LayoutRes;
@ -20,6 +19,9 @@ import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import android.view.View;
import com.gh.gamecenter.normal.NormalFragment;
import com.lightgame.adapter.BaseFragmentPagerAdapter;
import com.lightgame.config.CommonDebug;
import com.lightgame.view.DoubleTapTextView;
@ -34,7 +36,7 @@ import java.util.List;
* @author CsHeng
* @date 2013-3-6
*/
public abstract class BaseFragment_ViewPager extends ToolbarFragment implements DoubleTapTextView.OnDoubleTapListener {
public abstract class BaseFragment_ViewPager extends NormalFragment implements DoubleTapTextView.OnDoubleTapListener {
public static final String ARGS_INDEX = "index";
protected int mCheckedIndex = 0;
@ -50,10 +52,6 @@ public abstract class BaseFragment_ViewPager extends ToolbarFragment implements
protected abstract void initFragmentList(List<Fragment> fragments);
protected PagerAdapter provideAdapter() {
return BaseFragmentPagerAdapter.newInstance(getChildFragmentManager(), mFragmentsList);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -67,7 +65,7 @@ public abstract class BaseFragment_ViewPager extends ToolbarFragment implements
if (mFragmentsList.size() == 0) {
initFragmentList(mFragmentsList);
}
mAdapter = provideAdapter();
mAdapter = BaseFragmentPagerAdapter.newInstance(getChildFragmentManager(), mFragmentsList);
final Bundle args = getArguments();
if (args != null) {
mCheckedIndex = args.getInt(ARGS_INDEX);

View File

@ -7,21 +7,23 @@
* 2013-3-6 CsHeng
*/
package com.gh.gamecenter.common.base.fragment;
package com.gh.base.fragment;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Checkable;
import com.gh.gamecenter.fragment.MainWrapperFragment;
import java.util.List;
import androidx.annotation.IdRes;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.viewpager.widget.ViewPager;
import java.util.List;
/**
* ViewPager 配合ViewGroup Checkable实现双切换<br/>
@ -36,7 +38,7 @@ public abstract class BaseFragment_ViewPager_Checkable extends BaseFragment_View
protected ViewGroup mCheckableGroup;
private int mLastPosition = 0;
private int mLastPosition = MainWrapperFragment.INDEX_HOME;
@IdRes
protected abstract int getCheckableGroupId();
@ -80,14 +82,14 @@ public abstract class BaseFragment_ViewPager_Checkable extends BaseFragment_View
if (mFragmentsList.size() > mLastPosition) {
Fragment fragment = mFragmentsList.get(mLastPosition);
fragment.onPause();
FragmentManager childFragmentManager = fragment.getChildFragmentManager();
List<Fragment> fragments = childFragmentManager.getFragments();
for (Fragment childFragment : fragments) {
childFragment.onPause();
}
}
if (mFragmentsList.size() > index) {
Fragment fragment = mFragmentsList.get(index);
fragment.onResume();

View File

@ -0,0 +1,173 @@
package com.gh.base.fragment
import android.os.Bundle
import com.gh.gamecenter.normal.NormalFragment
/**
* 懒加载(支持多层嵌套)
*/
abstract class BaseLazyFragment : NormalFragment() {
private var mIsFirstVisible = true
private var isViewCreated = false
protected var isSupportVisible = false
/**
* 用于分发可见时间的时候获取 父fragment 是否隐藏
*
* @return true fragment 不可见, false 父 fragment 可见
*/
private val isParentInvisible: Boolean
get() {
val parentFragment = parentFragment
return if (parentFragment is BaseLazyFragment) {
val fragment = parentFragment as BaseLazyFragment?
!fragment!!.isSupportVisible
} else {
false
}
}
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
super.setUserVisibleHint(isVisibleToUser)
// 对于默认 tab 和 间隔 checked tab 需要等到 isViewCreated = true 后才可以通过此通知用户可见
// 这种情况下第一次可见不是在这里通知 因为 isViewCreated = false 成立,等从别的界面回到这里后会使用 onFragmentResume 通知可见
// 对于非默认 tab mIsFirstVisible = true 会一直保持到选择则这个 tab 的时候,因为在 onActivityCreated 会返回 false
if (isViewCreated) {
if (isVisibleToUser && !isSupportVisible) {
dispatchUserVisibleHint(true)
} else if (!isVisibleToUser && isSupportVisible) {
dispatchUserVisibleHint(false)
}
}
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
isViewCreated = true
// !isHidden() 默认为 true 在调用 hide show 的时候可以使用
if (!isHidden && userVisibleHint) {
dispatchUserVisibleHint(true)
}
}
override fun onHiddenChanged(hidden: Boolean) {
super.onHiddenChanged(hidden)
if (hidden) {
dispatchUserVisibleHint(false)
} else {
dispatchUserVisibleHint(true)
}
}
override fun onResume() {
super.onResume()
if (!mIsFirstVisible) {
if (!isHidden && !isSupportVisible && userVisibleHint) {
dispatchUserVisibleHint(true)
}
}
}
override fun onPause() {
super.onPause()
// 当前 Fragment 包含子 Fragment 的时候 dispatchUserVisibleHint 内部本身就会通知子 Fragment 不可见
// 子 fragment 走到这里的时候自身又会调用一遍
if (isSupportVisible && userVisibleHint) {
dispatchUserVisibleHint(false)
}
}
/**
* 统一处理 显示隐藏
*
* @param visible
*/
private fun dispatchUserVisibleHint(visible: Boolean) {
//当前 Fragment 是 child 时候 作为缓存 Fragment 的子 fragment getUserVisibleHint = true
//但当父 fragment 不可见所以 currentVisibleState = false 直接 return 掉
// 这里限制则可以限制多层嵌套的时候子 Fragment 的分发
if (visible && isParentInvisible) return
//此处是对子 Fragment 不可见的限制,因为 子 Fragment 先于父 Fragment回调本方法 currentVisibleState 置位 false
// 当父 dispatchChildVisibleState 的时候第二次回调本方法 visible = false 所以此处 visible 将直接返回
if (isSupportVisible == visible) {
return
}
isSupportVisible = visible
if (visible) {
// TODO 当 fragment 重建时这里的被调用很奇怪onActivityCreated 回调触发,但此时的 view 是空的,原因是 createView 还没被调用
// TODO 这样就造成了 onFragmentResume 里可能用到 view 的地方出现空指针异常,所以这里遇到 view 为空的时候 return 等下一次被调用才进去
if (view == null) {
return
}
if (mIsFirstVisible) {
mIsFirstVisible = false
onFragmentFirstVisible()
}
onFragmentResume()
dispatchChildVisibleState(true)
} else {
// 当 fragment 重建时,这个代码块可能在第一次 view 为空的 visible 后调用导致在 onFragmentPause 里可能用到 view 的地方出现空指针异常
if (!mIsFirstVisible) {
dispatchChildVisibleState(false)
onFragmentPause()
}
}
}
/**
* 当前 Fragment 是 child 时候 作为缓存 Fragment 的子 fragment 的唯一或者嵌套 VP 的第一 fragment 时 getUserVisibleHint = true
* 但是由于父 Fragment 还未进入可见状态所以自身也是不可见的, 这个方法可以存在是因为庆幸的是 父 fragment 的生命周期回调总是先于子 Fragment
* 所以在父 fragment 设置完成当前不可见状态后,需要通知子 Fragment 我不可见,你也不可见,
*
*
* 因为 dispatchUserVisibleHint 中判断了 isParentInvisible 所以当 子 fragment 走到了 onActivityCreated 的时候直接 return 掉了
*
*
* 当真正的外部 Fragment 可见的时候,走 setVisibleHint (VP 中)或者 onActivityCreated (hide show) 的时候
* 从对应的生命周期入口调用 dispatchChildVisibleState 通知子 Fragment 可见状态
*
* @param visible
*/
private fun dispatchChildVisibleState(visible: Boolean) {
val childFragmentManager = childFragmentManager
val fragments = childFragmentManager.fragments
if (!fragments.isEmpty()) {
for (child in fragments) {
if (child is BaseLazyFragment && !child.isHidden() && child.getUserVisibleHint()) {
child.dispatchUserVisibleHint(visible)
}
}
}
}
open fun onFragmentFirstVisible() {
//ULog.e("对用户第一次可见")
}
open fun onFragmentResume() {
//ULog.e("对用户可见")
}
open fun onFragmentPause() {
//ULog.e("对用户不可见")
}
override fun onDestroyView() {
super.onDestroyView()
isViewCreated = false
mIsFirstVisible = true
}
}

View File

@ -1,4 +1,4 @@
package com.gh.gamecenter.common.base.fragment
package com.gh.base.fragment
import android.content.Intent
import android.os.Bundle
@ -7,9 +7,9 @@ import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.viewpager.widget.PagerAdapter
import androidx.viewpager.widget.ViewPager
import com.gh.gamecenter.common.R
import com.gh.gamecenter.common.base.adapter.FragmentAdapter
import com.gh.gamecenter.common.view.TabIndicatorView
import com.gh.base.adapter.FragmentAdapter
import com.gh.common.view.TabIndicatorView
import com.gh.gamecenter.R
import com.google.android.material.tabs.TabLayout
import com.lightgame.view.NoScrollableViewPager
@ -100,7 +100,7 @@ abstract class BaseLazyTabFragment : BaseLazyFragment(), ViewPager.OnPageChangeL
BaseFragment_TabLayout.initTabStyle(mTabLayout, mCheckedIndex)
}
protected fun restoreFragments(): ArrayList<Fragment> {
private fun restoreFragments(): ArrayList<Fragment> {
val tag = "android:switcher:${mViewPager.id}:"
val fragments = ArrayList<Fragment>()
val childCount = mTabTitleList.size
@ -122,11 +122,11 @@ abstract class BaseLazyTabFragment : BaseLazyFragment(), ViewPager.OnPageChangeL
override fun onPageScrollStateChanged(state: Int) {}
override fun onDarkModeChanged() {
super.onDarkModeChanged()
override fun onNightModeChange() {
super.onNightModeChange()
val container = requireView().findViewById<View>(R.id.fragment_tab_container)
if (container != null) {
container.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.ui_surface))
container.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.background_white))
for (i in 0 until mTabLayout.tabCount) {
val tab = mTabLayout.getTabAt(i)
if (tab != null) {

View File

@ -1,9 +1,9 @@
package com.gh.gamecenter.common.base.fragment
package com.gh.base.fragment
import android.os.Bundle
import android.view.View
import android.view.ViewStub
import com.gh.gamecenter.common.R
import com.gh.gamecenter.R
/**
* 这是在 BaseLazyFragment 之上添加了一些通用功能的抽象类

View File

@ -0,0 +1,5 @@
package com.gh.base.fragment;
public interface OnDialogBackListener {
void onBack();
}

View File

@ -1,4 +1,4 @@
package com.gh.gamecenter.common.base.fragment;
package com.gh.base.fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
@ -11,9 +11,9 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentManager;
import com.gh.gamecenter.common.R;
import com.gh.gamecenter.common.callback.OnDialogBackListener;
import com.gh.gamecenter.core.utils.DisplayUtils;
import com.gh.common.util.DisplayUtils;
import com.gh.common.util.ExtensionsKt;
import com.gh.gamecenter.R;
/**
* @author CsHeng

View File

@ -0,0 +1,74 @@
package com.gh.common
import android.os.Handler
import android.os.Looper
import com.gh.base.GHThreadFactory
import com.gh.common.AppExecutor.heavyWeightIoExecutor
import com.gh.common.AppExecutor.ioExecutor
import com.gh.common.AppExecutor.lightWeightIoExecutor
import com.gh.common.AppExecutor.logExecutor
import com.gh.common.AppExecutor.uiExecutor
import io.reactivex.schedulers.Schedulers
import java.util.concurrent.*
/**
* APP 线程池管理类
*
* [ioExecutor] 是一个最大线程数固定的线程池,较为繁重的 IO 任务可以交给它
* [uiExecutor] 是主线程的包裹,需要切换至主线程执行可以用它
* [lightWeightIoExecutor] 是一个单线程的线程池,轻量级且需要保证同一线程的 IO 任务可以交给它
* [heavyWeightIoExecutor] 重量级的线程池,一些高频调用但不用保证结果的任务可以交给它
* [logExecutor] 只为上传 log 而使用的线程池
*/
object AppExecutor {
private val mCoreSize = Runtime.getRuntime().availableProcessors()
private val mMinimumPoolSize = 6.coerceAtLeast(mCoreSize)
private val mMaximumPoolSize = 24.coerceAtLeast(mCoreSize * 3)
@JvmStatic
val uiExecutor by lazy { MainThreadExecutor() }
@JvmStatic
val lightWeightIoExecutor: ExecutorService by lazy { Executors.newSingleThreadExecutor(GHThreadFactory("GH_LIGHT_WEIGHT_IO_THREAD")) }
@JvmStatic
val heavyWeightIoExecutor: ExecutorService by lazy { Executors.newFixedThreadPool(2, GHThreadFactory("GH_HEAVY_WEIGHT_IO_THREAD")) }
@JvmStatic
val logExecutor: ExecutorService by lazy { Executors.newSingleThreadExecutor(GHThreadFactory("GH_LOG_THREAD")) }
@JvmStatic
val ioExecutor = ThreadPoolExecutor(
mMinimumPoolSize,
mMaximumPoolSize,
20L, TimeUnit.SECONDS,
LinkedBlockingQueue(256),
GHThreadFactory("GH_IO_THREAD"))
val cachedScheduler by lazy { Schedulers.from(ioExecutor) }
class MainThreadExecutor : Executor {
private val mainThreadHandler = Handler(Looper.getMainLooper())
override fun execute(command: Runnable) {
mainThreadHandler.post(command)
}
fun executeWithDelay(command: Runnable, delay: Long) {
mainThreadHandler.postDelayed(command, delay)
}
}
}
fun runOnIoThread(isLightWeightTask: Boolean = false, isHeavyWightTask: Boolean = false, f: () -> Unit) {
when {
isLightWeightTask -> lightWeightIoExecutor.execute(f)
isHeavyWightTask -> heavyWeightIoExecutor.execute(f)
else -> ioExecutor.execute(f)
}
}
fun runOnUiThread(f: () -> Unit) {
uiExecutor.execute(f)
}

View File

@ -0,0 +1,5 @@
package com.gh.common
object Base64ImageHolder {
var image: String = ""
}

View File

@ -4,90 +4,37 @@ import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.util.Base64
import android.view.View
import android.webkit.JavascriptInterface
import androidx.annotation.Keep
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import com.alibaba.android.arouter.launcher.ARouter
import com.gh.common.exposure.ExposureManager
import com.gh.base.CurrentActivityHolder
import com.gh.common.constant.Constants
import com.gh.common.loghub.LoghubUtils
import com.gh.common.tracker.Tracker
import com.gh.common.util.*
import com.gh.common.util.LogUtils
import com.gh.download.DownloadManager
import com.gh.download.PackageObserver
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.ImageViewerActivity
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.common.callback.BiCallback
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.entity.NotificationUgc
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.loghub.LoghubUtils
import com.gh.gamecenter.common.provider.IHelpAndFeedbackProvider
import com.gh.gamecenter.common.tracker.Tracker
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.utils.NewFlatLogUtils
import com.gh.gamecenter.common.view.dsbridge.CompletionHandler
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.entity.SensorsEvent
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.feature.entity.Badge
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.login.user.LoginTag
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.login.user.UserRepository
import com.gh.gamecenter.login.utils.LoginHelper
import com.gh.gamecenter.login.view.LoginActivity
import com.gh.common.view.dsbridge.CompletionHandler
import com.gh.gamecenter.*
import com.gh.gamecenter.energy.EnergyCenterActivity
import com.gh.gamecenter.energy.EnergyHouseActivity
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.help.QaFeedbackDialogFragment
import com.gh.gamecenter.manager.UserManager
import com.gh.gamecenter.personalhome.border.AvatarBorderActivity
import com.gh.gamecenter.setting.SettingBridge
import com.gh.vspace.VHelper
import com.gh.gamecenter.security.BindPhoneActivity
import com.gh.gamecenter.user.LoginTag
import com.gh.gamecenter.user.UserRepository
import com.halo.assistant.HaloApp
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus.*
import com.lightgame.utils.Utils
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.json.JSONObject
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileOutputStream
import java.util.*
class DefaultJsApi(
var context: Context,
val entrance: String = "",
private var mFragment: Fragment? = null,
private var mBbsId: String? = "",
private var mOriginUrl: String? = "",
private val mForumName: String? = ""
) {
companion object {
private const val SOURCE_ENTRANCE = "webView"
}
class DefaultJsApi(var context: Context) {
private var mLoginHandler: CompletionHandler<Any>? = null
private var mDownloadWatcher: DataWatcher? = null // 下载观察者
private var mDownloadUrlSet: HashSet<String>? = null // 下载的 url 集合
private var mDownloadHandler: CompletionHandler<Any>? = null // 下载信息回调
private var mExposureEvent: ExposureEvent? = null // 活动曝光实体
init {
if (mFragment != null) {
EventBus.getDefault().register(this)
autoUnregisterDownloadObserverIfNeeded(mFragment)
}
}
@JavascriptInterface
fun isGhzs(msg: Any): String {
@ -101,20 +48,9 @@ class DefaultJsApi(
@JavascriptInterface
fun logMtaEvent(event: Any) {
// do nothing, mta is deprecated
}
val mtaEvent = event.toString().toObject() ?: MtaEvent()
@JavascriptInterface
fun logSensorsEvent(event: Any) {
val sensorsEvent = event.toString().toObject() ?: SensorsEvent()
val trackEvent = JSONObject()
tryCatchInRelease {
sensorsEvent.kv.split(",").forEach {
val kv = it.split(":")
trackEvent.put(kv[0], kv[1])
}
}
SensorsBridge.trackEvent(sensorsEvent.name, trackEvent)
MtaHelper.onEvent(mtaEvent.name, mtaEvent.key, mtaEvent.value)
}
@JavascriptInterface
@ -129,12 +65,12 @@ class DefaultJsApi(
@JavascriptInterface
fun login(msg: Any) {
// if (SPUtils.getBoolean(Constants.SP_HAS_GET_PHONE_INFO) || NetworkUtils.isOpenMobileData(context)) {
// QuickLoginHelper.startLogin(context, "浏览器")
// } else {
if (SPUtils.getBoolean(Constants.SP_HAS_GET_PHONE_INFO) || NetworkUtils.isOpenMobileData(context)) {
QuickLoginHelper.startLogin(context, "浏览器")
} else {
val intent = LoginActivity.getIntent(context, "浏览器")
context.startActivity(intent)
// }
}
}
@JavascriptInterface
@ -179,6 +115,7 @@ class DefaultJsApi(
WechatBindHelper.bindWechat(wechatLoginInfoMap, object : BiCallback<Boolean, Boolean> {
override fun onFirst(first: Boolean) {
EnergyTaskHelper.postEnergyTask("bind_wechat")
handler.complete(true)
}
@ -214,18 +151,7 @@ class DefaultJsApi(
@JavascriptInterface
fun startApp(msg: Any) {
val packageName = msg.toString()
val context = HaloApp.getInstance().application
runOnUiThread {
// 若畅玩列表中安装了,优先启动畅玩游戏
if (VHelper.isInstalled(packageName)) {
if (!VHelper.showDialogIfVSpaceIsNeeded(context, "", "", "", "")) {
VHelper.launch(context, packageName)
}
} else {
PackageLauncher.launchApp(context, packageName = packageName)
}
}
PackageUtils.launchApplicationByPackageName(HaloApp.getInstance().application, packageName)
}
@JavascriptInterface
@ -234,14 +160,7 @@ class DefaultJsApi(
val context = CurrentActivityHolder.getCurrentActivity()
context?.startActivity(
ImageViewerActivity.getIntent(
context,
imageEvent.imageList,
imageEvent.position,
"浏览器"
)
)
context?.startActivity(ImageViewerActivity.getIntent(context, imageEvent.imageList, imageEvent.position, "浏览器"))
}
@JavascriptInterface
@ -262,7 +181,7 @@ class DefaultJsApi(
fun openBase64Image(event: Any) {
val context = CurrentActivityHolder.getCurrentActivity()
ImageViewerActivity.base64Image = event.toString()
Base64ImageHolder.image = event.toString()
context?.startActivity(ImageViewerActivity.getBase64Intent(context, true))
}
@ -280,31 +199,6 @@ class DefaultJsApi(
}
}
/**
* 是否为论坛详情的专区
*/
@JavascriptInterface
fun isForumZone(msg: Any): Boolean {
return !mBbsId.isNullOrEmpty()
}
/**
* 打开论坛搜索页
* 如果用户是从 webView跳转到论坛搜索页则sourceEntrance为空
*/
@JavascriptInterface
fun openForumSearch(msg: Any) {
runOnUiThread {
DirectUtils.directToForumOrUserSearch(
context,
mBbsId ?: "",
entrance.ifBlank { "内部网页" },
SOURCE_ENTRANCE,
mForumName ?: ""
)
}
}
@JavascriptInterface
fun exitWebView(msg: Any) {
runOnUiThread { (context as Activity).finish() }
@ -313,6 +207,7 @@ class DefaultJsApi(
@JavascriptInterface
fun updateRegulationTestStatus(msg: Any) {
if (msg.toString().toLowerCase(Locale.getDefault()) == "pass") {
EnergyTaskHelper.postEnergyTask("finish_etiquette_exam")
SPUtils.setString(Constants.SP_REGULATION_TEST_PASS_STATUS, "pass")
}
}
@ -328,11 +223,6 @@ class DefaultJsApi(
return HaloApp.getInstance().gid
}
@JavascriptInterface
fun getOaid(msg: Any): String {
return HaloApp.getInstance().oaid
}
@JavascriptInterface
fun showIncompatibleVersionDialog(msg: Any) {
DialogHelper.showUpgradeDialog(context)
@ -342,7 +232,7 @@ class DefaultJsApi(
fun shareBase64Image(event: Any) {
val imageShareEvent = event.toString().toObject() ?: ImageShareEvent()
val context = CurrentActivityHolder.getCurrentActivity()
ImageViewerActivity.base64Image = imageShareEvent.image.run {
Base64ImageHolder.image = imageShareEvent.image.run {
if (this.startsWith("data:image/png;base64")) this.split(",")[1] else this
}
MessageShareUtils.getInstance(context).shareFromWeb(context, imageShareEvent.type)
@ -353,7 +243,7 @@ class DefaultJsApi(
val inviteEvent = event.toString().toObject() ?: InviteFriendsEvent()
val context = CurrentActivityHolder.getCurrentActivity()
if ("poster" == inviteEvent.type) {
ImageViewerActivity.base64Image = inviteEvent.poster.run {
Base64ImageHolder.image = inviteEvent.poster.run {
if (this.startsWith("data:image/png;base64")) this.split(",")[1] else this
}
MessageShareUtils.getInstance(context).shareInviteFriends(context, inviteEvent.way)
@ -364,7 +254,7 @@ class DefaultJsApi(
@JavascriptInterface
fun bindPhone(msg: Any) {
val intent = SettingBridge.getBindPhoneNormalIntent(context, false)
val intent = BindPhoneActivity.getNormalIntent(context, false)
context.startActivity(intent)
}
@ -388,29 +278,27 @@ class DefaultJsApi(
@JavascriptInterface
fun openInNewWebview(url: Any) {
runOnUiThread { DirectUtils.directToWebView(context, url.toString(), entrance.ifBlank { "内部网页" }) }
runOnUiThread { DirectUtils.directToWebView(context, url.toString(), "内部网页") }
}
@JavascriptInterface
fun postWearBadgeTask(msg: Any) {
// do nothing
EnergyTaskHelper.postEnergyTask("wear_badge")
}
@JavascriptInterface
fun startEnergyCenter(msg: Any) {
// do nothing
context.startActivity(EnergyCenterActivity.getIntent(context))
}
@JavascriptInterface
fun startEnergyHouse(msg: Any) {
// do nothing
context.startActivity(EnergyHouseActivity.getIntent(context))
}
@JavascriptInterface
fun showQaFeedbackDialog(msg: Any) {
val mHelpAndFeedbackHelp =
ARouter.getInstance().build(RouteConsts.provider.helpAndFeedback).navigation() as? IHelpAndFeedbackProvider
mHelpAndFeedbackHelp?.showQaFeedbackDialogFragment(context as AppCompatActivity, msg.toString())
QaFeedbackDialogFragment.show(context as AppCompatActivity, msg.toString())
}
@JavascriptInterface
@ -457,6 +345,11 @@ class DefaultJsApi(
FloatingBackViewManager.enableBackView(FloatingBackViewManager.TYPE_ACTIVITY, msg.toString())
}
@JavascriptInterface
fun startBBSStayTimeCount(msg: Any) {
BbsStayTimeHelper.enableStayTimeCount(msg.toString().toInt())
}
@JavascriptInterface
fun saveBase64ImageToGallery(msg: Any) {
val base64StringData = msg.toString()
@ -465,8 +358,7 @@ class DefaultJsApi(
runOnIoThread {
val base64String = base64StringData.replace("data:image/png;base64", "")
tryWithDefaultCatch {
val imageFile =
File(HaloApp.getInstance().cacheDir.absolutePath + File.separator + System.currentTimeMillis() + ".png")
val imageFile = File(HaloApp.getInstance().cacheDir.absolutePath + File.separator + System.currentTimeMillis() + ".png")
val decodedString = Base64.decode(base64String, Base64.DEFAULT)
val bos = BufferedOutputStream(FileOutputStream(imageFile))
bos.write(decodedString)
@ -493,12 +385,21 @@ class DefaultJsApi(
@JavascriptInterface
fun openInNewFullWebview(url: Any) {
runOnUiThread { DirectUtils.directToFullScreenWebPage(context, url.toString(), true, entrance) }
runOnUiThread { DirectUtils.directToFullScreenWebPage(context, url.toString(), true) }
}
@JavascriptInterface
fun startGameCollectionSquareBrowseTask(event: Any) {
val browseTimeEvent = event.toString().toObject() ?: BrowseTaskEvent()
GameCollectionSquareBrowseTaskHelper.enableBrowseTimeCount(
browseTimeEvent.timeout.toInt(),
browseTimeEvent.isFinished == "true"
)
}
@JavascriptInterface
fun checkUpdateGhzs(msg: Any) {
context.startActivity(SettingBridge.getAboutIntent(context, true))
context.startActivity(AboutActivity.getIntent(context, true))
}
@JavascriptInterface
@ -519,235 +420,14 @@ class DefaultJsApi(
GameActivityDownloadHelper.postExposureEvent(gameActivityEvent)
}
@JavascriptInterface
fun getEntrance(msg: Any): String {
return when {
entrance.contains("论坛-活动") -> "社区-活动tab-活动banner"
entrance.contains("启动弹窗") -> "首页_弹窗"
entrance.contains("新首页-轮播图") -> "首页banner"
entrance.contains("论坛banner") -> "社区banner"
entrance.contains("启动广告") -> "app_开屏文案"
// entrance.contains("资讯广场-轮播图") -> "资讯_活动banner"
entrance.contains("通用链接合集") -> "资讯_活动banner"
entrance.contains("视频流广告位") -> "视频流_广告位"
entrance.contains("我的光环banner") -> "我的光环_banner"
entrance.contains("论坛详情页置顶栏") -> "社区_论坛置顶"
else -> entrance
}
}
@JavascriptInterface
fun getInstallStatus(event: Any): String {
val localInstalledPackageList = PackageUtils.getAllPackageName(HaloApp.getInstance().application)
val packageNameList: ArrayList<String> = event.toString().toObject() ?: ArrayList()
val installStatusMap: HashMap<String, Boolean> = hashMapOf()
for (packageName in packageNameList) {
installStatusMap[packageName] =
localInstalledPackageList.contains(packageName) || VHelper.isInstalled(packageName)
}
return installStatusMap.toJson()
}
@JavascriptInterface
fun installDownloadedGame(event: Any) {
val url = event.toString()
val downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(url, null)
?: DownloadManager.getInstance().getDownloadEntitySnapshot(url, null)
NewFlatLogUtils.logGameInstall(
gameId = downloadEntity?.gameId ?: "",
gameName = downloadEntity?.name ?: "",
trigger = "主动安装"
)
SensorsBridge.trackInstallGameClick(
gameId = downloadEntity?.gameId ?: "",
gameName = downloadEntity?.name ?: "",
action = "主动安装"
)
downloadEntity?.let {
PackageInstaller.install(context, it, showUnzipToast = false, ignoreAsVGame = false)
}
}
@JavascriptInterface
fun registerDownloadCallback(msg: Any, handler: CompletionHandler<Any>) {
val downloadUrlSet: HashSet<String> = msg.toString().toObject() ?: return
mDownloadHandler = handler
mDownloadUrlSet = downloadUrlSet
if (mDownloadWatcher == null) {
mDownloadWatcher = object : DataWatcher() {
override fun onDataInit(downloadEntity: DownloadEntity) {
onDataChanged(downloadEntity)
}
override fun onDataChanged(downloadEntity: DownloadEntity?) {
val url = VHelper.getOriginalUrl(downloadEntity?.url)
if (downloadEntity != null && mDownloadUrlSet?.contains(url) == true) {
mDownloadHandler?.setProgressData(
SimpleDownloadEntity.fromDownloadEntity(downloadEntity).toJson()
)
}
}
}
DownloadManager.getInstance().addObserver(mDownloadWatcher)
}
}
@JavascriptInterface
fun registerPackageChangesCallback(msg: Any, handler: CompletionHandler<Any>) {
PackageObserver.registerPackageChangeChangeListener(object : PackageObserver.PackageChangeListener {
override fun onChanged(data: EBPackage) {
handler.setProgressData(data.toJson())
}
})
}
@JavascriptInterface
fun startDownload(msg: Any) {
val gameEntity: GameEntity? = msg.toString().toObject()
if (gameEntity == null) {
ToastUtils.toast("下载异常,请稍后重试")
return
}
runOnUiThread {
// 用一个假的 view 来当 downloadView
val stubView = View(context)
DownloadItemUtils.setOnClickListener(
position = 0,
context = context,
downloadBtn = stubView,
gameEntity = gameEntity,
adapter = null,
entrance = "(网页活动)",
location = "",
traceEvent = null,
clickCallback = null,
refreshCallback = null,
allStateClickCallback = null
)
stubView.performClick()
}
}
@JavascriptInterface
fun resumeDownload(msg: Any) {
val url = msg.toString()
DownloadManager.getInstance().resumeDownload(url)
}
@JavascriptInterface
fun pauseDownload(msg: Any) {
val url = msg.toString()
DownloadManager.getInstance().pause(url)
}
@JavascriptInterface
fun shareText(event: Any) {
val textShareEvent = event.toString().toObject() ?: TextShareEvent()
if (textShareEvent.text.isNotEmpty() && textShareEvent.type.isNotEmpty()) {
val activity = CurrentActivityHolder.getCurrentActivity()
MessageShareUtils.getInstance(activity).shareTextFromWeb(activity, textShareEvent.text, textShareEvent.type)
}
}
@JavascriptInterface
fun logExposure(event: Any) {
val simpleExposureEvent = event.toString().toObject() ?: SimpleExposureEvent()
if (simpleExposureEvent.id.isNotEmpty()) {
val sourceKey = if (mOriginUrl?.contains(Constants.URL_QUERY_FROM_FLOATING_WINDOW) == true) {
"落地页"
} else {
"游戏活动"
}
val exposureSource = ExposureSource(sourceKey, "${simpleExposureEvent.title}+${simpleExposureEvent.id}")
mExposureEvent = ExposureEvent.createEvent(
gameEntity = null,
source = arrayListOf(exposureSource),
)
ExposureManager.log(mExposureEvent!!)
ExposureManager.commitSavedExposureEvents(true)
}
}
/**
* 获取 ExposureEvent可能为空
*/
fun getExposureEvent(): ExposureEvent? {
return mExposureEvent
}
private fun autoUnregisterDownloadObserverIfNeeded(fragment: Fragment?) {
fragment?.parentFragmentManager?.registerFragmentLifecycleCallbacks(
object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentViewDestroyed(fm: FragmentManager, f: Fragment) {
super.onFragmentViewDestroyed(fm, f)
if (f === fragment) {
fragment.parentFragmentManager.unregisterFragmentLifecycleCallbacks(this)
if (mDownloadWatcher != null) {
DownloadManager.getInstance().removeObserver(mDownloadWatcher)
}
EventBus.getDefault().unregister(this@DefaultJsApi)
}
}
override fun onFragmentResumed(fm: FragmentManager, f: Fragment) {
super.onFragmentResumed(fm, f)
if (f === fragment && mDownloadWatcher != null) {
DownloadManager.getInstance().addObserver(mDownloadWatcher)
}
}
override fun onFragmentPaused(fm: FragmentManager, f: Fragment) {
super.onFragmentPaused(fm, f)
if (f === fragment && mDownloadWatcher != null) {
DownloadManager.getInstance().removeObserver(mDownloadWatcher)
}
}
}, false
)
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(status: EBDownloadStatus) {
// 将下载任务删除事件回调给网页
if (mDownloadHandler != null && "delete" == status.status) {
mDownloadHandler?.setProgressData(SimpleDownloadEntity(status.url, 0F, "UNKNOWN").toJson())
}
}
@Keep
internal data class ImageEvent(var imageList: ArrayList<String> = arrayListOf(), var position: Int = 0)
@Keep
internal class ImageEvent(var imageList: ArrayList<String> = arrayListOf(), var position: Int = 0)
internal data class ImageShareEvent(var image: String = "", var type: String = "")
@Keep
internal class ImageShareEvent(var image: String = "", var type: String = "")
@Keep
internal class TextShareEvent(var text: String = "", var type: String = "")
@Keep
internal class SimpleExposureEvent(var title: String = "", var id: String = "")
@Keep
internal class InviteFriendsEvent(
internal data class InviteFriendsEvent(
var type: String = "",
var way: String = "",
var url: String = "",
@ -755,49 +435,16 @@ class DefaultJsApi(
)
@Keep
internal class LogEvent(var jsonString: String = "", var logStore: String = "")
internal data class LogEvent(var jsonString: String = "", var logStore: String = "")
@Keep
class GameActivityEvent(
internal data class BrowseTaskEvent(var timeout: String = "", var isFinished: String = "")
@Keep
data class GameActivityEvent(
var gameId: String = "",
var activityTitle: String = "",
var activityId: String = "",
var platform: String = ""
)
@Keep
class SimpleDownloadEntity(
var url: String = "",
var progress: Float = 0F,
var status: String = "" // DOWNLOADING, PAUSED, DOWNLOADED, ERROR, UNKNOWN
) {
companion object {
fun fromDownloadEntity(downloadEntity: DownloadEntity): SimpleDownloadEntity {
val status: String = when (downloadEntity.status) {
add,
download,
downloading -> "DOWNLOADING"
done -> "DOWNLOADED"
pause,
resume,
subscribe,
waiting -> "PAUSED"
cancel,
delete -> "UNKNOWN"
else -> "ERROR"
}
return SimpleDownloadEntity(
url = VHelper.getOriginalUrl(downloadEntity.url),
progress = downloadEntity.percent.toFloat(),
status = status
)
}
}
}
}

View File

@ -5,8 +5,9 @@ import android.content.Intent
import android.net.Uri
import android.text.TextUtils
import android.util.Base64
import com.gh.common.util.CheckLoginUtils
import com.gh.common.util.DirectUtils
import com.gh.base.CurrentActivityHolder
import com.gh.common.constant.Constants
import com.gh.common.util.*
import com.gh.common.util.DirectUtils.directToFeedback
import com.gh.common.util.DirectUtils.directToGameDetailVideoStreaming
import com.gh.common.util.DirectUtils.directToGameServerCalendar
@ -14,57 +15,32 @@ import com.gh.common.util.DirectUtils.directToGameVideo
import com.gh.common.util.DirectUtils.directToLegacyVideoDetail
import com.gh.common.util.DirectUtils.directToLinkPage
import com.gh.common.util.DirectUtils.directToQa
import com.gh.common.util.PackageUtils
import com.gh.common.util.GsonUtils.gson
import com.gh.gamecenter.LibaoDetailActivity
import com.gh.gamecenter.MainActivity
import com.gh.gamecenter.NewsDetailActivity
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.entity.CommunityEntity
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.common.entity.SimpleGameEntity
import com.gh.gamecenter.common.eventbus.EBReuse
import com.gh.gamecenter.common.utils.DialogHelper
import com.gh.gamecenter.common.utils.EnvHelper
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.core.utils.GsonUtils.gson
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.entity.ActivityLabelEntity
import com.gh.gamecenter.entity.SubjectRecommendEntity
import com.gh.gamecenter.entity.VideoLinkEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.utils.PlatformUtils
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.gamecollection.publish.GameCollectionEditActivity
import com.gh.gamecenter.libao.LibaoDetailActivity
import com.gh.gamecenter.newsdetail.NewsDetailActivity
import com.gh.gamecenter.qa.BbsType
import com.gh.gamecenter.qa.video.publish.VideoPublishActivity
import com.gh.gamecenter.subject.SubjectActivity
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
import com.lightgame.utils.Utils
import org.greenrobot.eventbus.EventBus
import java.nio.charset.Charset
object DefaultUrlHandler {
@JvmStatic
fun interceptUrl(context: Context, url: String, entrance: String, sourceEntrance: String = ""): Boolean {
return interceptUrl(context, url, null, entrance, false, sourceEntrance)
fun interceptUrl(context: Context, url: String, entrance: String): Boolean {
return interceptUrl(context, url, entrance, false)
}
/**
* 检查并拦截部分内部处理的 url
* @param traceEvent 供一些页面用于登记曝光来源的实体
* @param bringAppToFront 是否需要在不匹配 host 的时候把 APP 调回到前台 (如微信调起)
*
* @return 是否已拦截处理
*/
@JvmStatic
fun interceptUrl(context: Context, url: String,
traceEvent: ExposureEvent? = null,
entrance: String,
bringAppToFront: Boolean = false,
sourceEntrance: String = ""): Boolean {
fun interceptUrl(context: Context, url: String, entrance: String, bringAppToFront: Boolean = false): Boolean {
val uri = Uri.parse(url)
if ("ghzhushou" == uri.scheme) {
Utils.log("url = $url")
@ -88,18 +64,10 @@ object DefaultUrlHandler {
id = id,
tab = uri.getQueryParameter("to"),
autoDownload = uri.getQueryParameter("auto_download") == "true",
traceEvent = traceEvent,
entrance = entrance
)
"column" -> SubjectActivity.startSubjectActivity(
context,
id,
uri.getQueryParameter("name"),
false,
null,
entrance
)
"column" -> SubjectActivity.startSubjectActivity(context, id, uri.getQueryParameter("name"), false, entrance)
"libao" -> context.startActivity(LibaoDetailActivity.getIntentById(context, id, entrance))
@ -110,7 +78,7 @@ object DefaultUrlHandler {
e.printStackTrace()
}
EntranceConsts.HOST_QQ_QUN -> {
EntranceUtils.HOST_QQ_QUN -> {
val key = uri.getQueryParameter("key")
if (!DirectUtils.directToQqGroup(context, key)) {
Utils.toast(context, "请检查是否已经安装手机QQ")
@ -118,7 +86,7 @@ object DefaultUrlHandler {
}
"inurl" -> {
DirectUtils.directToWebView(context, uri.getQueryParameter("url") ?: "", entrance)
DirectUtils.directToWebView(context, uri.getQueryParameter("url") ?: "")
}
"outurl" -> {
@ -133,7 +101,7 @@ object DefaultUrlHandler {
}
}
"question" -> DirectUtils.directToQuestionDetail(context, id, entrance, "文章链接", sourceEntrance)
"question" -> DirectUtils.directToQuestionDetail(context, id, entrance, "文章链接")
"real_name" -> DirectUtils.directToRealName(context)
@ -176,11 +144,11 @@ object DefaultUrlHandler {
if ("articles" == type) {
DirectUtils.directToCommunityArticle(
context, typeId, communityId,
entrance, "文章链接", sourceEntrance
entrance, "文章链接"
)
}
}
EntranceConsts.HOST_UPLOAD_VIDEO -> {
EntranceUtils.HOST_UPLOAD_VIDEO -> {
val titleParameter = uri.getQueryParameter("title")
val title = if (titleParameter.isNullOrEmpty()) "" else "#$titleParameter#"
val categoryId = uri.getQueryParameter("category_id") ?: ""
@ -191,31 +159,16 @@ object DefaultUrlHandler {
val tagActivityName = uri.getQueryParameter("tagActivityName") ?: ""
val linkEntity = VideoLinkEntity(title, categoryId, link, tagActivityId, tagActivityName)
val simpleGameEntity = SimpleGameEntity(gameId, gameName)
CheckLoginUtils.checkLogin(context, null, true, EntranceConsts.ENTRANCE_BROWSER) {
DirectUtils.directToVideoManager(
context,
linkEntity,
simpleGameEntity,
EntranceConsts.ENTRANCE_BROWSER,
""
)
CheckLoginUtils.checkLogin(context, null, true, EntranceUtils.ENTRANCE_BROWSER) {
DirectUtils.directToVideoManager(context, linkEntity, simpleGameEntity, EntranceUtils.ENTRANCE_BROWSER, "")
}
}
EntranceConsts.HOST_USERHOME -> {
EntranceUtils.HOST_USERHOME -> {
val position = uri.getQueryParameter("position")
val subtype = uri.getQueryParameter("sub_type") ?: ""
val subGameType = uri.getQueryParameter("sub_game_type") ?: "game_collection"
DirectUtils.directToHomeActivity(
context,
id,
subtype,
subGameType,
if (position.isNullOrEmpty()) -1 else position.toInt(),
entrance,
""
)
DirectUtils.directToHomeActivity(context, id, subtype, if (position.isNullOrEmpty()) -1 else position.toInt(), entrance, "")
}
EntranceConsts.HOST_VIDEO_MORE -> {
EntranceUtils.HOST_VIDEO_MORE -> {
val referer = uri.getQueryParameter("referer") ?: ""
val type = uri.getQueryParameter("type") ?: ""
val act = uri.getQueryParameter("act") ?: ""
@ -244,127 +197,144 @@ object DefaultUrlHandler {
act,
paginationType,
fieldId,
sectionName,
sourceEntrance = sourceEntrance
sectionName
)
}
EntranceConsts.HOST_VIDEO_DETAIL -> {
DirectUtils.directToVideoDetail(context, id, entrance, path, sourceEntrance)
EntranceUtils.HOST_VIDEO_DETAIL -> {
DirectUtils.directToVideoDetail(context, id, entrance, path)
}
EntranceConsts.HOST_VIDEO_SINGLE -> {
EntranceUtils.HOST_VIDEO_SINGLE -> {
val referer = uri.getQueryParameter("referer") ?: ""
DirectUtils.directToVideoDetail(
context, id, VideoDetailContainerViewModel.Location.SINGLE_VIDEO.value,
false, "", entrance, "", if (TextUtils.isEmpty(referer)) "" else referer, sourceEntrance
false, "", entrance, "", if (TextUtils.isEmpty(referer)) "" else referer
)
}
EntranceConsts.HOST_VIDEO_STREAMING_HOME -> {
DirectUtils.directToHomeVideoTab(context)
EntranceUtils.HOST_VIDEO_STREAMING_HOME -> {
intent = Intent(context, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
intent.putExtra(MainActivity.SWITCH_TO_VIDEO, true)
context.startActivity(intent)
}
EntranceConsts.HOST_VIDEO_STREAMING_DESC -> {
EntranceUtils.HOST_VIDEO_STREAMING_DESC -> {
directToGameDetailVideoStreaming(context, id, entrance)
}
EntranceConsts.HOST_VIDEO_COLLECTION -> {
EntranceUtils.HOST_VIDEO_COLLECTION -> {
directToGameVideo(context, id, entrance, "")
}
EntranceConsts.HOST_CATEGORY -> {
EntranceUtils.HOST_CATEGORY -> {
val title = uri.getQueryParameter("title")
DirectUtils.directCategoryDirectory(context, id, title ?: "", entrance, "")
}
EntranceConsts.HOST_COLUMN_COLLECTION -> {
EntranceUtils.HOST_COLUMN_COLLECTION -> {
val name = uri.getQueryParameter("name")
DirectUtils.directToColumnCollection(context, id, -1, entrance, name ?: "")
}
EntranceConsts.HOST_COLUMN -> {
DirectUtils.directToSubject(context, id, uri.getQueryParameter(EntranceConsts.KEY_NAME), entrance)
EntranceUtils.HOST_COLUMN -> {
DirectUtils.directToSubject(context, id, uri.getQueryParameter(EntranceUtils.KEY_NAME), entrance)
}
EntranceConsts.HOST_BLOCK -> {
EntranceUtils.HOST_COMMUNITY_QUESTION_LABEL_DETAIL -> {
val community = CommunityEntity()
community.id = uri.getQueryParameter("community_id") ?: ""
community.name = uri.getQueryParameter("community_name") ?: ""
val tag = uri.getQueryParameter("tag") ?: ""
DirectUtils.directAskColumnLabelDetail(context, tag, community, entrance, "")
}
EntranceUtils.HOST_COMMUNITY_COLUMN_DETAIL -> {
val community = CommunityEntity()
community.id = uri.getQueryParameter("community_id") ?: ""
community.name = uri.getQueryParameter("community_name") ?: ""
val columnId = uri.getQueryParameter("column_id") ?: ""
DirectUtils.directAskColumnDetail(context, columnId, community, entrance, "")
}
EntranceUtils.HOST_BLOCK -> {
val name = uri.getQueryParameter("name")
?: ""
val entity = SubjectRecommendEntity(link = id, name = name, text = name)
DirectUtils.directToBlock(context, entity, entrance)
}
EntranceConsts.HOST_SERVER_BLOCK -> {
EntranceUtils.HOST_SERVER_BLOCK -> {
DirectUtils.directToGameServers(context, entrance = entrance, path = "")
}
EntranceConsts.HOST_AMWAY_BLOCK -> {
EntranceUtils.HOST_AMWAY_BLOCK -> {
DirectUtils.directToAmway(context, entrance = entrance, path = "")
}
EntranceConsts.HOST_HELP -> {
EntranceUtils.HOST_HELP -> {
val name = uri.getQueryParameter("name")
?: ""
DirectUtils.directToQa(context, name, id)
}
EntranceConsts.HOST_HELP_COLLECTION -> {
EntranceUtils.HOST_HELP_COLLECTION -> {
val name = uri.getQueryParameter("name")
?: ""
DirectUtils.directToQaCollection(context, name, id)
}
EntranceConsts.HOST_GAME_UPLOAD -> {
EntranceUtils.HOST_GAME_UPLOAD -> {
DirectUtils.directGameUpload(context, entrance = entrance, path = "")
}
EntranceConsts.HOST_GAME_ZONE -> {
EntranceUtils.HOST_GAME_ZONE -> {
val zoneUrl = uri.getQueryParameter("url") ?: ""
DirectUtils.directGameZone(context, id, zoneUrl, entrance)
}
EntranceConsts.HOST_LINK -> {
EntranceUtils.HOST_LINK -> {
try {
val dataString = uri.getQueryParameter("data")
if (!TextUtils.isEmpty(dataString)) {
val linkData = Base64.decode(dataString, Base64.DEFAULT)
val linkDataString = String(linkData, Charset.defaultCharset())
val le = gson.fromJson(linkDataString, LinkEntity::class.java)
directToLinkPage(context, le, entrance, sourceEntrance, "")
directToLinkPage(context, le, entrance, "")
}
} catch (e: Exception) {
e.printStackTrace()
}
}
EntranceConsts.HOST_GAME_NEWS -> {
EntranceUtils.HOST_GAME_NEWS -> {
DirectUtils.directToGameNews(
context,
uri.getQueryParameter(EntranceConsts.KEY_GAME_ID),
uri.getQueryParameter(EntranceConsts.KEY_GAME_NAME),
uri.getQueryParameter(EntranceUtils.KEY_GAME_ID),
uri.getQueryParameter(EntranceUtils.KEY_GAME_NAME),
entrance
);
}
EntranceConsts.HOST_GAME_CALENDAR -> {
directToGameServerCalendar(context, uri.getQueryParameter(EntranceConsts.KEY_GAME_ID))
EntranceUtils.HOST_GAME_CALENDAR -> {
directToGameServerCalendar(context, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID))
}
EntranceConsts.HOST_HISTORY_APK -> {
DirectUtils.directToHistoryApk(context, uri.getQueryParameter(EntranceConsts.KEY_GAME_ID))
EntranceUtils.HOST_HISTORY_APK -> {
DirectUtils.directToHistoryApk(context, uri.getQueryParameter(EntranceUtils.KEY_GAME_ID))
}
EntranceConsts.HOST_FORUM_DETAIL -> {
val sectionId = uri.getQueryParameter("section_id") ?: ""
DirectUtils.directForumDetailSection(context, id, sectionId, entrance)
EntranceUtils.HOST_FORUM_DETAIL -> {
DirectUtils.directForumDetail(context, id, entrance)
}
EntranceConsts.HOST_GAME_RATING_DETAIL -> {
EntranceUtils.HOST_GAME_RATING_DETAIL -> {
DirectUtils.directToGameRatingDetail(
context,
uri.getQueryParameter(EntranceConsts.KEY_GAME_ID),
uri.getQueryParameter(EntranceConsts.KEY_COMMENT_ID),
EntranceConsts.ENTRANCE_BROWSER
uri.getQueryParameter(EntranceUtils.KEY_GAME_ID),
uri.getQueryParameter(EntranceUtils.KEY_COMMENT_ID),
EntranceUtils.ENTRANCE_BROWSER
)
}
EntranceConsts.HOST_FORUM -> {
EntranceUtils.HOST_FORUM -> {
val position = uri.getQueryParameter(EntranceUtils.KEY_POSITION)?.toInt()
DirectUtils.directToHomeCommunityTab(context)
DirectUtils.directToForum(context, position ?: 0)
}
EntranceConsts.HOST_UPLOAD_VIDEO_NEW -> {
EntranceUtils.HOST_UPLOAD_VIDEO_NEW -> {
val activityName = uri.getQueryParameter("activity_name") ?: ""
val activityId = uri.getQueryParameter("activity_id") ?: ""
val original = uri.getQueryParameter("original") ?: ""
@ -381,16 +351,11 @@ object DefaultUrlHandler {
GameEntity(id = gameId, mName = gameName, mIcon = icon, mIconSubscript = iconSubscript)
} else null
val activityLabelEntity = if (activityId.isNotEmpty() && activityName.isNotEmpty()) {
ActivityLabelEntity(
id = activityId,
name = activityName,
original = original.ifEmpty { "false" }.toBoolean()
)
ActivityLabelEntity(id = activityId, name = activityName, original = original.ifEmpty { "false" }.toBoolean())
} else null
val communityEntity = if (forumId.isNotEmpty() && forumName.isNotEmpty() && forumIcon.isNotEmpty()) {
CommunityEntity(id = forumId, name = forumName, icon = forumIcon)
} else null
val communityEntity =
if (forumId.isNotEmpty() && forumName.isNotEmpty() && forumIcon.isNotEmpty()) {
CommunityEntity(id = forumId, name = forumName, icon = forumIcon)
} else null
context.startActivity(
VideoPublishActivity.getIntent(
@ -407,47 +372,39 @@ object DefaultUrlHandler {
)
}
EntranceConsts.HOST_SUGGESTION -> {
val platform = uri.getQueryParameter(EntranceConsts.KEY_PLATFORM)
EntranceUtils.HOST_SUGGESTION -> {
val platform = uri.getQueryParameter(EntranceUtils.KEY_PLATFORM)
val platformName = PlatformUtils.getInstance(context).getPlatformName(platform)
val gameId = uri.getQueryParameter(EntranceConsts.KEY_GAMEID)
val packageMd5 = uri.getQueryParameter(EntranceConsts.KEY_PACKAGE_MD5)
val isQaFeedback = uri.getQueryParameter(EntranceConsts.KEY_IS_QA_FEEDBACK) == "true"
val gameId = uri.getQueryParameter(EntranceUtils.KEY_GAMEID)
val packageMd5 = uri.getQueryParameter(EntranceUtils.KEY_PACKAGE_MD5)
val isQaFeedback = uri.getQueryParameter(EntranceUtils.KEY_IS_QA_FEEDBACK) == "true"
val content = if (TextUtils.isEmpty(gameId) || TextUtils.isEmpty(packageMd5)) String.format(
"%s—V%s—%sV%s",
uri.getQueryParameter(EntranceConsts.KEY_GAME_NAME),
uri.getQueryParameter(EntranceConsts.KEY_VERSION),
"%s-%s-V%s",
uri.getQueryParameter(EntranceUtils.KEY_GAME_NAME),
if (TextUtils.isEmpty(platformName)) platform else platformName,
uri.getQueryParameter(EntranceConsts.KEY_PLATFORM_VERSION),
uri.getQueryParameter(EntranceUtils.KEY_VERSION)
) else String.format(
"%s-%s-V%s\n游戏ID%s\n游戏包MD5%s\n",
uri.getQueryParameter(EntranceConsts.KEY_GAME_NAME),
uri.getQueryParameter(EntranceUtils.KEY_GAME_NAME),
if (TextUtils.isEmpty(platformName)) platform else platformName,
uri.getQueryParameter(EntranceConsts.KEY_VERSION), gameId, packageMd5
uri.getQueryParameter(EntranceUtils.KEY_VERSION), gameId, packageMd5
)
val qaId = uri.getQueryParameter("qa_id") ?: ""
val qaContentId = uri.getQueryParameter(EntranceConsts.KEY_QA_CONTENT_ID) ?: ""
val qaTitle = uri.getQueryParameter(EntranceConsts.KEY_QA_TITLE)
val qaContentId = uri.getQueryParameter(EntranceUtils.KEY_QA_CONTENT_ID) ?: ""
val qaTitle = uri.getQueryParameter(EntranceUtils.KEY_QA_TITLE)
if (!TextUtils.isEmpty(qaId)) {
directToQa(context, qaTitle, qaId)
} else {
directToFeedback(
context,
content,
isQaFeedback,
qaContentId,
isPlugin = false,
isSmoothGame = false,
EntranceConsts.ENTRANCE_BROWSER
)
directToFeedback(context, content, null, isQaFeedback, qaContentId, EntranceUtils.ENTRANCE_BROWSER)
}
}
EntranceConsts.HOST_HELP_AND_FEEDBACK -> {
DirectUtils.directToHelpAndFeedback(context)
EntranceUtils.HOST_HELP_AND_FEEDBACK -> {
val position = uri.getQueryParameter("position") ?: ""
DirectUtils.directToHelpAndFeedback(context, position.toInt())
}
EntranceConsts.HOST_HELP_DETAIL -> {
EntranceUtils.HOST_HELP_DETAIL -> {
var url = uri.getQueryParameter("url")
if (!url.isNullOrEmpty()) {
context.startActivity(WebActivity.getIntent(context, url, false))
@ -460,50 +417,20 @@ object DefaultUrlHandler {
val id = uri.getQueryParameter("id")
val name = uri.getQueryParameter("name")
val qaCollectionId = uri.getQueryParameter("collection_id")
context.startActivity(
WebActivity.getIntent(
context,
"$url$id",
name,
true,
!qaCollectionId.isNullOrEmpty()
)
)
context.startActivity(WebActivity.getIntent(context, "$url$id", name, true, !qaCollectionId.isNullOrEmpty()))
}
}
EntranceConsts.HOST_GAME_COLLECTION_DETAIL -> {
DirectUtils.directToGameCollectionDetail(context, id, entrance, traceEvent = traceEvent)
EntranceUtils.HOST_GAME_COLLECTION_DETAIL -> {
DirectUtils.directToGameCollectionDetail(context, id, entrance)
}
EntranceConsts.HOST_GAME_COLLECTION_SQUARE -> {
EntranceUtils.HOST_GAME_COLLECTION_SQUARE -> {
DirectUtils.directToGameCollectionSquare(context, entrance)
}
EntranceConsts.HOST_GAME_COLLECTION_EDIT -> {
val activityId = uri.getQueryParameter("activity_id") ?: ""
val activityName = uri.getQueryParameter("activity_name") ?: ""
val gameId = uri.getQueryParameter("game_id") ?: ""
context.startActivity(
GameCollectionEditActivity.getCreateIntent(
context,
activityId,
activityName,
gameId,
entrance,
"其他"
)
)
}
EntranceConsts.HOST_GAME_LIBRARY -> {
DirectUtils.directToMainActivity(context)
}
EntranceConsts.HOST_HOME_GAME_COLLECTION_SQUARE -> {
DirectUtils.directToMainActivity(context)
DirectUtils.directToHomeDefaultTab(context)
EventBus.getDefault().post(EBReuse(host))
EntranceUtils.HOST_GAME_COLLECTION_EDIT -> {
context.startActivity(GameCollectionEditActivity.getIntent(context, entrance))
}
else -> {
@ -557,7 +484,7 @@ object DefaultUrlHandler {
}
// 处理内部页面逻辑
if (transformNormalScheme(context, url, entrance, sourceEntrance)) {
if (transformNormalScheme(context, url, entrance)) {
return true
}
@ -566,14 +493,7 @@ object DefaultUrlHandler {
}
@JvmStatic
fun transformNormalScheme(context: Context, url: String, entrance: String, sourceEntrance: String): Boolean {
val b = transformNewNormalScheme(context, url, entrance, sourceEntrance)
if (b) return b
return transformOldNormalScheme(context, url, entrance, sourceEntrance)
}
@JvmStatic
fun transformOldNormalScheme(context: Context, url: String, entrance: String, sourceEntrance: String): Boolean {
fun transformNormalScheme(context: Context, url: String, entrance: String): Boolean {
val uri = Uri.parse(url)
if (uri.host == "www.ghzs666.com"
|| uri.host == "www.ghzs.com"
@ -585,21 +505,15 @@ object DefaultUrlHandler {
uri.path?.apply {
when {
contains("game") -> {
val gameId = uri.getQueryParameter("gameId") ?: uri.pathSegments.last() ?: ""
DirectUtils.directToGameDetail(
context,
gameId,
"",
entrance,
autoDownload = false,
traceEvent = null
)
val gameId = uri.getQueryParameter("gameId") ?: uri.pathSegments.last()
?: ""
DirectUtils.directToGameDetail(context, gameId, entrance, autoDownload = false, traceEvent = null)
}
contains("question") -> {
val questionId = split("/")[2]
val answerId = uri.getQueryParameter("answer")
if (answerId.isNullOrEmpty()) {
DirectUtils.directToQuestionDetail(context, questionId, entrance, "", sourceEntrance)
DirectUtils.directToQuestionDetail(context, questionId, entrance, "")
} else {
DirectUtils.directToAnswerDetail(context, answerId, entrance, "")
}
@ -610,8 +524,7 @@ object DefaultUrlHandler {
var type = ""
var typeId = ""
val split =
replace("/communities", "").replace("/bbs", "").replace(".html", "").split("/".toRegex())
.dropLastWhile { it.isEmpty() }
replace("/communities", "").replace("/bbs", "").replace(".html", "").split("/".toRegex()).dropLastWhile { it.isEmpty() }
.toTypedArray()
for (text in split) {
if (TextUtils.isEmpty(communityId)) {
@ -629,7 +542,7 @@ object DefaultUrlHandler {
if ("articles" == type || "article" == type) {
DirectUtils.directToCommunityArticle(
context, typeId, communityId,
entrance, "文章链接", sourceEntrance
entrance, "文章链接"
)
}
}
@ -659,55 +572,6 @@ object DefaultUrlHandler {
return false
}
@JvmStatic
fun transformNewNormalScheme(context: Context, url: String, entrance: String, sourceEntrance: 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, "文章链接", sourceEntrance
)
}
//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, sourceEntrance)
}
else -> return false
}
}
return true
}
return false
}
/**
* 将 url 转换为 LinkEntity (实际只有 type 和 link 两个字段,仅供日志,不保证能用)
*/

View File

@ -2,25 +2,24 @@ package com.gh.common
import com.gh.common.exposure.ExposureManager
import com.gh.common.filter.RegionSettingHelper
import com.gh.common.loghub.LoghubUtils
import com.gh.common.util.doOnMainProcessOnly
import com.gh.common.util.tryCatchInRelease
import com.gh.common.videolog.VideoRecordUtils
import com.gh.download.DownloadDataHelper
import com.gh.gamecenter.common.loghub.LoghubUtils
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.tryCatchInRelease
import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.entity.TimeEntity
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import io.reactivex.schedulers.Schedulers
import kotlin.concurrent.fixedRateTimer
object FixedRateJobHelper {
private const val CHECKER_PERIOD: Long = 15 * 1000L
private const val TIME_PERIOD: Long = 10 * 60 * 1000L
private const val LOGHUB_PERIOD: Long = 2 * 60 * 1000L
private const val EXPOSURE_PERIOD: Long = 1 * 60 * 1000L
private const val REGION_SETTING_PERIOD: Long = 60 * 1000L
private const val TIME_PERIOD: Long = 600 * 1000L
private const val LOGHUB_PERIOD: Long = 120 * 1000L
private const val EXPOSURE_PERIOD: Long = 300 * 1000L
private const val REGION_SETTING_PERIOD: Long = 300 * 1000L
private const val VIDEO_RECORD_PERIOD: Long = 60 * 1000L
private const val DOWNLOAD_HEARTBEAT_PERIOD: Long = 60 * 1000L
@ -32,56 +31,53 @@ object FixedRateJobHelper {
@JvmStatic
fun begin() {
// 时间检查每15秒检查一次
fixedRateTimer("Global-Fixed-Rate-Timer", initialDelay = 100, period = CHECKER_PERIOD) {
val elapsedTime = mExecuteCount * CHECKER_PERIOD
// 时间校对10分钟一次
if (elapsedTime % TIME_PERIOD == 0L) {
RetrofitManager.getInstance().api.time
.subscribeOn(Schedulers.io())
.subscribe(object : Response<TimeEntity>() {
override fun onResponse(response: TimeEntity?) {
val serverTime = response?.time
serverTime?.let {
timeDeltaBetweenServerAndClient = it * 1000 - System.currentTimeMillis()
}
}
})
}
// 提交曝光数据
if (elapsedTime % EXPOSURE_PERIOD == 0L) {
ExposureManager.commitSavedExposureEvents(true)
}
// 分片检测下载进度
if (elapsedTime % DOWNLOAD_HEARTBEAT_SHEET_PERIOD == 0L) {
tryCatchInRelease {
val upload = (mExecuteCount * CHECKER_PERIOD) % DOWNLOAD_HEARTBEAT_PERIOD == 0L
DownloadDataHelper.uploadDownloadHeartbeat(upload)
doOnMainProcessOnly {
fixedRateTimer("Global-Fixed-Rate-Timer", initialDelay = 100, period = CHECKER_PERIOD) {
// 时间校对10分钟一次
if ((mExecuteCount * CHECKER_PERIOD) % TIME_PERIOD == 0L) {
RetrofitManager.getInstance().api.time
.subscribeOn(Schedulers.io())
.subscribe(object : Response<TimeEntity>() {
override fun onResponse(response: TimeEntity?) {
val serverTime = response?.time
serverTime?.let { timeDeltaBetweenServerAndClient = it * 1000 - System.currentTimeMillis() }
}
})
}
}
// 提交普通 loghub 数据
if (elapsedTime % LOGHUB_PERIOD == 0L) {
runOnUiThread {
LoghubUtils.commitSavedLoghubEvents(true)
// 提交曝光数据
if ((mExecuteCount * CHECKER_PERIOD) % EXPOSURE_PERIOD == 0L) {
ExposureManager.commitSavedExposureEvents(true)
}
}
// 更新游戏屏蔽信息
if (elapsedTime % REGION_SETTING_PERIOD == 0L) {
if (HaloApp.getInstance().isRunningForeground) {
RegionSettingHelper.getRegionSetting()
// 分片检测下载进度
if ((mExecuteCount * CHECKER_PERIOD) % DOWNLOAD_HEARTBEAT_SHEET_PERIOD == 0L) {
tryCatchInRelease {
val upload = (mExecuteCount * CHECKER_PERIOD) % DOWNLOAD_HEARTBEAT_PERIOD == 0L
DownloadDataHelper.uploadDownloadHeartbeat(upload)
}
}
}
// 提交视频浏览记录数据
if (elapsedTime % VIDEO_RECORD_PERIOD == 0L) {
VideoRecordUtils.commitVideoRecord()
}
// 提交普通 loghub 数据
if ((mExecuteCount * CHECKER_PERIOD) % LOGHUB_PERIOD == 0L) {
LoghubUtils.commitSavedLoghubEvents()
}
mExecuteCount++
// 更新游戏屏蔽信息
if ((mExecuteCount * CHECKER_PERIOD) % REGION_SETTING_PERIOD == 0L) {
if (HaloApp.getInstance().isRunningForeground) {
RegionSettingHelper.getRegionSetting()
}
}
// 提交视频浏览记录数据
if ((mExecuteCount * CHECKER_PERIOD) % VIDEO_RECORD_PERIOD == 0L) {
VideoRecordUtils.commitVideoRecord()
}
// ExposureUtils.logADownloadCompleteExposureEvent(GameEntity(id = mExecuteCount.toString(), name = "测试曝光上传"), platform = "", trace = null, downloadType = ExposureUtils.DownloadType.DOWNLOAD)
mExecuteCount++
}
}
}
}

View File

@ -0,0 +1,39 @@
//package com.gh.common
//
//import android.content.BroadcastReceiver
//import android.content.Context
//import android.content.Intent
//import com.gh.common.im.ImManager
//import com.gh.gamecenter.manager.UserManager
//import com.gh.gamecenter.retrofit.RetrofitManager
//import com.halo.assistant.HaloApp
//import com.m7.imkfsdk.chat.ChatActivity
//import io.reactivex.schedulers.Schedulers
//
///**
// * 可使用 [LocalBroadcastManager] 来进行简单的模块间消息通知
// */
//
//class LocalBroadcastReceiver : BroadcastReceiver() {
//
// override fun onReceive(context: Context?, intent: Intent?) {
// intent?.let {
// when (intent.action) {
// ChatActivity.ACTION_DISMISS_FLOATING_WINDOW -> {
// ImManager.dismissFloatingWindow()
//
// RetrofitManager.getInstance().api.postImEnding(UserManager.getInstance().userId)
// .subscribeOn(Schedulers.io())
// .subscribe()
// }
//
// ChatActivity.ACTION_HIDE_UNREAD_DOT -> {
// ImManager.updateShouldShowFloatingWindowDot(false)
// }
//
// else -> return
// }
// }
// }
//
//}

View File

@ -0,0 +1,117 @@
package com.gh.common
import android.annotation.SuppressLint
import com.gh.gamecenter.entity.AliasEntity
import com.halo.assistant.HaloApp
object PushManager {
var deviceToken: String? = ""
private var mPreviousAlias: AliasEntity? = null
private var mApplication = HaloApp.getInstance().application
const val SP_PUSH_ALIAS = "push_alias"
@JvmStatic
fun init(channel: String) {
// tryWithDefaultCatch {
// //初始化友盟推送
// UMConfigure.init(mApplication, Config.UMENG_APPKEY, channel, UMConfigure.DEVICE_TYPE_PHONE, Config.UMENG_MESSAGE_SECRET)
//
// val pushAgent = PushAgent.getInstance(mApplication)
//
// runOnIoThread { registerDevice() }
//
// // 注册小米、华为和魅族通道
// MiPushRegistar.register(mApplication, Config.MIPUSH_APPID, Config.MIPUSH_APPKEY)
// HuaWeiRegister.register(mApplication)
// MeizuRegister.register(mApplication, BuildConfig.MEIZUPUSH_APPID, BuildConfig.MEIZUPUSH_APPKEY)
//
// val aliasInSp = PreferenceManager.getDefaultSharedPreferences(mApplication).getString(SP_PUSH_ALIAS, "")
// mPreviousAlias = aliasInSp?.toObject()
//
// if (mPreviousAlias == null) {
// getAndSetAlias()
// }
//
// // 完全自定义处理(透传)
// pushAgent.setPushIntentServiceClass(GHUmengNotificationService::class.java)
// }
}
private fun registerDevice() {
// PushAgent.getInstance(mApplication).register(object : IUmengRegisterCallback {
// override fun onSuccess(dToken: String) {
// //注册成功会返回device token
// deviceToken = dToken
// getAndSetAlias()
// Utils.log("deviceToken::$dToken")
// }
//
// override fun onFailure(s: String, s1: String) {
// Utils.log("deviceToken::" + "注册失败")
// }
// })
}
@SuppressLint("CheckResult")
@JvmStatic
fun getAndSetAlias() {
// if (deviceToken.isNullOrEmpty()) {
// registerDevice()
// return
// }
//
// val meta = MetaUtil.getMeta()
//
// val jsonObject = JSONObject()
// jsonObject.put("device_token", deviceToken)
// jsonObject.put("imei", meta.imei)
// jsonObject.put("android_id", meta.android_id)
// jsonObject.put("model", meta.model)
// jsonObject.put("manufacturer", meta.manufacturer)
// jsonObject.put("os", meta.os)
// jsonObject.put("os_version", meta.android_version)
// jsonObject.put("mac", meta.mac)
// jsonObject.put("gid", meta.gid)
//
// val body = RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())
//
// RetrofitManager.getInstance().api.getAlias(body)
// .subscribeOn(Schedulers.io())
// .subscribe(
// { setAlias(it) },
// { it.printStackTrace() }
// )
}
@JvmStatic
fun setAlias(alias: AliasEntity) {
// val pushAgent = PushAgent.getInstance(mApplication)
//
// mPreviousAlias = alias
// PreferenceManager.getDefaultSharedPreferences(mApplication).edit {
// putString(SP_PUSH_ALIAS, mPreviousAlias?.toJson())
// }
//
// pushAgent.setAlias(alias.alias, alias.aliasType) { b, s ->
// Utils.log("注册别名 $b + $s")
// }
}
@JvmStatic
fun deleteAlias() {
// val pushAgent = PushAgent.getInstance(mApplication)
//
// mPreviousAlias?.let {
// pushAgent.deleteAlias(it.alias, it.aliasType) { b, s ->
// Utils.log("删除别名 $b + $s")
// }
// }
// PreferenceManager.getDefaultSharedPreferences(mApplication).edit {
// putString(SP_PUSH_ALIAS, "")
// }
// mPreviousAlias = null
}
}

Some files were not shown because too many files have changed in this diff Show More