Merge branch 'release/0.1.0' into main
906
.editorconfig
Normal file
|
|
@ -0,0 +1,906 @@
|
|||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
max_line_length = 160
|
||||
tab_width = 4
|
||||
ij_continuation_indent_size = 4
|
||||
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
|
||||
|
||||
# Ktlint rule, for more information see https://pinterest.github.io/ktlint/faq/#why-is-editorconfig-property-disabled_rules-deprecated-and-how-do-i-resolve-this
|
||||
ktlint_standard_wrapping = disabled
|
||||
ktlint_standard_trailing-comma-on-call-site = disabled
|
||||
|
||||
|
||||
[*.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_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_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_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_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_names_count_to_use_import_on_demand = 99
|
||||
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_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_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
|
||||
|
||||
[*.properties]
|
||||
ij_properties_align_group_field_declarations = false
|
||||
ij_properties_keep_blank_lines = false
|
||||
ij_properties_key_value_delimiter = equals
|
||||
ij_properties_spaces_around_key_value_delimiter = 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_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
|
||||
|
||||
[{*.bash,*.sh,*.zsh}]
|
||||
indent_size = 2
|
||||
tab_width = 2
|
||||
ij_shell_binary_ops_start_line = false
|
||||
ij_shell_keep_column_alignment_padding = false
|
||||
ij_shell_minify_program = false
|
||||
ij_shell_redirect_followed_by_space = false
|
||||
ij_shell_switch_cases_indented = false
|
||||
ij_shell_use_unix_line_separator = true
|
||||
|
||||
[{*.c,*.c++,*.cc,*.cp,*.cpp,*.cu,*.cuh,*.cxx,*.h,*.h++,*.hh,*.hp,*.hpp,*.hxx,*.i,*.icc,*.ii,*.inl,*.ino,*.ipp,*.m,*.mm,*.pch,*.tcc,*.tpp}]
|
||||
ij_c_add_brief_tag = false
|
||||
ij_c_add_getter_prefix = true
|
||||
ij_c_add_setter_prefix = true
|
||||
ij_c_align_dictionary_pair_values = false
|
||||
ij_c_align_group_field_declarations = false
|
||||
ij_c_align_init_list_in_columns = true
|
||||
ij_c_align_multiline_array_initializer_expression = true
|
||||
ij_c_align_multiline_assignment = true
|
||||
ij_c_align_multiline_binary_operation = true
|
||||
ij_c_align_multiline_chained_methods = false
|
||||
ij_c_align_multiline_for = true
|
||||
ij_c_align_multiline_ternary_operation = true
|
||||
ij_c_array_initializer_comma_on_next_line = false
|
||||
ij_c_array_initializer_new_line_after_left_brace = false
|
||||
ij_c_array_initializer_right_brace_on_new_line = false
|
||||
ij_c_array_initializer_wrap = normal
|
||||
ij_c_assignment_wrap = off
|
||||
ij_c_binary_operation_sign_on_next_line = false
|
||||
ij_c_binary_operation_wrap = normal
|
||||
ij_c_blank_lines_after_class_header = 0
|
||||
ij_c_blank_lines_after_imports = 1
|
||||
ij_c_blank_lines_around_class = 1
|
||||
ij_c_blank_lines_around_field = 0
|
||||
ij_c_blank_lines_around_field_in_interface = 0
|
||||
ij_c_blank_lines_around_method = 1
|
||||
ij_c_blank_lines_around_method_in_interface = 1
|
||||
ij_c_blank_lines_around_namespace = 0
|
||||
ij_c_blank_lines_around_properties_in_declaration = 0
|
||||
ij_c_blank_lines_around_properties_in_interface = 0
|
||||
ij_c_blank_lines_before_imports = 1
|
||||
ij_c_blank_lines_before_method_body = 0
|
||||
ij_c_block_brace_placement = end_of_line
|
||||
ij_c_block_brace_style = end_of_line
|
||||
ij_c_block_comment_at_first_column = true
|
||||
ij_c_catch_on_new_line = false
|
||||
ij_c_class_brace_style = end_of_line
|
||||
ij_c_class_constructor_init_list_align_multiline = true
|
||||
ij_c_class_constructor_init_list_comma_on_next_line = false
|
||||
ij_c_class_constructor_init_list_new_line_after_colon = never
|
||||
ij_c_class_constructor_init_list_new_line_before_colon = if_long
|
||||
ij_c_class_constructor_init_list_wrap = normal
|
||||
ij_c_copy_is_deep = false
|
||||
ij_c_create_interface_for_categories = true
|
||||
ij_c_declare_generated_methods = true
|
||||
ij_c_description_include_member_names = true
|
||||
ij_c_discharged_short_ternary_operator = false
|
||||
ij_c_do_not_add_breaks = false
|
||||
ij_c_do_while_brace_force = never
|
||||
ij_c_else_on_new_line = false
|
||||
ij_c_enum_constants_comma_on_next_line = false
|
||||
ij_c_enum_constants_wrap = on_every_item
|
||||
ij_c_for_brace_force = never
|
||||
ij_c_for_statement_new_line_after_left_paren = false
|
||||
ij_c_for_statement_right_paren_on_new_line = false
|
||||
ij_c_for_statement_wrap = off
|
||||
ij_c_function_brace_placement = end_of_line
|
||||
ij_c_function_call_arguments_align_multiline = true
|
||||
ij_c_function_call_arguments_align_multiline_pars = false
|
||||
ij_c_function_call_arguments_comma_on_next_line = false
|
||||
ij_c_function_call_arguments_new_line_after_lpar = false
|
||||
ij_c_function_call_arguments_new_line_before_rpar = false
|
||||
ij_c_function_call_arguments_wrap = normal
|
||||
ij_c_function_non_top_after_return_type_wrap = normal
|
||||
ij_c_function_parameters_align_multiline = true
|
||||
ij_c_function_parameters_align_multiline_pars = false
|
||||
ij_c_function_parameters_comma_on_next_line = false
|
||||
ij_c_function_parameters_new_line_after_lpar = false
|
||||
ij_c_function_parameters_new_line_before_rpar = false
|
||||
ij_c_function_parameters_wrap = normal
|
||||
ij_c_function_top_after_return_type_wrap = normal
|
||||
ij_c_generate_additional_eq_operators = true
|
||||
ij_c_generate_additional_rel_operators = true
|
||||
ij_c_generate_class_constructor = true
|
||||
ij_c_generate_comparison_operators_use_std_tie = false
|
||||
ij_c_generate_instance_variables_for_properties = ask
|
||||
ij_c_generate_operators_as_members = true
|
||||
ij_c_header_guard_style_pattern = ${PROJECT_NAME}_${FILE_NAME}_${EXT}
|
||||
ij_c_if_brace_force = never
|
||||
ij_c_in_line_short_ternary_operator = true
|
||||
ij_c_indent_block_comment = true
|
||||
ij_c_indent_c_struct_members = 4
|
||||
ij_c_indent_case_from_switch = true
|
||||
ij_c_indent_class_members = 4
|
||||
ij_c_indent_directive_as_code = false
|
||||
ij_c_indent_implementation_members = 0
|
||||
ij_c_indent_inside_code_block = 4
|
||||
ij_c_indent_interface_members = 0
|
||||
ij_c_indent_interface_members_except_ivars_block = false
|
||||
ij_c_indent_namespace_members = 4
|
||||
ij_c_indent_preprocessor_directive = 0
|
||||
ij_c_indent_visibility_keywords = 0
|
||||
ij_c_insert_override = true
|
||||
ij_c_insert_virtual_with_override = false
|
||||
ij_c_introduce_auto_vars = false
|
||||
ij_c_introduce_const_params = false
|
||||
ij_c_introduce_const_vars = false
|
||||
ij_c_introduce_generate_property = false
|
||||
ij_c_introduce_generate_synthesize = true
|
||||
ij_c_introduce_globals_to_header = true
|
||||
ij_c_introduce_prop_to_private_category = false
|
||||
ij_c_introduce_static_consts = true
|
||||
ij_c_introduce_use_ns_types = false
|
||||
ij_c_ivars_prefix = _
|
||||
ij_c_keep_blank_lines_before_end = 2
|
||||
ij_c_keep_blank_lines_before_right_brace = 2
|
||||
ij_c_keep_blank_lines_in_code = 2
|
||||
ij_c_keep_blank_lines_in_declarations = 2
|
||||
ij_c_keep_case_expressions_in_one_line = false
|
||||
ij_c_keep_control_statement_in_one_line = true
|
||||
ij_c_keep_directive_at_first_column = true
|
||||
ij_c_keep_first_column_comment = true
|
||||
ij_c_keep_line_breaks = true
|
||||
ij_c_keep_nested_namespaces_in_one_line = false
|
||||
ij_c_keep_simple_blocks_in_one_line = true
|
||||
ij_c_keep_simple_methods_in_one_line = true
|
||||
ij_c_keep_structures_in_one_line = false
|
||||
ij_c_lambda_capture_list_align_multiline = false
|
||||
ij_c_lambda_capture_list_align_multiline_bracket = false
|
||||
ij_c_lambda_capture_list_comma_on_next_line = false
|
||||
ij_c_lambda_capture_list_new_line_after_lbracket = false
|
||||
ij_c_lambda_capture_list_new_line_before_rbracket = false
|
||||
ij_c_lambda_capture_list_wrap = off
|
||||
ij_c_line_comment_add_space = false
|
||||
ij_c_line_comment_at_first_column = true
|
||||
ij_c_method_brace_placement = end_of_line
|
||||
ij_c_method_call_arguments_align_by_colons = true
|
||||
ij_c_method_call_arguments_align_multiline = false
|
||||
ij_c_method_call_arguments_special_dictionary_pairs_treatment = true
|
||||
ij_c_method_call_arguments_wrap = off
|
||||
ij_c_method_call_chain_wrap = off
|
||||
ij_c_method_parameters_align_by_colons = true
|
||||
ij_c_method_parameters_align_multiline = false
|
||||
ij_c_method_parameters_wrap = off
|
||||
ij_c_namespace_brace_placement = end_of_line
|
||||
ij_c_parentheses_expression_new_line_after_left_paren = false
|
||||
ij_c_parentheses_expression_right_paren_on_new_line = false
|
||||
ij_c_place_assignment_sign_on_next_line = false
|
||||
ij_c_property_nonatomic = true
|
||||
ij_c_put_ivars_to_implementation = true
|
||||
ij_c_refactor_compatibility_aliases_and_classes = true
|
||||
ij_c_refactor_properties_and_ivars = true
|
||||
ij_c_release_style = ivar
|
||||
ij_c_retain_object_parameters_in_constructor = true
|
||||
ij_c_semicolon_after_method_signature = false
|
||||
ij_c_shift_operation_align_multiline = true
|
||||
ij_c_shift_operation_wrap = normal
|
||||
ij_c_show_non_virtual_functions = false
|
||||
ij_c_space_after_colon = true
|
||||
ij_c_space_after_colon_in_selector = false
|
||||
ij_c_space_after_comma = true
|
||||
ij_c_space_after_cup_in_blocks = false
|
||||
ij_c_space_after_dictionary_literal_colon = true
|
||||
ij_c_space_after_for_semicolon = true
|
||||
ij_c_space_after_init_list_colon = true
|
||||
ij_c_space_after_method_parameter_type_parentheses = false
|
||||
ij_c_space_after_method_return_type_parentheses = false
|
||||
ij_c_space_after_pointer_in_declaration = false
|
||||
ij_c_space_after_quest = true
|
||||
ij_c_space_after_reference_in_declaration = false
|
||||
ij_c_space_after_reference_in_rvalue = false
|
||||
ij_c_space_after_structures_rbrace = true
|
||||
ij_c_space_after_superclass_colon = true
|
||||
ij_c_space_after_type_cast = true
|
||||
ij_c_space_after_visibility_sign_in_method_declaration = true
|
||||
ij_c_space_before_autorelease_pool_lbrace = true
|
||||
ij_c_space_before_catch_keyword = true
|
||||
ij_c_space_before_catch_left_brace = true
|
||||
ij_c_space_before_catch_parentheses = true
|
||||
ij_c_space_before_category_parentheses = true
|
||||
ij_c_space_before_chained_send_message = true
|
||||
ij_c_space_before_class_left_brace = true
|
||||
ij_c_space_before_colon = true
|
||||
ij_c_space_before_comma = false
|
||||
ij_c_space_before_dictionary_literal_colon = false
|
||||
ij_c_space_before_do_left_brace = true
|
||||
ij_c_space_before_else_keyword = true
|
||||
ij_c_space_before_else_left_brace = true
|
||||
ij_c_space_before_for_left_brace = true
|
||||
ij_c_space_before_for_parentheses = true
|
||||
ij_c_space_before_for_semicolon = false
|
||||
ij_c_space_before_if_left_brace = true
|
||||
ij_c_space_before_if_parentheses = true
|
||||
ij_c_space_before_init_list = false
|
||||
ij_c_space_before_init_list_colon = true
|
||||
ij_c_space_before_method_call_parentheses = false
|
||||
ij_c_space_before_method_left_brace = true
|
||||
ij_c_space_before_method_parentheses = false
|
||||
ij_c_space_before_namespace_lbrace = true
|
||||
ij_c_space_before_pointer_in_declaration = true
|
||||
ij_c_space_before_property_attributes_parentheses = false
|
||||
ij_c_space_before_protocols_brackets = true
|
||||
ij_c_space_before_quest = true
|
||||
ij_c_space_before_reference_in_declaration = true
|
||||
ij_c_space_before_superclass_colon = true
|
||||
ij_c_space_before_switch_left_brace = true
|
||||
ij_c_space_before_switch_parentheses = true
|
||||
ij_c_space_before_template_call_lt = false
|
||||
ij_c_space_before_template_declaration_lt = false
|
||||
ij_c_space_before_try_left_brace = true
|
||||
ij_c_space_before_while_keyword = true
|
||||
ij_c_space_before_while_left_brace = true
|
||||
ij_c_space_before_while_parentheses = true
|
||||
ij_c_space_between_adjacent_brackets = false
|
||||
ij_c_space_between_operator_and_punctuator = false
|
||||
ij_c_space_within_empty_array_initializer_braces = false
|
||||
ij_c_spaces_around_additive_operators = true
|
||||
ij_c_spaces_around_assignment_operators = true
|
||||
ij_c_spaces_around_bitwise_operators = true
|
||||
ij_c_spaces_around_equality_operators = true
|
||||
ij_c_spaces_around_lambda_arrow = true
|
||||
ij_c_spaces_around_logical_operators = true
|
||||
ij_c_spaces_around_multiplicative_operators = true
|
||||
ij_c_spaces_around_pm_operators = false
|
||||
ij_c_spaces_around_relational_operators = true
|
||||
ij_c_spaces_around_shift_operators = true
|
||||
ij_c_spaces_around_unary_operator = false
|
||||
ij_c_spaces_within_array_initializer_braces = false
|
||||
ij_c_spaces_within_braces = true
|
||||
ij_c_spaces_within_brackets = false
|
||||
ij_c_spaces_within_cast_parentheses = false
|
||||
ij_c_spaces_within_catch_parentheses = false
|
||||
ij_c_spaces_within_category_parentheses = false
|
||||
ij_c_spaces_within_empty_braces = false
|
||||
ij_c_spaces_within_empty_function_call_parentheses = false
|
||||
ij_c_spaces_within_empty_function_declaration_parentheses = false
|
||||
ij_c_spaces_within_empty_lambda_capture_list_bracket = false
|
||||
ij_c_spaces_within_empty_template_call_ltgt = false
|
||||
ij_c_spaces_within_empty_template_declaration_ltgt = false
|
||||
ij_c_spaces_within_for_parentheses = false
|
||||
ij_c_spaces_within_function_call_parentheses = false
|
||||
ij_c_spaces_within_function_declaration_parentheses = false
|
||||
ij_c_spaces_within_if_parentheses = false
|
||||
ij_c_spaces_within_lambda_capture_list_bracket = false
|
||||
ij_c_spaces_within_method_parameter_type_parentheses = false
|
||||
ij_c_spaces_within_method_return_type_parentheses = false
|
||||
ij_c_spaces_within_parentheses = false
|
||||
ij_c_spaces_within_property_attributes_parentheses = false
|
||||
ij_c_spaces_within_protocols_brackets = false
|
||||
ij_c_spaces_within_send_message_brackets = false
|
||||
ij_c_spaces_within_switch_parentheses = false
|
||||
ij_c_spaces_within_template_call_ltgt = false
|
||||
ij_c_spaces_within_template_declaration_ltgt = false
|
||||
ij_c_spaces_within_template_double_gt = true
|
||||
ij_c_spaces_within_while_parentheses = false
|
||||
ij_c_special_else_if_treatment = true
|
||||
ij_c_superclass_list_after_colon = never
|
||||
ij_c_superclass_list_align_multiline = true
|
||||
ij_c_superclass_list_before_colon = if_long
|
||||
ij_c_superclass_list_comma_on_next_line = false
|
||||
ij_c_superclass_list_wrap = on_every_item
|
||||
ij_c_tag_prefix_of_block_comment = at
|
||||
ij_c_tag_prefix_of_line_comment = back_slash
|
||||
ij_c_template_call_arguments_align_multiline = false
|
||||
ij_c_template_call_arguments_align_multiline_pars = false
|
||||
ij_c_template_call_arguments_comma_on_next_line = false
|
||||
ij_c_template_call_arguments_new_line_after_lt = false
|
||||
ij_c_template_call_arguments_new_line_before_gt = false
|
||||
ij_c_template_call_arguments_wrap = off
|
||||
ij_c_template_declaration_function_body_indent = false
|
||||
ij_c_template_declaration_function_wrap = split_into_lines
|
||||
ij_c_template_declaration_struct_body_indent = false
|
||||
ij_c_template_declaration_struct_wrap = split_into_lines
|
||||
ij_c_template_parameters_align_multiline = false
|
||||
ij_c_template_parameters_align_multiline_pars = false
|
||||
ij_c_template_parameters_comma_on_next_line = false
|
||||
ij_c_template_parameters_new_line_after_lt = false
|
||||
ij_c_template_parameters_new_line_before_gt = false
|
||||
ij_c_template_parameters_wrap = off
|
||||
ij_c_ternary_operation_signs_on_next_line = true
|
||||
ij_c_ternary_operation_wrap = normal
|
||||
ij_c_type_qualifiers_placement = before
|
||||
ij_c_use_modern_casts = true
|
||||
ij_c_use_setters_in_constructor = true
|
||||
ij_c_while_brace_force = never
|
||||
ij_c_while_on_new_line = false
|
||||
ij_c_wrap_property_declaration = off
|
||||
|
||||
[{*.cmake,CMakeLists.txt}]
|
||||
ij_cmake_align_multiline_parameters_in_calls = false
|
||||
ij_cmake_force_commands_case = 2
|
||||
ij_cmake_keep_blank_lines_in_code = 2
|
||||
ij_cmake_space_before_for_parentheses = true
|
||||
ij_cmake_space_before_if_parentheses = true
|
||||
ij_cmake_space_before_method_call_parentheses = false
|
||||
ij_cmake_space_before_method_parentheses = false
|
||||
ij_cmake_space_before_while_parentheses = true
|
||||
ij_cmake_spaces_within_for_parentheses = false
|
||||
ij_cmake_spaces_within_if_parentheses = false
|
||||
ij_cmake_spaces_within_method_call_parentheses = false
|
||||
ij_cmake_spaces_within_method_parentheses = false
|
||||
ij_cmake_spaces_within_while_parentheses = false
|
||||
|
||||
[{*.gant,*.gradle,*.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_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_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_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_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_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_long_lines = false
|
||||
|
||||
[{*.gradle.kts,*.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 = true
|
||||
ij_kotlin_allow_trailing_comma_on_call_site = false
|
||||
ij_kotlin_assignment_wrap = off
|
||||
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_at_first_column = true
|
||||
ij_kotlin_call_parameters_new_line_after_left_paren = false
|
||||
ij_kotlin_call_parameters_right_paren_on_new_line = false
|
||||
ij_kotlin_call_parameters_wrap = off
|
||||
ij_kotlin_catch_on_new_line = false
|
||||
ij_kotlin_class_annotation_wrap = off
|
||||
ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL
|
||||
ij_kotlin_continuation_indent_for_chained_calls = true
|
||||
ij_kotlin_continuation_indent_for_expression_bodies = true
|
||||
ij_kotlin_continuation_indent_in_argument_lists = true
|
||||
ij_kotlin_continuation_indent_in_elvis = true
|
||||
ij_kotlin_continuation_indent_in_if_conditions = true
|
||||
ij_kotlin_continuation_indent_in_parameter_lists = true
|
||||
ij_kotlin_continuation_indent_in_supertype_lists = true
|
||||
ij_kotlin_else_on_new_line = false
|
||||
ij_kotlin_enum_constants_wrap = off
|
||||
ij_kotlin_extends_list_wrap = off
|
||||
ij_kotlin_field_annotation_wrap = normal
|
||||
ij_kotlin_finally_on_new_line = false
|
||||
ij_kotlin_if_rparen_on_new_line = false
|
||||
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 = 0
|
||||
ij_kotlin_keep_blank_lines_in_code = 1
|
||||
ij_kotlin_keep_blank_lines_in_declarations = 1
|
||||
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_at_first_column = true
|
||||
ij_kotlin_method_annotation_wrap = split_into_lines
|
||||
ij_kotlin_method_call_chain_wrap = off
|
||||
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 = off
|
||||
ij_kotlin_name_count_to_use_star_import = 2147483647
|
||||
ij_kotlin_name_count_to_use_star_import_for_members = 2147483647
|
||||
ij_kotlin_packages_to_use_import_on_demand = kotlinx.android.synthetic.**
|
||||
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 = 0
|
||||
ij_kotlin_wrap_first_method_in_call_chain = false
|
||||
|
||||
[{*.har,*.json}]
|
||||
indent_size = 2
|
||||
ij_json_keep_blank_lines_in_code = 0
|
||||
ij_json_keep_indents_on_empty_lines = false
|
||||
ij_json_keep_line_breaks = true
|
||||
ij_json_space_after_colon = true
|
||||
ij_json_space_after_comma = true
|
||||
ij_json_space_before_colon = true
|
||||
ij_json_space_before_comma = false
|
||||
ij_json_spaces_within_braces = false
|
||||
ij_json_spaces_within_brackets = false
|
||||
ij_json_wrap_long_lines = false
|
||||
|
||||
[{*.htm,*.html,*.sht,*.shtm,*.shtml}]
|
||||
ij_html_add_new_line_before_tags = body, div, p, form, h1, h2, h3
|
||||
ij_html_align_attributes = true
|
||||
ij_html_align_text = false
|
||||
ij_html_attribute_wrap = normal
|
||||
ij_html_block_comment_at_first_column = true
|
||||
ij_html_do_not_align_children_of_min_lines = 0
|
||||
ij_html_do_not_break_if_inline_tags = title, h1, h2, h3, h4, h5, h6, p
|
||||
ij_html_do_not_indent_children_of_tags = html, body, thead, tbody, tfoot
|
||||
ij_html_enforce_quotes = false
|
||||
ij_html_inline_tags = a, abbr, acronym, b, basefont, bdo, big, br, cite, cite, code, dfn, em, font, i, img, input, kbd, label, q, s, samp, select, small, span, strike, strong, sub, sup, textarea, tt, u, var
|
||||
ij_html_keep_blank_lines = 2
|
||||
ij_html_keep_indents_on_empty_lines = false
|
||||
ij_html_keep_line_breaks = true
|
||||
ij_html_keep_line_breaks_in_text = true
|
||||
ij_html_keep_whitespaces = false
|
||||
ij_html_keep_whitespaces_inside = span, pre, textarea
|
||||
ij_html_line_comment_at_first_column = true
|
||||
ij_html_new_line_after_last_attribute = never
|
||||
ij_html_new_line_before_first_attribute = never
|
||||
ij_html_quote_style = double
|
||||
ij_html_remove_new_line_before_tags = br
|
||||
ij_html_space_after_tag_name = false
|
||||
ij_html_space_around_equality_in_attribute = false
|
||||
ij_html_space_inside_empty_tag = false
|
||||
ij_html_text_wrap = normal
|
||||
ij_html_uniform_ident = false
|
||||
|
||||
[{*.yaml,*.yml}]
|
||||
indent_size = 2
|
||||
ij_yaml_align_values_properties = do_not_align
|
||||
ij_yaml_autoinsert_sequence_marker = true
|
||||
ij_yaml_block_mapping_on_new_line = false
|
||||
ij_yaml_indent_sequence_value = true
|
||||
ij_yaml_keep_indents_on_empty_lines = false
|
||||
ij_yaml_keep_line_breaks = true
|
||||
ij_yaml_sequence_on_new_line = false
|
||||
ij_yaml_space_before_colon = false
|
||||
ij_yaml_spaces_within_braces = true
|
||||
ij_yaml_spaces_within_brackets = true
|
||||
1
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
**/snapshots/**/*.png filter=lfs diff=lfs merge=lfs -text
|
||||
86
.github/ISSUE_TEMPLATE/bug.yml
vendored
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
name: Bug report for the Element X Android app
|
||||
description: Report any issues that you have found with the Element X app. Please [check open issues](https://github.com/vector-im/element-x-android/issues) first, in case it has already been reported.
|
||||
labels: [T-Defect]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
|
||||
Please report security issues by email to security@matrix.org
|
||||
- type: textarea
|
||||
id: reproduction-steps
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: Please attach screenshots, videos or logs if you can.
|
||||
placeholder: Tell us what you see!
|
||||
value: |
|
||||
1. Where are you starting? What can you see?
|
||||
2. What do you click?
|
||||
3. More steps…
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: result
|
||||
attributes:
|
||||
label: Outcome
|
||||
placeholder: Tell us what went wrong
|
||||
value: |
|
||||
#### What did you expect?
|
||||
|
||||
#### What happened instead?
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: device
|
||||
attributes:
|
||||
label: Your phone model
|
||||
placeholder: e.g. Samsung S6
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: os
|
||||
attributes:
|
||||
label: Operating system version
|
||||
placeholder: e.g. Android 10.0
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Application version and app store
|
||||
description: You can find the version information in Settings -> Help & About.
|
||||
placeholder: e.g. Element X version 1.7.34, olm version 3.2.3 from F-Droid
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: homeserver
|
||||
attributes:
|
||||
label: Homeserver
|
||||
description: |
|
||||
Which server is your account registered on? If it is a local or non-public homeserver, please tell us what is the homeserver implementation (ex: Synapse/Dendrite/etc.) and the version.
|
||||
placeholder: e.g. matrix.org or Synapse 1.50.0rc1
|
||||
validations:
|
||||
required: false
|
||||
- type: dropdown
|
||||
id: rageshake
|
||||
attributes:
|
||||
label: Will you send logs?
|
||||
description: |
|
||||
Did you know that you can shake your phone to submit logs for this issue? Trigger the defect, then shake your phone and you will see a popup asking if you would like to open the bug report screen. Click YES, and describe the issue, mentioning that you have also filed a bug (it's helpful if you can include a link to the bug). Send the report to submit anonymous logs to the developers.
|
||||
options:
|
||||
- 'Yes'
|
||||
- 'No'
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: pr
|
||||
attributes:
|
||||
label: Are you willing to provide a PR?
|
||||
description: |
|
||||
Providing a PR can drastically speed up the process of fixing this bug. Don't worry, it's still OK to answer 'No' :).
|
||||
options:
|
||||
- 'Yes'
|
||||
- 'No'
|
||||
validations:
|
||||
required: true
|
||||
47
.github/ISSUE_TEMPLATE/enhancement.yml
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
name: Enhancement request
|
||||
description: Do you have a suggestion or feature request?
|
||||
labels: [T-Enhancement]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for taking the time to propose an enhancement to an existing feature. If you would like to propose a new feature or a major cross-platform change, please [start a discussion here](https://github.com/vector-im/element-meta/discussions/new?category=ideas).
|
||||
- type: textarea
|
||||
id: usecase
|
||||
attributes:
|
||||
label: Your use case
|
||||
description: Please feel welcome to include screenshots or mock ups.
|
||||
placeholder: Tell us what you would like to do!
|
||||
value: |
|
||||
#### What would you like to do?
|
||||
|
||||
#### Why would you like to do it?
|
||||
|
||||
#### How would you like to achieve it?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: alternative
|
||||
attributes:
|
||||
label: Have you considered any alternatives?
|
||||
placeholder: A clear and concise description of any alternative solutions or features you've considered.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: additional-context
|
||||
attributes:
|
||||
label: Additional context
|
||||
placeholder: Is there anything else you'd like to add?
|
||||
validations:
|
||||
required: false
|
||||
- type: dropdown
|
||||
id: pr
|
||||
attributes:
|
||||
label: Are you willing to provide a PR?
|
||||
description: |
|
||||
Don't worry, it's still OK to answer 'No' :).
|
||||
options:
|
||||
- 'Yes'
|
||||
- 'No'
|
||||
validations:
|
||||
required: true
|
||||
35
.github/ISSUE_TEMPLATE/story.yml
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
name: User story issue
|
||||
description: Second-level planning issue template. A story should take about a week or a sprint to finish.
|
||||
title: "[Story] <title>"
|
||||
labels: [T-Story]
|
||||
|
||||
body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Story
|
||||
description: A story should take roughly a week or a sprint to finish. Each story is usually made up of a number of tasks that take half to a full day.
|
||||
value: |
|
||||
As a user…
|
||||
I want to…
|
||||
so that I can…
|
||||
|
||||
## Scope
|
||||
<!--These should be a list of technical tasks which take ½-1 day to complete-->
|
||||
```[tasklist]
|
||||
### Tasklist
|
||||
- [ ] Task 1
|
||||
```
|
||||
|
||||
- [ ] QA signoff on completion
|
||||
- [ ] Design signoff on completion
|
||||
- [ ] Product signoff on completion
|
||||
|
||||
|
||||
## Stretch goals
|
||||
None at this time
|
||||
<!--or add a tasklist-->
|
||||
|
||||
## Out of scope
|
||||
-
|
||||
validations:
|
||||
required: false
|
||||
57
.github/PULL_REQUEST_TEMPLATE/pull_request_template.md
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
<!-- Please read [CONTRIBUTING.md](https://github.com/vector-im/element-android/blob/develop/CONTRIBUTING.md) before submitting your pull request -->
|
||||
|
||||
## Type of change
|
||||
|
||||
- [ ] Feature
|
||||
- [ ] Bugfix
|
||||
- [ ] Technical
|
||||
- [ ] Other :
|
||||
|
||||
## Content
|
||||
|
||||
<!-- Describe shortly what has been changed -->
|
||||
|
||||
## Motivation and context
|
||||
|
||||
<!-- Provide link to the corresponding issue if applicable or explain the context -->
|
||||
|
||||
## Screenshots / GIFs
|
||||
|
||||
<!-- Only if UI have been changed
|
||||
You can use a table like this to show screenshots comparison.
|
||||
Uncomment this markdown table below and edit the last line `|||`:
|
||||
|copy screenshot of before here|copy screenshot of after here|
|
||||
-->
|
||||
|
||||
<!--
|
||||
|Before|After|
|
||||
|-|-|
|
||||
|||
|
||||
-->
|
||||
|
||||
## Tests
|
||||
|
||||
<!-- Explain how you tested your development -->
|
||||
|
||||
- Step 1
|
||||
- Step 2
|
||||
- Step ...
|
||||
|
||||
## Tested devices
|
||||
|
||||
- [ ] Physical
|
||||
- [ ] Emulator
|
||||
- OS version(s):
|
||||
|
||||
## Checklist
|
||||
|
||||
<!-- Depending on the Pull Request content, it can be acceptable if some of the following checkboxes stay unchecked. -->
|
||||
|
||||
- [ ] Changes has been tested on an Android device or Android emulator with API 21
|
||||
- [ ] UI change has been tested on both light and dark themes
|
||||
- [ ] Accessibility has been taken into account. See https://github.com/vector-im/element-android/blob/develop/CONTRIBUTING.md#accessibility
|
||||
- [ ] Pull request is based on the develop branch
|
||||
- [ ] Pull request includes a new file under ./changelog.d. See https://github.com/vector-im/element-android/blob/develop/CONTRIBUTING.md#changelog
|
||||
- [ ] Pull request includes screenshots or videos if containing UI changes
|
||||
- [ ] Pull request includes a [sign off](https://matrix-org.github.io/synapse/latest/development/contributing_guide.html#sign-off)
|
||||
- [ ] You've made a self review of your PR
|
||||
26
.github/dependabot.yml
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
# Updates for Github Actions used in the repo
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
ignore:
|
||||
- dependency-name: "*"
|
||||
reviewers:
|
||||
- "vector-im/element-x-android-reviewers"
|
||||
# Updates for Gradle dependencies used in the app
|
||||
- package-ecosystem: "gradle"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
open-pull-requests-limit: 200
|
||||
ignore:
|
||||
- dependency-name: "*"
|
||||
reviewers:
|
||||
- "vector-im/element-x-android-reviewers"
|
||||
34
.github/renovate.json
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"$schema" : "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends" : [
|
||||
"config:base"
|
||||
],
|
||||
"labels" : [
|
||||
"dependencies"
|
||||
],
|
||||
"ignoreDeps" : [
|
||||
"string:app_name"
|
||||
],
|
||||
"packageRules" : [
|
||||
{
|
||||
"matchPackagePatterns" : [
|
||||
"^org.jetbrains.kotlin",
|
||||
"^com.google.devtools.ksp",
|
||||
"^androidx.compose.compiler"
|
||||
],
|
||||
"groupName" : "kotlin"
|
||||
},
|
||||
{
|
||||
"matchPackageNames" : [
|
||||
"org.jetbrains.kotlinx.kover"
|
||||
],
|
||||
"enabled" : false
|
||||
},
|
||||
{
|
||||
"matchPackagePatterns" : [
|
||||
"^org.maplibre"
|
||||
],
|
||||
"versioning" : "semver"
|
||||
}
|
||||
]
|
||||
}
|
||||
77
.github/workflows/build.yml
vendored
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
name: APK Build
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request: { }
|
||||
push:
|
||||
branches: [ main, develop ]
|
||||
|
||||
# Enrich gradle.properties for CI/CD
|
||||
env:
|
||||
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx3072m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -Dkotlin.daemon.jvm.options="-Xmx2560m" -Dkotlin.incremental=false
|
||||
CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 2 --no-daemon
|
||||
|
||||
jobs:
|
||||
debug:
|
||||
name: Build debug APKs
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref != 'refs/heads/main'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
# Allow all jobs on develop. Just one per PR.
|
||||
concurrency:
|
||||
group: ${{ github.ref == 'refs/heads/develop' && format('build-develop-{0}', github.sha) || format('build-debug-{0}', github.ref) }}
|
||||
cancel-in-progress: true
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
# Ensure we are building the branch and not the branch after being merged on develop
|
||||
# https://github.com/actions/checkout/issues/881
|
||||
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
||||
- name: Use JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||
java-version: '17'
|
||||
- name: Configure gradle
|
||||
uses: gradle/gradle-build-action@v2.6.1
|
||||
with:
|
||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||
- name: Assemble debug APK
|
||||
env:
|
||||
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
|
||||
run: ./gradlew assembleDebug $CI_GRADLE_ARG_PROPERTIES
|
||||
- name: Upload debug APKs
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: elementx-debug
|
||||
path: |
|
||||
app/build/outputs/apk/debug/*.apk
|
||||
- uses: rnkdsh/action-upload-diawi@v1.5.1
|
||||
id: diawi
|
||||
# Do not fail the whole build if Diawi upload fails
|
||||
continue-on-error: true
|
||||
env:
|
||||
token: ${{ secrets.DIAWI_TOKEN }}
|
||||
if: ${{ github.event_name == 'pull_request' && env.token != '' }}
|
||||
with:
|
||||
token: ${{ env.token }}
|
||||
file: app/build/outputs/apk/debug/app-arm64-v8a-debug.apk
|
||||
- name: Add or update PR comment with QR Code to download APK.
|
||||
if: ${{ github.event_name == 'pull_request' && steps.diawi.conclusion == 'success' }}
|
||||
uses: NejcZdovc/comment-pr@v2
|
||||
with:
|
||||
message: |
|
||||
:iphone: Scan the QR code below to install the build (arm64 only) for this PR.
|
||||

|
||||
If you can't scan the QR code you can install the build via this link: ${{ steps.diawi.outputs['url'] }}
|
||||
# Enables to identify and update existing Ad-hoc release message on new commit in the PR
|
||||
identifier: "GITHUB_COMMENT_QR_CODE"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Compile release sources
|
||||
run: ./gradlew compileReleaseSources $CI_GRADLE_ARG_PROPERTIES
|
||||
- name: Compile nightly sources
|
||||
run: ./gradlew compileNightlySources $CI_GRADLE_ARG_PROPERTIES
|
||||
- name: Compile samples minimal
|
||||
run: ./gradlew :samples:minimal:assemble $CI_GRADLE_ARG_PROPERTIES
|
||||
20
.github/workflows/danger.yml
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
name: Danger CI
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
name: Danger main check
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- run: |
|
||||
npm install --save-dev @babel/plugin-transform-flow-strip-types
|
||||
- name: Danger
|
||||
uses: danger/danger-js@11.2.6
|
||||
with:
|
||||
args: "--dangerfile ./tools/danger/dangerfile.js"
|
||||
env:
|
||||
DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
|
||||
# Fallback for forks
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
18
.github/workflows/gradle-wrapper-update.yml
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
name: Update Gradle Wrapper
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
jobs:
|
||||
update-gradle-wrapper:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Update Gradle Wrapper
|
||||
uses: gradle-update/update-gradle-wrapper-action@v1
|
||||
# Skip in forks
|
||||
if: github.repository == 'vector-im/element-x-android'
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
target-branch: develop
|
||||
14
.github/workflows/gradle-wrapper-validation.yml
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
name: "Validate Gradle Wrapper"
|
||||
on:
|
||||
pull_request: { }
|
||||
push:
|
||||
branches: [ main, develop ]
|
||||
|
||||
jobs:
|
||||
validation:
|
||||
name: "Validation"
|
||||
runs-on: ubuntu-latest
|
||||
# No concurrency required, this is a prerequisite to other actions and should run every time.
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: gradle/wrapper-validation-action@v1
|
||||
57
.github/workflows/maestro.yml
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
name: Maestro
|
||||
|
||||
# Run this flow only on pull request, and only when the pull request has been approved, to limit our usage of maestro cloud.
|
||||
# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#running-a-workflow-when-a-pull-request-is-approved
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request_review:
|
||||
types: [submitted]
|
||||
|
||||
# Enrich gradle.properties for CI/CD
|
||||
env:
|
||||
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx3072m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -Dkotlin.daemon.jvm.options="-Xmx2560m" -Dkotlin.incremental=false
|
||||
CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 2 --no-daemon
|
||||
|
||||
jobs:
|
||||
maestro-cloud:
|
||||
name: Maestro test suite
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.review.state == 'approved' || github.event_name == 'workflow_dispatch'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
# Allow one per PR.
|
||||
concurrency:
|
||||
group: ${{ format('maestro-{0}', github.ref) }}
|
||||
cancel-in-progress: true
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
# Ensure we are building the branch and not the branch after being merged on develop
|
||||
# https://github.com/actions/checkout/issues/881
|
||||
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
||||
- uses: actions/setup-java@v3
|
||||
name: Use JDK 17
|
||||
with:
|
||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||
java-version: '17'
|
||||
- name: Assemble debug APK
|
||||
run: ./gradlew assembleDebug $CI_GRADLE_ARG_PROPERTIES
|
||||
env:
|
||||
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
|
||||
- name: Upload debug APKs
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: elementx-debug
|
||||
path: |
|
||||
app/build/outputs/apk/debug/*.apk
|
||||
- uses: mobile-dev-inc/action-maestro-cloud@v1.4.1
|
||||
with:
|
||||
api-key: ${{ secrets.MAESTRO_CLOUD_API_KEY }}
|
||||
app-file: app/build/outputs/apk/debug/app-universal-debug.apk
|
||||
env: |
|
||||
USERNAME=maestroelement
|
||||
PASSWORD=${{ secrets.MATRIX_MAESTRO_ACCOUNT_PASSWORD }}
|
||||
ROOM_NAME=MyRoom
|
||||
INVITEE1_MXID=@maestroelement2:matrix.org
|
||||
INVITEE2_MXID=@maestroelement3:matrix.org
|
||||
APP_ID=io.element.android.x.debug
|
||||
48
.github/workflows/nightly.yml
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
name: Build and release nightly APK
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
# Every nights at 4
|
||||
- cron: "0 4 * * *"
|
||||
|
||||
env:
|
||||
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx3072m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -Dkotlin.daemon.jvm.options="-Xmx2560m" -Dkotlin.incremental=false
|
||||
CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 2 --no-daemon
|
||||
|
||||
jobs:
|
||||
nightly:
|
||||
name: Build and publish nightly APK to Firebase
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.repository == 'vector-im/element-x-android' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Use JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||
java-version: '17'
|
||||
- name: Install towncrier
|
||||
run: |
|
||||
python3 -m pip install towncrier
|
||||
- name: Prepare changelog file
|
||||
run: |
|
||||
mv towncrier.toml towncrier.toml.bak
|
||||
sed 's/CHANGES\.md/CHANGES_NIGHTLY\.md/' towncrier.toml.bak > towncrier.toml
|
||||
rm towncrier.toml.bak
|
||||
yes n | towncrier build --version nightly
|
||||
- name: Build and upload Nightly APK
|
||||
run: |
|
||||
./gradlew assembleNightly appDistributionUploadNightly $CI_GRADLE_ARG_PROPERTIES
|
||||
env:
|
||||
ELEMENT_ANDROID_MAPTILER_API_KEY: ${{ secrets.MAPTILER_KEY }}
|
||||
ELEMENT_ANDROID_NIGHTLY_KEYID: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_KEYID }}
|
||||
ELEMENT_ANDROID_NIGHTLY_KEYPASSWORD: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_KEYPASSWORD }}
|
||||
ELEMENT_ANDROID_NIGHTLY_STOREPASSWORD: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_STOREPASSWORD }}
|
||||
FIREBASE_TOKEN: ${{ secrets.ELEMENT_ANDROID_NIGHTLY_FIREBASE_TOKEN }}
|
||||
- name: Additionally upload Nightly APK to browserstack for testing
|
||||
continue-on-error: true # don't block anything by this upload failing (for now)
|
||||
run: curl -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_PASSWORD" -X POST "https://api-cloud.browserstack.com/app-automate/upload" -F "file=@app/build/outputs/apk/nightly/app-universal-nightly.apk" -F "custom_id=element-x-android-nightly"
|
||||
env:
|
||||
BROWSERSTACK_USERNAME: ${{ secrets.ELEMENT_ANDROID_BROWSERSTACK_USERNAME }}
|
||||
BROWSERSTACK_PASSWORD: ${{ secrets.ELEMENT_ANDROID_BROWSERSTACK_ACCESS_KEY }}
|
||||
75
.github/workflows/nightlyReports.yml
vendored
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
name: Nightly reports
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
# Every nights at 5
|
||||
- cron: "0 5 * * *"
|
||||
|
||||
# Enrich gradle.properties for CI/CD
|
||||
env:
|
||||
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx3072m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -Dkotlin.daemon.jvm.options="-Xmx2560m" -Dkotlin.incremental=false
|
||||
CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 4
|
||||
|
||||
jobs:
|
||||
nightlyReports:
|
||||
name: Create kover report artifact and upload sonar result.
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.repository == 'vector-im/element-x-android' }}
|
||||
steps:
|
||||
- name: ⏬ Checkout with LFS
|
||||
uses: nschloe/action-cached-lfs-checkout@v1.2.1
|
||||
|
||||
- name: Use JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||
java-version: '17'
|
||||
|
||||
- name: ⚙️ Run unit tests, debug and release
|
||||
run: ./gradlew test $CI_GRADLE_ARG_PROPERTIES
|
||||
|
||||
- name: 📸 Run screenshot tests
|
||||
run: ./gradlew verifyPaparazziDebug $CI_GRADLE_ARG_PROPERTIES
|
||||
|
||||
- name: 📈 Generate kover report and verify coverage
|
||||
run: ./gradlew koverMergedReport koverMergedVerify $CI_GRADLE_ARG_PROPERTIES -Pci-build=true
|
||||
|
||||
- name: ✅ Upload kover report
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: kover-results
|
||||
path: |
|
||||
**/build/reports/kover/merged
|
||||
|
||||
- name: 🔊 Publish results to Sonar
|
||||
env:
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
ORG_GRADLE_PROJECT_SONAR_LOGIN: ${{ secrets.SONAR_TOKEN }}
|
||||
if: ${{ always() && env.SONAR_TOKEN != '' && env.ORG_GRADLE_PROJECT_SONAR_LOGIN != '' }}
|
||||
run: ./gradlew sonar $CI_GRADLE_ARG_PROPERTIES
|
||||
|
||||
# Gradle dependency analysis using https://github.com/autonomousapps/dependency-analysis-android-gradle-plugin
|
||||
dependency-analysis:
|
||||
name: Dependency analysis
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Use JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||
java-version: '17'
|
||||
- name: Configure gradle
|
||||
uses: gradle/gradle-build-action@v2.6.1
|
||||
with:
|
||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||
- name: Dependency analysis
|
||||
run: ./gradlew dependencyCheckAnalyze $CI_GRADLE_ARG_PROPERTIES
|
||||
- name: Upload dependency analysis
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: dependency-analysis
|
||||
path: build/reports/dependency-check-report.html
|
||||
74
.github/workflows/quality.yml
vendored
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
name: Code Quality Checks
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request: { }
|
||||
push:
|
||||
branches: [ main, develop ]
|
||||
|
||||
# Enrich gradle.properties for CI/CD
|
||||
env:
|
||||
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx3072m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -XX:MaxMetaspaceSize=512m -Dkotlin.daemon.jvm.options="-Xmx2g" -Dkotlin.incremental=false
|
||||
CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 2 --no-daemon --warn
|
||||
|
||||
jobs:
|
||||
checkScript:
|
||||
name: Search for forbidden patterns
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Run code quality check suite
|
||||
run: ./tools/check/check_code_quality.sh
|
||||
|
||||
check:
|
||||
name: Project Check Suite
|
||||
runs-on: ubuntu-latest
|
||||
# Allow all jobs on main and develop. Just one per PR.
|
||||
concurrency:
|
||||
group: ${{ github.ref == 'refs/heads/main' && format('check-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('check-develop-{0}', github.sha) || format('check-{0}', github.ref) }}
|
||||
cancel-in-progress: true
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
# Ensure we are building the branch and not the branch after being merged on develop
|
||||
# https://github.com/actions/checkout/issues/881
|
||||
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
||||
- name: Use JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||
java-version: '17'
|
||||
- name: Configure gradle
|
||||
uses: gradle/gradle-build-action@v2.6.1
|
||||
with:
|
||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||
- name: Run code quality check suite
|
||||
run: ./gradlew runQualityChecks $CI_GRADLE_ARG_PROPERTIES
|
||||
- name: Upload reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: linting-report
|
||||
path: |
|
||||
*/build/reports/**/*.*
|
||||
- name: 🔊 Publish results to Sonar
|
||||
env:
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
ORG_GRADLE_PROJECT_SONAR_LOGIN: ${{ secrets.SONAR_TOKEN }}
|
||||
if: ${{ always() && env.SONAR_TOKEN != '' && env.ORG_GRADLE_PROJECT_SONAR_LOGIN != '' }}
|
||||
run: ./gradlew sonar $CI_GRADLE_ARG_PROPERTIES
|
||||
- name: Prepare Danger
|
||||
if: always()
|
||||
run: |
|
||||
npm install --save-dev @babel/core
|
||||
npm install --save-dev @babel/plugin-transform-flow-strip-types
|
||||
yarn add danger-plugin-lint-report --dev
|
||||
- name: Danger lint
|
||||
if: always()
|
||||
uses: danger/danger-js@11.2.6
|
||||
with:
|
||||
args: "--dangerfile ./tools/danger/dangerfile-lint.js"
|
||||
env:
|
||||
DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
|
||||
# Fallback for forks
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
35
.github/workflows/recordScreenshots.yml
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
name: Record screenshots
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
# Enrich gradle.properties for CI/CD
|
||||
env:
|
||||
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx3072m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -Dkotlin.daemon.jvm.options="-Xmx2560m" -Dkotlin.incremental=false
|
||||
|
||||
jobs:
|
||||
record:
|
||||
name: Record screenshots on branch ${{ github.ref_name }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: ⏬ Checkout with LFS
|
||||
uses: nschloe/action-cached-lfs-checkout@v1.2.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: ☕️ Use JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||
java-version: '17'
|
||||
# Add gradle cache, this should speed up the process
|
||||
- name: Configure gradle
|
||||
uses: gradle/gradle-build-action@v2.6.1
|
||||
with:
|
||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||
- name: Record screenshots
|
||||
run: "./.github/workflows/scripts/recordScreenshots.sh"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
|
||||
GITHUB_REPOSITORY: ${{ secrets.GITHUB_REPOSITORY }}
|
||||
|
||||
77
.github/workflows/scripts/recordScreenshots.sh
vendored
Executable file
|
|
@ -0,0 +1,77 @@
|
|||
#!/bin/bash
|
||||
|
||||
#
|
||||
# Copyright (c) 2023 New Vector Ltd
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
TOKEN=$GITHUB_TOKEN
|
||||
REPO=$GITHUB_REPOSITORY
|
||||
|
||||
SHORT=t:,r:
|
||||
LONG=token:,repo:
|
||||
OPTS=$(getopt -a -n recordScreenshots --options $SHORT --longoptions $LONG -- "$@")
|
||||
|
||||
eval set -- "$OPTS"
|
||||
while :
|
||||
do
|
||||
case "$1" in
|
||||
-t | --token )
|
||||
TOKEN="$2"
|
||||
shift 2
|
||||
;;
|
||||
-r | --repo )
|
||||
REPO="$2"
|
||||
shift 2
|
||||
;;
|
||||
--)
|
||||
shift;
|
||||
break
|
||||
;;
|
||||
*)
|
||||
echo "Unexpected option: $1"
|
||||
help
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z ${TOKEN} ]]; then
|
||||
echo "No token specified, either set the env var GITHUB_TOKEN or use the --token option"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z ${REPO} ]]; then
|
||||
echo "No repo specified, either set the env var GITHUB_REPOSITORY or use the --repo option"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Deleting previous screenshots"
|
||||
./gradlew removeOldSnapshots --stacktrace -PpreDexEnable=false --max-workers 4 --warn
|
||||
|
||||
echo "Record screenshots"
|
||||
./gradlew recordPaparazziDebug --stacktrace -PpreDexEnable=false --max-workers 4 --warn
|
||||
|
||||
echo "Committing changes"
|
||||
git config user.name "ElementBot"
|
||||
git config user.email "benoitm+elementbot@element.io"
|
||||
git add -A
|
||||
git commit -m "Update screenshots"
|
||||
|
||||
BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||||
|
||||
echo "Pushing changes"
|
||||
git push "https://$TOKEN@github.com/$REPO.git" $BRANCH:refs/heads/$BRANCH
|
||||
echo "Done!"
|
||||
35
.github/workflows/sync-localazy.yml
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
name: Sync Localazy
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
# At 00:00 on every Monday UTC
|
||||
- cron: '0 0 * * 1'
|
||||
|
||||
jobs:
|
||||
sync-localazy:
|
||||
runs-on: ubuntu-latest
|
||||
# Skip in forks
|
||||
if: github.repository == 'vector-im/element-x-android'
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python 3.9
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.9
|
||||
- name: Setup Localazy
|
||||
run: |
|
||||
curl -sS https://dist.localazy.com/debian/pubkey.gpg | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/localazy.gpg
|
||||
echo "deb [arch=amd64 signed-by=/etc/apt/trusted.gpg.d/localazy.gpg] https://maven.localazy.com/repository/apt/ stable main" | sudo tee /etc/apt/sources.list.d/localazy.list
|
||||
sudo apt-get update && sudo apt-get install localazy
|
||||
- name: Run Localazy script
|
||||
run: ./tools/localazy/downloadStrings.sh --all
|
||||
- name: Create Pull Request for Strings
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
token: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
|
||||
commit-message: Sync Strings from Localazy
|
||||
title: Sync Strings
|
||||
body: |
|
||||
- Update Strings from Localazy
|
||||
branch: sync-localazy
|
||||
base: develop
|
||||
91
.github/workflows/tests.yml
vendored
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
name: Test
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request: { }
|
||||
push:
|
||||
branches: [ main, develop ]
|
||||
|
||||
# Enrich gradle.properties for CI/CD
|
||||
env:
|
||||
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx3072m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -Dkotlin.daemon.jvm.options="-Xmx2560m" -Dkotlin.incremental=false
|
||||
CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 4 --warn
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
name: Runs unit tests
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# Allow all jobs on main and develop. Just one per PR.
|
||||
concurrency:
|
||||
group: ${{ github.ref == 'refs/heads/main' && format('unit-tests-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('unit-tests-develop-{0}', github.sha) || format('unit-tests-{0}', github.ref) }}
|
||||
cancel-in-progress: true
|
||||
steps:
|
||||
- name: ⏬ Checkout with LFS
|
||||
uses: nschloe/action-cached-lfs-checkout@v1.2.1
|
||||
with:
|
||||
# Ensure we are building the branch and not the branch after being merged on develop
|
||||
# https://github.com/actions/checkout/issues/881
|
||||
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
||||
- name: ☕️ Use JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||
java-version: '17'
|
||||
- name: Configure gradle
|
||||
uses: gradle/gradle-build-action@v2.6.1
|
||||
with:
|
||||
cache-read-only: ${{ github.ref != 'refs/heads/develop' }}
|
||||
|
||||
- name: ⚙️ Run unit tests, debug and release
|
||||
run: ./gradlew test $CI_GRADLE_ARG_PROPERTIES
|
||||
|
||||
- name: 📸 Run screenshot tests
|
||||
run: ./gradlew verifyPaparazziDebug $CI_GRADLE_ARG_PROPERTIES
|
||||
|
||||
- name: 📈Generate kover report and verify coverage
|
||||
run: ./gradlew koverMergedReport koverMergedVerify $CI_GRADLE_ARG_PROPERTIES -Pci-build=true
|
||||
|
||||
- name: 🚫 Upload kover failed coverage reports
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: kover-error-report
|
||||
path: |
|
||||
**/kover/merged/verification/errors.txt
|
||||
|
||||
- name: 📸 Upload Screenshot test report
|
||||
uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: reports
|
||||
path: tests/uitests/build/reports/tests/testDebugUnitTest/
|
||||
retention-days: 5
|
||||
|
||||
- name: 🚫 Upload Screenshot failure differences on error
|
||||
uses: actions/upload-artifact@v3
|
||||
if: failure()
|
||||
with:
|
||||
name: failures
|
||||
path: tests/uitests/out/failures/
|
||||
retention-days: 5
|
||||
|
||||
- name: ✅ Upload kover report (disabled)
|
||||
if: always()
|
||||
run: echo "This is now done only once a day, see nightlyReports.yml"
|
||||
|
||||
- name: 🚫 Upload test results on error
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: tests-and-screenshot-tests-results
|
||||
path: |
|
||||
**/out/failures/
|
||||
**/build/reports/tests/*UnitTest/
|
||||
|
||||
# https://github.com/codecov/codecov-action
|
||||
- name: ☂️ Upload coverage reports to codecov
|
||||
if: always()
|
||||
uses: codecov/codecov-action@v3
|
||||
# with:
|
||||
# files: build/reports/kover/merged/xml/report.xml
|
||||
14
.github/workflows/triage-incoming.yml
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
name: Move new issues onto issue triage board v2
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [ opened ]
|
||||
|
||||
jobs:
|
||||
triage-new-issues:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/add-to-project@main
|
||||
with:
|
||||
project-url: https://github.com/orgs/vector-im/projects/91
|
||||
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
83
.github/workflows/triage-labelled.yml
vendored
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
name: Move labelled issues to correct boards and columns
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [labeled]
|
||||
|
||||
jobs:
|
||||
move_element_x_issues:
|
||||
name: ElementX issues to ElementX project board
|
||||
runs-on: ubuntu-latest
|
||||
# Skip in forks
|
||||
if: >
|
||||
github.repository == 'vector-im/element-x-android'
|
||||
steps:
|
||||
- uses: actions/add-to-project@main
|
||||
with:
|
||||
project-url: https://github.com/orgs/vector-im/projects/43
|
||||
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
|
||||
move_needs_info:
|
||||
name: Move triaged needs info issues on board
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/add-to-project@main
|
||||
id: addItem
|
||||
with:
|
||||
project-url: https://github.com/orgs/vector-im/projects/91
|
||||
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
labeled: X-Needs-Info
|
||||
- name: Print itemId
|
||||
run: echo ${{ steps.addItem.outputs.itemId }}
|
||||
- uses: kalgurn/update-project-item-status@main
|
||||
if: ${{ steps.addItem.outputs.itemId }}
|
||||
with:
|
||||
project-url: https://github.com/orgs/vector-im/projects/91
|
||||
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
item-id: ${{ steps.addItem.outputs.itemId }}
|
||||
status: "Needs info"
|
||||
|
||||
ex_plorers:
|
||||
name: Add labelled issues to X-Plorer project
|
||||
runs-on: ubuntu-latest
|
||||
if: >
|
||||
contains(github.event.issue.labels.*.name, 'Team: Element X Feature')
|
||||
steps:
|
||||
- uses: actions/add-to-project@main
|
||||
with:
|
||||
project-url: https://github.com/orgs/vector-im/projects/73
|
||||
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
|
||||
verticals_feature:
|
||||
name: Add labelled issues to Verticals Feature project
|
||||
runs-on: ubuntu-latest
|
||||
if: >
|
||||
contains(github.event.issue.labels.*.name, 'Team: Verticals Feature')
|
||||
steps:
|
||||
- uses: actions/add-to-project@main
|
||||
with:
|
||||
project-url: https://github.com/orgs/vector-im/projects/57
|
||||
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
|
||||
qa:
|
||||
name: Add labelled issues to QA project
|
||||
runs-on: ubuntu-latest
|
||||
if: >
|
||||
contains(github.event.issue.labels.*.name, 'Team: QA') ||
|
||||
contains(github.event.issue.labels.*.name, 'X-Needs-Signoff')
|
||||
steps:
|
||||
- uses: actions/add-to-project@main
|
||||
with:
|
||||
project-url: https://github.com/orgs/vector-im/projects/69
|
||||
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
|
||||
signoff:
|
||||
name: Add labelled issues to signoff project
|
||||
runs-on: ubuntu-latest
|
||||
if: >
|
||||
contains(github.event.issue.labels.*.name, 'X-Needs-Signoff')
|
||||
steps:
|
||||
- uses: actions/add-to-project@main
|
||||
with:
|
||||
project-url: https://github.com/orgs/vector-im/projects/89
|
||||
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
13
.github/workflows/validate-lfs.yml
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
name: Validate Git LFS
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
name: Validate
|
||||
steps:
|
||||
- uses: nschloe/action-cached-lfs-checkout@v1.2.1
|
||||
|
||||
- run: |
|
||||
./tools/git/validate_lfs.sh
|
||||
26
.gitignore
vendored
|
|
@ -1,6 +1,5 @@
|
|||
# Built application files
|
||||
*.apk
|
||||
*.aar
|
||||
*.ap_
|
||||
*.aab
|
||||
|
||||
|
|
@ -38,17 +37,25 @@ captures/
|
|||
|
||||
# IntelliJ
|
||||
*.iml
|
||||
.idea/workspace.xml
|
||||
.idea/tasks.xml
|
||||
.idea/gradle.xml
|
||||
.idea/.name
|
||||
.idea/assetWizardSettings.xml
|
||||
.idea/dictionaries
|
||||
.idea/libraries
|
||||
# Android Studio 3 in .gitignore file.
|
||||
.idea/caches
|
||||
.idea/compiler.xml
|
||||
.idea/deploymentTargetDropDown.xml
|
||||
.idea/gradle.xml
|
||||
.idea/jarRepositories.xml
|
||||
.idea/misc.xml
|
||||
.idea/modules.xml
|
||||
# Comment next line if keeping position of elements in Navigation Editor is relevant for you
|
||||
.idea/navEditor.xml
|
||||
.idea/tasks.xml
|
||||
.idea/workspace.xml
|
||||
.idea/libraries
|
||||
# Android Studio 3 in .gitignore file.
|
||||
.idea/caches
|
||||
.idea/inspectionProfiles
|
||||
# Shelved changes in the IDE
|
||||
.idea/shelf
|
||||
.idea/sonarlint
|
||||
|
||||
# Keystore files
|
||||
# Uncomment the following lines if you do not want to check your keystore files in.
|
||||
|
|
@ -83,3 +90,6 @@ lint/generated/
|
|||
lint/outputs/
|
||||
lint/tmp/
|
||||
# lint/reports/
|
||||
|
||||
/tmp
|
||||
.DS_Store
|
||||
|
|
|
|||
124
.idea/codeStyles/Project.xml
generated
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<JetCodeStyleSettings>
|
||||
<option name="LINE_BREAK_AFTER_MULTILINE_WHEN_ENTRY" value="false" />
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</JetCodeStyleSettings>
|
||||
<codeStyleSettings language="XML">
|
||||
<option name="FORCE_REARRANGE_MODE" value="1" />
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
<arrangement>
|
||||
<rules>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:android</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:id</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>style</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
</rules>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="kotlin">
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
||||
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
||||
6
.idea/copyright/NewVector.xml
generated
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<component name="CopyrightManager">
|
||||
<copyright>
|
||||
<option name="notice" value="Copyright (c) &#36;today.year New Vector Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License." />
|
||||
<option name="myName" value="NewVector" />
|
||||
</copyright>
|
||||
</component>
|
||||
3
.idea/copyright/profiles_settings.xml
generated
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<component name="CopyrightManager">
|
||||
<settings default="NewVector" />
|
||||
</component>
|
||||
17
.idea/dictionaries/shared.xml
generated
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="shared">
|
||||
<words>
|
||||
<w>backstack</w>
|
||||
<w>ftue</w>
|
||||
<w>homeserver</w>
|
||||
<w>kover</w>
|
||||
<w>measurables</w>
|
||||
<w>onboarding</w>
|
||||
<w>placeables</w>
|
||||
<w>showkase</w>
|
||||
<w>snackbar</w>
|
||||
<w>swipeable</w>
|
||||
<w>textfields</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
</component>
|
||||
BIN
.idea/icon.png
generated
Normal file
|
After Width: | Height: | Size: 14 KiB |
6
.idea/kotlinc.xml
generated
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="KotlinJpsPluginSettings">
|
||||
<option name="version" value="1.8.22" />
|
||||
</component>
|
||||
</project>
|
||||
73
.maestro/README.md
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
# Maestro
|
||||
|
||||
Maestro is a framework that we are using to test navigation across the application.
|
||||
To setup, please refer at [https://maestro.mobile.dev](https://maestro.mobile.dev)
|
||||
|
||||
<!--- TOC -->
|
||||
|
||||
* [Run test](#run-test)
|
||||
* [Output](#output)
|
||||
* [Write test](#write-test)
|
||||
* [CI](#ci)
|
||||
* [iOS](#ios)
|
||||
* [Future](#future)
|
||||
|
||||
<!--- END -->
|
||||
|
||||
## Run test
|
||||
|
||||
From root dir of the project
|
||||
|
||||
*Note: Since ElementX does not allow account creation nor room creation, we have to use an existing account with an existing room to run maestro test suite. So to run locally, please replace `user` and `123` with your test matrix.org account credentials, and `my room` with one of a room this account has join. Note that the test will send messages to this room.*
|
||||
|
||||
```shell
|
||||
maestro test \
|
||||
-e APP_ID=io.element.android.x.debug \
|
||||
-e USERNAME=user1 \
|
||||
-e PASSWORD=123 \
|
||||
-e ROOM_NAME="MyRoom" \
|
||||
-e INVITEE1_MXID=user2 \
|
||||
-e INVITEE2_MXID=user3 \
|
||||
.maestro/allTests.yaml
|
||||
```
|
||||
|
||||
### Output
|
||||
|
||||
Test result will be printed on the console, and screenshots will be generated at `./build/maestro`
|
||||
|
||||
## Write test
|
||||
|
||||
Tests are yaml files. Generally each yaml file should leave the app in the same screen than at the beginning.
|
||||
|
||||
Start the ElementX app and run this command to help writing test.
|
||||
|
||||
```shell
|
||||
maestro studio
|
||||
```
|
||||
|
||||
Note that sometimes, this prevent running the test. So kill the `maestro studio` process to be able to run the test again.
|
||||
|
||||
Also, if updating the application code, do not forget to deploy again the application before running the maestro tests.
|
||||
|
||||
## CI
|
||||
|
||||
The CI is running maestro using the workflow `.github/worflow/maestro.yaml` and [maestro cloud](https://cloud.mobile.dev/). For now we are limited to 100 runs a month.
|
||||
Some GitHub secrets are used to be able to do that: `MAESTRO_CLOUD_API_KEY`, for now api key from `benoitm@element.io` maestro cloud account, and `MATRIX_MAESTRO_ACCOUNT_PASSWORD` which is the password of the account `@maestroelement:matrix.org`. This account contains a room `MyRoom` to be able to run the maestro test suite.
|
||||
|
||||
## iOS
|
||||
|
||||
Need to install `idb-companion` first
|
||||
|
||||
```shell
|
||||
brew install idb-companion
|
||||
```
|
||||
|
||||
Also:
|
||||
https://github.com/mobile-dev-inc/maestro/issues/146
|
||||
https://github.com/mobile-dev-inc/maestro/issues/107
|
||||
So you have to change your input keyboard to QWERTY for it to work properly.
|
||||
|
||||
## Future
|
||||
|
||||
- run on Element X iOS. This is already working but it need some change on the test to make it works. Could pass a PLATFORM parameter to have unique test and use conditional test.
|
||||
- run specific test on both iOS and Android devices to make them communicate together. Could be possible to test room invite and join, verification, call, etc. To be done when Element X will be able to create account and create room. A main script would be able to detect the Android device and the iOS device, and run several maestro tests sequentially, using `--device` parameter to perform a global test.
|
||||
7
.maestro/allTests.yaml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
- runFlow: tests/init.yaml
|
||||
- runFlow: tests/account/login.yaml
|
||||
- runFlow: tests/settings/settings.yaml
|
||||
- runFlow: tests/roomList/roomList.yaml
|
||||
- runFlow: tests/account/logout.yaml
|
||||
17
.maestro/tests/account/changeServer.yaml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
- tapOn:
|
||||
id: "login-change_server"
|
||||
- takeScreenshot: build/maestro/200-ChangeServer
|
||||
- tapOn: "matrix.org"
|
||||
- tapOn:
|
||||
id: "login-change_server"
|
||||
- tapOn: "Other"
|
||||
- tapOn:
|
||||
id: "change_server-server"
|
||||
- inputText: "element"
|
||||
- hideKeyboard
|
||||
- tapOn: "element.io"
|
||||
- tapOn: "Cancel"
|
||||
- back
|
||||
- back
|
||||
30
.maestro/tests/account/login.yaml
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
- tapOn: "Continue"
|
||||
- runFlow: ../assertions/assertLoginDisplayed.yaml
|
||||
- takeScreenshot: build/maestro/100-SignIn
|
||||
- runFlow: changeServer.yaml
|
||||
- runFlow: ../assertions/assertLoginDisplayed.yaml
|
||||
- tapOn:
|
||||
id: "login-continue"
|
||||
- tapOn:
|
||||
id: "login-email_username"
|
||||
- inputText: ${USERNAME}
|
||||
- pressKey: Enter
|
||||
- tapOn:
|
||||
id: "login-password"
|
||||
- inputText: "wrong-password"
|
||||
- pressKey: Enter
|
||||
- tapOn: "Continue"
|
||||
- tapOn: "OK"
|
||||
- tapOn:
|
||||
id: "login-password"
|
||||
- eraseText: 20
|
||||
- inputText: ${PASSWORD}
|
||||
- pressKey: Enter
|
||||
- tapOn: "Continue"
|
||||
- runFlow: ../assertions/assertWelcomeScreenDisplayed.yaml
|
||||
- tapOn: "Continue"
|
||||
- runFlow: ../assertions/assertAnalyticsDisplayed.yaml
|
||||
- tapOn: "Not now"
|
||||
- runFlow: ../assertions/assertHomeDisplayed.yaml
|
||||
13
.maestro/tests/account/logout.yaml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
- tapOn:
|
||||
id: "home_screen-settings"
|
||||
- tapOn: "Sign out"
|
||||
- takeScreenshot: build/maestro/900-SignOutDialg
|
||||
# Ensure cancel cancels
|
||||
- tapOn: "Cancel"
|
||||
- tapOn: "Sign out"
|
||||
- tapOn:
|
||||
text: "Sign out"
|
||||
index: 1
|
||||
- runFlow: ../assertions/assertInitDisplayed.yaml
|
||||
5
.maestro/tests/assertions/assertAnalyticsDisplayed.yaml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
- extendedWaitUntil:
|
||||
visible: "Help improve Element X dbg"
|
||||
timeout: 10_000
|
||||
5
.maestro/tests/assertions/assertHomeDisplayed.yaml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
- extendedWaitUntil:
|
||||
visible: "All Chats"
|
||||
timeout: 10_000
|
||||
5
.maestro/tests/assertions/assertInitDisplayed.yaml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
- extendedWaitUntil:
|
||||
visible: "Be in your element"
|
||||
timeout: 10_000
|
||||
5
.maestro/tests/assertions/assertLoginDisplayed.yaml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
- extendedWaitUntil:
|
||||
visible: "Change account provider"
|
||||
timeout: 10_000
|
||||
5
.maestro/tests/assertions/assertRoomListSynced.yaml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
- extendedWaitUntil:
|
||||
visible: ${ROOM_NAME}
|
||||
timeout: 10_000
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
- extendedWaitUntil:
|
||||
visible:
|
||||
id: "welcome_screen-title"
|
||||
timeout: 10_000
|
||||
7
.maestro/tests/init.yaml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
- clearState
|
||||
- launchApp:
|
||||
clearKeychain: true
|
||||
- runFlow: ./assertions/assertInitDisplayed.yaml
|
||||
- takeScreenshot: build/maestro/000-FirstScreen
|
||||
13
.maestro/tests/roomList/createAndDeleteDM.yaml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
# Purpose: Test the creation and deletion of a DM room.
|
||||
- tapOn: "Create a new conversation or room"
|
||||
- tapOn: "Search for someone"
|
||||
- inputText: ${INVITEE1_MXID}
|
||||
- tapOn:
|
||||
text: ${INVITEE1_MXID}
|
||||
index: 1
|
||||
- takeScreenshot: build/maestro/330-createAndDeleteDM
|
||||
- tapOn: "maestroelement2"
|
||||
- tapOn: "Leave room"
|
||||
- tapOn: "Leave"
|
||||
33
.maestro/tests/roomList/createAndDeleteRoom.yaml
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
# Purpose: Test the creation and deletion of a room
|
||||
- tapOn: "Create a new conversation or room"
|
||||
- tapOn: "New room"
|
||||
- tapOn: "Search for someone"
|
||||
- inputText: ${INVITEE1_MXID}
|
||||
- tapOn:
|
||||
text: ${INVITEE1_MXID}
|
||||
index: 1
|
||||
- tapOn: "Next"
|
||||
- tapOn: "e.g. your project name"
|
||||
- inputText: "aRoomName"
|
||||
- tapOn: "What is this room about?"
|
||||
- inputText: "aRoomTopic"
|
||||
- tapOn: "Create"
|
||||
- takeScreenshot: build/maestro/320-createAndDeleteRoom
|
||||
- tapOn: "aRoomName"
|
||||
- tapOn: "Invite people"
|
||||
# assert there's 1 memeber and 1 invitee
|
||||
- tapOn: "Search for someone"
|
||||
- inputText: ${INVITEE2_MXID}
|
||||
- tapOn:
|
||||
text: ${INVITEE2_MXID}
|
||||
index: 1
|
||||
- tapOn: "Send"
|
||||
- tapOn: "Back"
|
||||
- tapOn: "aRoomName"
|
||||
- tapOn: "People"
|
||||
# assert there's 1 memeber and 2 invitees
|
||||
- tapOn: "Back"
|
||||
- tapOn: "Leave room"
|
||||
- tapOn: "Leave"
|
||||
14
.maestro/tests/roomList/roomContextMenu.yaml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
# Purpose: Test the context menu of a room in the room list
|
||||
- longPressOn: ${ROOM_NAME}
|
||||
- takeScreenshot: build/maestro/310-RoomList-ContextMenu
|
||||
- tapOn:
|
||||
text: "Settings"
|
||||
index: 0
|
||||
- tapOn: "Back"
|
||||
- longPressOn: ${ROOM_NAME}
|
||||
- tapOn:
|
||||
text: "Leave room"
|
||||
index: 0
|
||||
- tapOn: "Cancel"
|
||||
8
.maestro/tests/roomList/roomList.yaml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
- runFlow: searchRoomList.yaml
|
||||
- takeScreenshot: build/maestro/300-RoomList
|
||||
- runFlow: timeline/timeline.yaml
|
||||
- runFlow: roomContextMenu.yaml
|
||||
- runFlow: createAndDeleteRoom.yaml
|
||||
- runFlow: createAndDeleteDM.yaml
|
||||
14
.maestro/tests/roomList/searchRoomList.yaml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
- runFlow: ../assertions/assertRoomListSynced.yaml
|
||||
- tapOn: "search"
|
||||
- inputText: ${ROOM_NAME.substring(0, 3)}
|
||||
- takeScreenshot: build/maestro/400-SearchRoom
|
||||
- tapOn: ${ROOM_NAME}
|
||||
# Back from timeline
|
||||
- back
|
||||
# Close keyboard
|
||||
- hideKeyboard
|
||||
# Back from search
|
||||
- back
|
||||
- runFlow: ../assertions/assertHomeDisplayed.yaml
|
||||
7
.maestro/tests/roomList/timeline/messages/location.yaml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
- takeScreenshot: build/maestro/520-Timeline
|
||||
- tapOn: "Add attachment"
|
||||
- tapOn: "Location"
|
||||
- tapOn: "Share my location"
|
||||
- takeScreenshot: build/maestro/521-Timeline
|
||||
8
.maestro/tests/roomList/timeline/messages/text.yaml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
- takeScreenshot: build/maestro/510-Timeline
|
||||
- tapOn: "Message"
|
||||
- inputText: "Hello world!"
|
||||
- tapOn: "Send"
|
||||
- hideKeyboard
|
||||
- takeScreenshot: build/maestro/511-Timeline
|
||||
9
.maestro/tests/roomList/timeline/timeline.yaml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
# This is the name of one room
|
||||
- tapOn: ${ROOM_NAME}
|
||||
- takeScreenshot: build/maestro/500-Timeline
|
||||
- runFlow: messages/text.yaml
|
||||
- runFlow: messages/location.yaml
|
||||
- back
|
||||
- runFlow: ../../assertions/assertHomeDisplayed.yaml
|
||||
30
.maestro/tests/settings/settings.yaml
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
appId: ${APP_ID}
|
||||
---
|
||||
- tapOn:
|
||||
id: "home_screen-settings"
|
||||
- assertVisible: "Settings"
|
||||
- takeScreenshot: build/maestro/600-Settings
|
||||
- tapOn:
|
||||
text: "Analytics"
|
||||
- assertVisible: "Share analytics data"
|
||||
- back
|
||||
|
||||
- tapOn:
|
||||
text: "Report bug"
|
||||
- assertVisible: "Report a bug"
|
||||
- back
|
||||
|
||||
- tapOn:
|
||||
text: "About"
|
||||
- assertVisible: "Copyright"
|
||||
- assertVisible: "Acceptable use policy"
|
||||
- assertVisible: "Privacy policy"
|
||||
- back
|
||||
|
||||
- tapOn:
|
||||
text: "Developer options"
|
||||
- assertVisible: "Feature flags"
|
||||
- back
|
||||
|
||||
- back
|
||||
- runFlow: ../assertions/assertHomeDisplayed.yaml
|
||||
17
AUTHORS.md
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
A full developer contributors list can be found [here](https://github.com/vector-im/element-x-android/graphs/contributors).
|
||||
|
||||
# Core team:
|
||||
|
||||
The element.io Android developer team.
|
||||
|
||||
# Other contributors
|
||||
|
||||
First of all, we thank all contributors who use Element and report problems on this GitHub project or via the integrated rageshake function.
|
||||
|
||||
We do not forget all translators, for their work of translating Element into many languages. They are also the authors of Element.
|
||||
|
||||
Feel free to add your name below, when you contribute to the project!
|
||||
|
||||
Name | Matrix ID | GitHub
|
||||
----------|-----------------------------|--------------------------------------
|
||||
name | @name:matrix.org | [githubID](https://github.com/githubID)
|
||||
4
CHANGES.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
Changes in Element X v0.1.0 (2023-07-19)
|
||||
========================================
|
||||
|
||||
First release of Element X 🚀!
|
||||
1
CODEOWNERS
Normal file
|
|
@ -0,0 +1 @@
|
|||
* @vector-im/element-x-android-reviewers
|
||||
177
CONTRIBUTING.md
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
# Contributing to Element Android
|
||||
|
||||
<!--- TOC -->
|
||||
|
||||
* [Contributing code to Matrix](#contributing-code-to-matrix)
|
||||
* [Developer onboarding](#developer-onboarding)
|
||||
* [Android Studio settings](#android-studio-settings)
|
||||
* [Compilation](#compilation)
|
||||
* [Strings](#strings)
|
||||
* [I want to add new strings to the project](#i-want-to-add-new-strings-to-the-project)
|
||||
* [I want to help translating Element](#i-want-to-help-translating-element)
|
||||
* [I want to submit a PR to fix an issue](#i-want-to-submit-a-pr-to-fix-an-issue)
|
||||
* [Kotlin](#kotlin)
|
||||
* [Changelog](#changelog)
|
||||
* [Code quality](#code-quality)
|
||||
* [ktlint](#ktlint)
|
||||
* [knit](#knit)
|
||||
* [lint](#lint)
|
||||
* [Unit tests](#unit-tests)
|
||||
* [Tests](#tests)
|
||||
* [Accessibility](#accessibility)
|
||||
* [Jetpack Compose](#jetpack-compose)
|
||||
* [Authors](#authors)
|
||||
* [Thanks](#thanks)
|
||||
|
||||
<!--- END -->
|
||||
|
||||
## Contributing code to Matrix
|
||||
|
||||
Please read https://github.com/matrix-org/synapse/blob/master/CONTRIBUTING.md
|
||||
|
||||
Element X Android support can be found in this room: [](https://matrix.to/#/#element-android:matrix.org).
|
||||
|
||||
The rest of the document contains specific rules for Matrix Android projects
|
||||
|
||||
## Developer onboarding
|
||||
|
||||
For a detailed overview of the project, see [Developer Onboarding](./docs/_developer_onboarding.md).
|
||||
|
||||
## Android Studio settings
|
||||
|
||||
Please set the "hard wrap" setting of Android Studio to 160 chars, this is the setting we use internally to format the source code (Menu `Settings/Editor/Code Style` then `Hard wrap at`).
|
||||
Please ensure that you're using the project formatting rules (which are in the project at .idea/codeStyles/), and format the file before committing them.
|
||||
|
||||
## Compilation
|
||||
|
||||
This project should compile without any special action. Just clone it and open it with Android Studio, or compile from command line using `gradlew`.
|
||||
|
||||
Note: please make sure that the configuration is `app` and not `samples.minimal`.
|
||||
|
||||
## Strings
|
||||
|
||||
The strings of the project are managed externally using [https://localazy.com](https://localazy.com) and shared with ElementX iOS.
|
||||
|
||||
### I want to add new strings to the project
|
||||
|
||||
Only the core team can modify or add English strings to Localazy. As an external contributor, if you want to add new strings, feel free to add an Android resource file to the project (for instance a file named `temporary.xml`), with a note in the description of the PR for the reviewer to integrate the String into `Localazy`. If accepted, the reviewer will add the String(s) for you, and then you can download them on your branch (following these [instructions](./tools/localazy/README.md#download-translations)) and remove the temporary file.
|
||||
|
||||
Please follow the naming rules for the key. More details in [the dedicated section in this README.md](./tools/localazy/README.md#key-naming-rules)
|
||||
|
||||
### I want to help translating Element
|
||||
|
||||
Please note that the Localazy project is not open yet for external contributions.
|
||||
|
||||
To help translating, please go to [https://localazy.com/p/element](https://localazy.com/p/element).
|
||||
|
||||
- If you want to fix an issue with an English string, please open an issue on the github project of ElementX (Android or iOS). Only the core team can modify or add English strings.
|
||||
- If you want to fix an issue in other languages, or add a missing translation, or even add a new language, please go to [https://localazy.com/p/element](https://localazy.com/p/element).
|
||||
|
||||
More informations can be found [in this README.md](./tools/localazy/README.md).
|
||||
|
||||
## I want to submit a PR to fix an issue
|
||||
|
||||
Please have a look in the [dedicated documentation](./docs/pull_request.md) about pull request.
|
||||
|
||||
Please check if a corresponding issue exists. If yes, please let us know in a comment that you're working on it.
|
||||
If an issue does not exist yet, it may be relevant to open a new issue and let us know that you're implementing it.
|
||||
|
||||
### Kotlin
|
||||
|
||||
This project is full Kotlin. Please do not write Java classes.
|
||||
|
||||
### Changelog
|
||||
|
||||
Please create at least one file under ./changelog.d containing details about your change. Towncrier will be used when preparing the release.
|
||||
|
||||
Towncrier says to use the PR number for the filename, but the issue number is also fine.
|
||||
|
||||
Supported filename extensions are:
|
||||
|
||||
- ``.feature``: Signifying a new feature in Element Android or in the Matrix SDK.
|
||||
- ``.bugfix``: Signifying a bug fix.
|
||||
- ``.wip``: Signifying a work in progress change, typically a component of a larger feature which will be enabled once all tasks are complete.
|
||||
- ``.doc``: Signifying a documentation improvement.
|
||||
- ``.misc``: Any other changes.
|
||||
|
||||
See https://github.com/twisted/towncrier#news-fragments if you need more details.
|
||||
|
||||
### Code quality
|
||||
|
||||
Make sure the following commands execute without any error:
|
||||
|
||||
<pre>
|
||||
./gradlew check
|
||||
</pre>
|
||||
|
||||
Some separate commands can also be run, see below.
|
||||
|
||||
#### ktlint
|
||||
|
||||
<pre>
|
||||
./gradlew ktlintCheck --continue
|
||||
</pre>
|
||||
|
||||
Note that you can run
|
||||
|
||||
<pre>
|
||||
./gradlew ktlintFormat
|
||||
</pre>
|
||||
|
||||
For ktlint to fix some detected errors for you (you still have to check and commit the fix of course)
|
||||
|
||||
#### knit
|
||||
|
||||
[knit](https://github.com/Kotlin/kotlinx-knit) is a tool which checks markdown files on the project. Also it generates/updates the table of content (toc) of the markdown files.
|
||||
|
||||
So everytime the toc should be updated, just run
|
||||
<pre>
|
||||
./gradlew knit
|
||||
</pre>
|
||||
|
||||
and commit the changes.
|
||||
|
||||
The CI will check that markdown files are up to date by running
|
||||
|
||||
<pre>
|
||||
./gradlew knitCheck
|
||||
</pre>
|
||||
|
||||
#### lint
|
||||
|
||||
<pre>
|
||||
./gradlew lint
|
||||
</pre>
|
||||
|
||||
### Unit tests
|
||||
|
||||
Make sure the following commands execute without any error:
|
||||
|
||||
<pre>
|
||||
./gradlew test
|
||||
</pre>
|
||||
|
||||
### Tests
|
||||
|
||||
Element X is currently supported on Android Lollipop (API 21+): please test your change on an Android device (or Android emulator) running with API 21. Many issues can happen (including crashes) on older devices.
|
||||
Also, if possible, please test your change on a real device. Testing on Android emulator may not be sufficient.
|
||||
|
||||
You should consider adding Unit tests with your PR, and also integration tests (AndroidTest). Please refer to [this document](./docs/integration_tests.md) to install and run the integration test environment.
|
||||
|
||||
### Accessibility
|
||||
|
||||
Please consider accessibility as an important point. As a minimum requirement, in layout XML files please use attributes such as `android:contentDescription` and `android:importantForAccessibility`, and test with a screen reader if it's working well. You can add new string resources, dedicated to accessibility, in this case, please prefix theirs id with `a11y_`.
|
||||
|
||||
For instance, when updating the image `src` of an ImageView, please also consider updating its `contentDescription`. A good example is a play pause button.
|
||||
|
||||
### Jetpack Compose
|
||||
|
||||
When adding or editing `@Composable`, make sure that you create a `@Preview` function, with suffix `Preview`. This will also create a UI test automatically.
|
||||
|
||||
### Authors
|
||||
|
||||
Feel free to add an entry in file AUTHORS.md
|
||||
|
||||
## Thanks
|
||||
|
||||
Thanks for contributing to Matrix projects!
|
||||
3
Gemfile
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
source "https://rubygems.org"
|
||||
|
||||
gem 'danger'
|
||||
71
README.md
|
|
@ -1,2 +1,69 @@
|
|||
# element-x-android-poc
|
||||
Prrof Of Concept to run a Matrix client on Android devices using the Matrix Rust Sdk and Jetpack compose
|
||||
[](https://github.com/vector-im/element-x-android/actions/workflows/build.yml?query=branch%3Adevelop)
|
||||
[](https://sonarcloud.io/summary/new_code?id=vector-im_element-x-android)
|
||||
[](https://sonarcloud.io/summary/new_code?id=vector-im_element-x-android)
|
||||
[](https://sonarcloud.io/summary/new_code?id=vector-im_element-x-android)
|
||||
[](https://codecov.io/github/vector-im/element-x-android)
|
||||
[](https://matrix.to/#/#element-android:matrix.org)
|
||||
[](https://translate.element.io/engage/element-android/?utm_source=widget)
|
||||
|
||||
# element-x-android
|
||||
|
||||
ElementX Android is a [Matrix](https://matrix.org/) Android Client provided by [Element](https://element.io/). This app is currently in a pre-alpha release stage with only basic functionality.
|
||||
|
||||
The application is a total rewrite of [Element-Android](https://github.com/vector-im/element-android) using the [Matrix Rust SDK](https://github.com/matrix-org/matrix-rust-sdk) underneath and targeting devices running Android 6+. The UI layer is written using Jetpack compose.
|
||||
|
||||
<!--- TOC -->
|
||||
|
||||
* [Screenshots](#screenshots)
|
||||
* [Rust SDK](#rust-sdk)
|
||||
* [Status](#status)
|
||||
* [Contributing](#contributing)
|
||||
* [Build instructions](#build-instructions)
|
||||
* [Support](#support)
|
||||
* [Copyright & License](#copyright-&-license)
|
||||
|
||||
<!--- END -->
|
||||
|
||||
## Screenshots
|
||||
|
||||
Here are some early screenshots of the application:
|
||||
|
||||
|<img src=./docs/images/screen1.png width=280 />|<img src=./docs/images/screen2.png width=280 />|<img src=./docs/images/screen3.png width=280 />|<img src=./docs/images/screen4.png width=280 />|
|
||||
|-|-|-|-|
|
||||
|
||||
## Rust SDK
|
||||
|
||||
ElementX leverages the [Matrix Rust SDK](https://github.com/matrix-org/matrix-rust-sdk) through an FFI layer that the final client can directly import and use.
|
||||
|
||||
We're doing this as a way to share code between platforms and while we've seen promising results it's still in the experimental stage and bound to change.
|
||||
|
||||
## Status
|
||||
|
||||
This project is in work in progress. The app does not cover yet all functionalities we expect.
|
||||
|
||||
## Contributing
|
||||
|
||||
Please see our [contribution guide](CONTRIBUTING.md).
|
||||
|
||||
Come chat with the community in the dedicated Matrix [room](https://matrix.to/#/#element-android:matrix.org).
|
||||
|
||||
## Build instructions
|
||||
|
||||
Just clone the project and open it in Android Studio.
|
||||
Makes sure to select the `app` configuration when building (as we also have sample apps in the project).
|
||||
|
||||
## Support
|
||||
|
||||
When you are experiencing an issue on ElementX Android, please first search in [GitHub issues](https://github.com/vector-im/element-x-android/issues)
|
||||
and then in [#element-android:matrix.org](https://matrix.to/#/#element-android:matrix.org).
|
||||
If after your research you still have a question, ask at [#element-android:matrix.org](https://matrix.to/#/#element-android:matrix.org). Otherwise feel free to create a GitHub issue if you encounter a bug or a crash, by explaining clearly in detail what happened. You can also perform bug reporting (Rageshake) from the Element application by shaking your phone or going to the application settings. This is especially recommended when you encounter a crash.
|
||||
|
||||
## Copyright & License
|
||||
|
||||
Copyright (c) 2022 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. You may obtain a copy of the License in the [LICENSE](LICENSE) file, or at:
|
||||
|
||||
[http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
||||
|
|
|
|||
1
anvilannotations/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
23
anvilannotations/build.gradle.kts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
plugins {
|
||||
alias(libs.plugins.kotlin.jvm)
|
||||
id("com.android.lint")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(libs.inject)
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.anvilannotations
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Adds Node to the specified component graph.
|
||||
* Equivalent to the following declaration:
|
||||
*
|
||||
* @Module
|
||||
* @ContributesTo(Scope::class)
|
||||
* abstract class YourNodeModule {
|
||||
|
||||
* @Binds
|
||||
* @IntoMap
|
||||
* @NodeKey(YourNode::class)
|
||||
* abstract fun bindYourNodeFactory(factory: YourNode.Factory): AssistedNodeFactory<*>
|
||||
*}
|
||||
|
||||
*/
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
annotation class ContributesNode(
|
||||
val scope: KClass<*>,
|
||||
)
|
||||
1
anvilcodegen/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
30
anvilcodegen/build.gradle.kts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.kotlin.jvm)
|
||||
alias(libs.plugins.kapt)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.anvilannotations)
|
||||
api(libs.anvil.compiler.api)
|
||||
implementation(libs.anvil.compiler.utils)
|
||||
implementation("com.squareup:kotlinpoet:1.14.2")
|
||||
implementation(libs.dagger)
|
||||
compileOnly(libs.google.autoservice.annotations)
|
||||
kapt(libs.google.autoservice)
|
||||
}
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalAnvilApi::class)
|
||||
|
||||
package io.element.android.anvilcodegen
|
||||
|
||||
import com.google.auto.service.AutoService
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import com.squareup.anvil.annotations.ExperimentalAnvilApi
|
||||
import com.squareup.anvil.compiler.api.AnvilCompilationException
|
||||
import com.squareup.anvil.compiler.api.AnvilContext
|
||||
import com.squareup.anvil.compiler.api.CodeGenerator
|
||||
import com.squareup.anvil.compiler.api.GeneratedFile
|
||||
import com.squareup.anvil.compiler.api.createGeneratedFile
|
||||
import com.squareup.anvil.compiler.internal.asClassName
|
||||
import com.squareup.anvil.compiler.internal.buildFile
|
||||
import com.squareup.anvil.compiler.internal.fqName
|
||||
import com.squareup.anvil.compiler.internal.reference.ClassReference
|
||||
import com.squareup.anvil.compiler.internal.reference.asClassName
|
||||
import com.squareup.anvil.compiler.internal.reference.classAndInnerClassReferences
|
||||
import com.squareup.kotlinpoet.AnnotationSpec
|
||||
import com.squareup.kotlinpoet.ClassName
|
||||
import com.squareup.kotlinpoet.FileSpec
|
||||
import com.squareup.kotlinpoet.FunSpec
|
||||
import com.squareup.kotlinpoet.KModifier
|
||||
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
|
||||
import com.squareup.kotlinpoet.STAR
|
||||
import com.squareup.kotlinpoet.TypeSpec
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import dagger.multibindings.IntoMap
|
||||
import io.element.android.anvilannotations.ContributesNode
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* This is an anvil plugin that allows Node to use [ContributesNode] alone and let this plugin automatically
|
||||
* handle the rest of the Dagger wiring required for constructor injection.
|
||||
*/
|
||||
@AutoService(CodeGenerator::class)
|
||||
class ContributesNodeCodeGenerator : CodeGenerator {
|
||||
|
||||
override fun isApplicable(context: AnvilContext): Boolean = true
|
||||
|
||||
override fun generateCode(codeGenDir: File, module: ModuleDescriptor, projectFiles: Collection<KtFile>): Collection<GeneratedFile> {
|
||||
return projectFiles.classAndInnerClassReferences(module)
|
||||
.filter { it.isAnnotatedWith(ContributesNode::class.fqName) }
|
||||
.flatMap { listOf(generateModule(it, codeGenDir, module), generateAssistedFactory(it, codeGenDir, module)) }
|
||||
.toList()
|
||||
}
|
||||
|
||||
private fun generateModule(nodeClass: ClassReference.Psi, codeGenDir: File, module: ModuleDescriptor): GeneratedFile {
|
||||
val generatedPackage = nodeClass.packageFqName.toString()
|
||||
val moduleClassName = "${nodeClass.shortName}_Module"
|
||||
val scope = nodeClass.annotations.single { it.fqName == ContributesNode::class.fqName }.scope()
|
||||
val content = FileSpec.buildFile(generatedPackage, moduleClassName) {
|
||||
addType(
|
||||
TypeSpec.classBuilder(moduleClassName)
|
||||
.addModifiers(KModifier.ABSTRACT)
|
||||
.addAnnotation(Module::class)
|
||||
.addAnnotation(AnnotationSpec.builder(ContributesTo::class).addMember("%T::class", scope.asClassName()).build())
|
||||
.addFunction(
|
||||
FunSpec.builder("bind${nodeClass.shortName}Factory")
|
||||
.addModifiers(KModifier.ABSTRACT)
|
||||
.addParameter("factory", ClassName(generatedPackage, "${nodeClass.shortName}_AssistedFactory"))
|
||||
.returns(assistedNodeFactoryFqName.asClassName(module).parameterizedBy(STAR))
|
||||
.addAnnotation(Binds::class)
|
||||
.addAnnotation(IntoMap::class)
|
||||
.addAnnotation(
|
||||
AnnotationSpec.Companion.builder(nodeKeyFqName.asClassName(module)).addMember(
|
||||
"%T::class",
|
||||
nodeClass.asClassName()
|
||||
).build()
|
||||
)
|
||||
.build(),
|
||||
)
|
||||
.build(),
|
||||
)
|
||||
}
|
||||
return createGeneratedFile(codeGenDir, generatedPackage, moduleClassName, content)
|
||||
}
|
||||
|
||||
private fun generateAssistedFactory(nodeClass: ClassReference.Psi, codeGenDir: File, module: ModuleDescriptor): GeneratedFile {
|
||||
val generatedPackage = nodeClass.packageFqName.toString()
|
||||
val assistedFactoryClassName = "${nodeClass.shortName}_AssistedFactory"
|
||||
val constructor = nodeClass.constructors.singleOrNull { it.isAnnotatedWith(AssistedInject::class.fqName) }
|
||||
val assistedParameters = constructor?.parameters?.filter { it.isAnnotatedWith(Assisted::class.fqName) }.orEmpty()
|
||||
if (constructor == null || assistedParameters.size != 2) {
|
||||
throw AnvilCompilationException(
|
||||
"${nodeClass.fqName} must have an @AssistedInject constructor with 2 @Assisted parameters",
|
||||
element = nodeClass.clazz,
|
||||
)
|
||||
}
|
||||
val contextAssistedParam = assistedParameters[0]
|
||||
if (contextAssistedParam.name != "buildContext") {
|
||||
throw AnvilCompilationException(
|
||||
"${nodeClass.fqName} @Assisted parameter must be named buildContext",
|
||||
element = contextAssistedParam.parameter,
|
||||
)
|
||||
}
|
||||
val pluginsAssistedParam = assistedParameters[1]
|
||||
if (pluginsAssistedParam.name != "plugins") {
|
||||
throw AnvilCompilationException(
|
||||
"${nodeClass.fqName} @Assisted parameter must be named plugins",
|
||||
element = pluginsAssistedParam.parameter,
|
||||
)
|
||||
}
|
||||
|
||||
val nodeClassName = nodeClass.asClassName()
|
||||
val buildContextClassName = contextAssistedParam.type().asTypeName()
|
||||
val pluginsClassName = pluginsAssistedParam.type().asTypeName()
|
||||
val content = FileSpec.buildFile(generatedPackage, assistedFactoryClassName) {
|
||||
addType(
|
||||
TypeSpec.interfaceBuilder(assistedFactoryClassName)
|
||||
.addSuperinterface(assistedNodeFactoryFqName.asClassName(module).parameterizedBy(nodeClassName))
|
||||
.addAnnotation(AssistedFactory::class)
|
||||
.addFunction(
|
||||
FunSpec.builder("create")
|
||||
.addModifiers(KModifier.OVERRIDE, KModifier.ABSTRACT)
|
||||
.addParameter("buildContext", buildContextClassName)
|
||||
.addParameter("plugins", pluginsClassName)
|
||||
.returns(nodeClassName)
|
||||
.build(),
|
||||
)
|
||||
.build(),
|
||||
)
|
||||
}
|
||||
return createGeneratedFile(codeGenDir, generatedPackage, assistedFactoryClassName, content)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val assistedNodeFactoryFqName = FqName("io.element.android.libraries.architecture.AssistedNodeFactory")
|
||||
private val nodeKeyFqName = FqName("io.element.android.libraries.architecture.NodeKey")
|
||||
}
|
||||
}
|
||||
234
app/build.gradle.kts
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@file:Suppress("UnstableApiUsage")
|
||||
|
||||
import com.android.build.api.variant.FilterConfiguration.FilterType.ABI
|
||||
import extension.allFeaturesImpl
|
||||
import extension.allLibrariesImpl
|
||||
import extension.allServicesImpl
|
||||
|
||||
plugins {
|
||||
id("io.element.android-compose-application")
|
||||
alias(libs.plugins.kotlin.android)
|
||||
alias(libs.plugins.anvil)
|
||||
alias(libs.plugins.ksp)
|
||||
alias(libs.plugins.kapt)
|
||||
id("com.google.firebase.appdistribution") version "4.0.0"
|
||||
id("org.jetbrains.kotlinx.knit") version "0.4.0"
|
||||
id("kotlin-parcelize")
|
||||
// To be able to update the firebase.xml files, uncomment and build the project
|
||||
// id("com.google.gms.google-services")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "io.element.android.x"
|
||||
|
||||
testOptions { unitTests.isIncludeAndroidResources = true }
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "io.element.android.x"
|
||||
targetSdk = Versions.targetSdk
|
||||
versionCode = Versions.versionCode
|
||||
versionName = Versions.versionName
|
||||
|
||||
vectorDrawables {
|
||||
useSupportLibrary = true
|
||||
}
|
||||
|
||||
// Keep abiFilter for the universalApk
|
||||
ndk {
|
||||
abiFilters += listOf("armeabi-v7a", "x86", "arm64-v8a", "x86_64")
|
||||
}
|
||||
|
||||
// Ref: https://developer.android.com/studio/build/configure-apk-splits.html#configure-abi-split
|
||||
splits {
|
||||
// Configures multiple APKs based on ABI.
|
||||
abi {
|
||||
// Enables building multiple APKs per ABI.
|
||||
isEnable = true
|
||||
// By default all ABIs are included, so use reset() and include to specify that we only
|
||||
// want APKs for armeabi-v7a, x86, arm64-v8a and x86_64.
|
||||
// Resets the list of ABIs that Gradle should create APKs for to none.
|
||||
reset()
|
||||
// Specifies a list of ABIs that Gradle should create APKs for.
|
||||
include("armeabi-v7a", "x86", "arm64-v8a", "x86_64")
|
||||
// Generate a universal APK that includes all ABIs, so user who installs from CI tool can use this one by default.
|
||||
isUniversalApk = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
named("debug") {
|
||||
keyAlias = "androiddebugkey"
|
||||
keyPassword = "android"
|
||||
storeFile = file("./signature/debug.keystore")
|
||||
storePassword = "android"
|
||||
}
|
||||
register("nightly") {
|
||||
keyAlias = System.getenv("ELEMENT_ANDROID_NIGHTLY_KEYID")
|
||||
?: project.property("signing.element.nightly.keyId") as? String?
|
||||
keyPassword = System.getenv("ELEMENT_ANDROID_NIGHTLY_KEYPASSWORD")
|
||||
?: project.property("signing.element.nightly.keyPassword") as? String?
|
||||
storeFile = file("./signature/nightly.keystore")
|
||||
storePassword = System.getenv("ELEMENT_ANDROID_NIGHTLY_STOREPASSWORD")
|
||||
?: project.property("signing.element.nightly.storePassword") as? String?
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
named("debug") {
|
||||
resValue("string", "app_name", "Element X dbg")
|
||||
applicationIdSuffix = ".debug"
|
||||
signingConfig = signingConfigs.getByName("debug")
|
||||
}
|
||||
|
||||
named("release") {
|
||||
resValue("string", "app_name", "Element X")
|
||||
signingConfig = signingConfigs.getByName("debug")
|
||||
|
||||
postprocessing {
|
||||
isRemoveUnusedCode = true
|
||||
isObfuscate = false
|
||||
isOptimizeCode = true
|
||||
isRemoveUnusedResources = true
|
||||
proguardFiles("proguard-rules.pro")
|
||||
}
|
||||
}
|
||||
|
||||
register("nightly") {
|
||||
val release = getByName("release")
|
||||
initWith(release)
|
||||
applicationIdSuffix = ".nightly"
|
||||
versionNameSuffix = "-nightly"
|
||||
resValue("string", "app_name", "Element X nightly")
|
||||
matchingFallbacks += listOf("release")
|
||||
signingConfig = signingConfigs.getByName("nightly")
|
||||
|
||||
postprocessing {
|
||||
initWith(release.postprocessing)
|
||||
}
|
||||
|
||||
firebaseAppDistribution {
|
||||
artifactType = "APK"
|
||||
// We upload the universal APK to fix this error:
|
||||
// "App Distribution found more than 1 output file for this variant.
|
||||
// Please contact firebase-support@google.com for help using APK splits with App Distribution."
|
||||
artifactPath = "$rootDir/app/build/outputs/apk/nightly/app-universal-nightly.apk"
|
||||
// This file will be generated by the GitHub action
|
||||
releaseNotesFile = "CHANGES_NIGHTLY.md"
|
||||
groups = "external-testers"
|
||||
// This should not be required, but if I do not add the appId, I get this error:
|
||||
// "App Distribution halted because it had a problem uploading the APK: [404] Requested entity was not found."
|
||||
appId = "1:912726360885:android:e17435e0beb0303000427c"
|
||||
}
|
||||
}
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
buildConfig = true
|
||||
}
|
||||
}
|
||||
|
||||
androidComponents {
|
||||
// map for the version codes last digit
|
||||
// x86 must have greater values than arm
|
||||
// 64 bits have greater value than 32 bits
|
||||
val abiVersionCodes = mapOf(
|
||||
"armeabi-v7a" to 1,
|
||||
"arm64-v8a" to 2,
|
||||
"x86" to 3,
|
||||
"x86_64" to 4,
|
||||
)
|
||||
|
||||
onVariants { variant ->
|
||||
// Assigns a different version code for each output APK
|
||||
// other than the universal APK.
|
||||
variant.outputs.forEach { output ->
|
||||
val name = output.filters.find { it.filterType == ABI }?.identifier
|
||||
|
||||
// Stores the value of abiCodes that is associated with the ABI for this variant.
|
||||
val abiCode = abiVersionCodes[name] ?: 0
|
||||
// Assigns the new version code to output.versionCode, which changes the version code
|
||||
// for only the output APK, not for the variant itself.
|
||||
output.versionCode.set((output.versionCode.get() ?: 0) * 10 + abiCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Knit
|
||||
apply {
|
||||
plugin("kotlinx-knit")
|
||||
}
|
||||
|
||||
knit {
|
||||
files = fileTree(project.rootDir) {
|
||||
include(
|
||||
"**/*.md",
|
||||
"**/*.kt",
|
||||
"*/*.kts",
|
||||
)
|
||||
exclude(
|
||||
"**/build/**",
|
||||
"*/.gradle/**",
|
||||
"*/towncrier/template.md",
|
||||
"**/CHANGES.md",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
allLibrariesImpl()
|
||||
allServicesImpl()
|
||||
allFeaturesImpl(rootDir, logger)
|
||||
implementation(projects.anvilannotations)
|
||||
implementation(projects.appnav)
|
||||
anvil(projects.anvilcodegen)
|
||||
|
||||
coreLibraryDesugaring(libs.android.desugar)
|
||||
implementation(libs.appyx.core)
|
||||
implementation(libs.androidx.splash)
|
||||
implementation(libs.androidx.core)
|
||||
implementation(libs.androidx.corektx)
|
||||
implementation(libs.androidx.lifecycle.runtime)
|
||||
implementation(libs.androidx.lifecycle.process)
|
||||
implementation(libs.androidx.activity.compose)
|
||||
implementation(libs.androidx.startup)
|
||||
implementation(libs.androidx.preference)
|
||||
implementation(libs.coil)
|
||||
|
||||
implementation(platform(libs.network.okhttp.bom))
|
||||
implementation(libs.network.okhttp.logging)
|
||||
implementation(libs.serialization.json)
|
||||
|
||||
implementation(libs.vanniktech.emoji)
|
||||
|
||||
implementation(libs.dagger)
|
||||
kapt(libs.dagger.compiler)
|
||||
|
||||
testImplementation(libs.test.junit)
|
||||
testImplementation(libs.coroutines.test)
|
||||
testImplementation(libs.molecule.runtime)
|
||||
testImplementation(libs.test.truth)
|
||||
testImplementation(libs.test.turbine)
|
||||
testImplementation(projects.libraries.matrix.test)
|
||||
|
||||
ksp(libs.showkase.processor)
|
||||
}
|
||||
34
app/proguard-rules.pro
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.kts.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# JNA
|
||||
-dontwarn java.awt.*
|
||||
-keep class com.sun.jna.** { *; }
|
||||
-keep class * implements com.sun.jna.** { *; }
|
||||
|
||||
# kotlinx.serialization
|
||||
|
||||
# Kotlin serialization looks up the generated serializer classes through a function on companion
|
||||
# objects. The companions are looked up reflectively so we need to explicitly keep these functions.
|
||||
-keepclasseswithmembers class **.*$Companion {
|
||||
kotlinx.serialization.KSerializer serializer(...);
|
||||
}
|
||||
# If a companion has the serializer function, keep the companion field on the original type so that
|
||||
# the reflective lookup succeeds.
|
||||
-if class **.*$Companion {
|
||||
kotlinx.serialization.KSerializer serializer(...);
|
||||
}
|
||||
-keepclassmembers class <1>.<2> {
|
||||
<1>.<2>$Companion Companion;
|
||||
}
|
||||
|
||||
# OkHttp platform used only on JVM and when Conscrypt and other security providers are available.
|
||||
# Taken from https://raw.githubusercontent.com/square/okhttp/master/okhttp/src/jvmMain/resources/META-INF/proguard/okhttp3.pro
|
||||
-dontwarn okhttp3.internal.platform.**
|
||||
-dontwarn org.conscrypt.**
|
||||
-dontwarn org.bouncycastle.**
|
||||
-dontwarn org.openjsse.**
|
||||
BIN
app/signature/debug.keystore
Normal file
BIN
app/signature/nightly.keystore
Normal file
94
app/src/main/AndroidManifest.xml
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) 2022 New Vector Ltd
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<!-- To be able to install APK from the application -->
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
|
||||
<application
|
||||
android:name=".ElementXApplication"
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.ElementX"
|
||||
tools:targetApi="33">
|
||||
|
||||
<provider
|
||||
android:name="androidx.startup.InitializationProvider"
|
||||
android:authorities="${applicationId}.androidx-startup"
|
||||
android:exported="false"
|
||||
tools:node="merge">
|
||||
|
||||
<meta-data
|
||||
android:name='androidx.lifecycle.ProcessLifecycleInitializer'
|
||||
android:value='androidx.startup' />
|
||||
|
||||
</provider>
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden|uiMode"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/Theme.ElementX.Splash"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
<!-- Handle deep-link for notification ./tools/adb/deeplink.sh -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data
|
||||
android:host="open"
|
||||
android:scheme="elementx" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data android:scheme="io.element" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<provider
|
||||
android:name="androidx.startup.InitializationProvider"
|
||||
android:authorities="${applicationId}.androidx-startup"
|
||||
android:exported="false"
|
||||
tools:node="remove" />
|
||||
|
||||
<provider
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:grantUriPermissions="true"
|
||||
android:exported="false">
|
||||
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_providers" />
|
||||
</provider>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
BIN
app/src/main/ic_launcher-playstore.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.x
|
||||
|
||||
import android.app.Application
|
||||
import androidx.startup.AppInitializer
|
||||
import io.element.android.libraries.di.DaggerComponentOwner
|
||||
import io.element.android.x.di.AppComponent
|
||||
import io.element.android.x.di.DaggerAppComponent
|
||||
import io.element.android.x.info.logApplicationInfo
|
||||
import io.element.android.x.initializer.CrashInitializer
|
||||
import io.element.android.x.initializer.EmojiInitializer
|
||||
import io.element.android.x.initializer.MatrixInitializer
|
||||
import io.element.android.x.initializer.TimberInitializer
|
||||
|
||||
class ElementXApplication : Application(), DaggerComponentOwner {
|
||||
|
||||
private lateinit var appComponent: AppComponent
|
||||
|
||||
override val daggerComponent: Any
|
||||
get() = appComponent
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
appComponent = DaggerAppComponent.factory().create(applicationContext)
|
||||
AppInitializer.getInstance(this).apply {
|
||||
initializeComponent(CrashInitializer::class.java)
|
||||
initializeComponent(TimberInitializer::class.java)
|
||||
initializeComponent(MatrixInitializer::class.java)
|
||||
initializeComponent(EmojiInitializer::class.java)
|
||||
}
|
||||
logApplicationInfo()
|
||||
}
|
||||
}
|
||||
127
app/src/main/kotlin/io/element/android/x/MainActivity.kt
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.x
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.core.view.WindowCompat
|
||||
import com.bumble.appyx.core.integration.NodeHost
|
||||
import com.bumble.appyx.core.integrationpoint.NodeComponentActivity
|
||||
import com.bumble.appyx.core.plugin.NodeReadyObserver
|
||||
import io.element.android.libraries.architecture.bindings
|
||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||
import io.element.android.libraries.theme.ElementTheme
|
||||
import io.element.android.libraries.designsystem.utils.LocalSnackbarDispatcher
|
||||
import io.element.android.x.di.AppBindings
|
||||
import io.element.android.x.intent.SafeUriHandler
|
||||
import timber.log.Timber
|
||||
|
||||
private val loggerTag = LoggerTag("MainActivity")
|
||||
|
||||
class MainActivity : NodeComponentActivity() {
|
||||
|
||||
private lateinit var mainNode: MainNode
|
||||
|
||||
private lateinit var appBindings: AppBindings
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
Timber.tag(loggerTag.value).w("onCreate, with savedInstanceState: ${savedInstanceState != null}")
|
||||
installSplashScreen()
|
||||
super.onCreate(savedInstanceState)
|
||||
appBindings = bindings()
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
setContent {
|
||||
MainContent(appBindings)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MainContent(appBindings: AppBindings) {
|
||||
ElementTheme {
|
||||
CompositionLocalProvider(
|
||||
LocalSnackbarDispatcher provides appBindings.snackbarDispatcher(),
|
||||
LocalUriHandler provides SafeUriHandler(this),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(MaterialTheme.colorScheme.background),
|
||||
) {
|
||||
NodeHost(integrationPoint = appyxIntegrationPoint) {
|
||||
MainNode(
|
||||
it,
|
||||
appBindings.mainDaggerComponentOwner(),
|
||||
plugins = listOf(
|
||||
object : NodeReadyObserver<MainNode> {
|
||||
override fun init(node: MainNode) {
|
||||
Timber.tag(loggerTag.value).w("onMainNodeInit")
|
||||
mainNode = node
|
||||
mainNode.handleIntent(intent)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when:
|
||||
* - the launcher icon is clicked (if the app is already running);
|
||||
* - a notification is clicked.
|
||||
* - the app is going to background (<- this is strange)
|
||||
*/
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
super.onNewIntent(intent)
|
||||
Timber.tag(loggerTag.value).w("onNewIntent")
|
||||
// If the mainNode is not init yet, keep the intent for later.
|
||||
// It can happen when the activity is killed by the system. The methods are called in this order :
|
||||
// onCreate(savedInstanceState=true) -> onNewIntent -> onResume -> onMainNodeInit
|
||||
if (::mainNode.isInitialized) {
|
||||
mainNode.handleIntent(intent)
|
||||
} else {
|
||||
setIntent(intent)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
Timber.tag(loggerTag.value).w("onPause")
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
Timber.tag(loggerTag.value).w("onResume")
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
Timber.tag(loggerTag.value).w("onDestroy")
|
||||
}
|
||||
}
|
||||
104
app/src/main/kotlin/io/element/android/x/MainNode.kt
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.x
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Parcelable
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.bumble.appyx.core.composable.Children
|
||||
import com.bumble.appyx.core.modality.BuildContext
|
||||
import com.bumble.appyx.core.navigation.model.permanent.PermanentNavModel
|
||||
import com.bumble.appyx.core.node.Node
|
||||
import com.bumble.appyx.core.node.ParentNode
|
||||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import io.element.android.appnav.LoggedInFlowNode
|
||||
import io.element.android.appnav.room.RoomLoadedFlowNode
|
||||
import io.element.android.appnav.RootFlowNode
|
||||
import io.element.android.libraries.architecture.bindings
|
||||
import io.element.android.libraries.architecture.createNode
|
||||
import io.element.android.libraries.di.DaggerComponentOwner
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.x.di.MainDaggerComponentsOwner
|
||||
import io.element.android.x.di.RoomComponent
|
||||
import io.element.android.x.di.SessionComponent
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
class MainNode(
|
||||
buildContext: BuildContext,
|
||||
private val mainDaggerComponentOwner: MainDaggerComponentsOwner,
|
||||
plugins: List<Plugin>,
|
||||
) :
|
||||
ParentNode<MainNode.RootNavTarget>(
|
||||
navModel = PermanentNavModel(
|
||||
navTargets = setOf(RootNavTarget),
|
||||
savedStateMap = buildContext.savedStateMap,
|
||||
),
|
||||
buildContext = buildContext,
|
||||
plugins = plugins,
|
||||
),
|
||||
DaggerComponentOwner by mainDaggerComponentOwner {
|
||||
|
||||
private val loggedInFlowNodeCallback = object : LoggedInFlowNode.LifecycleCallback {
|
||||
override fun onFlowCreated(identifier: String, client: MatrixClient) {
|
||||
val component = bindings<SessionComponent.ParentBindings>().sessionComponentBuilder().client(client).build()
|
||||
mainDaggerComponentOwner.addComponent(identifier, component)
|
||||
}
|
||||
|
||||
override fun onFlowReleased(identifier: String, client: MatrixClient) {
|
||||
mainDaggerComponentOwner.removeComponent(identifier)
|
||||
}
|
||||
}
|
||||
|
||||
private val roomFlowNodeCallback = object : RoomLoadedFlowNode.LifecycleCallback {
|
||||
override fun onFlowCreated(identifier: String, room: MatrixRoom) {
|
||||
val component = bindings<RoomComponent.ParentBindings>().roomComponentBuilder().room(room).build()
|
||||
mainDaggerComponentOwner.addComponent(identifier, component)
|
||||
}
|
||||
|
||||
override fun onFlowReleased(identifier: String, room: MatrixRoom) {
|
||||
mainDaggerComponentOwner.removeComponent(identifier)
|
||||
}
|
||||
}
|
||||
|
||||
override fun resolve(navTarget: RootNavTarget, buildContext: BuildContext): Node {
|
||||
return createNode<RootFlowNode>(
|
||||
context = buildContext,
|
||||
plugins = listOf(
|
||||
loggedInFlowNodeCallback,
|
||||
roomFlowNodeCallback,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun View(modifier: Modifier) {
|
||||
Children(navModel = navModel)
|
||||
}
|
||||
|
||||
fun handleIntent(intent: Intent) {
|
||||
lifecycleScope.launch {
|
||||
waitForChildAttached<RootFlowNode>().handleIntent(intent)
|
||||
}
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
object RootNavTarget : Parcelable
|
||||
}
|
||||
27
app/src/main/kotlin/io/element/android/x/di/AppBindings.kt
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.x.di
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import io.element.android.libraries.designsystem.utils.SnackbarDispatcher
|
||||
import io.element.android.libraries.di.AppScope
|
||||
|
||||
@ContributesTo(AppScope::class)
|
||||
interface AppBindings {
|
||||
fun mainDaggerComponentOwner(): MainDaggerComponentsOwner
|
||||
fun snackbarDispatcher(): SnackbarDispatcher
|
||||
}
|
||||
36
app/src/main/kotlin/io/element/android/x/di/AppComponent.kt
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.x.di
|
||||
|
||||
import android.content.Context
|
||||
import com.squareup.anvil.annotations.MergeComponent
|
||||
import dagger.BindsInstance
|
||||
import dagger.Component
|
||||
import io.element.android.libraries.architecture.NodeFactoriesBindings
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
|
||||
@SingleIn(AppScope::class)
|
||||
@MergeComponent(AppScope::class)
|
||||
interface AppComponent : NodeFactoriesBindings {
|
||||
|
||||
@Component.Factory
|
||||
interface Factory {
|
||||
fun create(@ApplicationContext @BindsInstance context: Context): AppComponent
|
||||
}
|
||||
}
|
||||
108
app/src/main/kotlin/io/element/android/x/di/AppModule.kt
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.x.di
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.content.res.Resources
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.libraries.core.meta.BuildType
|
||||
import io.element.android.libraries.designsystem.utils.SnackbarDispatcher
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.di.DefaultPreferences
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
import io.element.android.x.BuildConfig
|
||||
import io.element.android.x.R
|
||||
import kotlinx.coroutines.CoroutineName
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.plus
|
||||
import java.io.File
|
||||
|
||||
@Module
|
||||
@ContributesTo(AppScope::class)
|
||||
object AppModule {
|
||||
|
||||
@Provides
|
||||
fun providesBaseDirectory(@ApplicationContext context: Context): File {
|
||||
return File(context.filesDir, "sessions")
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun providesResources(@ApplicationContext context: Context): Resources {
|
||||
return context.resources
|
||||
}
|
||||
|
||||
@Provides
|
||||
@SingleIn(AppScope::class)
|
||||
fun providesAppCoroutineScope(): CoroutineScope {
|
||||
return MainScope() + CoroutineName("ElementX Scope")
|
||||
}
|
||||
|
||||
@Provides
|
||||
@SingleIn(AppScope::class)
|
||||
fun providesBuildType(): BuildType {
|
||||
return BuildType.valueOf(BuildConfig.BUILD_TYPE.uppercase())
|
||||
}
|
||||
|
||||
@Provides
|
||||
@SingleIn(AppScope::class)
|
||||
fun providesBuildMeta(@ApplicationContext context: Context, buildType: BuildType) = BuildMeta(
|
||||
isDebuggable = BuildConfig.DEBUG,
|
||||
buildType = buildType,
|
||||
applicationName = context.getString(R.string.app_name),
|
||||
applicationId = BuildConfig.APPLICATION_ID,
|
||||
lowPrivacyLoggingEnabled = false, // TODO EAx Config.LOW_PRIVACY_LOG_ENABLE,
|
||||
versionName = BuildConfig.VERSION_NAME,
|
||||
versionCode = BuildConfig.VERSION_CODE,
|
||||
gitRevision = "TODO", // BuildConfig.GIT_REVISION,
|
||||
gitRevisionDate = "TODO", // BuildConfig.GIT_REVISION_DATE,
|
||||
gitBranchName = "TODO", // BuildConfig.GIT_BRANCH_NAME,
|
||||
flavorDescription = "TODO", // BuildConfig.FLAVOR_DESCRIPTION,
|
||||
flavorShortDescription = "TODO", // BuildConfig.SHORT_FLAVOR_DESCRIPTION,
|
||||
)
|
||||
|
||||
@Provides
|
||||
@SingleIn(AppScope::class)
|
||||
@DefaultPreferences
|
||||
fun providesDefaultSharedPreferences(@ApplicationContext context: Context): SharedPreferences {
|
||||
return PreferenceManager.getDefaultSharedPreferences(context)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@SingleIn(AppScope::class)
|
||||
fun providesCoroutineDispatchers(): CoroutineDispatchers {
|
||||
return CoroutineDispatchers(
|
||||
io = Dispatchers.IO,
|
||||
computation = Dispatchers.Default,
|
||||
main = Dispatchers.Main,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@SingleIn(AppScope::class)
|
||||
fun provideSnackbarDispatcher(): SnackbarDispatcher {
|
||||
return SnackbarDispatcher()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.x.di
|
||||
|
||||
import android.content.Context
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.di.DaggerComponentOwner
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
import javax.inject.Inject
|
||||
|
||||
@SingleIn(AppScope::class)
|
||||
class MainDaggerComponentsOwner @Inject constructor(@ApplicationContext context: Context) : DaggerComponentOwner {
|
||||
|
||||
private val daggerComponents = LinkedHashMap<String, Any>().apply {
|
||||
put("app", (context as DaggerComponentOwner).daggerComponent)
|
||||
}
|
||||
|
||||
fun addComponent(identifier: String, component: Any) {
|
||||
daggerComponents[identifier] = component
|
||||
}
|
||||
|
||||
fun removeComponent(identifier: String) {
|
||||
daggerComponents.remove(identifier)
|
||||
}
|
||||
|
||||
/**
|
||||
* We expose the dagger components in the opposite order they arrived.
|
||||
* So we pick the most recent component when searching with the [io.element.android.libraries.architecture.bindings] methods.
|
||||
*/
|
||||
override val daggerComponent: Any
|
||||
get() = daggerComponents.values.reversed()
|
||||
}
|
||||
44
app/src/main/kotlin/io/element/android/x/di/RoomComponent.kt
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.x.di
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import com.squareup.anvil.annotations.MergeSubcomponent
|
||||
import dagger.BindsInstance
|
||||
import dagger.Subcomponent
|
||||
import io.element.android.libraries.architecture.NodeFactoriesBindings
|
||||
import io.element.android.libraries.di.RoomScope
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
|
||||
@SingleIn(RoomScope::class)
|
||||
@MergeSubcomponent(RoomScope::class)
|
||||
interface RoomComponent : NodeFactoriesBindings {
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
@BindsInstance
|
||||
fun room(room: MatrixRoom): Builder
|
||||
fun build(): RoomComponent
|
||||
}
|
||||
|
||||
@ContributesTo(SessionScope::class)
|
||||
interface ParentBindings {
|
||||
fun roomComponentBuilder(): Builder
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.x.di
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import com.squareup.anvil.annotations.MergeSubcomponent
|
||||
import dagger.BindsInstance
|
||||
import dagger.Subcomponent
|
||||
import io.element.android.libraries.architecture.NodeFactoriesBindings
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
|
||||
@SingleIn(SessionScope::class)
|
||||
@MergeSubcomponent(SessionScope::class)
|
||||
interface SessionComponent : NodeFactoriesBindings {
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
@BindsInstance
|
||||
fun client(matrixClient: MatrixClient): Builder
|
||||
fun build(): SessionComponent
|
||||
}
|
||||
|
||||
@ContributesTo(AppScope::class)
|
||||
interface ParentBindings {
|
||||
fun sessionComponentBuilder(): Builder
|
||||
}
|
||||
}
|
||||
49
app/src/main/kotlin/io/element/android/x/icon/IconPreview.kt
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.x.icon
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.x.R
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun IconPreview(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Box(modifier = modifier) {
|
||||
Image(painter = painterResource(id = R.mipmap.ic_launcher_background), contentDescription = null)
|
||||
Image(painter = painterResource(id = R.mipmap.ic_launcher_foreground), contentDescription = null)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun RoundIconPreview(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Box(modifier = modifier.clip(shape = CircleShape)) {
|
||||
Image(painter = painterResource(id = R.mipmap.ic_launcher_background), contentDescription = null)
|
||||
Image(painter = painterResource(id = R.mipmap.ic_launcher_foreground), contentDescription = null)
|
||||
}
|
||||
}
|
||||
44
app/src/main/kotlin/io/element/android/x/info/Logs.kt
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.x.info
|
||||
|
||||
import io.element.android.x.BuildConfig
|
||||
import timber.log.Timber
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
fun logApplicationInfo() {
|
||||
val appVersion = buildString {
|
||||
append(BuildConfig.VERSION_NAME)
|
||||
append(" (")
|
||||
append(BuildConfig.VERSION_CODE)
|
||||
append(") - ")
|
||||
append(BuildConfig.BUILD_TYPE)
|
||||
}
|
||||
// TODO Get SDK version somehow
|
||||
val sdkVersion = "SDK VERSION (TODO)"
|
||||
val date = SimpleDateFormat("MM-dd HH:mm:ss.SSSZ", Locale.US).format(Date())
|
||||
|
||||
Timber.d("----------------------------------------------------------------")
|
||||
Timber.d("----------------------------------------------------------------")
|
||||
Timber.d(" Application version: $appVersion")
|
||||
Timber.d(" SDK version: $sdkVersion")
|
||||
Timber.d(" Local time: $date")
|
||||
Timber.d("----------------------------------------------------------------")
|
||||
Timber.d("----------------------------------------------------------------\n\n\n\n")
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.x.initializer
|
||||
|
||||
import android.content.Context
|
||||
import androidx.startup.Initializer
|
||||
import io.element.android.features.rageshake.impl.crash.VectorUncaughtExceptionHandler
|
||||
|
||||
class CrashInitializer : Initializer<Unit> {
|
||||
|
||||
override fun create(context: Context) {
|
||||
VectorUncaughtExceptionHandler(context).activate()
|
||||
}
|
||||
|
||||
override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.x.initializer
|
||||
|
||||
import androidx.startup.Initializer
|
||||
import com.vanniktech.emoji.EmojiManager
|
||||
import com.vanniktech.emoji.google.GoogleEmojiProvider
|
||||
|
||||
class EmojiInitializer : Initializer<Unit> {
|
||||
override fun create(context: android.content.Context) {
|
||||
EmojiManager.install(GoogleEmojiProvider())
|
||||
}
|
||||
|
||||
override fun dependencies(): MutableList<Class<out Initializer<*>>> = mutableListOf()
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.x.initializer
|
||||
|
||||
import android.content.Context
|
||||
import androidx.startup.Initializer
|
||||
import io.element.android.libraries.matrix.impl.tracing.setupTracing
|
||||
import io.element.android.libraries.matrix.api.tracing.TracingConfigurations
|
||||
import io.element.android.x.BuildConfig
|
||||
|
||||
class MatrixInitializer : Initializer<Unit> {
|
||||
|
||||
override fun create(context: Context) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
setupTracing(TracingConfigurations.debug)
|
||||
} else {
|
||||
setupTracing(TracingConfigurations.release)
|
||||
}
|
||||
}
|
||||
|
||||
override fun dependencies(): List<Class<out Initializer<*>>> = listOf(TimberInitializer::class.java)
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.x.initializer
|
||||
|
||||
import android.content.Context
|
||||
import androidx.startup.Initializer
|
||||
import io.element.android.features.rageshake.impl.logs.VectorFileLogger
|
||||
import io.element.android.x.BuildConfig
|
||||
import timber.log.Timber
|
||||
|
||||
class TimberInitializer : Initializer<Unit> {
|
||||
|
||||
override fun create(context: Context) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Timber.plant(Timber.DebugTree())
|
||||
}
|
||||
Timber.plant(VectorFileLogger(context))
|
||||
}
|
||||
|
||||
override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.x.intent
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.core.net.toUri
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.deeplink.DeepLinkCreator
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.core.ThreadId
|
||||
import io.element.android.libraries.push.impl.intent.IntentProvider
|
||||
import io.element.android.x.MainActivity
|
||||
import javax.inject.Inject
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class IntentProviderImpl @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
private val deepLinkCreator: DeepLinkCreator,
|
||||
) : IntentProvider {
|
||||
override fun getViewRoomIntent(
|
||||
sessionId: SessionId,
|
||||
roomId: RoomId?,
|
||||
threadId: ThreadId?,
|
||||
): Intent {
|
||||
return Intent(context, MainActivity::class.java).apply {
|
||||
action = Intent.ACTION_VIEW
|
||||
data = deepLinkCreator.room(sessionId, roomId, threadId).toUri()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getInviteListIntent(sessionId: SessionId): Intent {
|
||||
return Intent(context, MainActivity::class.java).apply {
|
||||
action = Intent.ACTION_VIEW
|
||||
data = deepLinkCreator.inviteList(sessionId).toUri()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.x.intent
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.compose.ui.platform.UriHandler
|
||||
import io.element.android.libraries.androidutils.system.openUrlInExternalApp
|
||||
|
||||
class SafeUriHandler(private val activity: Activity) : UriHandler {
|
||||
override fun openUri(uri: String) {
|
||||
activity.openUrlInExternalApp(uri)
|
||||
}
|
||||
}
|
||||
20
app/src/main/res/drawable/transparent.xml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) 2023 New Vector Ltd
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<solid android:color="#00000000" />
|
||||
|
||||
</shape>
|
||||
6
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@mipmap/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<!-- Waiting for design monochrome android:drawable="@mipmap/ic_launcher_monochrome" /-->
|
||||
</adaptive-icon>
|
||||
6
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@mipmap/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<!-- Waiting for design monochrome android:drawable="@mipmap/ic_launcher_monochrome" /-->
|
||||
</adaptive-icon>
|
||||
BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_background.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_background.png
Normal file
|
After Width: | Height: | Size: 7 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_background.png
Normal file
|
After Width: | Height: | Size: 17 KiB |