First Commit
This commit is contained in:
928
.editorconfig
Normal file
928
.editorconfig
Normal file
@@ -0,0 +1,928 @@
|
|||||||
|
[*]
|
||||||
|
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/latest/faq/#how-do-i-enable-or-disable-a-rule
|
||||||
|
ktlint_standard_wrapping = disabled
|
||||||
|
ktlint_standard_trailing-comma-on-call-site = disabled
|
||||||
|
ktlint_standard_trailing-comma-on-declaration-site = disabled
|
||||||
|
ktlint_standard_multiline-expression-wrapping = disabled
|
||||||
|
ktlint_standard_string-template-indent = disabled
|
||||||
|
ktlint_standard_spacing-between-declarations-with-annotations = disabled
|
||||||
|
ktlint_standard_function-signature = disabled
|
||||||
|
ktlint_standard_annotation = disabled
|
||||||
|
ktlint_standard_parameter-list-wrapping = disabled
|
||||||
|
ktlint_standard_indent = disabled
|
||||||
|
ktlint_standard_blank-line-before-declaration = disabled
|
||||||
|
ktlint_function_naming_ignore_when_annotated_with = Composable
|
||||||
|
# Added when upgrading to 1.7.1
|
||||||
|
ktlint_standard_function-expression-body = disabled
|
||||||
|
ktlint_standard_chain-method-continuation = disabled
|
||||||
|
ktlint_standard_class-signature = disabled
|
||||||
|
# Added when upgrading to 1.8.0
|
||||||
|
ktlint_standard_when-entry-bracing = disabled
|
||||||
|
ktlint_standard_blank-line-between-when-conditions = disabled
|
||||||
|
ktlint_standard_mixed-condition-operators = 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
|
||||||
|
|
||||||
|
[**/generated/**]
|
||||||
|
generated_code = true
|
||||||
|
ij_formatter_enabled = false
|
||||||
|
ktlint = disabled
|
||||||
5
.gitattributes
vendored
Normal file
5
.gitattributes
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
screenshots/**/*.png filter=lfs diff=lfs merge=lfs -text
|
||||||
|
libraries/compound/screenshots/** filter=lfs diff=lfs merge=lfs -text
|
||||||
|
**/snapshots/**/*.png filter=lfs diff=lfs merge=lfs -text
|
||||||
|
**/docs/images-lfs/*.png filter=lfs diff=lfs merge=lfs -text
|
||||||
|
libraries/mediaupload/impl/src/test/assets/* filter=lfs diff=lfs merge=lfs -text
|
||||||
117
.gitignore
vendored
Normal file
117
.gitignore
vendored
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
# Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
# Please see LICENSE files in the repository root for full details.
|
||||||
|
|
||||||
|
# Built application files
|
||||||
|
*.apk
|
||||||
|
*.ap_
|
||||||
|
*.aab
|
||||||
|
|
||||||
|
# Files for the ART/Dalvik VM
|
||||||
|
*.dex
|
||||||
|
|
||||||
|
# Java class files
|
||||||
|
*.class
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
bin/
|
||||||
|
gen/
|
||||||
|
out/
|
||||||
|
# Uncomment the following line in case you need and you don't have the release build type files in your app
|
||||||
|
# release/
|
||||||
|
|
||||||
|
# Gradle files
|
||||||
|
.gradle/
|
||||||
|
build/
|
||||||
|
|
||||||
|
# Python cache
|
||||||
|
__pycache__/
|
||||||
|
|
||||||
|
# Local configuration file (sdk path, etc)
|
||||||
|
local.properties
|
||||||
|
|
||||||
|
# Proguard folder generated by Eclipse
|
||||||
|
proguard/
|
||||||
|
|
||||||
|
# Log Files
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Android Studio Navigation editor temp files
|
||||||
|
.navigation/
|
||||||
|
|
||||||
|
# Android Studio captures folder
|
||||||
|
captures/
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
*.iml
|
||||||
|
.idea/.name
|
||||||
|
.idea/androidTestResultsUserPreferences.xml
|
||||||
|
.idea/assetWizardSettings.xml
|
||||||
|
.idea/AndroidProjectSystem.xml
|
||||||
|
.idea/compiler.xml
|
||||||
|
.idea/deploymentTargetDropDown.xml
|
||||||
|
.idea/deploymentTargetSelector.xml
|
||||||
|
.idea/deviceManager.xml
|
||||||
|
.idea/gradle.xml
|
||||||
|
.idea/jarRepositories.xml
|
||||||
|
.idea/markdown.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/other.xml
|
||||||
|
.idea/runConfigurations.xml
|
||||||
|
.idea/tasks.xml
|
||||||
|
.idea/workspace.xml
|
||||||
|
.idea/libraries
|
||||||
|
# Android Studio 3 in .gitignore file.
|
||||||
|
.idea/caches
|
||||||
|
.idea/copilot
|
||||||
|
.idea/copilot.*
|
||||||
|
.idea/inspectionProfiles
|
||||||
|
# Shelved changes in the IDE
|
||||||
|
.idea/shelf
|
||||||
|
.idea/sonarlint
|
||||||
|
|
||||||
|
# .kotlin folder
|
||||||
|
.kotlin
|
||||||
|
|
||||||
|
# Keystore files
|
||||||
|
# Uncomment the following lines if you do not want to check your keystore files in.
|
||||||
|
#*.jks
|
||||||
|
#*.keystore
|
||||||
|
|
||||||
|
# External native build folder generated in Android Studio 2.2 and later
|
||||||
|
.externalNativeBuild
|
||||||
|
.cxx/
|
||||||
|
|
||||||
|
# Google Services (e.g. APIs or Firebase)
|
||||||
|
# google-services.json
|
||||||
|
|
||||||
|
# Freeline
|
||||||
|
freeline.py
|
||||||
|
freeline/
|
||||||
|
freeline_project_description.json
|
||||||
|
|
||||||
|
# fastlane
|
||||||
|
fastlane/report.xml
|
||||||
|
fastlane/Preview.html
|
||||||
|
fastlane/screenshots
|
||||||
|
fastlane/test_output
|
||||||
|
fastlane/readme.md
|
||||||
|
|
||||||
|
# Version control
|
||||||
|
vcs.xml
|
||||||
|
|
||||||
|
# lint
|
||||||
|
lint/intermediates/
|
||||||
|
lint/generated/
|
||||||
|
lint/outputs/
|
||||||
|
lint/tmp/
|
||||||
|
# lint/reports/
|
||||||
|
|
||||||
|
/tmp
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
checkouts/**
|
||||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "enterprise"]
|
||||||
|
path = enterprise
|
||||||
|
url = git@github.com:element-hq/element-android-enterprise.git
|
||||||
124
.idea/codeStyles/Project.xml
generated
Normal file
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
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/Element_Enterprise.xml
generated
Normal file
6
.idea/copyright/Element_Enterprise.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<component name="CopyrightManager">
|
||||||
|
<copyright>
|
||||||
|
<option name="notice" value="© &#36;today.year Element Creations Ltd. Element Creations Ltd, Element Software SARL, Element Software Inc., and Element Software GmbH (the "Element Group") only make this file available under a proprietary license model. Without a proprietary license with us, you cannot use this file. The terms of the proprietary license agreement between you and any member of the Element Group shall always apply to your use of this file. Unauthorised use, copying, distribution, or modification of this file, via any medium, is strictly prohibited. For details about the licensing terms, you must either visit our website or contact a member of our sales team." />
|
||||||
|
<option name="myName" value="Element Enterprise" />
|
||||||
|
</copyright>
|
||||||
|
</component>
|
||||||
6
.idea/copyright/Element_FOSS.xml
generated
Normal file
6
.idea/copyright/Element_FOSS.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<component name="CopyrightManager">
|
||||||
|
<copyright>
|
||||||
|
<option name="notice" value="Copyright (c) &#36;today.year Element Creations Ltd. SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. Please see LICENSE files in the repository root for full details." />
|
||||||
|
<option name="myName" value="Element FOSS" />
|
||||||
|
</copyright>
|
||||||
|
</component>
|
||||||
7
.idea/copyright/profiles_settings.xml
generated
Normal file
7
.idea/copyright/profiles_settings.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<component name="CopyrightManager">
|
||||||
|
<settings default="Element FOSS">
|
||||||
|
<module2copyright>
|
||||||
|
<element module="Enterprise" copyright="Element Enterprise" />
|
||||||
|
</module2copyright>
|
||||||
|
</settings>
|
||||||
|
</component>
|
||||||
27
.idea/dictionaries/shared.xml
generated
Normal file
27
.idea/dictionaries/shared.xml
generated
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<component name="ProjectDictionaryState">
|
||||||
|
<dictionary name="shared">
|
||||||
|
<words>
|
||||||
|
<w>agpl</w>
|
||||||
|
<w>backstack</w>
|
||||||
|
<w>blurhash</w>
|
||||||
|
<w>fdroid</w>
|
||||||
|
<w>ftue</w>
|
||||||
|
<w>gplay</w>
|
||||||
|
<w>homeserver</w>
|
||||||
|
<w>konsist</w>
|
||||||
|
<w>kover</w>
|
||||||
|
<w>measurables</w>
|
||||||
|
<w>onboarding</w>
|
||||||
|
<w>placeables</w>
|
||||||
|
<w>posthog</w>
|
||||||
|
<w>rageshake</w>
|
||||||
|
<w>securebackup</w>
|
||||||
|
<w>showkase</w>
|
||||||
|
<w>snackbar</w>
|
||||||
|
<w>spdx</w>
|
||||||
|
<w>swipeable</w>
|
||||||
|
<w>textfields</w>
|
||||||
|
<w>tombstoned</w>
|
||||||
|
</words>
|
||||||
|
</dictionary>
|
||||||
|
</component>
|
||||||
BIN
.idea/icon.png
generated
Normal file
BIN
.idea/icon.png
generated
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
6
.idea/kotlinc.xml
generated
Normal file
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="2.2.20" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
10
.idea/migrations.xml
generated
Normal file
10
.idea/migrations.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectMigrations">
|
||||||
|
<option name="MigrateToGradleLocalJavaHome">
|
||||||
|
<set>
|
||||||
|
<option value="$PROJECT_DIR$" />
|
||||||
|
</set>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
3
.idea/scopes/Enterprise.xml
generated
Normal file
3
.idea/scopes/Enterprise.xml
generated
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<component name="DependencyValidationManager">
|
||||||
|
<scope name="Enterprise" pattern="file://*||file[ElementX.enterprise*]:*//*" />
|
||||||
|
</component>
|
||||||
74
.maestro/README.md
Normal file
74
.maestro/README.md
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
# 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 Element X does not allow account creation, we have to use an existing account 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 joined. Note that the test will send messages to this room.*
|
||||||
|
|
||||||
|
```shell
|
||||||
|
maestro test \
|
||||||
|
-e MAESTRO_APP_ID=io.element.android.x.debug \
|
||||||
|
-e MAESTRO_USERNAME=user1 \
|
||||||
|
-e MAESTRO_PASSWORD=123 \
|
||||||
|
-e MAESTRO_RECOVERY_KEY=ABC \
|
||||||
|
-e MAESTRO_ROOM_NAME="MyRoom" \
|
||||||
|
-e MAESTRO_INVITEE1_MXID=user2 \
|
||||||
|
-e MAESTRO_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 Element X 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.
|
||||||
10
.maestro/allTests.yaml
Normal file
10
.maestro/allTests.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
appId: ${MAESTRO_APP_ID}
|
||||||
|
androidWebViewHierarchy: devtools
|
||||||
|
---
|
||||||
|
## Check that all env variables required in the whole test suite are declared (to fail faster)
|
||||||
|
- runScript: ./scripts/checkEnv.js
|
||||||
|
- runFlow: tests/init.yaml
|
||||||
|
- runFlow: tests/account/login.yaml
|
||||||
|
- runFlow: tests/settings/settings.yaml
|
||||||
|
- runFlow: tests/roomList/roomList.yaml
|
||||||
|
- runFlow: tests/account/logout.yaml
|
||||||
10
.maestro/scripts/checkEnv.js
Normal file
10
.maestro/scripts/checkEnv.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
// This array contains all the required environment variable. When adding a variable, add it here also.
|
||||||
|
// If a variable is missing, an error will occur.
|
||||||
|
|
||||||
|
if (MAESTRO_APP_ID == null) throw "Fatal: missing env variable MAESTRO_APP_ID"
|
||||||
|
if (MAESTRO_USERNAME == null) throw "Fatal: missing env variable MAESTRO_USERNAME"
|
||||||
|
if (MAESTRO_PASSWORD == null) throw "Fatal: missing env variable MAESTRO_PASSWORD"
|
||||||
|
if (MAESTRO_RECOVERY_KEY == null) throw "Fatal: missing env variable MAESTRO_RECOVERY_KEY"
|
||||||
|
if (MAESTRO_ROOM_NAME == null) throw "Fatal: missing env variable MAESTRO_ROOM_NAME"
|
||||||
|
if (MAESTRO_INVITEE1_MXID == null) throw "Fatal: missing env variable MAESTRO_INVITEE1_MXID"
|
||||||
|
if (MAESTRO_INVITEE2_MXID == null) throw "Fatal: missing env variable MAESTRO_INVITEE2_MXID"
|
||||||
21
.maestro/tests/account/changeServer.yaml
Normal file
21
.maestro/tests/account/changeServer.yaml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
appId: ${MAESTRO_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
|
||||||
|
- extendedWaitUntil:
|
||||||
|
visible: "element.io"
|
||||||
|
timeout: 10000
|
||||||
|
- tapOn: "element.io"
|
||||||
|
# Revert to matrix.org
|
||||||
|
- tapOn:
|
||||||
|
id: "login-change_server"
|
||||||
|
- tapOn: "matrix.org"
|
||||||
47
.maestro/tests/account/login.yaml
Normal file
47
.maestro/tests/account/login.yaml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
appId: ${MAESTRO_APP_ID}
|
||||||
|
---
|
||||||
|
- tapOn: "Sign in manually"
|
||||||
|
- runFlow: ../assertions/assertLoginDisplayed.yaml
|
||||||
|
- takeScreenshot: build/maestro/100-SignIn
|
||||||
|
- runFlow: changeServer.yaml
|
||||||
|
- runFlow: ../assertions/assertLoginDisplayed.yaml
|
||||||
|
- tapOn:
|
||||||
|
id: "login-continue"
|
||||||
|
## MAS page
|
||||||
|
## Conditional workflow to pass the Chrome first launch welcome page.
|
||||||
|
- runFlow:
|
||||||
|
when:
|
||||||
|
visible: 'Use without an account'
|
||||||
|
commands:
|
||||||
|
- tapOn: "Use without an account"
|
||||||
|
## For older chrome versions
|
||||||
|
- runFlow:
|
||||||
|
when:
|
||||||
|
visible: 'Accept & continue'
|
||||||
|
commands:
|
||||||
|
- tapOn: "Accept & continue"
|
||||||
|
- runFlow:
|
||||||
|
when:
|
||||||
|
visible: 'No thanks'
|
||||||
|
commands:
|
||||||
|
- tapOn: "No thanks"
|
||||||
|
## Working when running Maestro locally, but not on the CI yet.
|
||||||
|
- extendedWaitUntil:
|
||||||
|
visible:
|
||||||
|
id: "form-1"
|
||||||
|
timeout: 10000
|
||||||
|
- tapOn:
|
||||||
|
id: "form-1"
|
||||||
|
- inputText: ${MAESTRO_USERNAME}
|
||||||
|
- pressKey: Enter
|
||||||
|
- tapOn:
|
||||||
|
id: "form-3"
|
||||||
|
- inputText: ${MAESTRO_PASSWORD}
|
||||||
|
- pressKey: Enter
|
||||||
|
- tapOn: "Continue"
|
||||||
|
## Back to native world
|
||||||
|
- runFlow: ../assertions/assertSessionVerificationDisplayed.yaml
|
||||||
|
- runFlow: ./verifySession.yaml
|
||||||
|
- runFlow: ../assertions/assertAnalyticsDisplayed.yaml
|
||||||
|
- tapOn: "Not now"
|
||||||
|
- runFlow: ../assertions/assertHomeDisplayed.yaml
|
||||||
15
.maestro/tests/account/logout.yaml
Normal file
15
.maestro/tests/account/logout.yaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
appId: ${MAESTRO_APP_ID}
|
||||||
|
---
|
||||||
|
- tapOn:
|
||||||
|
id: "home_screen-settings"
|
||||||
|
- tapOn: "Sign out"
|
||||||
|
- takeScreenshot: build/maestro/900-SignOutScreen
|
||||||
|
- back
|
||||||
|
- tapOn: "Sign out"
|
||||||
|
# Ensure cancel cancels
|
||||||
|
- tapOn:
|
||||||
|
id: "dialog-negative"
|
||||||
|
- tapOn: "Sign out"
|
||||||
|
- tapOn:
|
||||||
|
id: "dialog-positive"
|
||||||
|
- runFlow: ../assertions/assertInitDisplayed.yaml
|
||||||
13
.maestro/tests/account/verifySession.yaml
Normal file
13
.maestro/tests/account/verifySession.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
appId: ${MAESTRO_APP_ID}
|
||||||
|
---
|
||||||
|
- takeScreenshot: build/maestro/150-Verify
|
||||||
|
- tapOn: "Enter recovery key"
|
||||||
|
- tapOn:
|
||||||
|
id: "verification-recovery_key"
|
||||||
|
- inputText: ${MAESTRO_RECOVERY_KEY}
|
||||||
|
- hideKeyboard
|
||||||
|
- tapOn: "Continue"
|
||||||
|
- extendedWaitUntil:
|
||||||
|
visible: "Device verified"
|
||||||
|
timeout: 30000
|
||||||
|
- tapOn: "Continue"
|
||||||
5
.maestro/tests/assertions/assertAnalyticsDisplayed.yaml
Normal file
5
.maestro/tests/assertions/assertAnalyticsDisplayed.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
appId: ${MAESTRO_APP_ID}
|
||||||
|
---
|
||||||
|
- extendedWaitUntil:
|
||||||
|
visible: "Help improve Element X dbg"
|
||||||
|
timeout: 10000
|
||||||
5
.maestro/tests/assertions/assertHomeDisplayed.yaml
Normal file
5
.maestro/tests/assertions/assertHomeDisplayed.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
appId: ${MAESTRO_APP_ID}
|
||||||
|
---
|
||||||
|
- extendedWaitUntil:
|
||||||
|
visible: "Chats"
|
||||||
|
timeout: 10000
|
||||||
5
.maestro/tests/assertions/assertInitDisplayed.yaml
Normal file
5
.maestro/tests/assertions/assertInitDisplayed.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
appId: ${MAESTRO_APP_ID}
|
||||||
|
---
|
||||||
|
- extendedWaitUntil:
|
||||||
|
visible: "Be in your element"
|
||||||
|
timeout: 10000
|
||||||
5
.maestro/tests/assertions/assertLoginDisplayed.yaml
Normal file
5
.maestro/tests/assertions/assertLoginDisplayed.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
appId: ${MAESTRO_APP_ID}
|
||||||
|
---
|
||||||
|
- extendedWaitUntil:
|
||||||
|
visible: "Change account provider"
|
||||||
|
timeout: 10000
|
||||||
5
.maestro/tests/assertions/assertRoomListSynced.yaml
Normal file
5
.maestro/tests/assertions/assertRoomListSynced.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
appId: ${MAESTRO_APP_ID}
|
||||||
|
---
|
||||||
|
- extendedWaitUntil:
|
||||||
|
visible: ${MAESTRO_ROOM_NAME}
|
||||||
|
timeout: 10000
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
appId: ${MAESTRO_APP_ID}
|
||||||
|
---
|
||||||
|
- extendedWaitUntil:
|
||||||
|
visible: "Confirm your identity"
|
||||||
|
timeout: 20000
|
||||||
7
.maestro/tests/init.yaml
Normal file
7
.maestro/tests/init.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
appId: ${MAESTRO_APP_ID}
|
||||||
|
---
|
||||||
|
- clearState
|
||||||
|
- launchApp:
|
||||||
|
clearKeychain: true
|
||||||
|
- runFlow: ./assertions/assertInitDisplayed.yaml
|
||||||
|
- takeScreenshot: build/maestro/000-FirstScreen
|
||||||
15
.maestro/tests/roomList/createAndDeleteDM.yaml
Normal file
15
.maestro/tests/roomList/createAndDeleteDM.yaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
appId: ${MAESTRO_APP_ID}
|
||||||
|
---
|
||||||
|
# Purpose: Test the creation and deletion of a DM room.
|
||||||
|
- tapOn: "Create a new conversation or room"
|
||||||
|
- tapOn: "Search for someone"
|
||||||
|
- inputText: ${MAESTRO_INVITEE1_MXID}
|
||||||
|
- tapOn:
|
||||||
|
text: ${MAESTRO_INVITEE1_MXID}
|
||||||
|
index: 1
|
||||||
|
- tapOn: "Send invite"
|
||||||
|
- takeScreenshot: build/maestro/330-createAndDeleteDM
|
||||||
|
- tapOn: "maestroelement2"
|
||||||
|
- scroll
|
||||||
|
- tapOn: "Leave room"
|
||||||
|
- tapOn: "Leave"
|
||||||
39
.maestro/tests/roomList/createAndDeleteRoom.yaml
Normal file
39
.maestro/tests/roomList/createAndDeleteRoom.yaml
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
appId: ${MAESTRO_APP_ID}
|
||||||
|
---
|
||||||
|
# Purpose: Test the creation and deletion of a room
|
||||||
|
- tapOn: "Create a new conversation or room"
|
||||||
|
- tapOn: "New room"
|
||||||
|
- tapOn: "e.g. your project name"
|
||||||
|
- inputText: "aRoomName"
|
||||||
|
- tapOn: "What is this room about?"
|
||||||
|
- inputText: "aRoomTopic"
|
||||||
|
- tapOn: "Create"
|
||||||
|
- takeScreenshot: build/maestro/320-createAndDeleteRoom
|
||||||
|
- tapOn: "Search for someone"
|
||||||
|
- inputText: ${MAESTRO_INVITEE1_MXID}
|
||||||
|
- tapOn:
|
||||||
|
text: ${MAESTRO_INVITEE1_MXID}
|
||||||
|
index: 1
|
||||||
|
- tapOn: "Finish"
|
||||||
|
- tapOn: "aRoomName"
|
||||||
|
- tapOn: "Invite"
|
||||||
|
# assert there's 1 member and 1 invitee
|
||||||
|
- tapOn: "Search for someone"
|
||||||
|
- inputText: ${MAESTRO_INVITEE2_MXID}
|
||||||
|
- tapOn:
|
||||||
|
text: ${MAESTRO_INVITEE2_MXID}
|
||||||
|
index: 1
|
||||||
|
- tapOn: "Invite"
|
||||||
|
- tapOn: "Back"
|
||||||
|
- tapOn: "aRoomName"
|
||||||
|
- scrollUntilVisible:
|
||||||
|
direction: DOWN
|
||||||
|
element:
|
||||||
|
text: "People"
|
||||||
|
- tapOn: "People"
|
||||||
|
# assert there's 1 member and 2 invitees
|
||||||
|
- tapOn: "Back"
|
||||||
|
- scroll
|
||||||
|
- scroll
|
||||||
|
- tapOn: "Leave room"
|
||||||
|
- tapOn: "Leave"
|
||||||
14
.maestro/tests/roomList/roomContextMenu.yaml
Normal file
14
.maestro/tests/roomList/roomContextMenu.yaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
appId: ${MAESTRO_APP_ID}
|
||||||
|
---
|
||||||
|
# Purpose: Test the context menu of a room in the room list
|
||||||
|
- longPressOn: ${MAESTRO_ROOM_NAME}
|
||||||
|
- takeScreenshot: build/maestro/310-RoomList-ContextMenu
|
||||||
|
- tapOn:
|
||||||
|
text: "Settings"
|
||||||
|
index: 0
|
||||||
|
- tapOn: "Back"
|
||||||
|
- longPressOn: ${MAESTRO_ROOM_NAME}
|
||||||
|
- tapOn:
|
||||||
|
text: "Leave room"
|
||||||
|
index: 0
|
||||||
|
- tapOn: "Cancel"
|
||||||
8
.maestro/tests/roomList/roomList.yaml
Normal file
8
.maestro/tests/roomList/roomList.yaml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
appId: ${MAESTRO_APP_ID}
|
||||||
|
---
|
||||||
|
- runFlow: searchRoomList.yaml
|
||||||
|
- takeScreenshot: build/maestro/300-RoomList
|
||||||
|
- runFlow: timeline/timeline.yaml
|
||||||
|
- runFlow: roomContextMenu.yaml
|
||||||
|
- runFlow: createAndDeleteRoom.yaml
|
||||||
|
- runFlow: createAndDeleteDM.yaml
|
||||||
18
.maestro/tests/roomList/searchRoomList.yaml
Normal file
18
.maestro/tests/roomList/searchRoomList.yaml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
appId: ${MAESTRO_APP_ID}
|
||||||
|
---
|
||||||
|
- runFlow: ../assertions/assertRoomListSynced.yaml
|
||||||
|
- tapOn: "search"
|
||||||
|
- inputText: ${MAESTRO_ROOM_NAME.substring(0, 3)}
|
||||||
|
- takeScreenshot: build/maestro/400-SearchRoom
|
||||||
|
- tapOn: ${MAESTRO_ROOM_NAME}
|
||||||
|
# Back from timeline to search
|
||||||
|
- back
|
||||||
|
- extendedWaitUntil:
|
||||||
|
visible: ${MAESTRO_ROOM_NAME.substring(0, 3)}
|
||||||
|
timeout: 10000
|
||||||
|
# Back to close the keyboard
|
||||||
|
- back
|
||||||
|
- waitForAnimationToEnd
|
||||||
|
# Back to close the home screen
|
||||||
|
- back
|
||||||
|
- runFlow: ../assertions/assertHomeDisplayed.yaml
|
||||||
13
.maestro/tests/roomList/timeline/call/call.yaml
Normal file
13
.maestro/tests/roomList/timeline/call/call.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
appId: ${MAESTRO_APP_ID}
|
||||||
|
---
|
||||||
|
- tapOn: "Start a call"
|
||||||
|
- takeScreenshot: build/maestro/700-Call
|
||||||
|
- extendedWaitUntil:
|
||||||
|
visible: "maestroelement"
|
||||||
|
timeout: 10000
|
||||||
|
- takeScreenshot: build/maestro/710-Call
|
||||||
|
# Hangup
|
||||||
|
- tapOn: "End call"
|
||||||
|
- extendedWaitUntil:
|
||||||
|
visible: "MyRoom"
|
||||||
|
timeout: 10000
|
||||||
7
.maestro/tests/roomList/timeline/messages/location.yaml
Normal file
7
.maestro/tests/roomList/timeline/messages/location.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
appId: ${MAESTRO_APP_ID}
|
||||||
|
---
|
||||||
|
- takeScreenshot: build/maestro/520-Timeline
|
||||||
|
- tapOn: "Add attachment"
|
||||||
|
- tapOn: "Location"
|
||||||
|
- tapOn: "Share my location"
|
||||||
|
- takeScreenshot: build/maestro/521-Timeline
|
||||||
13
.maestro/tests/roomList/timeline/messages/poll.yaml
Normal file
13
.maestro/tests/roomList/timeline/messages/poll.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
appId: ${MAESTRO_APP_ID}
|
||||||
|
---
|
||||||
|
- takeScreenshot: build/maestro/530-Timeline
|
||||||
|
- tapOn: "Add attachment"
|
||||||
|
- tapOn: "Poll"
|
||||||
|
- tapOn: "What is the poll about?"
|
||||||
|
- inputText: "I am a poll"
|
||||||
|
- tapOn: "Option 1"
|
||||||
|
- inputText: "Answer 1"
|
||||||
|
- tapOn: "Option 2"
|
||||||
|
- inputText: "Answer 2"
|
||||||
|
- tapOn: "Create"
|
||||||
|
- takeScreenshot: build/maestro/531-Timeline
|
||||||
9
.maestro/tests/roomList/timeline/messages/text.yaml
Normal file
9
.maestro/tests/roomList/timeline/messages/text.yaml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
appId: ${MAESTRO_APP_ID}
|
||||||
|
---
|
||||||
|
- takeScreenshot: build/maestro/510-Timeline
|
||||||
|
- tapOn:
|
||||||
|
id: "text_editor"
|
||||||
|
- inputText: "Hello world!"
|
||||||
|
- tapOn: "Send message"
|
||||||
|
- hideKeyboard
|
||||||
|
- takeScreenshot: build/maestro/511-Timeline
|
||||||
14
.maestro/tests/roomList/timeline/timeline.yaml
Normal file
14
.maestro/tests/roomList/timeline/timeline.yaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
appId: ${MAESTRO_APP_ID}
|
||||||
|
---
|
||||||
|
# This is the name of one room
|
||||||
|
- tapOn: ${MAESTRO_ROOM_NAME}
|
||||||
|
- takeScreenshot: build/maestro/500-Timeline
|
||||||
|
- runFlow: messages/text.yaml
|
||||||
|
- runFlow: messages/location.yaml
|
||||||
|
- runFlow: messages/poll.yaml
|
||||||
|
|
||||||
|
# Restore once the call flow is fixed
|
||||||
|
#- runFlow: call/call.yaml
|
||||||
|
|
||||||
|
- back
|
||||||
|
- runFlow: ../../assertions/assertHomeDisplayed.yaml
|
||||||
46
.maestro/tests/settings/settings.yaml
Normal file
46
.maestro/tests/settings/settings.yaml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
appId: ${MAESTRO_APP_ID}
|
||||||
|
---
|
||||||
|
- tapOn:
|
||||||
|
id: "home_screen-settings"
|
||||||
|
- assertVisible: "Settings"
|
||||||
|
- takeScreenshot: build/maestro/600-Settings
|
||||||
|
- tapOn:
|
||||||
|
text: "Analytics"
|
||||||
|
- assertVisible: "Share analytics data"
|
||||||
|
- back
|
||||||
|
|
||||||
|
- tapOn:
|
||||||
|
text: "Notifications"
|
||||||
|
- assertVisible: "Enable notifications on this device"
|
||||||
|
- back
|
||||||
|
|
||||||
|
- tapOn:
|
||||||
|
text: "Report a problem"
|
||||||
|
- assertVisible: "Report a problem"
|
||||||
|
- back
|
||||||
|
|
||||||
|
- tapOn:
|
||||||
|
text: "About"
|
||||||
|
- assertVisible: "Copyright"
|
||||||
|
- assertVisible: "Acceptable use policy"
|
||||||
|
- assertVisible: "Privacy policy"
|
||||||
|
- back
|
||||||
|
|
||||||
|
- tapOn:
|
||||||
|
text: "Screen lock"
|
||||||
|
- assertVisible: "Choose PIN"
|
||||||
|
- hideKeyboard
|
||||||
|
- back
|
||||||
|
|
||||||
|
- tapOn:
|
||||||
|
text: "Advanced settings"
|
||||||
|
- assertVisible: "View source"
|
||||||
|
- back
|
||||||
|
|
||||||
|
- tapOn:
|
||||||
|
text: "Developer options"
|
||||||
|
- assertVisible: "Feature flags"
|
||||||
|
- back
|
||||||
|
|
||||||
|
- back
|
||||||
|
- runFlow: ../assertions/assertHomeDisplayed.yaml
|
||||||
17
AUTHORS.md
Normal file
17
AUTHORS.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
A full developer contributors list can be found [here](https://github.com/element-hq/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)
|
||||||
3034
CHANGES.md
Normal file
3034
CHANGES.md
Normal file
File diff suppressed because it is too large
Load Diff
1
CODEOWNERS
Normal file
1
CODEOWNERS
Normal file
@@ -0,0 +1 @@
|
|||||||
|
* @element-hq/element-x-android-reviewers
|
||||||
195
CONTRIBUTING.md
Normal file
195
CONTRIBUTING.md
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
# Contributing to Element X Android
|
||||||
|
|
||||||
|
<!--- TOC -->
|
||||||
|
|
||||||
|
* [Developer onboarding](#developer-onboarding)
|
||||||
|
* [Contributing code to Matrix](#contributing-code-to-matrix)
|
||||||
|
* [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)
|
||||||
|
* [Element X Android Gallery](#element-x-android-gallery)
|
||||||
|
* [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)
|
||||||
|
* [detekt](#detekt)
|
||||||
|
* [ktlint](#ktlint)
|
||||||
|
* [knit](#knit)
|
||||||
|
* [lint](#lint)
|
||||||
|
* [Unit tests](#unit-tests)
|
||||||
|
* [konsist](#konsist)
|
||||||
|
* [Tests](#tests)
|
||||||
|
* [Accessibility](#accessibility)
|
||||||
|
* [Jetpack Compose](#jetpack-compose)
|
||||||
|
* [Authors](#authors)
|
||||||
|
* [Thanks](#thanks)
|
||||||
|
|
||||||
|
<!--- END -->
|
||||||
|
|
||||||
|
## Developer onboarding
|
||||||
|
|
||||||
|
For a detailed overview of the project, see [Developer Onboarding](./docs/_developer_onboarding.md).
|
||||||
|
|
||||||
|
## Contributing code to Matrix
|
||||||
|
|
||||||
|
If instead of contributing to the Element X Android project, you want to contribute to Synapse, the homeserver implementation, please read the [Synapse contribution guide](https://element-hq.github.io/synapse/latest/development/contributing_guide.html).
|
||||||
|
|
||||||
|
Element X Android support can be found in this room: [](https://matrix.to/#/#element-x-android:matrix.org).
|
||||||
|
|
||||||
|
The rest of the document contains specific rules for Matrix Android projects.
|
||||||
|
|
||||||
|
## 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`.
|
||||||
|
|
||||||
|
## Strings
|
||||||
|
|
||||||
|
The strings of the project are managed externally using [https://localazy.com](https://localazy.com) and shared with Element X 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
|
||||||
|
|
||||||
|
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 Element X (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 information can be found [in this README.md](./tools/localazy/README.md).
|
||||||
|
|
||||||
|
Once a language is sufficiently translated, it will be added to the app. The core team will decide when a language is sufficiently translated.
|
||||||
|
|
||||||
|
### Element X Android Gallery
|
||||||
|
|
||||||
|
Once added to Localazy, translations can be checked screen per screen using our tool Element X Android Gallery, available at https://element-hq.github.io/element-x-android/.
|
||||||
|
|
||||||
|
Localazy syncs occur every Monday and the screenshots on this page are generated every Tuesday, so you'll have to wait to see your change appearing on Element X Android Gallery.
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
|
The release notes are generated from the pull request titles and labels. If possible, the title must describe best what will be the user facing change.
|
||||||
|
|
||||||
|
You will also need to add a label starting by `PR-` to you Pull Request to help categorize the release note. The label should be added by the PR author, but can be added by the reviewer if the submitter does not have right to add label. Also note that the label can be added after the PR has been merged, as soon as the release is not done yet.
|
||||||
|
|
||||||
|
### Code quality
|
||||||
|
|
||||||
|
Make sure the following commands execute without any error:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
./tools/quality/check.sh
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Some separate commands can also be run, see below.
|
||||||
|
|
||||||
|
#### detekt
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
./gradlew detekt
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
#### 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>
|
||||||
|
|
||||||
|
#### konsist
|
||||||
|
|
||||||
|
[konsist](https://github.com/LemonAppDev/konsist) is setup in the project to check that the architecture and the naming rules are followed. Konsist tests are classical Unit tests.
|
||||||
|
|
||||||
|
### Tests
|
||||||
|
|
||||||
|
Element X is currently supported on Android Marshmallow (API 23+): please test your change on an Android device (or Android emulator) running with API 23. 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 an internal function annotated with `@PreviewsDayNight`, with a name suffixed by `Preview`, and having `ElementPreview` as the root composable.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```kotlin
|
||||||
|
@PreviewsDayNight
|
||||||
|
@Composable
|
||||||
|
internal fun PinIconPreview() = ElementPreview {
|
||||||
|
PinIcon()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This will allow to preview the composable in both light and dark mode in Android Studio. This will also automatically add UI tests. The GitHub action [Record screenshots](https://github.com/element-hq/element-x-android/actions/workflows/recordScreenshots.yml) has to be run to record the new screenshots. The PR reviewer can trigger this for you if you're not part of the core team.
|
||||||
|
|
||||||
|
### Authors
|
||||||
|
|
||||||
|
Feel free to add an entry in file AUTHORS.md
|
||||||
|
|
||||||
|
## Thanks
|
||||||
|
|
||||||
|
Thanks for contributing to Matrix projects!
|
||||||
661
LICENSE
Normal file
661
LICENSE
Normal file
@@ -0,0 +1,661 @@
|
|||||||
|
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 19 November 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The GNU Affero General Public License is a free, copyleft license for
|
||||||
|
software and other kinds of works, specifically designed to ensure
|
||||||
|
cooperation with the community in the case of network server software.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed
|
||||||
|
to take away your freedom to share and change the works. By contrast,
|
||||||
|
our General Public Licenses are intended to guarantee your freedom to
|
||||||
|
share and change all versions of a program--to make sure it remains free
|
||||||
|
software for all its users.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
Developers that use our General Public Licenses protect your rights
|
||||||
|
with two steps: (1) assert copyright on the software, and (2) offer
|
||||||
|
you this License which gives you legal permission to copy, distribute
|
||||||
|
and/or modify the software.
|
||||||
|
|
||||||
|
A secondary benefit of defending all users' freedom is that
|
||||||
|
improvements made in alternate versions of the program, if they
|
||||||
|
receive widespread use, become available for other developers to
|
||||||
|
incorporate. Many developers of free software are heartened and
|
||||||
|
encouraged by the resulting cooperation. However, in the case of
|
||||||
|
software used on network servers, this result may fail to come about.
|
||||||
|
The GNU General Public License permits making a modified version and
|
||||||
|
letting the public access it on a server without ever releasing its
|
||||||
|
source code to the public.
|
||||||
|
|
||||||
|
The GNU Affero General Public License is designed specifically to
|
||||||
|
ensure that, in such cases, the modified source code becomes available
|
||||||
|
to the community. It requires the operator of a network server to
|
||||||
|
provide the source code of the modified version running there to the
|
||||||
|
users of that server. Therefore, public use of a modified version, on
|
||||||
|
a publicly accessible server, gives the public access to the source
|
||||||
|
code of the modified version.
|
||||||
|
|
||||||
|
An older license, called the Affero General Public License and
|
||||||
|
published by Affero, was designed to accomplish similar goals. This is
|
||||||
|
a different license, not a version of the Affero GPL, but Affero has
|
||||||
|
released a new version of the Affero GPL which permits relicensing under
|
||||||
|
this license.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, if you modify the
|
||||||
|
Program, your modified version must prominently offer all users
|
||||||
|
interacting with it remotely through a computer network (if your version
|
||||||
|
supports such interaction) an opportunity to receive the Corresponding
|
||||||
|
Source of your version by providing access to the Corresponding Source
|
||||||
|
from a network server at no charge, through some standard or customary
|
||||||
|
means of facilitating copying of software. This Corresponding Source
|
||||||
|
shall include the Corresponding Source for any work covered by version 3
|
||||||
|
of the GNU General Public License that is incorporated pursuant to the
|
||||||
|
following paragraph.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the work with which it is combined will remain governed by version
|
||||||
|
3 of the GNU General Public License.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU Affero General Public License from time to time. Such new versions
|
||||||
|
will be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Program specifies that a certain numbered version of the GNU Affero General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU Affero General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU Affero General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
state the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If your software can interact with users remotely through a computer
|
||||||
|
network, you should also make sure that it provides a way for users to
|
||||||
|
get its source. For example, if your program is a web application, its
|
||||||
|
interface could display a "Source" link that leads users to an archive
|
||||||
|
of the code. There are many ways you could offer source, and different
|
||||||
|
solutions will be better for different programs; see section 13 for the
|
||||||
|
specific requirements.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
|
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
6
LICENSE-COMMERCIAL
Normal file
6
LICENSE-COMMERCIAL
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
Licensees holding a valid commercial license with Element may use this
|
||||||
|
software in accordance with the terms contained in a written agreement
|
||||||
|
between you and Element.
|
||||||
|
|
||||||
|
To purchase a commercial license please contact our sales team at
|
||||||
|
licensing@element.io
|
||||||
114
README.md
Normal file
114
README.md
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
[](https://github.com/element-hq/element-x-android/actions/workflows/build.yml?query=branch%3Adevelop)
|
||||||
|
[](https://sonarcloud.io/summary/new_code?id=element-x-android)
|
||||||
|
[](https://sonarcloud.io/summary/new_code?id=element-x-android)
|
||||||
|
[](https://sonarcloud.io/summary/new_code?id=element-x-android)
|
||||||
|
[](https://codecov.io/github/element-hq/element-x-android)
|
||||||
|
[](https://matrix.to/#/#element-x-android:matrix.org)
|
||||||
|
[](https://localazy.com/p/element)
|
||||||
|
|
||||||
|
# Element X Android
|
||||||
|
|
||||||
|
Element X Android is the next-generation [Matrix](https://matrix.org/) client provided by [Element](https://element.io/).
|
||||||
|
|
||||||
|
Compared to the previous-generation [Element Classic](https://github.com/element-hq/element-android), the application is a total rewrite, using the [Matrix Rust SDK](https://github.com/matrix-org/matrix-rust-sdk) underneath and targeting devices running Android 7+. The UI layer is written using [Jetpack Compose](https://developer.android.com/jetpack/compose), and the navigation is managed using [Appyx](https://github.com/bumble-tech/appyx).
|
||||||
|
|
||||||
|
[<img src="https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png" alt="Get it on Google Play" height="80">](https://play.google.com/store/apps/details?id=io.element.android.x)[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" alt="Get it on F-Droid" height="80">](https://f-droid.org/packages/io.element.android.x)
|
||||||
|
|
||||||
|
## Table of contents
|
||||||
|
|
||||||
|
<!--- TOC -->
|
||||||
|
|
||||||
|
* [Screenshots](#screenshots)
|
||||||
|
* [Translations](#translations)
|
||||||
|
* [Rust SDK](#rust-sdk)
|
||||||
|
* [Status](#status)
|
||||||
|
* [Minimum SDK version](#minimum-sdk-version)
|
||||||
|
* [Contributing](#contributing)
|
||||||
|
* [Build instructions](#build-instructions)
|
||||||
|
* [Support](#support)
|
||||||
|
* [Copyright and License](#copyright-and-license)
|
||||||
|
|
||||||
|
<!--- END -->
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|
Here are some screenshots of the application:
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Commands run before taking the screenshots:
|
||||||
|
adb shell settings put system time_12_24 24
|
||||||
|
adb shell am broadcast -a com.android.systemui.demo -e command enter
|
||||||
|
adb shell am broadcast -a com.android.systemui.demo -e command clock -e hhmm 1337
|
||||||
|
adb shell am broadcast -a com.android.systemui.demo -e command network -e mobile show -e level 4
|
||||||
|
adb shell am broadcast -a com.android.systemui.demo -e command network -e wifi show -e level 4
|
||||||
|
adb shell am broadcast -a com.android.systemui.demo -e command notifications -e visible false
|
||||||
|
adb shell am broadcast -a com.android.systemui.demo -e command battery -e plugged false -e level 100
|
||||||
|
|
||||||
|
And to exit demo mode:
|
||||||
|
adb shell am broadcast -a com.android.systemui.demo -e command exit
|
||||||
|
-->
|
||||||
|
|
||||||
|
|<img src="./docs/images-lfs/screen_1_light.png" width="280" />|<img src="./docs/images-lfs/screen_2_light.png" width="280" />|<img src="./docs/images-lfs/screen_3_light.png" width="280" />|<img src="./docs/images-lfs/screen_4_light.png" width="280" />|
|
||||||
|
|-|-|-|-|
|
||||||
|
|<img src="./docs/images-lfs/screen_1_dark.png" width="280" />|<img src="./docs/images-lfs/screen_2_dark.png" width="280" />|<img src="./docs/images-lfs/screen_3_dark.png" width="280" />|<img src="./docs/images-lfs/screen_4_dark.png" width="280" />|
|
||||||
|
|
||||||
|
## Translations
|
||||||
|
|
||||||
|
Element X Android supports many languages. You can help us to translate the app in your language by joining our [Localazy project](https://localazy.com/p/element). You can also help us to improve the existing translations.
|
||||||
|
|
||||||
|
Note that for now, we keep control on the French and German translations.
|
||||||
|
|
||||||
|
Translations can be checked screen per screen using our tool Element X Android Gallery, available at https://element-hq.github.io/element-x-android/. Note that this page is updated every Tuesday.
|
||||||
|
|
||||||
|
More instructions about translating the application can be found at [CONTRIBUTING.md](CONTRIBUTING.md#strings).
|
||||||
|
|
||||||
|
## Rust SDK
|
||||||
|
|
||||||
|
Element X 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 actively developed and supported. New users are recommended to use Element X instead of the previous-generation app.
|
||||||
|
|
||||||
|
## Minimum SDK version
|
||||||
|
|
||||||
|
Element X Android requires a minimum SDK version of 24 (Android 7.0, Nougat). We aim to support devices running Android 7.0 and above, which covers a wide range of devices still in use today.
|
||||||
|
|
||||||
|
Element Android Enterprise requires a minimum SDK version of 33 (Android 13, Tiramisu). For Element Enterprise, we support only devices that still receive security updates, which means devices running Android 13 and above. Android does not have a documented support policy, but some information can be found at [https://endoflife.date/android](https://endoflife.date/android).
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Want to get actively involved in the project? You're more than welcome! A good way to start is to check the issues that are labelled with the [good first issue](https://github.com/element-hq/element-x-android/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) label. Let us know by commenting the issue that you're starting working on it.
|
||||||
|
|
||||||
|
But first make sure to read our [contribution guide](CONTRIBUTING.md) first.
|
||||||
|
|
||||||
|
You can also come chat with the community in the Matrix [room](https://matrix.to/#/#element-x-android:matrix.org) dedicated to the project.
|
||||||
|
|
||||||
|
## Build instructions
|
||||||
|
|
||||||
|
Just clone the project and open it in Android Studio. Make sure to select the
|
||||||
|
`app` configuration when building (as we also have sample apps in the project).
|
||||||
|
|
||||||
|
To build against a local copy of the Rust SDK, see the [Developer
|
||||||
|
onboarding](docs/_developer_onboarding.md#building-the-sdk-locally) instructions.
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
When you are experiencing an issue on Element X Android, please first search in [GitHub issues](https://github.com/element-hq/element-x-android/issues)
|
||||||
|
and then in [#element-x-android:matrix.org](https://matrix.to/#/#element-x-android:matrix.org).
|
||||||
|
If after your research you still have a question, ask at [#element-x-android:matrix.org](https://matrix.to/#/#element-x-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 from the application settings. This is especially recommended when you encounter a crash.
|
||||||
|
|
||||||
|
## Copyright and License
|
||||||
|
|
||||||
|
Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
Copyright (c) 2022 - 2025 New Vector Ltd.
|
||||||
|
|
||||||
|
This software is dual licensed by Element Creations Ltd (Element). It can be used either:
|
||||||
|
|
||||||
|
(1) for free under the terms of the GNU Affero General Public License (as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version); OR
|
||||||
|
|
||||||
|
(2) under the terms of a paid-for Element Commercial License agreement between you and Element (the terms of which may vary depending on what you and Element have agreed to).
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software distributed under the Licenses is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Licenses for the specific language governing permissions and limitations under the Licenses.
|
||||||
1
annotations/.gitignore
vendored
Normal file
1
annotations/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/build
|
||||||
11
annotations/build.gradle.kts
Normal file
11
annotations/build.gradle.kts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2022-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
plugins {
|
||||||
|
alias(libs.plugins.kotlin.jvm)
|
||||||
|
id("com.android.lint")
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2023-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.annotations
|
||||||
|
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds Node to the specified component graph.
|
||||||
|
* Equivalent to the following declaration:
|
||||||
|
*
|
||||||
|
* @BindingContainer
|
||||||
|
* @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<*>,
|
||||||
|
)
|
||||||
363
app/build.gradle.kts
Normal file
363
app/build.gradle.kts
Normal file
@@ -0,0 +1,363 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2022-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("UnstableApiUsage")
|
||||||
|
|
||||||
|
import com.android.build.api.variant.FilterConfiguration.FilterType.ABI
|
||||||
|
import com.android.build.gradle.internal.tasks.factory.dependsOn
|
||||||
|
import com.android.build.gradle.tasks.GenerateBuildConfig
|
||||||
|
import com.google.firebase.appdistribution.gradle.firebaseAppDistribution
|
||||||
|
import config.BuildTimeConfig
|
||||||
|
import extension.AssetCopyTask
|
||||||
|
import extension.GitBranchNameValueSource
|
||||||
|
import extension.GitRevisionValueSource
|
||||||
|
import extension.allEnterpriseImpl
|
||||||
|
import extension.allFeaturesImpl
|
||||||
|
import extension.allLibrariesImpl
|
||||||
|
import extension.allServicesImpl
|
||||||
|
import extension.buildConfigFieldStr
|
||||||
|
import extension.koverDependencies
|
||||||
|
import extension.locales
|
||||||
|
import extension.setupDependencyInjection
|
||||||
|
import extension.setupKover
|
||||||
|
import extension.testCommonDependencies
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("io.element.android-compose-application")
|
||||||
|
alias(libs.plugins.kotlin.android)
|
||||||
|
// When using precompiled plugins, we need to apply the firebase plugin like this
|
||||||
|
id(libs.plugins.firebaseAppDistribution.get().pluginId)
|
||||||
|
alias(libs.plugins.knit)
|
||||||
|
id("kotlin-parcelize")
|
||||||
|
alias(libs.plugins.licensee)
|
||||||
|
alias(libs.plugins.kotlin.serialization)
|
||||||
|
// To be able to update the firebase.xml files, uncomment and build the project
|
||||||
|
// alias(libs.plugins.gms.google.services)
|
||||||
|
}
|
||||||
|
|
||||||
|
setupKover()
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "io.element.android.x"
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
applicationId = BuildTimeConfig.APPLICATION_ID
|
||||||
|
targetSdk = Versions.TARGET_SDK
|
||||||
|
versionCode = Versions.VERSION_CODE
|
||||||
|
versionName = Versions.VERSION_NAME
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
val buildingAppBundle = gradle.startParameter.taskNames.any { it.contains("bundle") }
|
||||||
|
|
||||||
|
// Enables building multiple APKs per ABI. This should be disabled when building an AAB.
|
||||||
|
isEnable = !buildingAppBundle
|
||||||
|
|
||||||
|
// 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()
|
||||||
|
|
||||||
|
if (!buildingAppBundle) {
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
androidResources {
|
||||||
|
localeFilters += locales
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signingConfigs {
|
||||||
|
getByName("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?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val baseAppName = BuildTimeConfig.APPLICATION_NAME
|
||||||
|
val buildType = if (isEnterpriseBuild) "Enterprise" else "FOSS"
|
||||||
|
logger.warnInBox("Building ${defaultConfig.applicationId} ($baseAppName) [$buildType]")
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
val oidcRedirectSchemeBase = BuildTimeConfig.METADATA_HOST_REVERSED ?: "io.element.android"
|
||||||
|
getByName("debug") {
|
||||||
|
resValue("string", "app_name", "$baseAppName dbg")
|
||||||
|
resValue(
|
||||||
|
"string",
|
||||||
|
"login_redirect_scheme",
|
||||||
|
"$oidcRedirectSchemeBase.debug",
|
||||||
|
)
|
||||||
|
applicationIdSuffix = ".debug"
|
||||||
|
signingConfig = signingConfigs.getByName("debug")
|
||||||
|
}
|
||||||
|
|
||||||
|
getByName("release") {
|
||||||
|
resValue("string", "app_name", baseAppName)
|
||||||
|
resValue(
|
||||||
|
"string",
|
||||||
|
"login_redirect_scheme",
|
||||||
|
oidcRedirectSchemeBase,
|
||||||
|
)
|
||||||
|
signingConfig = signingConfigs.getByName("debug")
|
||||||
|
|
||||||
|
optimization {
|
||||||
|
enable = true
|
||||||
|
keepRules {
|
||||||
|
files.add(File(projectDir, "proguard-rules.pro"))
|
||||||
|
files.add(getDefaultProguardFile("proguard-android-optimize.txt"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
register("nightly") {
|
||||||
|
val release = getByName("release")
|
||||||
|
initWith(release)
|
||||||
|
applicationIdSuffix = ".nightly"
|
||||||
|
versionNameSuffix = "-nightly"
|
||||||
|
resValue("string", "app_name", "$baseAppName nightly")
|
||||||
|
resValue(
|
||||||
|
"string",
|
||||||
|
"login_redirect_scheme",
|
||||||
|
"$oidcRedirectSchemeBase.nightly",
|
||||||
|
)
|
||||||
|
matchingFallbacks += listOf("release")
|
||||||
|
signingConfig = signingConfigs.getByName("nightly")
|
||||||
|
|
||||||
|
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/gplay/nightly/app-gplay-universal-nightly.apk"
|
||||||
|
// artifactType = "AAB"
|
||||||
|
// artifactPath = "$rootDir/app/build/outputs/bundle/nightly/app-nightly.aab"
|
||||||
|
releaseNotesFile = "tools/release/ReleaseNotesNightly.md"
|
||||||
|
groups = if (isEnterpriseBuild) {
|
||||||
|
"enterprise-testers"
|
||||||
|
} else {
|
||||||
|
"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 = if (isEnterpriseBuild) {
|
||||||
|
"1:912726360885:android:3f7e1fe644d99d5a00427c"
|
||||||
|
} else {
|
||||||
|
"1:912726360885:android:e17435e0beb0303000427c"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildFeatures {
|
||||||
|
buildConfig = true
|
||||||
|
}
|
||||||
|
flavorDimensions += "store"
|
||||||
|
productFlavors {
|
||||||
|
create("gplay") {
|
||||||
|
dimension = "store"
|
||||||
|
isDefault = true
|
||||||
|
buildConfigFieldStr("SHORT_FLAVOR_DESCRIPTION", "G")
|
||||||
|
buildConfigFieldStr("FLAVOR_DESCRIPTION", "GooglePlay")
|
||||||
|
}
|
||||||
|
create("fdroid") {
|
||||||
|
dimension = "store"
|
||||||
|
buildConfigFieldStr("SHORT_FLAVOR_DESCRIPTION", "F")
|
||||||
|
buildConfigFieldStr("FLAVOR_DESCRIPTION", "FDroid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
packaging {
|
||||||
|
resources.pickFirsts += setOf(
|
||||||
|
"META-INF/versions/9/OSGI-INF/MANIFEST.MF",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.orNull ?: 0) * 10 + abiCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val reportingExtension: ReportingExtension = project.extensions.getByType(ReportingExtension::class.java)
|
||||||
|
configureLicensesTasks(reportingExtension)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Knit
|
||||||
|
apply {
|
||||||
|
plugin("kotlinx-knit")
|
||||||
|
}
|
||||||
|
|
||||||
|
knit {
|
||||||
|
files = fileTree(project.rootDir) {
|
||||||
|
include(
|
||||||
|
"**/*.md",
|
||||||
|
"**/*.kt",
|
||||||
|
"*/*.kts",
|
||||||
|
)
|
||||||
|
exclude(
|
||||||
|
"**/build/**",
|
||||||
|
"*/.gradle/**",
|
||||||
|
"**/CHANGES.md",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setupDependencyInjection()
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
allLibrariesImpl()
|
||||||
|
allServicesImpl()
|
||||||
|
if (isEnterpriseBuild) {
|
||||||
|
allEnterpriseImpl(project)
|
||||||
|
implementation(projects.appicon.enterprise)
|
||||||
|
} else {
|
||||||
|
implementation(projects.features.enterprise.implFoss)
|
||||||
|
implementation(projects.appicon.element)
|
||||||
|
}
|
||||||
|
allFeaturesImpl(project)
|
||||||
|
implementation(projects.features.migration.api)
|
||||||
|
implementation(projects.appnav)
|
||||||
|
implementation(projects.appconfig)
|
||||||
|
implementation(projects.libraries.uiStrings)
|
||||||
|
implementation(projects.services.analytics.compose)
|
||||||
|
|
||||||
|
if (ModulesConfig.pushProvidersConfig.includeFirebase) {
|
||||||
|
"gplayImplementation"(projects.libraries.pushproviders.firebase)
|
||||||
|
}
|
||||||
|
if (ModulesConfig.pushProvidersConfig.includeUnifiedPush) {
|
||||||
|
implementation(projects.libraries.pushproviders.unifiedpush)
|
||||||
|
}
|
||||||
|
|
||||||
|
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.matrix.emojibase.bindings)
|
||||||
|
|
||||||
|
testCommonDependencies(libs)
|
||||||
|
testImplementation(projects.libraries.matrix.test)
|
||||||
|
testImplementation(projects.services.toolbox.test)
|
||||||
|
|
||||||
|
koverDependencies()
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType<GenerateBuildConfig>().configureEach {
|
||||||
|
outputs.upToDateWhen { false }
|
||||||
|
val gitRevision = providers.of(GitRevisionValueSource::class.java) {}.get()
|
||||||
|
val gitBranchName = providers.of(GitBranchNameValueSource::class.java) {}.get()
|
||||||
|
android.defaultConfig.buildConfigFieldStr("GIT_REVISION", gitRevision)
|
||||||
|
android.defaultConfig.buildConfigFieldStr("GIT_BRANCH_NAME", gitBranchName)
|
||||||
|
}
|
||||||
|
|
||||||
|
licensee {
|
||||||
|
allow("Apache-2.0")
|
||||||
|
allow("MIT")
|
||||||
|
allow("BSD-2-Clause")
|
||||||
|
allow("BSD-3-Clause")
|
||||||
|
allow("EPL-1.0")
|
||||||
|
allowUrl("https://opensource.org/licenses/MIT")
|
||||||
|
allowUrl("https://developer.android.com/studio/terms.html")
|
||||||
|
allowUrl("https://www.zetetic.net/sqlcipher/license/")
|
||||||
|
allowUrl("https://jsoup.org/license")
|
||||||
|
allowUrl("https://asm.ow2.io/license.html")
|
||||||
|
allowUrl("https://www.gnu.org/licenses/agpl-3.0.txt")
|
||||||
|
allowUrl("https://github.com/mhssn95/compose-color-picker/blob/main/LICENSE")
|
||||||
|
ignoreDependencies("com.github.matrix-org", "matrix-analytics-events")
|
||||||
|
// Ignore dependency that are not third-party licenses to us.
|
||||||
|
ignoreDependencies(groupId = "io.element.android")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Project.configureLicensesTasks(reportingExtension: ReportingExtension) {
|
||||||
|
androidComponents {
|
||||||
|
onVariants { variant ->
|
||||||
|
val capitalizedVariantName = variant.name.replaceFirstChar {
|
||||||
|
if (it.isLowerCase()) {
|
||||||
|
it.titlecase(Locale.getDefault())
|
||||||
|
} else {
|
||||||
|
it.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val artifactsFile = reportingExtension.baseDirectory.file("licensee/android$capitalizedVariantName/artifacts.json")
|
||||||
|
|
||||||
|
val copyArtifactsTask =
|
||||||
|
project.tasks.register<AssetCopyTask>("copy${capitalizedVariantName}LicenseeReportToAssets") {
|
||||||
|
inputFile.set(artifactsFile)
|
||||||
|
targetFileName.set("licensee-artifacts.json")
|
||||||
|
}
|
||||||
|
variant.sources.assets?.addGeneratedSourceDirectory(
|
||||||
|
copyArtifactsTask,
|
||||||
|
AssetCopyTask::outputDirectory,
|
||||||
|
)
|
||||||
|
copyArtifactsTask.dependsOn("licenseeAndroid$capitalizedVariantName")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
configurations.all {
|
||||||
|
resolutionStrategy {
|
||||||
|
dependencySubstitution {
|
||||||
|
val tink = libs.google.tink.get()
|
||||||
|
substitute(module("com.google.crypto.tink:tink")).using(module("${tink.group}:${tink.name}:${tink.version}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
72
app/proguard-rules.pro
vendored
Normal file
72
app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
# 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.** { *; }
|
||||||
|
|
||||||
|
# TagSoup, coming from the RTE library
|
||||||
|
-keep class org.ccil.cowan.tagsoup.** { *; }
|
||||||
|
|
||||||
|
# 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.**
|
||||||
|
|
||||||
|
# Needed for Posthog
|
||||||
|
-keepclassmembers class android.view.JavaViewSpy {
|
||||||
|
static int windowAttachCount(android.view.View);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Keep LogSessionId class and related classes (https://github.com/androidx/media/issues/2535)
|
||||||
|
-keep class android.media.metrics.LogSessionId { *; }
|
||||||
|
-keep class android.media.metrics.** { *; }
|
||||||
|
|
||||||
|
# Keep Media3 classes that use reflection (https://github.com/androidx/media/issues/2535)
|
||||||
|
-keep class androidx.media3.** { *; }
|
||||||
|
-dontwarn android.media.metrics.**
|
||||||
|
|
||||||
|
# New rules after AGP 8.13.1 upgrade
|
||||||
|
-dontwarn androidx.window.extensions.WindowExtensions
|
||||||
|
-dontwarn androidx.window.extensions.WindowExtensionsProvider
|
||||||
|
-dontwarn androidx.window.extensions.area.ExtensionWindowAreaPresentation
|
||||||
|
-dontwarn androidx.window.extensions.layout.DisplayFeature
|
||||||
|
-dontwarn androidx.window.extensions.layout.FoldingFeature
|
||||||
|
-dontwarn androidx.window.extensions.layout.WindowLayoutComponent
|
||||||
|
-dontwarn androidx.window.extensions.layout.WindowLayoutInfo
|
||||||
|
-dontwarn androidx.window.sidecar.SidecarDeviceState
|
||||||
|
-dontwarn androidx.window.sidecar.SidecarDisplayFeature
|
||||||
|
-dontwarn androidx.window.sidecar.SidecarInterface$SidecarCallback
|
||||||
|
-dontwarn androidx.window.sidecar.SidecarInterface
|
||||||
|
-dontwarn androidx.window.sidecar.SidecarProvider
|
||||||
|
-dontwarn androidx.window.sidecar.SidecarWindowLayoutInfo
|
||||||
|
|
||||||
|
# Also needed after AGP 8.13.1 upgrade, it seems like proguard is now more aggressive on removing unused code
|
||||||
|
-keep class org.matrix.rustcomponents.sdk.** { *;}
|
||||||
|
-keep class uniffi.** { *;}
|
||||||
|
-keep class io.element.android.x.di.** { *; }
|
||||||
|
-keepnames class io.element.android.x.**
|
||||||
BIN
app/signature/debug.keystore
Normal file
BIN
app/signature/debug.keystore
Normal file
Binary file not shown.
BIN
app/signature/nightly.keystore
Normal file
BIN
app/signature/nightly.keystore
Normal file
Binary file not shown.
188
app/src/main/AndroidManifest.xml
Normal file
188
app/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
|
~ Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
~ Copyright 2022 New Vector Ltd.
|
||||||
|
~
|
||||||
|
~ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
~ Please see LICENSE files in the repository root for full details.
|
||||||
|
-->
|
||||||
|
<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="false"
|
||||||
|
android:appCategory="social"
|
||||||
|
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||||
|
android:enableOnBackInvokedCallback="true"
|
||||||
|
android:fullBackupContent="@xml/backup_rules"
|
||||||
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:largeHeap="true"
|
||||||
|
android:localeConfig="@xml/locales_config"
|
||||||
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
|
android:supportsRtl="true"
|
||||||
|
android:theme="@style/Theme.ElementX"
|
||||||
|
tools:targetApi="33">
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="com.google.android.gms.car.application"
|
||||||
|
android:resource="@xml/automotive_app_desc" />
|
||||||
|
|
||||||
|
<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' />
|
||||||
|
|
||||||
|
<!-- Remove to use Application workManagerConfiguration -->
|
||||||
|
<meta-data
|
||||||
|
android:name="androidx.work.WorkManagerInitializer"
|
||||||
|
android:value="androidx.startup"
|
||||||
|
tools:node="remove" />
|
||||||
|
</provider>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Using launchMode singleTask to avoid multiple instances of the Activity
|
||||||
|
when the app is already open. This is important for incoming share (see
|
||||||
|
https://github.com/element-hq/element-x-android/issues/4074) and for opening
|
||||||
|
the application from a mobile.element.io link.
|
||||||
|
-->
|
||||||
|
<activity
|
||||||
|
android:name=".MainActivity"
|
||||||
|
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden|uiMode"
|
||||||
|
android:exported="true"
|
||||||
|
android:launchMode="singleTask"
|
||||||
|
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>
|
||||||
|
<!--
|
||||||
|
Oidc redirection
|
||||||
|
-->
|
||||||
|
<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="@string/login_redirect_scheme" />
|
||||||
|
</intent-filter>
|
||||||
|
<!--
|
||||||
|
Element web links
|
||||||
|
-->
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
|
<data android:scheme="https" />
|
||||||
|
<!-- Note: we can't use "*.element.io" here because it'll intercept the "mas.element.io" domain too. -->
|
||||||
|
<!-- Matching asset file: https://app.element.io/.well-known/assetlinks.json -->
|
||||||
|
<data android:host="app.element.io" />
|
||||||
|
<!-- Matching asset file: https://develop.element.io/.well-known/assetlinks.json -->
|
||||||
|
<data android:host="develop.element.io" />
|
||||||
|
<!-- Matching asset file: https://staging.element.io/.well-known/assetlinks.json -->
|
||||||
|
<data android:host="staging.element.io" />
|
||||||
|
</intent-filter>
|
||||||
|
<!--
|
||||||
|
Element mobile links
|
||||||
|
Example: https://mobile.element.io/element/?account_provider=example.org&login_hint=mxid:@alice:example.org
|
||||||
|
-->
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
|
<data android:scheme="https" />
|
||||||
|
<!-- Matching asset file: https://mobile.element.io/.well-known/assetlinks.json -->
|
||||||
|
<data android:host="mobile.element.io" />
|
||||||
|
<data android:path="/element/" />
|
||||||
|
</intent-filter>
|
||||||
|
<!--
|
||||||
|
matrix.to links
|
||||||
|
Note: On Android 12 and higher clicking a web link (that is not an Android App Link) always shows content in a web browser
|
||||||
|
https://developer.android.com/training/app-links#web-links
|
||||||
|
-->
|
||||||
|
<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="https" />
|
||||||
|
<data android:host="matrix.to" />
|
||||||
|
</intent-filter>
|
||||||
|
<!--
|
||||||
|
matrix: links
|
||||||
|
-->
|
||||||
|
<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="matrix" />
|
||||||
|
</intent-filter>
|
||||||
|
<!--
|
||||||
|
links from matrix.to website
|
||||||
|
-->
|
||||||
|
<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="element" />
|
||||||
|
<data android:host="user" />
|
||||||
|
<data android:host="room" />
|
||||||
|
</intent-filter>
|
||||||
|
<!-- Incoming share simple -->
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
<data android:mimeType="*/*" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.OPENABLE" />
|
||||||
|
</intent-filter>
|
||||||
|
<!-- Incoming share multiple -->
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||||
|
<data android:mimeType="*/*" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.OPENABLE" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
|
<provider
|
||||||
|
android:name="androidx.core.content.FileProvider"
|
||||||
|
android:authorities="${applicationId}.fileprovider"
|
||||||
|
android:exported="false"
|
||||||
|
android:grantUriPermissions="true">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
|
android:resource="@xml/file_providers" />
|
||||||
|
</provider>
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2022-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.x
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import androidx.startup.AppInitializer
|
||||||
|
import androidx.work.Configuration
|
||||||
|
import dev.zacsweers.metro.createGraphFactory
|
||||||
|
import io.element.android.libraries.di.DependencyInjectionGraphOwner
|
||||||
|
import io.element.android.libraries.workmanager.api.di.MetroWorkerFactory
|
||||||
|
import io.element.android.x.di.AppGraph
|
||||||
|
import io.element.android.x.info.logApplicationInfo
|
||||||
|
import io.element.android.x.initializer.CacheCleanerInitializer
|
||||||
|
import io.element.android.x.initializer.CrashInitializer
|
||||||
|
import io.element.android.x.initializer.PlatformInitializer
|
||||||
|
|
||||||
|
class ElementXApplication : Application(), DependencyInjectionGraphOwner, Configuration.Provider {
|
||||||
|
override val graph: AppGraph = createGraphFactory<AppGraph.Factory>().create(this)
|
||||||
|
|
||||||
|
override val workManagerConfiguration: Configuration = Configuration.Builder()
|
||||||
|
.setWorkerFactory(MetroWorkerFactory(graph.workerProviders))
|
||||||
|
.build()
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
AppInitializer.getInstance(this).apply {
|
||||||
|
initializeComponent(CrashInitializer::class.java)
|
||||||
|
initializeComponent(PlatformInitializer::class.java)
|
||||||
|
initializeComponent(CacheCleanerInitializer::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
logApplicationInfo(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
170
app/src/main/kotlin/io/element/android/x/MainActivity.kt
Normal file
170
app/src/main/kotlin/io/element/android/x/MainActivity.kt
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2022-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.x
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.activity.enableEdgeToEdge
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
|
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
|
import com.bumble.appyx.core.integration.NodeHost
|
||||||
|
import com.bumble.appyx.core.integrationpoint.NodeActivity
|
||||||
|
import com.bumble.appyx.core.plugin.NodeReadyObserver
|
||||||
|
import io.element.android.compound.colors.SemanticColorsLightDark
|
||||||
|
import io.element.android.compound.theme.ElementTheme
|
||||||
|
import io.element.android.features.lockscreen.api.LockScreenEntryPoint
|
||||||
|
import io.element.android.features.lockscreen.api.LockScreenLockState
|
||||||
|
import io.element.android.features.lockscreen.api.LockScreenService
|
||||||
|
import io.element.android.features.lockscreen.api.handleSecureFlag
|
||||||
|
import io.element.android.libraries.architecture.bindings
|
||||||
|
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||||
|
import io.element.android.libraries.designsystem.theme.ElementThemeApp
|
||||||
|
import io.element.android.libraries.designsystem.utils.snackbar.LocalSnackbarDispatcher
|
||||||
|
import io.element.android.services.analytics.compose.LocalAnalyticsService
|
||||||
|
import io.element.android.x.di.AppBindings
|
||||||
|
import io.element.android.x.intent.SafeUriHandler
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
private val loggerTag = LoggerTag("MainActivity")
|
||||||
|
|
||||||
|
class MainActivity : NodeActivity() {
|
||||||
|
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()
|
||||||
|
setupLockManagement(appBindings.lockScreenService(), appBindings.lockScreenEntryPoint())
|
||||||
|
enableEdgeToEdge()
|
||||||
|
setContent {
|
||||||
|
MainContent(appBindings)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun MainContent(appBindings: AppBindings) {
|
||||||
|
val migrationState = appBindings.migrationEntryPoint().present()
|
||||||
|
val colors by remember {
|
||||||
|
appBindings.enterpriseService().semanticColorsFlow(sessionId = null)
|
||||||
|
}.collectAsState(SemanticColorsLightDark.default)
|
||||||
|
ElementThemeApp(
|
||||||
|
appPreferencesStore = appBindings.preferencesStore(),
|
||||||
|
compoundLight = colors.light,
|
||||||
|
compoundDark = colors.dark,
|
||||||
|
buildMeta = appBindings.buildMeta()
|
||||||
|
) {
|
||||||
|
CompositionLocalProvider(
|
||||||
|
LocalSnackbarDispatcher provides appBindings.snackbarDispatcher(),
|
||||||
|
LocalUriHandler provides SafeUriHandler(this),
|
||||||
|
LocalAnalyticsService provides appBindings.analyticsService(),
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(ElementTheme.colors.bgCanvasDefault),
|
||||||
|
) {
|
||||||
|
if (migrationState.migrationAction.isSuccess()) {
|
||||||
|
MainNodeHost()
|
||||||
|
} else {
|
||||||
|
appBindings.migrationEntryPoint().Render(
|
||||||
|
state = migrationState,
|
||||||
|
modifier = Modifier,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun MainNodeHost() {
|
||||||
|
NodeHost(integrationPoint = appyxV1IntegrationPoint) {
|
||||||
|
MainNode(
|
||||||
|
it,
|
||||||
|
plugins = listOf(
|
||||||
|
object : NodeReadyObserver<MainNode> {
|
||||||
|
override fun init(node: MainNode) {
|
||||||
|
Timber.tag(loggerTag.value).w("onMainNodeInit")
|
||||||
|
mainNode = node
|
||||||
|
mainNode.handleIntent(intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
context = applicationContext
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupLockManagement(
|
||||||
|
lockScreenService: LockScreenService,
|
||||||
|
lockScreenEntryPoint: LockScreenEntryPoint
|
||||||
|
) {
|
||||||
|
lockScreenService.handleSecureFlag(this)
|
||||||
|
lifecycleScope.launch {
|
||||||
|
repeatOnLifecycle(Lifecycle.State.RESUMED) {
|
||||||
|
lockScreenService.lockState.collect { state ->
|
||||||
|
if (state == LockScreenLockState.Locked) {
|
||||||
|
startActivity(lockScreenEntryPoint.pinUnlockIntent(this@MainActivity))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when:
|
||||||
|
* - the launcher icon is clicked (if the app is already running);
|
||||||
|
* - a notification is clicked.
|
||||||
|
* - a deep link have been 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")
|
||||||
|
}
|
||||||
|
}
|
||||||
62
app/src/main/kotlin/io/element/android/x/MainNode.kt
Normal file
62
app/src/main/kotlin/io/element/android/x/MainNode.kt
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2023-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.x
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
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.RootFlowNode
|
||||||
|
import io.element.android.libraries.architecture.createNode
|
||||||
|
import io.element.android.libraries.di.DependencyInjectionGraphOwner
|
||||||
|
import io.element.android.libraries.di.annotations.ApplicationContext
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
class MainNode(
|
||||||
|
buildContext: BuildContext,
|
||||||
|
plugins: List<Plugin>,
|
||||||
|
@ApplicationContext context: Context,
|
||||||
|
) : ParentNode<MainNode.RootNavTarget>(
|
||||||
|
navModel = PermanentNavModel(
|
||||||
|
navTargets = setOf(RootNavTarget),
|
||||||
|
savedStateMap = buildContext.savedStateMap,
|
||||||
|
),
|
||||||
|
buildContext = buildContext,
|
||||||
|
plugins = plugins,
|
||||||
|
),
|
||||||
|
DependencyInjectionGraphOwner {
|
||||||
|
override val graph = (context as DependencyInjectionGraphOwner).graph
|
||||||
|
|
||||||
|
override fun resolve(navTarget: RootNavTarget, buildContext: BuildContext): Node {
|
||||||
|
return createNode<RootFlowNode>(buildContext = buildContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun View(modifier: Modifier) {
|
||||||
|
Children(navModel = navModel)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun handleIntent(intent: Intent) {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
waitForChildAttached<RootFlowNode>().handleIntent(intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
object RootNavTarget : Parcelable
|
||||||
|
}
|
||||||
51
app/src/main/kotlin/io/element/android/x/di/AppBindings.kt
Normal file
51
app/src/main/kotlin/io/element/android/x/di/AppBindings.kt
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2023-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.x.di
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.AppScope
|
||||||
|
import dev.zacsweers.metro.ContributesTo
|
||||||
|
import io.element.android.features.api.MigrationEntryPoint
|
||||||
|
import io.element.android.features.enterprise.api.EnterpriseService
|
||||||
|
import io.element.android.features.lockscreen.api.LockScreenEntryPoint
|
||||||
|
import io.element.android.features.lockscreen.api.LockScreenService
|
||||||
|
import io.element.android.features.rageshake.api.reporter.BugReporter
|
||||||
|
import io.element.android.libraries.core.meta.BuildMeta
|
||||||
|
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
|
||||||
|
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||||
|
import io.element.android.libraries.matrix.api.platform.InitPlatformService
|
||||||
|
import io.element.android.libraries.matrix.api.tracing.TracingService
|
||||||
|
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
|
||||||
|
import io.element.android.services.analytics.api.AnalyticsService
|
||||||
|
|
||||||
|
@ContributesTo(AppScope::class)
|
||||||
|
interface AppBindings {
|
||||||
|
fun snackbarDispatcher(): SnackbarDispatcher
|
||||||
|
|
||||||
|
fun tracingService(): TracingService
|
||||||
|
|
||||||
|
fun platformService(): InitPlatformService
|
||||||
|
|
||||||
|
fun bugReporter(): BugReporter
|
||||||
|
|
||||||
|
fun lockScreenService(): LockScreenService
|
||||||
|
|
||||||
|
fun preferencesStore(): AppPreferencesStore
|
||||||
|
|
||||||
|
fun migrationEntryPoint(): MigrationEntryPoint
|
||||||
|
|
||||||
|
fun lockScreenEntryPoint(): LockScreenEntryPoint
|
||||||
|
|
||||||
|
fun analyticsService(): AnalyticsService
|
||||||
|
|
||||||
|
fun enterpriseService(): EnterpriseService
|
||||||
|
|
||||||
|
fun featureFlagService(): FeatureFlagService
|
||||||
|
|
||||||
|
fun buildMeta(): BuildMeta
|
||||||
|
}
|
||||||
37
app/src/main/kotlin/io/element/android/x/di/AppGraph.kt
Normal file
37
app/src/main/kotlin/io/element/android/x/di/AppGraph.kt
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.x.di
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.work.ListenableWorker
|
||||||
|
import dev.zacsweers.metro.AppScope
|
||||||
|
import dev.zacsweers.metro.DependencyGraph
|
||||||
|
import dev.zacsweers.metro.Multibinds
|
||||||
|
import dev.zacsweers.metro.Provides
|
||||||
|
import io.element.android.libraries.architecture.NodeFactoriesBindings
|
||||||
|
import io.element.android.libraries.di.annotations.ApplicationContext
|
||||||
|
import io.element.android.libraries.workmanager.api.di.MetroWorkerFactory
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
@DependencyGraph(AppScope::class)
|
||||||
|
interface AppGraph : NodeFactoriesBindings {
|
||||||
|
val sessionGraphFactory: SessionGraph.Factory
|
||||||
|
|
||||||
|
@Multibinds
|
||||||
|
val workerProviders:
|
||||||
|
Map<KClass<out ListenableWorker>, MetroWorkerFactory.WorkerInstanceFactory<*>>
|
||||||
|
|
||||||
|
@DependencyGraph.Factory
|
||||||
|
interface Factory {
|
||||||
|
fun create(
|
||||||
|
@ApplicationContext @Provides
|
||||||
|
context: Context
|
||||||
|
): AppGraph
|
||||||
|
}
|
||||||
|
}
|
||||||
124
app/src/main/kotlin/io/element/android/x/di/AppModule.kt
Normal file
124
app/src/main/kotlin/io/element/android/x/di/AppModule.kt
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2023-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.x.di
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.content.res.Resources
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
|
import dev.zacsweers.metro.AppScope
|
||||||
|
import dev.zacsweers.metro.BindingContainer
|
||||||
|
import dev.zacsweers.metro.ContributesTo
|
||||||
|
import dev.zacsweers.metro.Provides
|
||||||
|
import dev.zacsweers.metro.SingleIn
|
||||||
|
import io.element.android.appconfig.ApplicationConfig
|
||||||
|
import io.element.android.features.enterprise.api.EnterpriseService
|
||||||
|
import io.element.android.libraries.androidutils.system.getVersionCodeFromManifest
|
||||||
|
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.snackbar.SnackbarDispatcher
|
||||||
|
import io.element.android.libraries.di.BaseDirectory
|
||||||
|
import io.element.android.libraries.di.CacheDirectory
|
||||||
|
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
||||||
|
import io.element.android.libraries.di.annotations.ApplicationContext
|
||||||
|
import io.element.android.libraries.recentemojis.api.EmojibaseProvider
|
||||||
|
import io.element.android.libraries.recentemojis.impl.DefaultEmojibaseProvider
|
||||||
|
import io.element.android.x.BuildConfig
|
||||||
|
import io.element.android.x.R
|
||||||
|
import kotlinx.coroutines.CoroutineName
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.MainScope
|
||||||
|
import kotlinx.coroutines.plus
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
@BindingContainer
|
||||||
|
@ContributesTo(AppScope::class)
|
||||||
|
object AppModule {
|
||||||
|
@Provides
|
||||||
|
@BaseDirectory
|
||||||
|
fun providesBaseDirectory(@ApplicationContext context: Context): File {
|
||||||
|
return File(context.filesDir, "sessions")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@CacheDirectory
|
||||||
|
fun providesCacheDirectory(@ApplicationContext context: Context): File {
|
||||||
|
return context.cacheDir
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
fun providesResources(@ApplicationContext context: Context): Resources {
|
||||||
|
return context.resources
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@AppCoroutineScope
|
||||||
|
@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,
|
||||||
|
enterpriseService: EnterpriseService,
|
||||||
|
): BuildMeta {
|
||||||
|
val applicationName = ApplicationConfig.APPLICATION_NAME.takeIf { it.isNotEmpty() } ?: context.getString(R.string.app_name)
|
||||||
|
return BuildMeta(
|
||||||
|
isDebuggable = BuildConfig.DEBUG,
|
||||||
|
buildType = buildType,
|
||||||
|
applicationName = applicationName,
|
||||||
|
productionApplicationName = if (enterpriseService.isEnterpriseBuild) applicationName else ApplicationConfig.PRODUCTION_APPLICATION_NAME,
|
||||||
|
desktopApplicationName = if (enterpriseService.isEnterpriseBuild) applicationName else ApplicationConfig.DESKTOP_APPLICATION_NAME,
|
||||||
|
applicationId = BuildConfig.APPLICATION_ID,
|
||||||
|
isEnterpriseBuild = enterpriseService.isEnterpriseBuild,
|
||||||
|
// TODO EAx Config.LOW_PRIVACY_LOG_ENABLE,
|
||||||
|
lowPrivacyLoggingEnabled = false,
|
||||||
|
versionName = BuildConfig.VERSION_NAME,
|
||||||
|
versionCode = context.getVersionCodeFromManifest(),
|
||||||
|
gitRevision = BuildConfig.GIT_REVISION,
|
||||||
|
gitBranchName = BuildConfig.GIT_BRANCH_NAME,
|
||||||
|
flavorDescription = BuildConfig.FLAVOR_DESCRIPTION,
|
||||||
|
flavorShortDescription = BuildConfig.SHORT_FLAVOR_DESCRIPTION,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@SingleIn(AppScope::class)
|
||||||
|
fun providesSharedPreferences(@ApplicationContext context: Context): SharedPreferences {
|
||||||
|
return PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@SingleIn(AppScope::class)
|
||||||
|
fun providesCoroutineDispatchers(): CoroutineDispatchers {
|
||||||
|
return CoroutineDispatchers.Default
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@SingleIn(AppScope::class)
|
||||||
|
fun provideSnackbarDispatcher(): SnackbarDispatcher {
|
||||||
|
return SnackbarDispatcher()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@SingleIn(AppScope::class)
|
||||||
|
fun providesEmojibaseProvider(@ApplicationContext context: Context): EmojibaseProvider {
|
||||||
|
return DefaultEmojibaseProvider(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2023-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.x.di
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.ContributesBinding
|
||||||
|
import io.element.android.appnav.di.RoomGraphFactory
|
||||||
|
import io.element.android.libraries.di.SessionScope
|
||||||
|
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
|
|
||||||
|
@ContributesBinding(SessionScope::class)
|
||||||
|
class DefaultRoomGraphFactory(
|
||||||
|
private val sessionGraph: SessionGraph,
|
||||||
|
) : RoomGraphFactory {
|
||||||
|
override fun create(room: JoinedRoom): Any {
|
||||||
|
return sessionGraph.roomGraphFactory
|
||||||
|
.create(room, room)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2023-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.x.di
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.AppScope
|
||||||
|
import dev.zacsweers.metro.ContributesBinding
|
||||||
|
import io.element.android.appnav.di.SessionGraphFactory
|
||||||
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
|
|
||||||
|
@ContributesBinding(AppScope::class)
|
||||||
|
class DefaultSessionGraphFactory(
|
||||||
|
private val appGraph: AppGraph
|
||||||
|
) : SessionGraphFactory {
|
||||||
|
override fun create(client: MatrixClient): Any {
|
||||||
|
return appGraph.sessionGraphFactory.create(client)
|
||||||
|
}
|
||||||
|
}
|
||||||
28
app/src/main/kotlin/io/element/android/x/di/RoomGraph.kt
Normal file
28
app/src/main/kotlin/io/element/android/x/di/RoomGraph.kt
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.x.di
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.GraphExtension
|
||||||
|
import dev.zacsweers.metro.Provides
|
||||||
|
import io.element.android.appnav.di.TimelineBindings
|
||||||
|
import io.element.android.libraries.architecture.NodeFactoriesBindings
|
||||||
|
import io.element.android.libraries.di.RoomScope
|
||||||
|
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||||
|
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
|
|
||||||
|
@GraphExtension(RoomScope::class)
|
||||||
|
interface RoomGraph : NodeFactoriesBindings, TimelineBindings {
|
||||||
|
@GraphExtension.Factory
|
||||||
|
interface Factory {
|
||||||
|
fun create(
|
||||||
|
@Provides joinedRoom: JoinedRoom,
|
||||||
|
@Provides baseRoom: BaseRoom
|
||||||
|
): RoomGraph
|
||||||
|
}
|
||||||
|
}
|
||||||
25
app/src/main/kotlin/io/element/android/x/di/SessionGraph.kt
Normal file
25
app/src/main/kotlin/io/element/android/x/di/SessionGraph.kt
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.x.di
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.GraphExtension
|
||||||
|
import dev.zacsweers.metro.Provides
|
||||||
|
import io.element.android.libraries.architecture.NodeFactoriesBindings
|
||||||
|
import io.element.android.libraries.di.SessionScope
|
||||||
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
|
|
||||||
|
@GraphExtension(SessionScope::class)
|
||||||
|
interface SessionGraph : NodeFactoriesBindings {
|
||||||
|
val roomGraphFactory: RoomGraph.Factory
|
||||||
|
|
||||||
|
@GraphExtension.Factory
|
||||||
|
interface Factory {
|
||||||
|
fun create(@Provides matrixClient: MatrixClient): SessionGraph
|
||||||
|
}
|
||||||
|
}
|
||||||
41
app/src/main/kotlin/io/element/android/x/info/Logs.kt
Normal file
41
app/src/main/kotlin/io/element/android/x/info/Logs.kt
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2023-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.x.info
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import io.element.android.libraries.androidutils.system.getVersionCodeFromManifest
|
||||||
|
import io.element.android.x.BuildConfig
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Date
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
fun logApplicationInfo(context: Context) {
|
||||||
|
val appVersion = buildString {
|
||||||
|
append(BuildConfig.VERSION_NAME)
|
||||||
|
append(" (")
|
||||||
|
append(context.getVersionCodeFromManifest())
|
||||||
|
append(") - ")
|
||||||
|
append(BuildConfig.BUILD_TYPE)
|
||||||
|
append(" / ")
|
||||||
|
append(BuildConfig.FLAVOR)
|
||||||
|
}
|
||||||
|
// 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(" Git SHA: ${BuildConfig.GIT_REVISION}")
|
||||||
|
Timber.d(" SDK version: $sdkVersion")
|
||||||
|
Timber.d(" Local time: $date")
|
||||||
|
Timber.d("----------------------------------------------------------------")
|
||||||
|
Timber.d("----------------------------------------------------------------\n\n\n\n")
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2022-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.x.initializer
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.startup.Initializer
|
||||||
|
import io.element.android.features.cachecleaner.impl.CacheCleanerBindings
|
||||||
|
import io.element.android.libraries.architecture.bindings
|
||||||
|
|
||||||
|
class CacheCleanerInitializer : Initializer<Unit> {
|
||||||
|
override fun create(context: Context) {
|
||||||
|
context.bindings<CacheCleanerBindings>().cacheCleaner().clearCache()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2022-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.x.initializer
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.startup.Initializer
|
||||||
|
import io.element.android.features.rageshake.impl.crash.VectorUncaughtExceptionHandler
|
||||||
|
import io.element.android.features.rageshake.impl.di.RageshakeBindings
|
||||||
|
import io.element.android.libraries.architecture.bindings
|
||||||
|
|
||||||
|
class CrashInitializer : Initializer<Unit> {
|
||||||
|
override fun create(context: Context) {
|
||||||
|
VectorUncaughtExceptionHandler(
|
||||||
|
context.bindings<RageshakeBindings>().preferencesCrashDataStore(),
|
||||||
|
).activate()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2022-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.x.initializer
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.system.Os
|
||||||
|
import androidx.startup.Initializer
|
||||||
|
import io.element.android.features.rageshake.api.logs.createWriteToFilesConfiguration
|
||||||
|
import io.element.android.libraries.architecture.bindings
|
||||||
|
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||||
|
import io.element.android.libraries.matrix.api.tracing.TracingConfiguration
|
||||||
|
import io.element.android.x.di.AppBindings
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
private const val ELEMENT_X_TARGET = "elementx"
|
||||||
|
|
||||||
|
class PlatformInitializer : Initializer<Unit> {
|
||||||
|
override fun create(context: Context) {
|
||||||
|
val appBindings = context.bindings<AppBindings>()
|
||||||
|
val tracingService = appBindings.tracingService()
|
||||||
|
val platformService = appBindings.platformService()
|
||||||
|
val bugReporter = appBindings.bugReporter()
|
||||||
|
Timber.plant(tracingService.createTimberTree(ELEMENT_X_TARGET))
|
||||||
|
val preferencesStore = appBindings.preferencesStore()
|
||||||
|
val featureFlagService = appBindings.featureFlagService()
|
||||||
|
val logLevel = runBlocking { preferencesStore.getTracingLogLevelFlow().first() }
|
||||||
|
val tracingConfiguration = TracingConfiguration(
|
||||||
|
writesToLogcat = runBlocking { featureFlagService.isFeatureEnabled(FeatureFlags.PrintLogsToLogcat) },
|
||||||
|
writesToFilesConfiguration = bugReporter.createWriteToFilesConfiguration(),
|
||||||
|
logLevel = logLevel,
|
||||||
|
extraTargets = listOf(ELEMENT_X_TARGET),
|
||||||
|
traceLogPacks = runBlocking { preferencesStore.getTracingLogPacksFlow().first() },
|
||||||
|
)
|
||||||
|
bugReporter.setCurrentTracingLogLevel(logLevel.name)
|
||||||
|
platformService.init(tracingConfiguration)
|
||||||
|
// Also set env variable for rust back trace
|
||||||
|
Os.setenv("RUST_BACKTRACE", "1", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dependencies(): List<Class<out Initializer<*>>> = mutableListOf()
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2023-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.x.intent
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
import dev.zacsweers.metro.AppScope
|
||||||
|
import dev.zacsweers.metro.ContributesBinding
|
||||||
|
import io.element.android.libraries.deeplink.api.DeepLinkCreator
|
||||||
|
import io.element.android.libraries.di.annotations.ApplicationContext
|
||||||
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
|
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
|
||||||
|
|
||||||
|
@ContributesBinding(AppScope::class)
|
||||||
|
class DefaultIntentProvider(
|
||||||
|
@ApplicationContext private val context: Context,
|
||||||
|
private val deepLinkCreator: DeepLinkCreator,
|
||||||
|
) : IntentProvider {
|
||||||
|
override fun getViewRoomIntent(
|
||||||
|
sessionId: SessionId,
|
||||||
|
roomId: RoomId?,
|
||||||
|
threadId: ThreadId?,
|
||||||
|
eventId: EventId?,
|
||||||
|
extras: Bundle?,
|
||||||
|
): Intent {
|
||||||
|
return Intent(context, MainActivity::class.java).apply {
|
||||||
|
action = Intent.ACTION_VIEW
|
||||||
|
data = deepLinkCreator.create(sessionId, roomId, threadId, eventId).toUri()
|
||||||
|
extras?.let(::putExtras)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2023-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.x.oidc
|
||||||
|
|
||||||
|
import dev.zacsweers.metro.AppScope
|
||||||
|
import dev.zacsweers.metro.ContributesBinding
|
||||||
|
import io.element.android.libraries.matrix.api.auth.OidcRedirectUrlProvider
|
||||||
|
import io.element.android.services.toolbox.api.strings.StringProvider
|
||||||
|
import io.element.android.x.R
|
||||||
|
|
||||||
|
@ContributesBinding(AppScope::class)
|
||||||
|
class DefaultOidcRedirectUrlProvider(
|
||||||
|
private val stringProvider: StringProvider,
|
||||||
|
) : OidcRedirectUrlProvider {
|
||||||
|
override fun provide() = buildString {
|
||||||
|
append(stringProvider.getString(R.string.login_redirect_scheme))
|
||||||
|
append(":/")
|
||||||
|
}
|
||||||
|
}
|
||||||
12
app/src/main/res/drawable/transparent.xml
Normal file
12
app/src/main/res/drawable/transparent.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
|
~ Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
~ Copyright 2023 New Vector Ltd.
|
||||||
|
~
|
||||||
|
~ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
~ Please see LICENSE files in the repository root for full details.
|
||||||
|
-->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<solid android:color="#00000000" />
|
||||||
|
|
||||||
|
</shape>
|
||||||
7
app/src/main/res/resources.properties
Normal file
7
app/src/main/res/resources.properties
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
# Copyright 2024 New Vector Ltd.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
# Please see LICENSE files in the repository root for full details.
|
||||||
|
|
||||||
|
unqualifiedResLocale=en
|
||||||
17
app/src/main/res/values-night/themes.xml
Normal file
17
app/src/main/res/values-night/themes.xml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
|
~ Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
~ Copyright 2023 New Vector Ltd.
|
||||||
|
~
|
||||||
|
~ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
~ Please see LICENSE files in the repository root for full details.
|
||||||
|
-->
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<style name="Theme.ElementX.Splash" parent="Theme.SplashScreen">
|
||||||
|
<item name="windowSplashScreenBackground">@color/splashscreen_bg_dark</item>
|
||||||
|
<item name="windowSplashScreenAnimatedIcon">@drawable/transparent</item>
|
||||||
|
<item name="postSplashScreenTheme">@style/Theme.ElementX</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="Theme.ElementX" parent="Theme.Material3.Dark.NoActionBar" />
|
||||||
|
</resources>
|
||||||
13
app/src/main/res/values/colors.xml
Normal file
13
app/src/main/res/values/colors.xml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
|
~ Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
~ Copyright 2022 New Vector Ltd.
|
||||||
|
~
|
||||||
|
~ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
~ Please see LICENSE files in the repository root for full details.
|
||||||
|
-->
|
||||||
|
<resources>
|
||||||
|
<!-- Must be equal to DarkColorTokens.colorThemeBg -->
|
||||||
|
<color name="splashscreen_bg_dark">#FF101317</color>
|
||||||
|
<!-- Must be equal to LightColorTokens.colorThemeBg -->
|
||||||
|
<color name="splashscreen_bg_light">#FFFFFFFF</color>
|
||||||
|
</resources>
|
||||||
17
app/src/main/res/values/themes.xml
Normal file
17
app/src/main/res/values/themes.xml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
|
~ Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
~ Copyright 2022 New Vector Ltd.
|
||||||
|
~
|
||||||
|
~ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
~ Please see LICENSE files in the repository root for full details.
|
||||||
|
-->
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
<style name="Theme.ElementX.Splash" parent="Theme.SplashScreen">
|
||||||
|
<item name="windowSplashScreenBackground">@color/splashscreen_bg_light</item>
|
||||||
|
<item name="windowSplashScreenAnimatedIcon">@drawable/transparent</item>
|
||||||
|
<item name="postSplashScreenTheme">@style/Theme.ElementX</item>
|
||||||
|
</style>
|
||||||
|
<style name="Theme.ElementX" parent="Theme.Material3.Light.NoActionBar">
|
||||||
|
<item name="android:forceDarkAllowed" tools:targetApi="q">false</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
||||||
10
app/src/main/res/xml/automotive_app_desc.xml
Normal file
10
app/src/main/res/xml/automotive_app_desc.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
|
~ Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
~ Copyright 2025 New Vector Ltd.
|
||||||
|
~
|
||||||
|
~ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
~ Please see LICENSE files in the repository root for full details.
|
||||||
|
-->
|
||||||
|
<automotiveApp>
|
||||||
|
<uses name="notification" />
|
||||||
|
</automotiveApp>
|
||||||
17
app/src/main/res/xml/backup_rules.xml
Normal file
17
app/src/main/res/xml/backup_rules.xml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
|
~ Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
~ Copyright 2022 New Vector Ltd.
|
||||||
|
~
|
||||||
|
~ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
~ Please see LICENSE files in the repository root for full details.
|
||||||
|
-->
|
||||||
|
<!--
|
||||||
|
All backup is disabled since it would clash with encryption.
|
||||||
|
-->
|
||||||
|
<full-backup-content>
|
||||||
|
<exclude domain="root" path="." />
|
||||||
|
<exclude domain="file" path="." />
|
||||||
|
<exclude domain="database" path="." />
|
||||||
|
<exclude domain="sharedpref" path="." />
|
||||||
|
<exclude domain="external" path="."/>
|
||||||
|
</full-backup-content>
|
||||||
27
app/src/main/res/xml/data_extraction_rules.xml
Normal file
27
app/src/main/res/xml/data_extraction_rules.xml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
|
~ Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
~ Copyright 2023 New Vector Ltd.
|
||||||
|
~
|
||||||
|
~ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
~ Please see LICENSE files in the repository root for full details.
|
||||||
|
-->
|
||||||
|
<!--
|
||||||
|
All backup is disabled since it would clash with encryption.
|
||||||
|
-->
|
||||||
|
<data-extraction-rules>
|
||||||
|
<cloud-backup>
|
||||||
|
<exclude domain="root" path="."/>
|
||||||
|
<exclude domain="file" path="."/>
|
||||||
|
<exclude domain="database" path="."/>
|
||||||
|
<exclude domain="sharedpref" path="."/>
|
||||||
|
<exclude domain="external" path="."/>
|
||||||
|
</cloud-backup>
|
||||||
|
|
||||||
|
<device-transfer>
|
||||||
|
<exclude domain="root" path="."/>
|
||||||
|
<exclude domain="file" path="."/>
|
||||||
|
<exclude domain="database" path="."/>
|
||||||
|
<exclude domain="sharedpref" path="."/>
|
||||||
|
<exclude domain="external" path="."/>
|
||||||
|
</device-transfer>
|
||||||
|
</data-extraction-rules>
|
||||||
10
app/src/main/res/xml/file_providers.xml
Normal file
10
app/src/main/res/xml/file_providers.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
|
~ Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
~ Copyright 2023 New Vector Ltd.
|
||||||
|
~
|
||||||
|
~ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
~ Please see LICENSE files in the repository root for full details.
|
||||||
|
-->
|
||||||
|
<paths>
|
||||||
|
<cache-path name="cache" path="." />
|
||||||
|
</paths>
|
||||||
39
app/src/main/res/xml/locales_config.xml
Normal file
39
app/src/main/res/xml/locales_config.xml
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<!-- File generated by importSupportedLocalesFromLocalazy.py, do not edit -->
|
||||||
|
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<locale android:name="be"/>
|
||||||
|
<locale android:name="bg"/>
|
||||||
|
<locale android:name="cs"/>
|
||||||
|
<locale android:name="cy"/>
|
||||||
|
<locale android:name="da"/>
|
||||||
|
<locale android:name="de"/>
|
||||||
|
<locale android:name="el"/>
|
||||||
|
<locale android:name="en"/>
|
||||||
|
<locale android:name="en_US"/>
|
||||||
|
<locale android:name="es"/>
|
||||||
|
<locale android:name="et"/>
|
||||||
|
<locale android:name="eu"/>
|
||||||
|
<locale android:name="fa"/>
|
||||||
|
<locale android:name="fi"/>
|
||||||
|
<locale android:name="fr"/>
|
||||||
|
<locale android:name="hu"/>
|
||||||
|
<locale android:name="in"/>
|
||||||
|
<locale android:name="it"/>
|
||||||
|
<locale android:name="ka"/>
|
||||||
|
<locale android:name="ko"/>
|
||||||
|
<locale android:name="lt"/>
|
||||||
|
<locale android:name="nb"/>
|
||||||
|
<locale android:name="nl"/>
|
||||||
|
<locale android:name="pl"/>
|
||||||
|
<locale android:name="pt"/>
|
||||||
|
<locale android:name="pt_BR"/>
|
||||||
|
<locale android:name="ro"/>
|
||||||
|
<locale android:name="ru"/>
|
||||||
|
<locale android:name="sk"/>
|
||||||
|
<locale android:name="sv"/>
|
||||||
|
<locale android:name="tr"/>
|
||||||
|
<locale android:name="uk"/>
|
||||||
|
<locale android:name="ur"/>
|
||||||
|
<locale android:name="uz"/>
|
||||||
|
<locale android:name="zh-CN"/>
|
||||||
|
<locale android:name="zh-TW"/>
|
||||||
|
</locale-config>
|
||||||
34
app/src/main/res/xml/network_security_config.xml
Normal file
34
app/src/main/res/xml/network_security_config.xml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<network-security-config xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
<!-- Ref: https://developer.android.com/training/articles/security-config.html -->
|
||||||
|
<!-- By default, do not allow clearText traffic -->
|
||||||
|
<base-config cleartextTrafficPermitted="false">
|
||||||
|
<trust-anchors>
|
||||||
|
<certificates src="system" />
|
||||||
|
<certificates
|
||||||
|
src="user"
|
||||||
|
tools:ignore="AcceptsUserCertificates" />
|
||||||
|
</trust-anchors>
|
||||||
|
</base-config>
|
||||||
|
|
||||||
|
<!-- Allow clearText traffic on some specified host -->
|
||||||
|
<domain-config cleartextTrafficPermitted="true">
|
||||||
|
<!-- Localhost -->
|
||||||
|
<domain includeSubdomains="true">localhost</domain>
|
||||||
|
<domain includeSubdomains="true">127.0.0.1</domain>
|
||||||
|
<!-- Localhost for Android emulator -->
|
||||||
|
<domain includeSubdomains="true">10.0.2.2</domain>
|
||||||
|
<!-- Onion services -->
|
||||||
|
<domain includeSubdomains="true">onion</domain>
|
||||||
|
|
||||||
|
<!-- Domains that are used for LANs -->
|
||||||
|
<!-- These are IANA recognized special use domain names, see https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml -->
|
||||||
|
<domain includeSubdomains="true">home.arpa</domain>
|
||||||
|
<domain includeSubdomains="true">local</domain> <!-- Note this has been reserved for use with mDNS -->
|
||||||
|
<domain includeSubdomains="true">test</domain>
|
||||||
|
<!-- These are observed in the wild either by convention or RFCs that have not been accepted, and are not currently TLDs -->
|
||||||
|
<domain includeSubdomains="true">home</domain>
|
||||||
|
<domain includeSubdomains="true">lan</domain>
|
||||||
|
<domain includeSubdomains="true">localdomain</domain>
|
||||||
|
</domain-config>
|
||||||
|
</network-security-config>
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2023-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("SameParameterValue")
|
||||||
|
|
||||||
|
package io.element.android.x.intent
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import io.element.android.libraries.deeplink.api.DeepLinkCreator
|
||||||
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
|
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.matrix.test.AN_EVENT_ID
|
||||||
|
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||||
|
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||||
|
import io.element.android.libraries.matrix.test.A_THREAD_ID
|
||||||
|
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
|
import io.element.android.tests.testutils.lambda.value
|
||||||
|
import io.element.android.x.MainActivity
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.robolectric.RobolectricTestRunner
|
||||||
|
import org.robolectric.RuntimeEnvironment
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner::class)
|
||||||
|
class DefaultIntentProviderTest {
|
||||||
|
@Test
|
||||||
|
fun `test getViewRoomIntent with data`() {
|
||||||
|
val deepLinkCreator = lambdaRecorder<SessionId, RoomId?, ThreadId?, EventId?, String> { _, _, _, _ -> "deepLinkCreatorResult" }
|
||||||
|
val sut = createDefaultIntentProvider(
|
||||||
|
deepLinkCreator = { sessionId, roomId, threadId, eventId -> deepLinkCreator.invoke(sessionId, roomId, threadId, eventId) },
|
||||||
|
)
|
||||||
|
val result = sut.getViewRoomIntent(
|
||||||
|
sessionId = A_SESSION_ID,
|
||||||
|
roomId = A_ROOM_ID,
|
||||||
|
threadId = A_THREAD_ID,
|
||||||
|
eventId = AN_EVENT_ID,
|
||||||
|
)
|
||||||
|
result.commonAssertions()
|
||||||
|
assertThat(result.data.toString()).isEqualTo("deepLinkCreatorResult")
|
||||||
|
deepLinkCreator.assertions().isCalledOnce().with(
|
||||||
|
value(A_SESSION_ID),
|
||||||
|
value(A_ROOM_ID),
|
||||||
|
value(A_THREAD_ID),
|
||||||
|
value(AN_EVENT_ID),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createDefaultIntentProvider(
|
||||||
|
deepLinkCreator: DeepLinkCreator = DeepLinkCreator { _, _, _, _ -> "" },
|
||||||
|
): DefaultIntentProvider {
|
||||||
|
return DefaultIntentProvider(
|
||||||
|
context = RuntimeEnvironment.getApplication() as Context,
|
||||||
|
deepLinkCreator = deepLinkCreator,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Intent.commonAssertions() {
|
||||||
|
assertThat(action).isEqualTo(Intent.ACTION_VIEW)
|
||||||
|
assertThat(component?.className).isEqualTo(MainActivity::class.java.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.x.oidc
|
||||||
|
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import io.element.android.services.toolbox.test.strings.FakeStringProvider
|
||||||
|
import io.element.android.x.R
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class DefaultOidcRedirectUrlProviderTest {
|
||||||
|
@Test
|
||||||
|
fun `test provide`() {
|
||||||
|
val stringProvider = FakeStringProvider(
|
||||||
|
defaultResult = "str"
|
||||||
|
)
|
||||||
|
val sut = DefaultOidcRedirectUrlProvider(
|
||||||
|
stringProvider = stringProvider,
|
||||||
|
)
|
||||||
|
val result = sut.provide()
|
||||||
|
assertThat(result).isEqualTo("str:/")
|
||||||
|
assertThat(stringProvider.lastResIdParam).isEqualTo(R.string.login_redirect_scheme)
|
||||||
|
}
|
||||||
|
}
|
||||||
53
appconfig/build.gradle.kts
Normal file
53
appconfig/build.gradle.kts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import config.BuildTimeConfig
|
||||||
|
import extension.buildConfigFieldStr
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2022-2024 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
plugins {
|
||||||
|
id("io.element.android-library")
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "io.element.android.appconfig"
|
||||||
|
|
||||||
|
buildFeatures {
|
||||||
|
buildConfig = true
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
buildConfigFieldStr(
|
||||||
|
name = "URL_POLICY",
|
||||||
|
value = if (isEnterpriseBuild) {
|
||||||
|
BuildTimeConfig.URL_POLICY ?: ""
|
||||||
|
} else {
|
||||||
|
"https://element.io/cookie-policy"
|
||||||
|
},
|
||||||
|
)
|
||||||
|
buildConfigFieldStr(
|
||||||
|
name = "BUG_REPORT_URL",
|
||||||
|
value = if (isEnterpriseBuild) {
|
||||||
|
BuildTimeConfig.BUG_REPORT_URL ?: ""
|
||||||
|
} else {
|
||||||
|
"https://rageshakes.element.io/api/submit"
|
||||||
|
},
|
||||||
|
)
|
||||||
|
buildConfigFieldStr(
|
||||||
|
name = "BUG_REPORT_APP_NAME",
|
||||||
|
value = if (isEnterpriseBuild) {
|
||||||
|
BuildTimeConfig.BUG_REPORT_APP_NAME ?: ""
|
||||||
|
} else {
|
||||||
|
"element-x-android"
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(libs.androidx.annotationjvm)
|
||||||
|
implementation(projects.libraries.matrix.api)
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2023-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.appconfig
|
||||||
|
|
||||||
|
object AnalyticsConfig {
|
||||||
|
const val POLICY_LINK = BuildConfig.URL_POLICY
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2023-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.appconfig
|
||||||
|
|
||||||
|
object ApplicationConfig {
|
||||||
|
/**
|
||||||
|
* Application name used in the UI for string. If empty, the value is taken from the resources `R.string.app_name`.
|
||||||
|
* Note that this value is not used for the launcher icon.
|
||||||
|
* For Element, the value is empty, and so read from `R.string.app_name`, which depends on the build variant:
|
||||||
|
* - "Element X" for release builds;
|
||||||
|
* - "Element X dbg" for debug builds;
|
||||||
|
* - "Element X nightly" for nightly builds.
|
||||||
|
*/
|
||||||
|
const val APPLICATION_NAME: String = ""
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used in the strings to reference the Element client.
|
||||||
|
* Cannot be empty.
|
||||||
|
* For Element, the value is "Element".
|
||||||
|
*/
|
||||||
|
const val PRODUCTION_APPLICATION_NAME: String = "Element"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used in the strings to reference the Element Desktop client, for instance Element Web.
|
||||||
|
* Cannot be empty.
|
||||||
|
* For Element, the value is "Element". We use the same name for desktop and mobile for now.
|
||||||
|
*/
|
||||||
|
const val DESKTOP_APPLICATION_NAME: String = "Element"
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2023-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.appconfig
|
||||||
|
|
||||||
|
object AuthenticationConfig {
|
||||||
|
const val MATRIX_ORG_URL = "https://matrix.org"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL with some docs that explain what's sliding sync and how to add it to your home server.
|
||||||
|
*/
|
||||||
|
const val SLIDING_SYNC_READ_MORE_URL = "https://github.com/matrix-org/sliding-sync/blob/main/docs/Landing.md"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force a sliding sync proxy url, if not null, the proxy url in the .well-known file will be ignored.
|
||||||
|
*/
|
||||||
|
val SLIDING_SYNC_PROXY_URL: String? = null
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2023-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.appconfig
|
||||||
|
|
||||||
|
object ElementCallConfig {
|
||||||
|
/**
|
||||||
|
* The default duration of a ringing call in seconds before it's automatically dismissed.
|
||||||
|
*/
|
||||||
|
const val RINGING_CALL_DURATION_SECONDS = 90
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2023-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.appconfig
|
||||||
|
|
||||||
|
object LearnMoreConfig {
|
||||||
|
const val ENCRYPTION_URL: String = "https://element.io/help#encryption"
|
||||||
|
const val DEVICE_VERIFICATION_URL: String = "https://element.io/help#encryption-device-verification"
|
||||||
|
const val SECURE_BACKUP_URL: String = "https://element.io/help#encryption5"
|
||||||
|
const val IDENTITY_CHANGE_URL: String = "https://element.io/help#encryption18"
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2023-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.appconfig
|
||||||
|
|
||||||
|
import kotlin.time.Duration
|
||||||
|
import kotlin.time.Duration.Companion.minutes
|
||||||
|
|
||||||
|
object LockScreenConfig {
|
||||||
|
/** Whether the PIN is mandatory or not. */
|
||||||
|
const val IS_PIN_MANDATORY: Boolean = false
|
||||||
|
|
||||||
|
/** Set of forbidden PIN codes. */
|
||||||
|
val FORBIDDEN_PIN_CODES: Set<String> = setOf("0000", "1234")
|
||||||
|
|
||||||
|
/** The size of the PIN. */
|
||||||
|
const val PIN_SIZE: Int = 4
|
||||||
|
|
||||||
|
/** Number of attempts before the user is logged out. */
|
||||||
|
const val MAX_PIN_CODE_ATTEMPTS_BEFORE_LOGOUT: Int = 3
|
||||||
|
|
||||||
|
/** Time period before locking the app once backgrounded. */
|
||||||
|
val GRACE_PERIOD: Duration = 2.minutes
|
||||||
|
|
||||||
|
/** Authentication with strong methods (fingerprint, some face/iris unlock implementations) is supported. */
|
||||||
|
const val IS_STRONG_BIOMETRICS_ENABLED: Boolean = true
|
||||||
|
|
||||||
|
/** Authentication with weak methods (most face/iris unlock implementations) is supported. */
|
||||||
|
const val IS_WEAK_BIOMETRICS_ENABLED: Boolean = true
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2023-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.appconfig
|
||||||
|
|
||||||
|
object MatrixConfiguration {
|
||||||
|
const val MATRIX_TO_PERMALINK_BASE_URL: String = "https://matrix.to/#/"
|
||||||
|
val clientPermalinkBaseUrl: String? = null
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2024, 2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.appconfig
|
||||||
|
|
||||||
|
object MessageComposerConfig {
|
||||||
|
/**
|
||||||
|
* Enable the rich text editing in the composer.
|
||||||
|
*/
|
||||||
|
const val ENABLE_RICH_TEXT_EDITING = true
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2023-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.appconfig
|
||||||
|
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
|
import androidx.core.graphics.toColorInt
|
||||||
|
|
||||||
|
object NotificationConfig {
|
||||||
|
/**
|
||||||
|
* If set to true, the notification will have a "Mark as read" action.
|
||||||
|
*/
|
||||||
|
const val SHOW_MARK_AS_READ_ACTION = true
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set to true, the notification for invitation will have two actions to accept or decline the invite.
|
||||||
|
*/
|
||||||
|
const val SHOW_ACCEPT_AND_DECLINE_INVITE_ACTIONS = true
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set to true, the notification will have a "Quick reply" action, allow to compose and send a message to the room.
|
||||||
|
*/
|
||||||
|
const val SHOW_QUICK_REPLY_ACTION = true
|
||||||
|
|
||||||
|
@ColorInt
|
||||||
|
val NOTIFICATION_ACCENT_COLOR: Int = "#FF0DBD8B".toColorInt()
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2024, 2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.appconfig
|
||||||
|
|
||||||
|
object OnBoardingConfig {
|
||||||
|
/** Whether the user can create an account using the app. */
|
||||||
|
const val CAN_CREATE_ACCOUNT = true
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2023-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.appconfig
|
||||||
|
|
||||||
|
object PushConfig {
|
||||||
|
/**
|
||||||
|
* Note: pusher_app_id cannot exceed 64 chars.
|
||||||
|
*/
|
||||||
|
const val PUSHER_APP_ID: String = "im.vector.app.android"
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2024, 2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.appconfig
|
||||||
|
|
||||||
|
object RageshakeConfig {
|
||||||
|
/**
|
||||||
|
* The URL to submit bug reports to.
|
||||||
|
*/
|
||||||
|
const val BUG_REPORT_URL = BuildConfig.BUG_REPORT_URL
|
||||||
|
|
||||||
|
/**
|
||||||
|
* As per https://github.com/matrix-org/rageshake:
|
||||||
|
* Identifier for the application (eg 'riot-web').
|
||||||
|
* Should correspond to a mapping configured in the configuration file for github issue reporting to work.
|
||||||
|
*/
|
||||||
|
const val BUG_REPORT_APP_NAME = BuildConfig.BUG_REPORT_APP_NAME
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum size of the upload request. Default value is just below CloudFlare's max request size.
|
||||||
|
*/
|
||||||
|
const val MAX_LOG_UPLOAD_SIZE = 50 * 1024 * 1024L
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2023-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.appconfig
|
||||||
|
|
||||||
|
object RoomListConfig {
|
||||||
|
const val SHOW_INVITE_MENU_ITEM = false
|
||||||
|
const val SHOW_REPORT_PROBLEM_MENU_ITEM = false
|
||||||
|
|
||||||
|
const val HAS_DROP_DOWN_MENU = SHOW_INVITE_MENU_ITEM || SHOW_REPORT_PROBLEM_MENU_ITEM
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Element Creations Ltd.
|
||||||
|
* Copyright 2023-2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.appconfig
|
||||||
|
|
||||||
|
import io.element.android.libraries.matrix.api.room.StateEventType
|
||||||
|
|
||||||
|
object TimelineConfig {
|
||||||
|
const val MAX_READ_RECEIPT_TO_DISPLAY = 3
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event types that will be filtered out from the timeline (i.e. not displayed).
|
||||||
|
*/
|
||||||
|
val excludedEvents = listOf(
|
||||||
|
StateEventType.CALL_MEMBER,
|
||||||
|
StateEventType.ROOM_ALIASES,
|
||||||
|
StateEventType.ROOM_CANONICAL_ALIAS,
|
||||||
|
StateEventType.ROOM_GUEST_ACCESS,
|
||||||
|
StateEventType.ROOM_HISTORY_VISIBILITY,
|
||||||
|
StateEventType.ROOM_JOIN_RULES,
|
||||||
|
StateEventType.ROOM_POWER_LEVELS,
|
||||||
|
StateEventType.ROOM_SERVER_ACL,
|
||||||
|
StateEventType.ROOM_TOMBSTONE,
|
||||||
|
StateEventType.SPACE_CHILD,
|
||||||
|
StateEventType.SPACE_PARENT,
|
||||||
|
StateEventType.POLICY_RULE_ROOM,
|
||||||
|
StateEventType.POLICY_RULE_SERVER,
|
||||||
|
StateEventType.POLICY_RULE_USER,
|
||||||
|
)
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user