Merge pull request #16 from vector-im/feature/bma/ci
CI and quality check
This commit is contained in:
commit
3fd8ec1cd7
214 changed files with 2661 additions and 1842 deletions
901
.editorconfig
Normal file
901
.editorconfig
Normal file
|
|
@ -0,0 +1,901 @@
|
||||||
|
[*]
|
||||||
|
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
|
||||||
|
|
||||||
|
[*.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
|
||||||
33
.github/workflows/build.yml
vendored
Normal file
33
.github/workflows/build.yml
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
name: APK Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request: { }
|
||||||
|
push:
|
||||||
|
branches: [ main, develop ]
|
||||||
|
|
||||||
|
# Enrich gradle.properties for CI/CD
|
||||||
|
env:
|
||||||
|
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx3072m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -Dkotlin.daemon.jvm.options="-Xmx2560m" -Dkotlin.incremental=false
|
||||||
|
CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 2 --no-daemon
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
debug:
|
||||||
|
name: Build debug APKs
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.ref != 'refs/heads/main'
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
# Allow all jobs on develop. Just one per PR.
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.ref == 'refs/heads/develop' && format('build-develop-{0}', github.sha) || format('build-debug-{0}', github.ref) }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Assemble debug APK
|
||||||
|
run: ./gradlew assembleDebug $CI_GRADLE_ARG_PROPERTIES
|
||||||
|
- name: Upload debug APKs
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: elementx-debug
|
||||||
|
path: |
|
||||||
|
app/build/outputs/apk/debug/app-debug.apk
|
||||||
20
.github/workflows/danger.yml
vendored
Normal file
20
.github/workflows/danger.yml
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
name: Danger CI
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Danger
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- run: |
|
||||||
|
npm install --save-dev @babel/plugin-transform-flow-strip-types
|
||||||
|
- name: Danger
|
||||||
|
uses: danger/danger-js@11.2.0
|
||||||
|
with:
|
||||||
|
args: "--dangerfile ./tools/danger/dangerfile.js"
|
||||||
|
env:
|
||||||
|
DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
|
||||||
|
# Fallback for forks
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
46
.github/workflows/quality.yml
vendored
Normal file
46
.github/workflows/quality.yml
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
name: Code Quality Checks
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request: { }
|
||||||
|
push:
|
||||||
|
branches: [ main, develop ]
|
||||||
|
|
||||||
|
# Enrich gradle.properties for CI/CD
|
||||||
|
env:
|
||||||
|
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx3072m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -XX:MaxPermSize=512m -Dkotlin.daemon.jvm.options="-Xmx2g" -Dkotlin.incremental=false
|
||||||
|
CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 2 --no-daemon
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check:
|
||||||
|
name: Project Check Suite
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Allow all jobs on main and develop. Just one per PR.
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.ref == 'refs/heads/main' && format('check-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('check-develop-{0}', github.sha) || format('check-{0}', github.ref) }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Run code quality check suite
|
||||||
|
run: ./gradlew check $CI_GRADLE_ARG_PROPERTIES
|
||||||
|
- name: Upload reports
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: linting-report
|
||||||
|
path: |
|
||||||
|
*/build/reports/**/*.*
|
||||||
|
- name: Prepare Danger
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
npm install --save-dev @babel/core
|
||||||
|
npm install --save-dev @babel/plugin-transform-flow-strip-types
|
||||||
|
yarn add danger-plugin-lint-report --dev
|
||||||
|
- name: Danger lint
|
||||||
|
if: always()
|
||||||
|
uses: danger/danger-js@11.2.0
|
||||||
|
with:
|
||||||
|
args: "--dangerfile ./tools/danger/dangerfile-lint.js"
|
||||||
|
env:
|
||||||
|
DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
|
||||||
|
# Fallback for forks
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
25
.github/workflows/tests.yml
vendored
Normal file
25
.github/workflows/tests.yml
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
name: Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request: { }
|
||||||
|
push:
|
||||||
|
branches: [ main, develop ]
|
||||||
|
|
||||||
|
# Enrich gradle.properties for CI/CD
|
||||||
|
env:
|
||||||
|
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx3072m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError" -Dkotlin.daemon.jvm.options="-Xmx2560m" -Dkotlin.incremental=false
|
||||||
|
CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 4 --no-daemon
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
tests:
|
||||||
|
name: Runs unit tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
# Allow all jobs on main and develop. Just one per PR.
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.ref == 'refs/heads/main' && format('unit-tests-main-{0}', github.sha) || github.ref == 'refs/heads/develop' && format('unit-tests-develop-{0}', github.sha) || format('unit-tests-{0}', github.ref) }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Run tests
|
||||||
|
run: ./gradlew test $CI_GRADLE_ARG_PROPERTIES
|
||||||
2
.github/workflows/triage-labelled.yml
vendored
2
.github/workflows/triage-labelled.yml
vendored
|
|
@ -2,7 +2,7 @@ name: Move labelled issues to correct boards and columns
|
||||||
|
|
||||||
on:
|
on:
|
||||||
issues:
|
issues:
|
||||||
types: [labeled]
|
types: [ labeled ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
move_element_x_issues:
|
move_element_x_issues:
|
||||||
|
|
|
||||||
125
.idea/codeStyles/Project.xml
generated
Normal file
125
.idea/codeStyles/Project.xml
generated
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<code_scheme name="Project" version="173">
|
||||||
|
<JetCodeStyleSettings>
|
||||||
|
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
|
||||||
|
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
|
||||||
|
<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>
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
# element-x-android-poc
|
# element-x-android-poc
|
||||||
|
|
||||||
Proof Of Concept to run a Matrix client on Android devices using the Matrix Rust Sdk and Jetpack compose.
|
Proof Of Concept to run a Matrix client on Android devices using the Matrix Rust Sdk and Jetpack compose.
|
||||||
|
|
||||||
The plan is [here](https://github.com/vector-im/element-x-android-poc/issues/1)!
|
The plan is [here](https://github.com/vector-im/element-x-android-poc/issues/1)!
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ plugins {
|
||||||
id("org.jetbrains.kotlin.android")
|
id("org.jetbrains.kotlin.android")
|
||||||
alias(libs.plugins.ksp)
|
alias(libs.plugins.ksp)
|
||||||
id("com.google.firebase.appdistribution") version "3.0.2"
|
id("com.google.firebase.appdistribution") version "3.0.2"
|
||||||
|
id("org.jetbrains.kotlinx.knit") version "0.4.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
|
|
@ -10,7 +11,7 @@ android {
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "io.element.android.x"
|
applicationId = "io.element.android.x"
|
||||||
targetSdk = 33
|
targetSdk = 33 // TODO Use Versions.targetSdk
|
||||||
versionCode = 1
|
versionCode = 1
|
||||||
versionName = "1.0"
|
versionName = "1.0"
|
||||||
|
|
||||||
|
|
@ -79,7 +80,6 @@ android {
|
||||||
appId = "1:912726360885:android:e17435e0beb0303000427c"
|
appId = "1:912726360885:android:e17435e0beb0303000427c"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
|
@ -110,6 +110,27 @@ android {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Knit
|
||||||
|
apply {
|
||||||
|
plugin("kotlinx-knit")
|
||||||
|
}
|
||||||
|
|
||||||
|
knit {
|
||||||
|
files = fileTree(project.rootDir) {
|
||||||
|
include(
|
||||||
|
"**/*.md",
|
||||||
|
"**/*.kt",
|
||||||
|
"*/*.kts",
|
||||||
|
)
|
||||||
|
exclude(
|
||||||
|
"**/build/**",
|
||||||
|
"*/.gradle/**",
|
||||||
|
"*/towncrier/template.md",
|
||||||
|
"**/CHANGES.md",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":libraries:designsystem"))
|
implementation(project(":libraries:designsystem"))
|
||||||
implementation(project(":libraries:matrix"))
|
implementation(project(":libraries:matrix"))
|
||||||
|
|
@ -128,9 +149,8 @@ dependencies {
|
||||||
implementation(libs.androidx.lifecycle.viewmodel.compose)
|
implementation(libs.androidx.lifecycle.viewmodel.compose)
|
||||||
implementation(libs.androidx.activity.compose)
|
implementation(libs.androidx.activity.compose)
|
||||||
implementation(libs.coil)
|
implementation(libs.coil)
|
||||||
implementation(libs.timber)
|
|
||||||
implementation(libs.mavericks.compose)
|
implementation(libs.mavericks.compose)
|
||||||
|
|
||||||
implementation(libs.showkase)
|
implementation(libs.showkase)
|
||||||
ksp(libs.showkase.processor)
|
ksp(libs.showkase.processor)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,4 +4,4 @@ import com.airbnb.android.showkase.annotation.ShowkaseRoot
|
||||||
import com.airbnb.android.showkase.annotation.ShowkaseRootModule
|
import com.airbnb.android.showkase.annotation.ShowkaseRootModule
|
||||||
|
|
||||||
@ShowkaseRoot
|
@ShowkaseRoot
|
||||||
class ElementRootModule : ShowkaseRootModule
|
class ElementRootModule : ShowkaseRootModule
|
||||||
|
|
@ -29,4 +29,4 @@ class ElementXApplication : Application(), ImageLoaderFactory {
|
||||||
}
|
}
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,17 @@ import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Close
|
import androidx.compose.material.icons.filled.Close
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
|
@ -106,7 +115,6 @@ class MainActivity : ComponentActivity() {
|
||||||
OnLifecycleEvent { _, event ->
|
OnLifecycleEvent { _, event ->
|
||||||
Timber.v("OnLifecycleEvent: $event")
|
Timber.v("OnLifecycleEvent: $event")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -165,5 +173,4 @@ class MainActivity : ComponentActivity() {
|
||||||
fun MainContentPreview() {
|
fun MainContentPreview() {
|
||||||
MainContent(startRoute = OnBoardingScreenNavigationDestination)
|
MainContent(startRoute = OnBoardingScreenNavigationDestination)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -13,14 +13,14 @@ class MainViewModel : ViewModel() {
|
||||||
return matrix.isLoggedIn().first()
|
return matrix.isLoggedIn().first()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun startSyncIfLogged(){
|
fun startSyncIfLogged() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
if(!isLoggedIn()) return@launch
|
if (!isLoggedIn()) return@launch
|
||||||
matrix.activeClient().startSync()
|
matrix.activeClient().startSync()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stopSyncIfLogged(){
|
fun stopSyncIfLogged() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
if (!isLoggedIn()) return@launch
|
if (!isLoggedIn()) return@launch
|
||||||
matrix.activeClient().stopSync()
|
matrix.activeClient().stopSync()
|
||||||
|
|
@ -31,4 +31,4 @@ class MainViewModel : ViewModel() {
|
||||||
matrix.restoreSession()
|
matrix.restoreSession()
|
||||||
matrix.activeClient().startSync()
|
matrix.activeClient().startSync()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,11 @@ import com.ramcosta.composedestinations.annotation.Destination
|
||||||
import com.ramcosta.composedestinations.annotation.RootNavGraph
|
import com.ramcosta.composedestinations.annotation.RootNavGraph
|
||||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||||
import com.ramcosta.composedestinations.navigation.popUpTo
|
import com.ramcosta.composedestinations.navigation.popUpTo
|
||||||
import io.element.android.x.destinations.*
|
import io.element.android.x.destinations.ChangeServerScreenNavigationDestination
|
||||||
|
import io.element.android.x.destinations.LoginScreenNavigationDestination
|
||||||
|
import io.element.android.x.destinations.MessagesScreenNavigationDestination
|
||||||
|
import io.element.android.x.destinations.OnBoardingScreenNavigationDestination
|
||||||
|
import io.element.android.x.destinations.RoomListScreenNavigationDestination
|
||||||
import io.element.android.x.features.login.LoginScreen
|
import io.element.android.x.features.login.LoginScreen
|
||||||
import io.element.android.x.features.login.changeserver.ChangeServerScreen
|
import io.element.android.x.features.login.changeserver.ChangeServerScreen
|
||||||
import io.element.android.x.features.messages.MessagesScreen
|
import io.element.android.x.features.messages.MessagesScreen
|
||||||
|
|
@ -77,6 +81,3 @@ fun RoomListScreenNavigation(navigator: DestinationsNavigator) {
|
||||||
fun MessagesScreenNavigation(roomId: String, navigator: DestinationsNavigator) {
|
fun MessagesScreenNavigation(roomId: String, navigator: DestinationsNavigator) {
|
||||||
MessagesScreen(roomId, navigator::navigateUp)
|
MessagesScreen(roomId, navigator::navigateUp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,170 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="108dp"
|
|
||||||
android:height="108dp"
|
|
||||||
android:viewportWidth="108"
|
|
||||||
android:viewportHeight="108">
|
|
||||||
<path
|
|
||||||
android:fillColor="#3DDC84"
|
|
||||||
android:pathData="M0,0h108v108h-108z" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M9,0L9,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,0L19,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M29,0L29,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M39,0L39,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M49,0L49,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M59,0L59,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M69,0L69,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M79,0L79,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M89,0L89,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M99,0L99,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,9L108,9"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,19L108,19"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,29L108,29"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,39L108,39"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,49L108,49"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,59L108,59"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,69L108,69"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,79L108,79"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,89L108,89"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,99L108,99"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,29L89,29"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,39L89,39"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,49L89,49"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,59L89,59"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,69L89,69"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,79L89,79"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M29,19L29,89"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M39,19L39,89"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M49,19L49,89"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M59,19L59,89"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M69,19L69,89"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M79,19L79,89"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
</vector>
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="108dp"
|
|
||||||
android:height="108dp"
|
|
||||||
android:viewportWidth="108"
|
|
||||||
android:viewportHeight="108">
|
|
||||||
<group android:scaleX="0.675"
|
|
||||||
android:scaleY="0.675"
|
|
||||||
android:translateX="32.4"
|
|
||||||
android:translateY="32.4">
|
|
||||||
<path
|
|
||||||
android:pathData="M23.04,3.84C23.04,1.7192 24.7593,0 26.88,0C41.0185,0 52.48,11.4615 52.48,25.6C52.48,27.7208 50.7608,29.44 48.64,29.44C46.5193,29.44 44.8,27.7208 44.8,25.6C44.8,15.7031 36.777,7.68 26.88,7.68C24.7593,7.68 23.04,5.9608 23.04,3.84Z"
|
|
||||||
android:fillColor="#FFF"
|
|
||||||
android:fillType="evenOdd"/>
|
|
||||||
<path
|
|
||||||
android:pathData="M40.96,60.16C40.96,62.2808 39.2407,64 37.12,64C22.9815,64 11.52,52.5385 11.52,38.4C11.52,36.2792 13.2392,34.56 15.36,34.56C17.4807,34.56 19.2,36.2792 19.2,38.4C19.2,48.2969 27.223,56.32 37.12,56.32C39.2407,56.32 40.96,58.0392 40.96,60.16Z"
|
|
||||||
android:fillColor="#FFF"
|
|
||||||
android:fillType="evenOdd"/>
|
|
||||||
<path
|
|
||||||
android:pathData="M3.84,40.96C1.7192,40.96 -0,39.2407 -0,37.12C-0,22.9815 11.4615,11.52 25.6,11.52C27.7208,11.52 29.44,13.2392 29.44,15.36C29.44,17.4807 27.7208,19.2 25.6,19.2C15.7031,19.2 7.68,27.223 7.68,37.12C7.68,39.2407 5.9608,40.96 3.84,40.96Z"
|
|
||||||
android:fillColor="#FFF"
|
|
||||||
android:fillType="evenOdd"/>
|
|
||||||
<path
|
|
||||||
android:pathData="M60.16,23.04C62.2808,23.04 64,24.7593 64,26.88C64,41.0185 52.5385,52.48 38.4,52.48C36.2792,52.48 34.56,50.7608 34.56,48.64C34.56,46.5193 36.2792,44.8 38.4,44.8C48.2969,44.8 56.32,36.777 56.32,26.88C56.32,24.7593 58.0392,23.04 60.16,23.04Z"
|
|
||||||
android:fillColor="#FFF"
|
|
||||||
android:fillType="evenOdd"/>
|
|
||||||
</group>
|
|
||||||
</vector>
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<color name="ic_launcher_background">#000000</color>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -4,8 +4,78 @@ plugins {
|
||||||
alias(libs.plugins.android.library) apply false
|
alias(libs.plugins.android.library) apply false
|
||||||
alias(libs.plugins.kotlin.android) apply false
|
alias(libs.plugins.kotlin.android) apply false
|
||||||
alias(libs.plugins.ksp) apply false
|
alias(libs.plugins.ksp) apply false
|
||||||
|
alias(libs.plugins.detekt)
|
||||||
|
alias(libs.plugins.ktlint)
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register<Delete>("clean").configure {
|
tasks.register<Delete>("clean").configure {
|
||||||
delete(rootProject.buildDir)
|
delete(rootProject.buildDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
// Detekt
|
||||||
|
apply {
|
||||||
|
plugin("io.gitlab.arturbosch.detekt")
|
||||||
|
}
|
||||||
|
detekt {
|
||||||
|
// preconfigure defaults
|
||||||
|
buildUponDefaultConfig = true
|
||||||
|
// activate all available (even unstable) rules.
|
||||||
|
allRules = true
|
||||||
|
// point to your custom config defining rules to run, overwriting default behavior
|
||||||
|
config = files("$rootDir/tools/detekt/detekt.yml")
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
detektPlugins("com.twitter.compose.rules:detekt:0.0.26")
|
||||||
|
}
|
||||||
|
|
||||||
|
// KtLint
|
||||||
|
apply {
|
||||||
|
plugin("org.jlleitschuh.gradle.ktlint")
|
||||||
|
}
|
||||||
|
|
||||||
|
// See https://github.com/JLLeitschuh/ktlint-gradle#configuration
|
||||||
|
configure<org.jlleitschuh.gradle.ktlint.KtlintExtension> {
|
||||||
|
// See https://github.com/pinterest/ktlint/releases/
|
||||||
|
// TODO 0.47.1 is available
|
||||||
|
version.set("0.45.1")
|
||||||
|
android.set(true)
|
||||||
|
ignoreFailures.set(false)
|
||||||
|
enableExperimentalRules.set(true)
|
||||||
|
// display the corresponding rule
|
||||||
|
verbose.set(true)
|
||||||
|
reporters {
|
||||||
|
reporter(org.jlleitschuh.gradle.ktlint.reporter.ReporterType.PLAIN)
|
||||||
|
// To have XML report for Danger
|
||||||
|
reporter(org.jlleitschuh.gradle.ktlint.reporter.ReporterType.CHECKSTYLE)
|
||||||
|
}
|
||||||
|
filter {
|
||||||
|
exclude { element -> element.file.path.contains("$buildDir/generated/") }
|
||||||
|
}
|
||||||
|
disabledRules.set(
|
||||||
|
setOf(
|
||||||
|
// TODO Re-enable these 4 rules after reformatting project
|
||||||
|
"indent",
|
||||||
|
"experimental:argument-list-wrapping",
|
||||||
|
"max-line-length",
|
||||||
|
"parameter-list-wrapping",
|
||||||
|
|
||||||
|
"spacing-between-declarations-with-comments",
|
||||||
|
"no-multi-spaces",
|
||||||
|
"experimental:spacing-between-declarations-with-annotations",
|
||||||
|
"experimental:annotation",
|
||||||
|
// - Missing newline after "("
|
||||||
|
// - Missing newline before ")"
|
||||||
|
"wrapping",
|
||||||
|
// - Unnecessary trailing comma before ")"
|
||||||
|
"experimental:trailing-comma",
|
||||||
|
// - A block comment in between other elements on the same line is disallowed
|
||||||
|
"experimental:comment-wrapping",
|
||||||
|
// - A KDoc comment after any other element on the same line must be separated by a new line
|
||||||
|
"experimental:kdoc-wrapping",
|
||||||
|
// Ignore error "Redundant curly braces", since we use it to fix false positives, for instance in "elementLogs.${i}.txt"
|
||||||
|
"string-template",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,22 @@
|
||||||
|
<!--- TOC -->
|
||||||
|
|
||||||
|
* [VersionCatalog](#versioncatalog)
|
||||||
|
* [Jetpack Compose](#jetpack-compose)
|
||||||
|
|
||||||
|
<!--- END -->
|
||||||
|
|
||||||
### VersionCatalog
|
### VersionCatalog
|
||||||
|
|
||||||
|
https://docs.gradle.org/current/userguide/platforms.html
|
||||||
|
|
||||||
|
|
||||||
### Jetpack Compose
|
### Jetpack Compose
|
||||||
|
|
||||||
https://developer.android.com/jetpack/compose/mental-model
|
https://developer.android.com/jetpack/compose/mental-model
|
||||||
|
https://developer.android.com/jetpack/compose/libraries
|
||||||
|
https://developer.android.com/jetpack/compose/modifiers-list
|
||||||
|
|
||||||
https://android.googlesource.com/platform/frameworks/support/+/androidx-main/compose/docs/compose-api-guidelines.md#api-guidelines-for-jetpack-compose
|
https://android.googlesource.com/platform/frameworks/support/+/androidx-main/compose/docs/compose-api-guidelines.md#api-guidelines-for-jetpack-compose
|
||||||
|
|
||||||
Preview
|
Preview
|
||||||
https://alexzh.com/jetpack-compose-preview/
|
https://alexzh.com/jetpack-compose-preview/
|
||||||
https://github.com/airbnb/Showkase
|
https://github.com/airbnb/Showkase
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,6 @@ dependencies {
|
||||||
implementation(project(":libraries:elementresources"))
|
implementation(project(":libraries:elementresources"))
|
||||||
implementation(libs.mavericks.compose)
|
implementation(libs.mavericks.compose)
|
||||||
ksp(libs.showkase.processor)
|
ksp(libs.showkase.processor)
|
||||||
implementation(libs.timber)
|
|
||||||
testImplementation(libs.test.junit)
|
testImplementation(libs.test.junit)
|
||||||
androidTestImplementation(libs.test.junitext)
|
androidTestImplementation(libs.test.junitext)
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,11 @@
|
||||||
package io.element.android.x.features.login
|
package io.element.android.x.features.login
|
||||||
|
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
import org.junit.Assert.*
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instrumented test, which will execute on an Android device.
|
* Instrumented test, which will execute on an Android device.
|
||||||
*
|
*
|
||||||
|
|
@ -21,4 +19,4 @@ class ExampleInstrumentedTest {
|
||||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||||
assertEquals("io.element.android.x.features.login.test", appContext.packageName)
|
assertEquals("io.element.android.x.features.login.test", appContext.packageName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,13 @@
|
||||||
|
|
||||||
package io.element.android.x.features.login
|
package io.element.android.x.features.login
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.imePadding
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.systemBarsPadding
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.text.KeyboardActions
|
import androidx.compose.foundation.text.KeyboardActions
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
|
|
@ -10,8 +16,21 @@ import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Visibility
|
import androidx.compose.material.icons.filled.Visibility
|
||||||
import androidx.compose.material.icons.filled.VisibilityOff
|
import androidx.compose.material.icons.filled.VisibilityOff
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.OutlinedTextField
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
|
@ -55,19 +74,22 @@ fun LoginScreen(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun LoginContent(
|
fun LoginContent(
|
||||||
state: LoginViewState,
|
state: LoginViewState,
|
||||||
formState: LoginFormState,
|
formState: LoginFormState,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
onChangeServer: () -> Unit = {},
|
onChangeServer: () -> Unit = {},
|
||||||
onLoginChanged: (String) -> Unit = {},
|
onLoginChanged: (String) -> Unit = {},
|
||||||
onPasswordChanged: (String) -> Unit = {},
|
onPasswordChanged: (String) -> Unit = {},
|
||||||
onSubmitClicked: () -> Unit = {},
|
onSubmitClicked: () -> Unit = {},
|
||||||
onLoginWithSuccess: () -> Unit = {},
|
onLoginWithSuccess: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
Surface(color = MaterialTheme.colorScheme.background) {
|
Surface(
|
||||||
|
modifier = modifier,
|
||||||
|
color = MaterialTheme.colorScheme.background,
|
||||||
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
|
|
@ -95,7 +117,7 @@ fun LoginContent(
|
||||||
)
|
)
|
||||||
// Form
|
// Form
|
||||||
Column(
|
Column(
|
||||||
//modifier = Modifier.weight(1f),
|
// modifier = Modifier.weight(1f),
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
|
|
||||||
|
|
@ -55,4 +55,4 @@ class LoginViewModel(initialState: LoginViewState) :
|
||||||
formState.value = formState.value.copy(login = name)
|
formState.value = formState.value.copy(login = name)
|
||||||
setState { copy(isLoggedIn = Uninitialized) }
|
setState { copy(isLoggedIn = Uninitialized) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,5 +22,4 @@ data class LoginFormState(
|
||||||
companion object {
|
companion object {
|
||||||
val Default = LoginFormState("", "")
|
val Default = LoginFormState("", "")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,27 @@
|
||||||
package io.element.android.x.features.login.changeserver
|
package io.element.android.x.features.login.changeserver
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.defaultMinSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.imePadding
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.systemBarsPadding
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.text.KeyboardActions
|
import androidx.compose.foundation.text.KeyboardActions
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.OutlinedTextField
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
|
|
@ -45,15 +59,18 @@ fun ChangeServerScreen(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ChangeServerContent(
|
fun ChangeServerContent(
|
||||||
state: ChangeServerViewState,
|
state: ChangeServerViewState,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
onChangeServer: (String) -> Unit = {},
|
onChangeServer: (String) -> Unit = {},
|
||||||
onChangeServerSubmit: () -> Unit = {},
|
onChangeServerSubmit: () -> Unit = {},
|
||||||
onChangeServerSuccess: () -> Unit = {},
|
onChangeServerSuccess: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
Surface(color = MaterialTheme.colorScheme.background) {
|
Surface(
|
||||||
|
modifier = modifier,
|
||||||
|
color = MaterialTheme.colorScheme.background,
|
||||||
|
) {
|
||||||
val scrollState = rememberScrollState()
|
val scrollState = rememberScrollState()
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
@ -67,8 +84,7 @@ fun ChangeServerContent(
|
||||||
state = scrollState,
|
state = scrollState,
|
||||||
)
|
)
|
||||||
.padding(horizontal = 16.dp)
|
.padding(horizontal = 16.dp)
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
val isError = state.changeServerAction is Fail
|
val isError = state.changeServerAction is Fail
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
@ -101,7 +117,7 @@ fun ChangeServerContent(
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = "A server is a home for all your data.\n" +
|
text = "A server is a home for all your data.\n" +
|
||||||
"You choose your server and it’s easy to make one.", // TODO "Learn more.",
|
"You choose your server and it’s easy to make one.", // TODO "Learn more.",
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.align(Alignment.CenterHorizontally)
|
.align(Alignment.CenterHorizontally)
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,9 @@ class ChangeServerViewModel(initialState: ChangeServerViewState) :
|
||||||
suspend {
|
suspend {
|
||||||
val state = awaitState()
|
val state = awaitState()
|
||||||
matrix.setHomeserver(state.homeserver)
|
matrix.setHomeserver(state.homeserver)
|
||||||
}.execute { it ->
|
}.execute {
|
||||||
copy(changeServerAction = it)
|
copy(changeServerAction = it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,4 +10,4 @@ data class ChangeServerViewState(
|
||||||
val changeServerAction: Async<Unit> = Uninitialized,
|
val changeServerAction: Async<Unit> = Uninitialized,
|
||||||
) : MavericksState {
|
) : MavericksState {
|
||||||
val submitEnabled = homeserver.isNotEmpty() && changeServerAction !is Loading
|
val submitEnabled = homeserver.isNotEmpty() && changeServerAction !is Loading
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ package io.element.android.x.features.login.error
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import io.element.android.x.core.uri.isValidUrl
|
import io.element.android.x.core.uri.isValidUrl
|
||||||
import io.element.android.x.features.login.LoginFormState
|
|
||||||
import io.element.android.x.element.resources.R as ElementR
|
import io.element.android.x.element.resources.R as ElementR
|
||||||
|
import io.element.android.x.features.login.LoginFormState
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun loginError(
|
fun loginError(
|
||||||
|
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="64dp"
|
|
||||||
android:height="64dp"
|
|
||||||
android:viewportWidth="64"
|
|
||||||
android:viewportHeight="64">
|
|
||||||
<path
|
|
||||||
android:pathData="M23.04,3.84C23.04,1.7192 24.7593,0 26.88,0C41.0185,0 52.48,11.4615 52.48,25.6C52.48,27.7208 50.7608,29.44 48.64,29.44C46.5193,29.44 44.8,27.7208 44.8,25.6C44.8,15.7031 36.777,7.68 26.88,7.68C24.7593,7.68 23.04,5.9608 23.04,3.84Z"
|
|
||||||
android:fillColor="#0DBD8B"
|
|
||||||
android:fillType="evenOdd"/>
|
|
||||||
<path
|
|
||||||
android:pathData="M40.96,60.16C40.96,62.2808 39.2407,64 37.12,64C22.9815,64 11.52,52.5385 11.52,38.4C11.52,36.2792 13.2392,34.56 15.36,34.56C17.4807,34.56 19.2,36.2792 19.2,38.4C19.2,48.2969 27.223,56.32 37.12,56.32C39.2407,56.32 40.96,58.0392 40.96,60.16Z"
|
|
||||||
android:fillColor="#0DBD8B"
|
|
||||||
android:fillType="evenOdd"/>
|
|
||||||
<path
|
|
||||||
android:pathData="M3.84,40.96C1.7192,40.96 -0,39.2407 -0,37.12C-0,22.9815 11.4615,11.52 25.6,11.52C27.7208,11.52 29.44,13.2392 29.44,15.36C29.44,17.4807 27.7208,19.2 25.6,19.2C15.7031,19.2 7.68,27.223 7.68,37.12C7.68,39.2407 5.9608,40.96 3.84,40.96Z"
|
|
||||||
android:fillColor="#0DBD8B"
|
|
||||||
android:fillType="evenOdd"/>
|
|
||||||
<path
|
|
||||||
android:pathData="M60.16,23.04C62.2808,23.04 64,24.7593 64,26.88C64,41.0185 52.5385,52.48 38.4,52.48C36.2792,52.48 34.56,50.7608 34.56,48.64C34.56,46.5193 36.2792,44.8 38.4,44.8C48.2969,44.8 56.32,36.777 56.32,26.88C56.32,24.7593 58.0392,23.04 60.16,23.04Z"
|
|
||||||
android:fillColor="#0DBD8B"
|
|
||||||
android:fillType="evenOdd"/>
|
|
||||||
</vector>
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
<vector android:height="24dp" android:tint="#000000"
|
<vector android:height="24dp"
|
||||||
android:viewportHeight="24" android:viewportWidth="24"
|
android:tint="#000000"
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
android:viewportHeight="24"
|
||||||
<path android:fillColor="@android:color/white" android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM11,17H7v-4h4V17zM11,11H7V7h4V11zM17,17h-4v-4h4V17zM17,11h-4V7h4V11z"/>
|
android:viewportWidth="24"
|
||||||
|
android:width="24dp"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM11,17H7v-4h4V17zM11,11H7V7h4V11zM17,17h-4v-4h4V17zM17,11h-4V7h4V11z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
package io.element.android.x.features.login
|
package io.element.android.x.features.login
|
||||||
|
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
import org.junit.Assert.*
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Example local unit test, which will execute on the development machine (host).
|
* Example local unit test, which will execute on the development machine (host).
|
||||||
*
|
*
|
||||||
|
|
@ -14,4 +13,4 @@ class ExampleUnitTest {
|
||||||
fun addition_isCorrect() {
|
fun addition_isCorrect() {
|
||||||
assertEquals(4, 2 + 2)
|
assertEquals(4, 2 + 2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ dependencies {
|
||||||
implementation(project(":libraries:textcomposer"))
|
implementation(project(":libraries:textcomposer"))
|
||||||
implementation(libs.mavericks.compose)
|
implementation(libs.mavericks.compose)
|
||||||
implementation(libs.coil.compose)
|
implementation(libs.coil.compose)
|
||||||
implementation(libs.timber)
|
|
||||||
implementation(libs.datetime)
|
implementation(libs.datetime)
|
||||||
implementation(libs.accompanist.flowlayout)
|
implementation(libs.accompanist.flowlayout)
|
||||||
implementation(libs.androidx.recyclerview)
|
implementation(libs.androidx.recyclerview)
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,11 @@
|
||||||
package io.element.android.x.features.messages
|
package io.element.android.x.features.messages
|
||||||
|
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
import org.junit.Assert.*
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instrumented test, which will execute on an Android device.
|
* Instrumented test, which will execute on an Android device.
|
||||||
*
|
*
|
||||||
|
|
@ -21,4 +19,4 @@ class ExampleInstrumentedTest {
|
||||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||||
assertEquals("io.element.android.x.features.messages.test", appContext.packageName)
|
assertEquals("io.element.android.x.features.messages.test", appContext.packageName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,20 @@ import io.element.android.x.features.messages.model.AggregatedReaction
|
||||||
import io.element.android.x.features.messages.model.MessagesItemGroupPosition
|
import io.element.android.x.features.messages.model.MessagesItemGroupPosition
|
||||||
import io.element.android.x.features.messages.model.MessagesItemReactionState
|
import io.element.android.x.features.messages.model.MessagesItemReactionState
|
||||||
import io.element.android.x.features.messages.model.MessagesTimelineItemState
|
import io.element.android.x.features.messages.model.MessagesTimelineItemState
|
||||||
import io.element.android.x.features.messages.model.content.*
|
import io.element.android.x.features.messages.model.content.MessagesTimelineItemContent
|
||||||
|
import io.element.android.x.features.messages.model.content.MessagesTimelineItemEmoteContent
|
||||||
|
import io.element.android.x.features.messages.model.content.MessagesTimelineItemEncryptedContent
|
||||||
|
import io.element.android.x.features.messages.model.content.MessagesTimelineItemImageContent
|
||||||
|
import io.element.android.x.features.messages.model.content.MessagesTimelineItemNoticeContent
|
||||||
|
import io.element.android.x.features.messages.model.content.MessagesTimelineItemRedactedContent
|
||||||
|
import io.element.android.x.features.messages.model.content.MessagesTimelineItemTextContent
|
||||||
|
import io.element.android.x.features.messages.model.content.MessagesTimelineItemUnknownContent
|
||||||
import io.element.android.x.features.messages.util.invalidateLast
|
import io.element.android.x.features.messages.util.invalidateLast
|
||||||
import io.element.android.x.matrix.MatrixClient
|
import io.element.android.x.matrix.MatrixClient
|
||||||
import io.element.android.x.matrix.media.MediaResolver
|
import io.element.android.x.matrix.media.MediaResolver
|
||||||
import io.element.android.x.matrix.room.MatrixRoom
|
import io.element.android.x.matrix.room.MatrixRoom
|
||||||
import io.element.android.x.matrix.timeline.MatrixTimelineItem
|
import io.element.android.x.matrix.timeline.MatrixTimelineItem
|
||||||
|
import kotlin.system.measureTimeMillis
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
@ -28,7 +36,6 @@ import org.matrix.rustcomponents.sdk.FormattedBody
|
||||||
import org.matrix.rustcomponents.sdk.MessageFormat
|
import org.matrix.rustcomponents.sdk.MessageFormat
|
||||||
import org.matrix.rustcomponents.sdk.MessageType
|
import org.matrix.rustcomponents.sdk.MessageType
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import kotlin.system.measureTimeMillis
|
|
||||||
|
|
||||||
class MessageTimelineItemStateFactory(
|
class MessageTimelineItemStateFactory(
|
||||||
private val client: MatrixClient,
|
private val client: MatrixClient,
|
||||||
|
|
@ -83,7 +90,6 @@ class MessageTimelineItemStateFactory(
|
||||||
timelineItemStates.emit(newTimelineItemStates)
|
timelineItemStates.emit(newTimelineItemStates)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun calculateAndApplyDiff(newTimelineItems: List<MatrixTimelineItem>) {
|
private fun calculateAndApplyDiff(newTimelineItems: List<MatrixTimelineItem>) {
|
||||||
val timeToDiff = measureTimeMillis {
|
val timeToDiff = measureTimeMillis {
|
||||||
val diffCallback =
|
val diffCallback =
|
||||||
|
|
@ -192,7 +198,6 @@ class MessageTimelineItemStateFactory(
|
||||||
htmlDocument = messageType.content.formatted?.toHtmlDocument()
|
htmlDocument = messageType.content.formatted?.toHtmlDocument()
|
||||||
)
|
)
|
||||||
else -> MessagesTimelineItemUnknownContent
|
else -> MessagesTimelineItemUnknownContent
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -232,5 +237,4 @@ class MessageTimelineItemStateFactory(
|
||||||
.resolve(url, kind = MediaResolver.Kind.Thumbnail(size.value))
|
.resolve(url, kind = MediaResolver.Kind.Thumbnail(size.value))
|
||||||
return AvatarData(name, model, size)
|
return AvatarData(name, model, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,26 @@
|
||||||
|
|
||||||
package io.element.android.x.features.messages
|
package io.element.android.x.features.messages
|
||||||
|
|
||||||
import Avatar
|
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.BoxScope
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.imePadding
|
||||||
|
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||||
|
import androidx.compose.foundation.layout.offset
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.statusBars
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.layout.widthIn
|
||||||
|
import androidx.compose.foundation.layout.wrapContentHeight
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.LazyListState
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
|
|
@ -20,8 +37,24 @@ import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.ArrowBack
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.filled.ArrowDownward
|
import androidx.compose.material.icons.filled.ArrowDownward
|
||||||
import androidx.compose.material.rememberModalBottomSheetState
|
import androidx.compose.material.rememberModalBottomSheetState
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.FloatingActionButton
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.SnackbarHost
|
||||||
|
import androidx.compose.material3.SnackbarHostState
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.derivedStateOf
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.snapshotFlow
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Alignment.Companion.End
|
import androidx.compose.ui.Alignment.Companion.End
|
||||||
import androidx.compose.ui.Alignment.Companion.Start
|
import androidx.compose.ui.Alignment.Companion.Start
|
||||||
|
|
@ -41,18 +74,40 @@ import com.airbnb.mvrx.compose.mavericksViewModel
|
||||||
import io.element.android.x.core.compose.LogCompositions
|
import io.element.android.x.core.compose.LogCompositions
|
||||||
import io.element.android.x.core.compose.PairCombinedPreviewParameter
|
import io.element.android.x.core.compose.PairCombinedPreviewParameter
|
||||||
import io.element.android.x.core.data.StableCharSequence
|
import io.element.android.x.core.data.StableCharSequence
|
||||||
|
import io.element.android.x.designsystem.components.avatar.Avatar
|
||||||
import io.element.android.x.designsystem.components.avatar.AvatarData
|
import io.element.android.x.designsystem.components.avatar.AvatarData
|
||||||
import io.element.android.x.features.messages.components.*
|
import io.element.android.x.features.messages.components.MessageEventBubble
|
||||||
import io.element.android.x.features.messages.model.*
|
import io.element.android.x.features.messages.components.MessagesReactionsView
|
||||||
import io.element.android.x.features.messages.model.content.*
|
import io.element.android.x.features.messages.components.MessagesTimelineItemEncryptedView
|
||||||
|
import io.element.android.x.features.messages.components.MessagesTimelineItemImageView
|
||||||
|
import io.element.android.x.features.messages.components.MessagesTimelineItemRedactedView
|
||||||
|
import io.element.android.x.features.messages.components.MessagesTimelineItemTextView
|
||||||
|
import io.element.android.x.features.messages.components.MessagesTimelineItemUnknownView
|
||||||
|
import io.element.android.x.features.messages.components.TimelineItemActionsScreen
|
||||||
|
import io.element.android.x.features.messages.model.AggregatedReaction
|
||||||
|
import io.element.android.x.features.messages.model.MessagesItemGroupPosition
|
||||||
|
import io.element.android.x.features.messages.model.MessagesItemGroupPositionProvider
|
||||||
|
import io.element.android.x.features.messages.model.MessagesItemReactionState
|
||||||
|
import io.element.android.x.features.messages.model.MessagesTimelineItemState
|
||||||
|
import io.element.android.x.features.messages.model.MessagesViewState
|
||||||
|
import io.element.android.x.features.messages.model.content.MessagesTimelineItemContent
|
||||||
|
import io.element.android.x.features.messages.model.content.MessagesTimelineItemContentProvider
|
||||||
|
import io.element.android.x.features.messages.model.content.MessagesTimelineItemEncryptedContent
|
||||||
|
import io.element.android.x.features.messages.model.content.MessagesTimelineItemImageContent
|
||||||
|
import io.element.android.x.features.messages.model.content.MessagesTimelineItemRedactedContent
|
||||||
|
import io.element.android.x.features.messages.model.content.MessagesTimelineItemTextBasedContent
|
||||||
|
import io.element.android.x.features.messages.model.content.MessagesTimelineItemUnknownContent
|
||||||
import io.element.android.x.features.messages.textcomposer.MessageComposerViewModel
|
import io.element.android.x.features.messages.textcomposer.MessageComposerViewModel
|
||||||
import io.element.android.x.features.messages.textcomposer.MessageComposerViewState
|
import io.element.android.x.features.messages.textcomposer.MessageComposerViewState
|
||||||
import io.element.android.x.textcomposer.MessageComposerMode
|
import io.element.android.x.textcomposer.MessageComposerMode
|
||||||
import io.element.android.x.textcomposer.TextComposer
|
import io.element.android.x.textcomposer.TextComposer
|
||||||
|
import java.lang.Math.random
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.lang.Math.random
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MessagesScreen(
|
fun MessagesScreen(
|
||||||
|
|
@ -61,7 +116,6 @@ fun MessagesScreen(
|
||||||
viewModel: MessagesViewModel = mavericksViewModel(argsFactory = { roomId }),
|
viewModel: MessagesViewModel = mavericksViewModel(argsFactory = { roomId }),
|
||||||
composerViewModel: MessageComposerViewModel = mavericksViewModel(argsFactory = { roomId })
|
composerViewModel: MessageComposerViewModel = mavericksViewModel(argsFactory = { roomId })
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun onSendMessage(textMessage: String) {
|
fun onSendMessage(textMessage: String) {
|
||||||
viewModel.sendMessage(textMessage)
|
viewModel.sendMessage(textMessage)
|
||||||
composerViewModel.updateText("")
|
composerViewModel.updateText("")
|
||||||
|
|
@ -88,7 +142,7 @@ fun MessagesScreen(
|
||||||
MessagesScreenContent(
|
MessagesScreenContent(
|
||||||
roomTitle = roomTitle,
|
roomTitle = roomTitle,
|
||||||
roomAvatar = roomAvatar,
|
roomAvatar = roomAvatar,
|
||||||
timelineItems = timelineItems().orEmpty(),
|
timelineItems = timelineItems().orEmpty().toImmutableList(),
|
||||||
hasMoreToLoad = hasMoreToLoad,
|
hasMoreToLoad = hasMoreToLoad,
|
||||||
onReachedLoadMore = viewModel::loadMore,
|
onReachedLoadMore = viewModel::loadMore,
|
||||||
onBackPressed = onBackPressed,
|
onBackPressed = onBackPressed,
|
||||||
|
|
@ -130,7 +184,7 @@ fun MessagesScreen(
|
||||||
fun MessagesScreenContent(
|
fun MessagesScreenContent(
|
||||||
roomTitle: String?,
|
roomTitle: String?,
|
||||||
roomAvatar: AvatarData?,
|
roomAvatar: AvatarData?,
|
||||||
timelineItems: List<MessagesTimelineItemState>,
|
timelineItems: ImmutableList<MessagesTimelineItemState>,
|
||||||
hasMoreToLoad: Boolean,
|
hasMoreToLoad: Boolean,
|
||||||
onReachedLoadMore: () -> Unit,
|
onReachedLoadMore: () -> Unit,
|
||||||
onBackPressed: () -> Unit,
|
onBackPressed: () -> Unit,
|
||||||
|
|
@ -146,9 +200,11 @@ fun MessagesScreenContent(
|
||||||
composerCanSendMessage: Boolean,
|
composerCanSendMessage: Boolean,
|
||||||
composerText: StableCharSequence?,
|
composerText: StableCharSequence?,
|
||||||
snackbarHostState: SnackbarHostState,
|
snackbarHostState: SnackbarHostState,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
LogCompositions(tag = "MessagesScreen", msg = "Content")
|
LogCompositions(tag = "MessagesScreen", msg = "Content")
|
||||||
Scaffold(
|
Scaffold(
|
||||||
|
modifier = modifier,
|
||||||
contentWindowInsets = WindowInsets.statusBars,
|
contentWindowInsets = WindowInsets.statusBars,
|
||||||
topBar = {
|
topBar = {
|
||||||
MessagesTopAppBar(
|
MessagesTopAppBar(
|
||||||
|
|
@ -187,7 +243,7 @@ fun MessagesScreenContent(
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MessagesContent(
|
fun MessagesContent(
|
||||||
timelineItems: List<MessagesTimelineItemState>,
|
timelineItems: ImmutableList<MessagesTimelineItemState>,
|
||||||
hasMoreToLoad: Boolean,
|
hasMoreToLoad: Boolean,
|
||||||
onReachedLoadMore: () -> Unit,
|
onReachedLoadMore: () -> Unit,
|
||||||
onSendMessage: (String) -> Unit,
|
onSendMessage: (String) -> Unit,
|
||||||
|
|
@ -203,7 +259,6 @@ fun MessagesContent(
|
||||||
composerText: StableCharSequence?,
|
composerText: StableCharSequence?,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val lazyListState = rememberLazyListState()
|
val lazyListState = rememberLazyListState()
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
|
|
@ -249,9 +304,11 @@ fun MessagesContent(
|
||||||
fun MessagesTopAppBar(
|
fun MessagesTopAppBar(
|
||||||
roomTitle: String?,
|
roomTitle: String?,
|
||||||
roomAvatar: AvatarData?,
|
roomAvatar: AvatarData?,
|
||||||
onBackPressed: () -> Unit,
|
modifier: Modifier = Modifier,
|
||||||
|
onBackPressed: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
|
modifier = modifier,
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
IconButton(onClick = onBackPressed) {
|
IconButton(onClick = onBackPressed) {
|
||||||
Icon(
|
Icon(
|
||||||
|
|
@ -282,7 +339,7 @@ fun MessagesTopAppBar(
|
||||||
@Composable
|
@Composable
|
||||||
fun TimelineItems(
|
fun TimelineItems(
|
||||||
lazyListState: LazyListState,
|
lazyListState: LazyListState,
|
||||||
timelineItems: List<MessagesTimelineItemState>,
|
timelineItems: ImmutableList<MessagesTimelineItemState>,
|
||||||
highlightedEventId: String?,
|
highlightedEventId: String?,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
hasMoreToLoad: Boolean = false,
|
hasMoreToLoad: Boolean = false,
|
||||||
|
|
@ -322,7 +379,6 @@ fun TimelineItems(
|
||||||
onLoadMore = onReachedLoadMore
|
onLoadMore = onReachedLoadMore
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun MessagesTimelineItemState.key(): String {
|
private fun MessagesTimelineItemState.key(): String {
|
||||||
|
|
@ -339,7 +395,6 @@ private fun MessagesTimelineItemState.contentType(): Int {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TimelineItemRow(
|
fun TimelineItemRow(
|
||||||
timelineItem: MessagesTimelineItemState,
|
timelineItem: MessagesTimelineItemState,
|
||||||
|
|
@ -426,7 +481,6 @@ fun MessageEventRow(
|
||||||
content = messageEvent.content,
|
content = messageEvent.content,
|
||||||
modifier = contentModifier
|
modifier = contentModifier
|
||||||
)
|
)
|
||||||
else -> TODO() /* compiler issue ? */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MessagesReactionsView(
|
MessagesReactionsView(
|
||||||
|
|
@ -471,8 +525,8 @@ private fun MessageSenderInformation(
|
||||||
@Composable
|
@Composable
|
||||||
internal fun BoxScope.MessagesScrollHelper(
|
internal fun BoxScope.MessagesScrollHelper(
|
||||||
lazyListState: LazyListState,
|
lazyListState: LazyListState,
|
||||||
timelineItems: List<MessagesTimelineItemState>,
|
timelineItems: ImmutableList<MessagesTimelineItemState>,
|
||||||
onLoadMore: () -> Unit,
|
onLoadMore: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
val firstVisibleItemIndex by remember { derivedStateOf { lazyListState.firstVisibleItemIndex } }
|
val firstVisibleItemIndex by remember { derivedStateOf { lazyListState.firstVisibleItemIndex } }
|
||||||
|
|
@ -526,7 +580,6 @@ internal fun BoxScope.MessagesScrollHelper(
|
||||||
Icon(Icons.Default.ArrowDownward, "")
|
Icon(Icons.Default.ArrowDownward, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -543,7 +596,6 @@ internal fun MessagesLoadingMoreIndicator() {
|
||||||
color = MaterialTheme.colorScheme.primary
|
color = MaterialTheme.colorScheme.primary
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class MessagesItemGroupPositionToMessagesTimelineItemContentProvider :
|
class MessagesItemGroupPositionToMessagesTimelineItemContentProvider :
|
||||||
|
|
@ -551,6 +603,7 @@ class MessagesItemGroupPositionToMessagesTimelineItemContentProvider :
|
||||||
MessagesItemGroupPositionProvider() to MessagesTimelineItemContentProvider()
|
MessagesItemGroupPositionProvider() to MessagesTimelineItemContentProvider()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Suppress("PreviewPublic")
|
||||||
@Preview(showBackground = true)
|
@Preview(showBackground = true)
|
||||||
@Composable
|
@Composable
|
||||||
fun TimelineItemsPreview(
|
fun TimelineItemsPreview(
|
||||||
|
|
@ -559,7 +612,7 @@ fun TimelineItemsPreview(
|
||||||
) {
|
) {
|
||||||
TimelineItems(
|
TimelineItems(
|
||||||
lazyListState = LazyListState(),
|
lazyListState = LazyListState(),
|
||||||
timelineItems = listOf(
|
timelineItems = persistentListOf(
|
||||||
// 3 items (First Middle Last) with isMine = false
|
// 3 items (First Middle Last) with isMine = false
|
||||||
createMessageEvent(
|
createMessageEvent(
|
||||||
isMine = false,
|
isMine = false,
|
||||||
|
|
|
||||||
|
|
@ -230,4 +230,4 @@ class MessagesViewModel(
|
||||||
timeline.callback = null
|
timeline.callback = null
|
||||||
timeline.dispose()
|
timeline.dispose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,13 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Shape
|
import androidx.compose.ui.graphics.Shape
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import io.element.android.x.designsystem.*
|
import io.element.android.x.designsystem.LocalIsDarkTheme
|
||||||
|
import io.element.android.x.designsystem.MessageHighlightDark
|
||||||
|
import io.element.android.x.designsystem.MessageHighlightLight
|
||||||
|
import io.element.android.x.designsystem.SystemGrey5Dark
|
||||||
|
import io.element.android.x.designsystem.SystemGrey5Light
|
||||||
|
import io.element.android.x.designsystem.SystemGrey6Dark
|
||||||
|
import io.element.android.x.designsystem.SystemGrey6Light
|
||||||
import io.element.android.x.features.messages.model.MessagesItemGroupPosition
|
import io.element.android.x.features.messages.model.MessagesItemGroupPosition
|
||||||
|
|
||||||
private val BUBBLE_RADIUS = 16.dp
|
private val BUBBLE_RADIUS = 16.dp
|
||||||
|
|
@ -26,9 +32,9 @@ fun MessageEventBubble(
|
||||||
interactionSource: MutableInteractionSource,
|
interactionSource: MutableInteractionSource,
|
||||||
isHighlighted: Boolean,
|
isHighlighted: Boolean,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit = {},
|
||||||
onLongClick: () -> Unit,
|
onLongClick: () -> Unit = {},
|
||||||
content: @Composable () -> Unit,
|
content: @Composable () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
fun bubbleShape(): Shape {
|
fun bubbleShape(): Shape {
|
||||||
return when (groupPosition) {
|
return when (groupPosition) {
|
||||||
|
|
@ -102,4 +108,4 @@ fun MessageEventBubble(
|
||||||
shape = bubbleShape,
|
shape = bubbleShape,
|
||||||
content = content
|
content = content
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ fun MessagesReactionsView(
|
||||||
reactionsState: MessagesItemReactionState,
|
reactionsState: MessagesItemReactionState,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
if(reactionsState.reactions.isEmpty()) return
|
if (reactionsState.reactions.isEmpty()) return
|
||||||
FlowRow(
|
FlowRow(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
mainAxisSpacing = 2.dp,
|
mainAxisSpacing = 2.dp,
|
||||||
|
|
@ -53,4 +53,4 @@ fun MessagesReactionButton(reaction: AggregatedReaction, modifier: Modifier = Mo
|
||||||
Text(text = reaction.count, color = MaterialTheme.colorScheme.secondary, fontSize = 12.sp)
|
Text(text = reaction.count, color = MaterialTheme.colorScheme.secondary, fontSize = 12.sp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,28 @@
|
||||||
package io.element.android.x.features.messages.components
|
package io.element.android.x.features.messages.components
|
||||||
|
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.imePadding
|
||||||
|
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material.*
|
import androidx.compose.material.ExperimentalMaterialApi
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.material.ListItem
|
||||||
|
import androidx.compose.material.LocalContentColor
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.material.ModalBottomSheetLayout
|
||||||
|
import androidx.compose.material.ModalBottomSheetState
|
||||||
|
import androidx.compose.material.ModalBottomSheetValue
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.snapshotFlow
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.platform.LocalFocusManager
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.airbnb.mvrx.compose.collectAsState
|
import com.airbnb.mvrx.compose.collectAsState
|
||||||
import io.element.android.x.designsystem.components.VectorIcon
|
import io.element.android.x.designsystem.components.VectorIcon
|
||||||
|
|
@ -21,7 +35,6 @@ import io.element.android.x.features.messages.model.MessagesTimelineItemState
|
||||||
import io.element.android.x.features.messages.model.MessagesViewState
|
import io.element.android.x.features.messages.model.MessagesViewState
|
||||||
import io.element.android.x.features.messages.model.content.MessagesTimelineItemTextBasedContent
|
import io.element.android.x.features.messages.model.content.MessagesTimelineItemTextBasedContent
|
||||||
import io.element.android.x.features.messages.textcomposer.MessageComposerViewModel
|
import io.element.android.x.features.messages.textcomposer.MessageComposerViewModel
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
@ -63,7 +76,6 @@ fun TimelineItemActionsScreen(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ModalBottomSheetLayout(
|
ModalBottomSheetLayout(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
sheetState = modalBottomSheetState,
|
sheetState = modalBottomSheetState,
|
||||||
|
|
@ -71,46 +83,47 @@ fun TimelineItemActionsScreen(
|
||||||
SheetContent(
|
SheetContent(
|
||||||
actionsSheetState = itemActionsSheetState(),
|
actionsSheetState = itemActionsSheetState(),
|
||||||
onActionClicked = ::onItemActionClicked,
|
onActionClicked = ::onItemActionClicked,
|
||||||
modifier = Modifier.navigationBarsPadding().imePadding()
|
modifier = Modifier
|
||||||
|
.navigationBarsPadding()
|
||||||
|
.imePadding()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun SheetContent(
|
private fun SheetContent(
|
||||||
actionsSheetState: MessagesItemActionsSheetState?,
|
actionsSheetState: MessagesItemActionsSheetState?,
|
||||||
onActionClicked: (MessagesItemAction, MessagesTimelineItemState.MessageEvent) -> Unit,
|
modifier: Modifier = Modifier,
|
||||||
modifier: Modifier = Modifier
|
onActionClicked: (MessagesItemAction, MessagesTimelineItemState.MessageEvent) -> Unit = { _, _ -> },
|
||||||
) {
|
) {
|
||||||
if (actionsSheetState == null || actionsSheetState.actions.isEmpty()) {
|
if (actionsSheetState == null || actionsSheetState.actions.isEmpty()) {
|
||||||
// Crashes if sheetContent size is zero
|
// Crashes if sheetContent size is zero
|
||||||
Box(modifier = modifier.size(1.dp))
|
Box(modifier = modifier.size(1.dp))
|
||||||
return
|
} else {
|
||||||
}
|
LazyColumn(
|
||||||
LazyColumn(
|
modifier = modifier
|
||||||
modifier = modifier
|
.fillMaxWidth()
|
||||||
.fillMaxWidth()
|
) {
|
||||||
) {
|
items(actionsSheetState.actions) {
|
||||||
items(actionsSheetState.actions) {
|
ListItem(
|
||||||
ListItem(
|
modifier = Modifier.clickable {
|
||||||
modifier = Modifier.clickable {
|
onActionClicked(it, actionsSheetState.targetItem)
|
||||||
onActionClicked(it, actionsSheetState.targetItem)
|
},
|
||||||
},
|
text = {
|
||||||
text = {
|
Text(
|
||||||
Text(
|
text = it.title,
|
||||||
text = it.title,
|
color = if (it.destructive) MaterialTheme.colors.error else Color.Unspecified,
|
||||||
color = if (it.destructive) MaterialTheme.colors.error else Color.Unspecified,
|
)
|
||||||
)
|
},
|
||||||
},
|
icon = {
|
||||||
icon = {
|
VectorIcon(
|
||||||
VectorIcon(
|
resourceId = it.icon,
|
||||||
resourceId = it.icon,
|
tint = if (it.destructive) MaterialTheme.colors.error else LocalContentColor.current,
|
||||||
tint = if (it.destructive) MaterialTheme.colors.error else LocalContentColor.current,
|
)
|
||||||
)
|
}
|
||||||
}
|
)
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,4 +17,4 @@ fun MessagesTimelineItemEncryptedView(
|
||||||
icon = Icons.Default.Warning,
|
icon = Icons.Default.Warning,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.aspectRatio
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.heightIn
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
|
@ -16,7 +15,6 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.painter.ColorPainter
|
import androidx.compose.ui.graphics.painter.ColorPainter
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
import io.element.android.x.features.messages.model.content.MessagesTimelineItemImageContent
|
import io.element.android.x.features.messages.model.content.MessagesTimelineItemImageContent
|
||||||
|
|
@ -26,9 +24,9 @@ fun MessagesTimelineItemImageView(
|
||||||
content: MessagesTimelineItemImageContent,
|
content: MessagesTimelineItemImageContent,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val widthPercent = if(content.aspectRatio > 1f){
|
val widthPercent = if (content.aspectRatio > 1f) {
|
||||||
1f
|
1f
|
||||||
}else {
|
} else {
|
||||||
0.7f
|
0.7f
|
||||||
}
|
}
|
||||||
Box(
|
Box(
|
||||||
|
|
@ -37,7 +35,6 @@ fun MessagesTimelineItemImageView(
|
||||||
.aspectRatio(content.aspectRatio),
|
.aspectRatio(content.aspectRatio),
|
||||||
contentAlignment = Alignment.Center,
|
contentAlignment = Alignment.Center,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
var isLoading = rememberSaveable(content.imageMeta) { mutableStateOf(true) }
|
var isLoading = rememberSaveable(content.imageMeta) { mutableStateOf(true) }
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val model = ImageRequest.Builder(context)
|
val model = ImageRequest.Builder(context)
|
||||||
|
|
@ -52,4 +49,4 @@ fun MessagesTimelineItemImageView(
|
||||||
onSuccess = { isLoading.value = false },
|
onSuccess = { isLoading.value = false },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,4 +40,4 @@ fun MessagesTimelineItemInformativeView(
|
||||||
text = text
|
text = text
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,4 +17,4 @@ fun MessagesTimelineItemRedactedView(
|
||||||
icon = Icons.Default.Delete,
|
icon = Icons.Default.Delete,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@ fun MessagesTimelineItemTextView(
|
||||||
content: MessagesTimelineItemTextBasedContent,
|
content: MessagesTimelineItemTextBasedContent,
|
||||||
interactionSource: MutableInteractionSource,
|
interactionSource: MutableInteractionSource,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onTextClicked: () -> Unit,
|
onTextClicked: () -> Unit = {},
|
||||||
onTextLongClicked: () -> Unit,
|
onTextLongClicked: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val htmlDocument = content.htmlDocument
|
val htmlDocument = content.htmlDocument
|
||||||
if (htmlDocument != null) {
|
if (htmlDocument != null) {
|
||||||
|
|
@ -74,4 +74,4 @@ private fun String.linkify(
|
||||||
end = end
|
end = end
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,4 +17,4 @@ fun MessagesTimelineItemUnknownView(
|
||||||
icon = Icons.Default.Info,
|
icon = Icons.Default.Info,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,17 +9,25 @@ import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.text.InlineTextContent
|
import androidx.compose.foundation.text.InlineTextContent
|
||||||
import androidx.compose.foundation.text.appendInlineContent
|
import androidx.compose.foundation.text.appendInlineContent
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.ColorScheme
|
||||||
|
import androidx.compose.material3.LocalTextStyle
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.drawBehind
|
import androidx.compose.ui.draw.drawBehind
|
||||||
import androidx.compose.ui.geometry.Offset
|
import androidx.compose.ui.geometry.Offset
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.text.*
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
|
import androidx.compose.ui.text.SpanStyle
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.buildAnnotatedString
|
||||||
import androidx.compose.ui.text.font.FontFamily
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
import androidx.compose.ui.text.font.FontStyle
|
import androidx.compose.ui.text.font.FontStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextDecoration
|
import androidx.compose.ui.text.style.TextDecoration
|
||||||
|
import androidx.compose.ui.text.withStyle
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import com.google.accompanist.flowlayout.FlowRow
|
import com.google.accompanist.flowlayout.FlowRow
|
||||||
|
|
@ -27,6 +35,7 @@ import io.element.android.x.designsystem.LinkColor
|
||||||
import io.element.android.x.designsystem.components.ClickableLinkText
|
import io.element.android.x.designsystem.components.ClickableLinkText
|
||||||
import io.element.android.x.matrix.permalink.PermalinkData
|
import io.element.android.x.matrix.permalink.PermalinkData
|
||||||
import io.element.android.x.matrix.permalink.PermalinkParser
|
import io.element.android.x.matrix.permalink.PermalinkParser
|
||||||
|
import kotlinx.collections.immutable.persistentMapOf
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import org.jsoup.nodes.Node
|
import org.jsoup.nodes.Node
|
||||||
|
|
@ -38,34 +47,33 @@ private const val chipId = "chip"
|
||||||
fun HtmlDocument(
|
fun HtmlDocument(
|
||||||
document: Document,
|
document: Document,
|
||||||
interactionSource: MutableInteractionSource,
|
interactionSource: MutableInteractionSource,
|
||||||
onTextClicked: () -> Unit,
|
|
||||||
onTextLongClicked: () -> Unit,
|
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
onTextClicked: () -> Unit = {},
|
||||||
|
onTextLongClicked: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
HtmlBody(
|
HtmlBody(
|
||||||
body = document.body(),
|
body = document.body(),
|
||||||
|
interactionSource = interactionSource,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
onTextClicked = onTextClicked,
|
onTextClicked = onTextClicked,
|
||||||
onTextLongClicked = onTextLongClicked,
|
onTextLongClicked = onTextLongClicked,
|
||||||
interactionSource = interactionSource
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun HtmlBody(
|
private fun HtmlBody(
|
||||||
body: Element,
|
body: Element,
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
onTextClicked: () -> Unit,
|
|
||||||
onTextLongClicked: () -> Unit,
|
|
||||||
interactionSource: MutableInteractionSource,
|
interactionSource: MutableInteractionSource,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onTextClicked: () -> Unit = {},
|
||||||
|
onTextLongClicked: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun NodesFlowRode(
|
fun NodesFlowRode(
|
||||||
nodes: Iterator<Node>,
|
nodes: Iterator<Node>,
|
||||||
onTextClicked: () -> Unit,
|
|
||||||
onTextLongClicked: () -> Unit,
|
|
||||||
interactionSource: MutableInteractionSource,
|
interactionSource: MutableInteractionSource,
|
||||||
|
onTextClicked: () -> Unit = {},
|
||||||
|
onTextLongClicked: () -> Unit = {},
|
||||||
) = FlowRow(
|
) = FlowRow(
|
||||||
mainAxisSpacing = 2.dp,
|
mainAxisSpacing = 2.dp,
|
||||||
crossAxisSpacing = 8.dp,
|
crossAxisSpacing = 8.dp,
|
||||||
|
|
@ -106,9 +114,9 @@ private fun HtmlBody(
|
||||||
while (nodesIterator.hasNext()) {
|
while (nodesIterator.hasNext()) {
|
||||||
NodesFlowRode(
|
NodesFlowRode(
|
||||||
nodes = nodesIterator,
|
nodes = nodesIterator,
|
||||||
|
interactionSource = interactionSource,
|
||||||
onTextClicked = onTextClicked,
|
onTextClicked = onTextClicked,
|
||||||
onTextLongClicked = onTextLongClicked,
|
onTextLongClicked = onTextLongClicked,
|
||||||
interactionSource = interactionSource
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -125,10 +133,10 @@ private fun Element.isInline(): Boolean {
|
||||||
@Composable
|
@Composable
|
||||||
private fun HtmlBlock(
|
private fun HtmlBlock(
|
||||||
element: Element,
|
element: Element,
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
onTextClicked: () -> Unit,
|
|
||||||
onTextLongClicked: () -> Unit,
|
|
||||||
interactionSource: MutableInteractionSource,
|
interactionSource: MutableInteractionSource,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onTextClicked: () -> Unit = {},
|
||||||
|
onTextLongClicked: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val blockModifier = modifier
|
val blockModifier = modifier
|
||||||
.padding(top = 4.dp)
|
.padding(top = 4.dp)
|
||||||
|
|
@ -183,10 +191,10 @@ private fun HtmlBlock(
|
||||||
@Composable
|
@Composable
|
||||||
private fun HtmlInline(
|
private fun HtmlInline(
|
||||||
element: Element,
|
element: Element,
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
onTextClicked: () -> Unit,
|
|
||||||
onTextLongClicked: () -> Unit,
|
|
||||||
interactionSource: MutableInteractionSource,
|
interactionSource: MutableInteractionSource,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onTextClicked: () -> Unit = {},
|
||||||
|
onTextLongClicked: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
Box(modifier) {
|
Box(modifier) {
|
||||||
val styledText = buildAnnotatedString {
|
val styledText = buildAnnotatedString {
|
||||||
|
|
@ -202,7 +210,10 @@ private fun HtmlInline(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun HtmlPreformatted(pre: Element, modifier: Modifier = Modifier) {
|
private fun HtmlPreformatted(
|
||||||
|
pre: Element,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
val isCode = pre.firstElementChild()?.normalName() == "code"
|
val isCode = pre.firstElementChild()?.normalName() == "code"
|
||||||
val backgroundColor =
|
val backgroundColor =
|
||||||
if (isCode) MaterialTheme.colorScheme.codeBackground() else Color.Unspecified
|
if (isCode) MaterialTheme.colorScheme.codeBackground() else Color.Unspecified
|
||||||
|
|
@ -221,9 +232,10 @@ private fun HtmlPreformatted(pre: Element, modifier: Modifier = Modifier) {
|
||||||
@Composable
|
@Composable
|
||||||
private fun HtmlParagraph(
|
private fun HtmlParagraph(
|
||||||
paragraph: Element,
|
paragraph: Element,
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
onTextClicked: () -> Unit, onTextLongClicked: () -> Unit,
|
|
||||||
interactionSource: MutableInteractionSource,
|
interactionSource: MutableInteractionSource,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onTextClicked: () -> Unit = {},
|
||||||
|
onTextLongClicked: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
Box(modifier) {
|
Box(modifier) {
|
||||||
val styledText = buildAnnotatedString {
|
val styledText = buildAnnotatedString {
|
||||||
|
|
@ -239,9 +251,10 @@ private fun HtmlParagraph(
|
||||||
@Composable
|
@Composable
|
||||||
private fun HtmlBlockquote(
|
private fun HtmlBlockquote(
|
||||||
blockquote: Element,
|
blockquote: Element,
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
onTextClicked: () -> Unit, onTextLongClicked: () -> Unit,
|
|
||||||
interactionSource: MutableInteractionSource,
|
interactionSource: MutableInteractionSource,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onTextClicked: () -> Unit = {},
|
||||||
|
onTextLongClicked: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val color = MaterialTheme.colorScheme.onBackground
|
val color = MaterialTheme.colorScheme.onBackground
|
||||||
Box(
|
Box(
|
||||||
|
|
@ -268,13 +281,13 @@ private fun HtmlBlockquote(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun HtmlHeading(
|
private fun HtmlHeading(
|
||||||
heading: Element,
|
heading: Element,
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
onTextClicked: () -> Unit, onTextLongClicked: () -> Unit,
|
|
||||||
interactionSource: MutableInteractionSource,
|
interactionSource: MutableInteractionSource,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onTextClicked: () -> Unit = {},
|
||||||
|
onTextLongClicked: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val style = when (heading.normalName()) {
|
val style = when (heading.normalName()) {
|
||||||
"h1" -> MaterialTheme.typography.headlineLarge.copy(fontSize = 30.sp)
|
"h1" -> MaterialTheme.typography.headlineLarge.copy(fontSize = 30.sp)
|
||||||
|
|
@ -304,9 +317,10 @@ private fun HtmlHeading(
|
||||||
@Composable
|
@Composable
|
||||||
private fun HtmlMxReply(
|
private fun HtmlMxReply(
|
||||||
mxReply: Element,
|
mxReply: Element,
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
onTextClicked: () -> Unit, onTextLongClicked: () -> Unit,
|
|
||||||
interactionSource: MutableInteractionSource,
|
interactionSource: MutableInteractionSource,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onTextClicked: () -> Unit = {},
|
||||||
|
onTextLongClicked: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val blockquote = mxReply.childNodes().firstOrNull() ?: return
|
val blockquote = mxReply.childNodes().firstOrNull() ?: return
|
||||||
val shape = RoundedCornerShape(12.dp)
|
val shape = RoundedCornerShape(12.dp)
|
||||||
|
|
@ -356,9 +370,10 @@ private fun HtmlMxReply(
|
||||||
@Composable
|
@Composable
|
||||||
private fun HtmlOrderedList(
|
private fun HtmlOrderedList(
|
||||||
orderedList: Element,
|
orderedList: Element,
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
onTextClicked: () -> Unit, onTextLongClicked: () -> Unit,
|
|
||||||
interactionSource: MutableInteractionSource,
|
interactionSource: MutableInteractionSource,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onTextClicked: () -> Unit = {},
|
||||||
|
onTextLongClicked: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
var number = 1
|
var number = 1
|
||||||
val delimiter = "."
|
val delimiter = "."
|
||||||
|
|
@ -381,9 +396,10 @@ private fun HtmlOrderedList(
|
||||||
@Composable
|
@Composable
|
||||||
private fun HtmlUnorderedList(
|
private fun HtmlUnorderedList(
|
||||||
unorderedList: Element,
|
unorderedList: Element,
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
onTextClicked: () -> Unit, onTextLongClicked: () -> Unit,
|
|
||||||
interactionSource: MutableInteractionSource,
|
interactionSource: MutableInteractionSource,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onTextClicked: () -> Unit = {},
|
||||||
|
onTextLongClicked: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val marker = "・"
|
val marker = "・"
|
||||||
HtmlListItems(
|
HtmlListItems(
|
||||||
|
|
@ -402,14 +418,14 @@ private fun HtmlUnorderedList(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun HtmlListItems(
|
private fun HtmlListItems(
|
||||||
list: Element,
|
list: Element,
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
onTextClicked: () -> Unit, onTextLongClicked: () -> Unit,
|
|
||||||
interactionSource: MutableInteractionSource,
|
interactionSource: MutableInteractionSource,
|
||||||
content: @Composable (node: TextNode) -> Unit
|
modifier: Modifier = Modifier,
|
||||||
|
onTextClicked: () -> Unit = {},
|
||||||
|
onTextLongClicked: () -> Unit = {},
|
||||||
|
content: @Composable (node: TextNode) -> Unit = {}
|
||||||
) {
|
) {
|
||||||
Column(modifier = modifier) {
|
Column(modifier = modifier) {
|
||||||
for (node in list.children()) {
|
for (node in list.children()) {
|
||||||
|
|
@ -420,13 +436,12 @@ private fun HtmlListItems(
|
||||||
}
|
}
|
||||||
is Element -> HtmlBlock(
|
is Element -> HtmlBlock(
|
||||||
element = innerNode,
|
element = innerNode,
|
||||||
modifier = modifier.padding(start = 4.dp),
|
modifier = Modifier.padding(start = 4.dp),
|
||||||
onTextClicked = onTextClicked, onTextLongClicked = onTextLongClicked,
|
onTextClicked = onTextClicked, onTextLongClicked = onTextLongClicked,
|
||||||
interactionSource = interactionSource
|
interactionSource = interactionSource
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -439,7 +454,6 @@ private fun AnnotatedString.Builder.appendInlineChildrenElements(
|
||||||
childNodes: List<Node>,
|
childNodes: List<Node>,
|
||||||
colors: ColorScheme
|
colors: ColorScheme
|
||||||
) {
|
) {
|
||||||
|
|
||||||
for (node in childNodes) {
|
for (node in childNodes) {
|
||||||
when (node) {
|
when (node) {
|
||||||
is TextNode -> {
|
is TextNode -> {
|
||||||
|
|
@ -452,7 +466,6 @@ private fun AnnotatedString.Builder.appendInlineChildrenElements(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun AnnotatedString.Builder.appendInlineElement(element: Element, colors: ColorScheme) {
|
private fun AnnotatedString.Builder.appendInlineElement(element: Element, colors: ColorScheme) {
|
||||||
when (element.normalName()) {
|
when (element.normalName()) {
|
||||||
"br" -> {
|
"br" -> {
|
||||||
|
|
@ -490,7 +503,6 @@ private fun AnnotatedString.Builder.appendInlineElement(element: Element, colors
|
||||||
appendInlineChildrenElements(element.childNodes(), colors)
|
appendInlineChildrenElements(element.childNodes(), colors)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun AnnotatedString.Builder.appendLink(link: Element) {
|
private fun AnnotatedString.Builder.appendLink(link: Element) {
|
||||||
|
|
@ -521,13 +533,13 @@ private fun AnnotatedString.Builder.appendLink(link: Element) {
|
||||||
@Composable
|
@Composable
|
||||||
private fun HtmlText(
|
private fun HtmlText(
|
||||||
text: AnnotatedString,
|
text: AnnotatedString,
|
||||||
|
interactionSource: MutableInteractionSource,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
style: TextStyle = LocalTextStyle.current,
|
style: TextStyle = LocalTextStyle.current,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit = {},
|
||||||
onLongClick: () -> Unit,
|
onLongClick: () -> Unit = {},
|
||||||
interactionSource: MutableInteractionSource,
|
|
||||||
) {
|
) {
|
||||||
val inlineContentMap = emptyMap<String, InlineTextContent>()
|
val inlineContentMap = persistentMapOf<String, InlineTextContent>()
|
||||||
ClickableLinkText(
|
ClickableLinkText(
|
||||||
text = text,
|
text = text,
|
||||||
linkAnnotationTag = "URL",
|
linkAnnotationTag = "URL",
|
||||||
|
|
@ -539,4 +551,3 @@ private fun HtmlText(
|
||||||
onLongClick = onLongClick
|
onLongClick = onLongClick
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,5 +37,4 @@ internal class CacheInvalidator(private val itemStatesCache: MutableList<Message
|
||||||
itemStatesCache.removeAt(position)
|
itemStatesCache.removeAt(position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,5 +31,4 @@ internal class MatrixTimelineItemsDiffCallback(
|
||||||
val newItem = newList.getOrNull(newItemPosition)
|
val newItem = newList.getOrNull(newItemPosition)
|
||||||
return oldItem == newItem
|
return oldItem == newItem
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -15,4 +15,4 @@ sealed class MessagesItemAction(
|
||||||
object Redact : MessagesItemAction("Redact", VectorIcons.Delete, destructive = true)
|
object Redact : MessagesItemAction("Redact", VectorIcons.Delete, destructive = true)
|
||||||
object Reply : MessagesItemAction("Reply", VectorIcons.Reply)
|
object Reply : MessagesItemAction("Reply", VectorIcons.Reply)
|
||||||
object Edit : MessagesItemAction("Edit", VectorIcons.Edit)
|
object Edit : MessagesItemAction("Edit", VectorIcons.Edit)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ sealed interface MessagesItemGroupPosition {
|
||||||
First, None -> true
|
First, None -> true
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class MessagesItemGroupPositionProvider : PreviewParameterProvider<MessagesItemGroupPosition> {
|
internal class MessagesItemGroupPositionProvider : PreviewParameterProvider<MessagesItemGroupPosition> {
|
||||||
|
|
@ -22,4 +21,4 @@ internal class MessagesItemGroupPositionProvider : PreviewParameterProvider<Mess
|
||||||
MessagesItemGroupPosition.Last,
|
MessagesItemGroupPosition.Last,
|
||||||
MessagesItemGroupPosition.None,
|
MessagesItemGroupPosition.None,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,10 @@ import androidx.compose.runtime.Stable
|
||||||
data class MessagesItemReactionState(
|
data class MessagesItemReactionState(
|
||||||
val reactions: List<AggregatedReaction>
|
val reactions: List<AggregatedReaction>
|
||||||
)
|
)
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
data class AggregatedReaction(
|
data class AggregatedReaction(
|
||||||
val key: String,
|
val key: String,
|
||||||
val count: String,
|
val count: String,
|
||||||
val isHighlighted: Boolean = false
|
val isHighlighted: Boolean = false
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,5 @@ sealed interface MessagesTimelineItemState {
|
||||||
val showSenderInformation = groupPosition.isNew() && !isMine
|
val showSenderInformation = groupPosition.isNew() && !isMine
|
||||||
|
|
||||||
val safeSenderName: String = senderDisplayName ?: senderId
|
val safeSenderName: String = senderDisplayName ?: senderId
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@ package io.element.android.x.features.messages.model.content
|
||||||
|
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
import org.matrix.rustcomponents.sdk.EncryptedMessage
|
import org.matrix.rustcomponents.sdk.EncryptedMessage
|
||||||
import org.matrix.rustcomponents.sdk.FormattedBody
|
|
||||||
import org.matrix.rustcomponents.sdk.MessageFormat
|
|
||||||
|
|
||||||
sealed interface MessagesTimelineItemContent
|
sealed interface MessagesTimelineItemContent
|
||||||
|
|
||||||
|
|
@ -28,4 +26,4 @@ class MessagesTimelineItemContentProvider : PreviewParameterProvider<MessagesTim
|
||||||
),
|
),
|
||||||
MessagesTimelineItemUnknownContent,
|
MessagesTimelineItemUnknownContent,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,4 +5,4 @@ import org.jsoup.nodes.Document
|
||||||
data class MessagesTimelineItemEmoteContent(
|
data class MessagesTimelineItemEmoteContent(
|
||||||
override val body: String,
|
override val body: String,
|
||||||
override val htmlDocument: Document?
|
override val htmlDocument: Document?
|
||||||
) : MessagesTimelineItemTextBasedContent
|
) : MessagesTimelineItemTextBasedContent
|
||||||
|
|
|
||||||
|
|
@ -4,4 +4,4 @@ import org.matrix.rustcomponents.sdk.EncryptedMessage
|
||||||
|
|
||||||
data class MessagesTimelineItemEncryptedContent(
|
data class MessagesTimelineItemEncryptedContent(
|
||||||
val encryptedMessage: EncryptedMessage
|
val encryptedMessage: EncryptedMessage
|
||||||
) : MessagesTimelineItemContent
|
) : MessagesTimelineItemContent
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,4 @@ data class MessagesTimelineItemImageContent(
|
||||||
val imageMeta: MediaResolver.Meta,
|
val imageMeta: MediaResolver.Meta,
|
||||||
val blurhash: String?,
|
val blurhash: String?,
|
||||||
val aspectRatio: Float
|
val aspectRatio: Float
|
||||||
) : MessagesTimelineItemContent
|
) : MessagesTimelineItemContent
|
||||||
|
|
|
||||||
|
|
@ -5,4 +5,4 @@ import org.jsoup.nodes.Document
|
||||||
data class MessagesTimelineItemNoticeContent(
|
data class MessagesTimelineItemNoticeContent(
|
||||||
override val body: String,
|
override val body: String,
|
||||||
override val htmlDocument: Document?
|
override val htmlDocument: Document?
|
||||||
) : MessagesTimelineItemTextBasedContent
|
) : MessagesTimelineItemTextBasedContent
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
package io.element.android.x.features.messages.model.content
|
package io.element.android.x.features.messages.model.content
|
||||||
|
|
||||||
object MessagesTimelineItemRedactedContent : MessagesTimelineItemContent
|
object MessagesTimelineItemRedactedContent : MessagesTimelineItemContent
|
||||||
|
|
|
||||||
|
|
@ -5,4 +5,4 @@ import org.jsoup.nodes.Document
|
||||||
sealed interface MessagesTimelineItemTextBasedContent : MessagesTimelineItemContent {
|
sealed interface MessagesTimelineItemTextBasedContent : MessagesTimelineItemContent {
|
||||||
val body: String
|
val body: String
|
||||||
val htmlDocument: Document?
|
val htmlDocument: Document?
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,4 +5,4 @@ import org.jsoup.nodes.Document
|
||||||
data class MessagesTimelineItemTextContent(
|
data class MessagesTimelineItemTextContent(
|
||||||
override val body: String,
|
override val body: String,
|
||||||
override val htmlDocument: Document?
|
override val htmlDocument: Document?
|
||||||
) : MessagesTimelineItemTextBasedContent
|
) : MessagesTimelineItemTextBasedContent
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
package io.element.android.x.features.messages.model.content
|
package io.element.android.x.features.messages.model.content
|
||||||
|
|
||||||
object MessagesTimelineItemUnknownContent : MessagesTimelineItemContent
|
object MessagesTimelineItemUnknownContent : MessagesTimelineItemContent
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import io.element.android.x.core.data.StableCharSequence
|
||||||
import io.element.android.x.matrix.MatrixClient
|
import io.element.android.x.matrix.MatrixClient
|
||||||
import io.element.android.x.matrix.MatrixInstance
|
import io.element.android.x.matrix.MatrixInstance
|
||||||
|
|
||||||
|
|
||||||
class MessageComposerViewModel(
|
class MessageComposerViewModel(
|
||||||
private val client: MatrixClient,
|
private val client: MatrixClient,
|
||||||
private val initialState: MessageComposerViewState
|
private val initialState: MessageComposerViewState
|
||||||
|
|
@ -45,4 +44,4 @@ class MessageComposerViewModel(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,4 +16,4 @@ data class MessageComposerViewState(
|
||||||
// val voiceBroadcastState: VoiceBroadcastState? = null,
|
// val voiceBroadcastState: VoiceBroadcastState? = null,
|
||||||
val text: StableCharSequence? = null,
|
val text: StableCharSequence? = null,
|
||||||
val isFullScreen: Boolean = false,
|
val isFullScreen: Boolean = false,
|
||||||
) : MavericksState
|
) : MavericksState
|
||||||
|
|
|
||||||
|
|
@ -5,4 +5,4 @@ internal inline fun <reified T> MutableList<T?>.invalidateLast() {
|
||||||
if (indexOfLast > 0) {
|
if (indexOfLast > 0) {
|
||||||
set(indexOfLast - 1, null)
|
set(indexOfLast - 1, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
package io.element.android.x.features.messages
|
package io.element.android.x.features.messages
|
||||||
|
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
import org.junit.Assert.*
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Example local unit test, which will execute on the development machine (host).
|
* Example local unit test, which will execute on the development machine (host).
|
||||||
*
|
*
|
||||||
|
|
@ -14,4 +13,4 @@ class ExampleUnitTest {
|
||||||
fun addition_isCorrect() {
|
fun addition_isCorrect() {
|
||||||
assertEquals(4, 2 + 2)
|
assertEquals(4, 2 + 2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,9 @@ dependencies {
|
||||||
implementation(project(":libraries:elementresources"))
|
implementation(project(":libraries:elementresources"))
|
||||||
implementation(project(":libraries:designsystem"))
|
implementation(project(":libraries:designsystem"))
|
||||||
implementation(libs.mavericks.compose)
|
implementation(libs.mavericks.compose)
|
||||||
implementation(libs.timber)
|
|
||||||
implementation(libs.accompanist.pager)
|
implementation(libs.accompanist.pager)
|
||||||
implementation(libs.accompanist.pagerindicator)
|
implementation(libs.accompanist.pagerindicator)
|
||||||
testImplementation(libs.test.junit)
|
testImplementation(libs.test.junit)
|
||||||
androidTestImplementation(libs.test.junitext)
|
androidTestImplementation(libs.test.junitext)
|
||||||
ksp(libs.showkase.processor)
|
ksp(libs.showkase.processor)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,11 @@
|
||||||
package io.element.android.x.features.login
|
package io.element.android.x.features.login
|
||||||
|
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
import org.junit.Assert.*
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instrumented test, which will execute on an Android device.
|
* Instrumented test, which will execute on an Android device.
|
||||||
*
|
*
|
||||||
|
|
@ -21,4 +19,4 @@ class ExampleInstrumentedTest {
|
||||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||||
assertEquals("io.element.android.x.features.login.test", appContext.packageName)
|
assertEquals("io.element.android.x.features.login.test", appContext.packageName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,24 @@
|
||||||
package io.element.android.x.features.onboarding
|
package io.element.android.x.features.onboarding
|
||||||
|
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.systemBarsPadding
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.runtime.snapshotFlow
|
||||||
import androidx.compose.ui.Alignment.Companion.CenterHorizontally
|
import androidx.compose.ui.Alignment.Companion.CenterHorizontally
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
|
|
@ -42,19 +54,20 @@ fun OnBoardingScreen(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@OptIn(ExperimentalPagerApi::class)
|
@OptIn(ExperimentalPagerApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun OnBoardingContent(
|
fun OnBoardingContent(
|
||||||
state: OnBoardingViewState,
|
state: OnBoardingViewState,
|
||||||
onPageChanged: (Int) -> Unit,
|
modifier: Modifier = Modifier,
|
||||||
onSignUp: () -> Unit,
|
onPageChanged: (Int) -> Unit = {},
|
||||||
onSignIn: () -> Unit,
|
onSignUp: () -> Unit = {},
|
||||||
|
onSignIn: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val carrouselState = remember { SplashCarouselStateFactory().create() }
|
val carrouselState = remember { SplashCarouselStateFactory().create() }
|
||||||
val nbOfPages = carrouselState.items.size
|
val nbOfPages = carrouselState.items.size
|
||||||
var key by remember { mutableStateOf(false) }
|
var key by remember { mutableStateOf(false) }
|
||||||
Surface(
|
Surface(
|
||||||
|
modifier = modifier,
|
||||||
color = MaterialTheme.colorScheme.background,
|
color = MaterialTheme.colorScheme.background,
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
|
|
@ -125,8 +138,11 @@ fun OnBoardingContent(
|
||||||
@Composable
|
@Composable
|
||||||
fun OnBoardingPage(
|
fun OnBoardingPage(
|
||||||
item: SplashCarouselState.Item,
|
item: SplashCarouselState.Item,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
Box {
|
Box(
|
||||||
|
modifier = modifier,
|
||||||
|
) {
|
||||||
/*
|
/*
|
||||||
Image(
|
Image(
|
||||||
painterResource(id = item.pageBackground),
|
painterResource(id = item.pageBackground),
|
||||||
|
|
@ -164,4 +180,4 @@ fun OnBoardingPage(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,4 +12,4 @@ class OnBoardingViewModel(initialState: OnBoardingViewState) :
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,12 @@ import androidx.annotation.DrawableRes
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
|
|
||||||
data class SplashCarouselState(
|
data class SplashCarouselState(
|
||||||
val items: List<Item>
|
val items: List<Item>
|
||||||
) {
|
) {
|
||||||
data class Item(
|
data class Item(
|
||||||
@StringRes val title: Int,
|
@StringRes val title: Int,
|
||||||
@StringRes val body: Int,
|
@StringRes val body: Int,
|
||||||
@DrawableRes val image: Int,
|
@DrawableRes val image: Int,
|
||||||
@DrawableRes val pageBackground: Int
|
@DrawableRes val pageBackground: Int
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package io.element.android.x.features.onboarding
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import io.element.android.x.element.resources.R as ElementR
|
import io.element.android.x.element.resources.R as ElementR
|
||||||
|
|
||||||
class SplashCarouselStateFactory() {
|
class SplashCarouselStateFactory {
|
||||||
fun create(): SplashCarouselState {
|
fun create(): SplashCarouselState {
|
||||||
val lightTheme = true
|
val lightTheme = true
|
||||||
fun background(@DrawableRes lightDrawable: Int) =
|
fun background(@DrawableRes lightDrawable: Int) =
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
package io.element.android.x.features.login
|
package io.element.android.x.features.login
|
||||||
|
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
import org.junit.Assert.*
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Example local unit test, which will execute on the development machine (host).
|
* Example local unit test, which will execute on the development machine (host).
|
||||||
*
|
*
|
||||||
|
|
@ -14,4 +13,4 @@ class ExampleUnitTest {
|
||||||
fun addition_isCorrect() {
|
fun addition_isCorrect() {
|
||||||
assertEquals(4, 2 + 2)
|
assertEquals(4, 2 + 2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,9 @@ dependencies {
|
||||||
implementation(project(":libraries:matrix"))
|
implementation(project(":libraries:matrix"))
|
||||||
implementation(project(":libraries:designsystem"))
|
implementation(project(":libraries:designsystem"))
|
||||||
implementation(libs.mavericks.compose)
|
implementation(libs.mavericks.compose)
|
||||||
implementation(libs.timber)
|
|
||||||
implementation(libs.datetime)
|
implementation(libs.datetime)
|
||||||
implementation(libs.accompanist.placeholder)
|
implementation(libs.accompanist.placeholder)
|
||||||
testImplementation(libs.test.junit)
|
testImplementation(libs.test.junit)
|
||||||
androidTestImplementation(libs.test.junitext)
|
androidTestImplementation(libs.test.junitext)
|
||||||
ksp(libs.showkase.processor)
|
ksp(libs.showkase.processor)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,11 @@
|
||||||
package io.element.android.x.features.roomlist
|
package io.element.android.x.features.roomlist
|
||||||
|
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
import org.junit.Assert.*
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instrumented test, which will execute on an Android device.
|
* Instrumented test, which will execute on an Android device.
|
||||||
*
|
*
|
||||||
|
|
@ -21,4 +19,4 @@ class ExampleInstrumentedTest {
|
||||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||||
assertEquals("io.element.android.x.features.roomlist.test", appContext.packageName)
|
assertEquals("io.element.android.x.features.roomlist.test", appContext.packageName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,18 @@ package io.element.android.x.features.roomlist
|
||||||
|
|
||||||
import android.text.format.DateFormat
|
import android.text.format.DateFormat
|
||||||
import android.text.format.DateUtils
|
import android.text.format.DateUtils
|
||||||
import kotlinx.datetime.*
|
|
||||||
import kotlinx.datetime.TimeZone
|
|
||||||
import java.time.Period
|
import java.time.Period
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
import java.util.*
|
import java.util.Locale
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
|
import kotlinx.datetime.Clock
|
||||||
|
import kotlinx.datetime.Instant
|
||||||
|
import kotlinx.datetime.LocalDateTime
|
||||||
|
import kotlinx.datetime.TimeZone
|
||||||
|
import kotlinx.datetime.toInstant
|
||||||
|
import kotlinx.datetime.toJavaLocalDate
|
||||||
|
import kotlinx.datetime.toJavaLocalDateTime
|
||||||
|
import kotlinx.datetime.toLocalDateTime
|
||||||
|
|
||||||
class LastMessageFormatter(
|
class LastMessageFormatter(
|
||||||
private val clock: Clock = Clock.System,
|
private val clock: Clock = Clock.System,
|
||||||
|
|
@ -29,7 +35,6 @@ class LastMessageFormatter(
|
||||||
DateTimeFormatter.ofPattern(pattern)
|
DateTimeFormatter.ofPattern(pattern)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun format(timestamp: Long?): String {
|
fun format(timestamp: Long?): String {
|
||||||
if (timestamp == null) return ""
|
if (timestamp == null) return ""
|
||||||
val now: Instant = clock.now()
|
val now: Instant = clock.now()
|
||||||
|
|
@ -77,6 +82,4 @@ class LastMessageFormatter(
|
||||||
DateUtils.FORMAT_SHOW_WEEKDAY
|
DateUtils.FORMAT_SHOW_WEEKDAY
|
||||||
).toString()
|
).toString()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,8 @@ import io.element.android.x.features.roomlist.model.RoomListRoomSummary
|
||||||
import io.element.android.x.features.roomlist.model.RoomListViewState
|
import io.element.android.x.features.roomlist.model.RoomListViewState
|
||||||
import io.element.android.x.features.roomlist.model.stubbedRoomSummaries
|
import io.element.android.x.features.roomlist.model.stubbedRoomSummaries
|
||||||
import io.element.android.x.matrix.core.RoomId
|
import io.element.android.x.matrix.core.RoomId
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RoomListScreen(
|
fun RoomListScreen(
|
||||||
|
|
@ -53,7 +55,7 @@ fun RoomListScreen(
|
||||||
val roomSummaries by viewModel.collectAsState(RoomListViewState::rooms)
|
val roomSummaries by viewModel.collectAsState(RoomListViewState::rooms)
|
||||||
val matrixUser by viewModel.collectAsState(RoomListViewState::user)
|
val matrixUser by viewModel.collectAsState(RoomListViewState::user)
|
||||||
RoomListContent(
|
RoomListContent(
|
||||||
roomSummaries = roomSummaries().orEmpty(),
|
roomSummaries = roomSummaries().orEmpty().toImmutableList(),
|
||||||
matrixUser = matrixUser(),
|
matrixUser = matrixUser(),
|
||||||
onRoomClicked = onRoomClicked,
|
onRoomClicked = onRoomClicked,
|
||||||
onLogoutClicked = viewModel::logout,
|
onLogoutClicked = viewModel::logout,
|
||||||
|
|
@ -66,16 +68,16 @@ fun RoomListScreen(
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RoomListContent(
|
fun RoomListContent(
|
||||||
roomSummaries: List<RoomListRoomSummary>,
|
roomSummaries: ImmutableList<RoomListRoomSummary>,
|
||||||
matrixUser: MatrixUser?,
|
matrixUser: MatrixUser?,
|
||||||
onRoomClicked: (RoomId) -> Unit,
|
|
||||||
filter: String,
|
filter: String,
|
||||||
onFilterChanged: (String) -> Unit,
|
|
||||||
onLogoutClicked: () -> Unit,
|
|
||||||
onScrollOver: (IntRange) -> Unit,
|
|
||||||
isLoginOut: Boolean,
|
isLoginOut: Boolean,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onRoomClicked: (RoomId) -> Unit = {},
|
||||||
|
onFilterChanged: (String) -> Unit = {},
|
||||||
|
onLogoutClicked: () -> Unit = {},
|
||||||
|
onScrollOver: (IntRange) -> Unit = {},
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun onRoomClicked(room: RoomListRoomSummary) {
|
fun onRoomClicked(room: RoomListRoomSummary) {
|
||||||
onRoomClicked(room.roomId)
|
onRoomClicked(room.roomId)
|
||||||
}
|
}
|
||||||
|
|
@ -104,7 +106,7 @@ fun RoomListContent(
|
||||||
}
|
}
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
topBar = {
|
topBar = {
|
||||||
RoomListTopBar(
|
RoomListTopBar(
|
||||||
matrixUser = matrixUser,
|
matrixUser = matrixUser,
|
||||||
|
|
@ -133,7 +135,7 @@ fun RoomListContent(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
if (isLoginOut) {
|
if (isLoginOut) {
|
||||||
ProgressDialog("Login out...")
|
ProgressDialog(text = "Login out...")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -176,4 +178,3 @@ fun PreviewableDarkRoomListContent() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
package io.element.android.x.features.roomlist
|
package io.element.android.x.features.roomlist
|
||||||
|
|
||||||
import com.airbnb.mvrx.*
|
import com.airbnb.mvrx.Loading
|
||||||
import io.element.android.x.core.data.parallelMap
|
import com.airbnb.mvrx.MavericksViewModel
|
||||||
|
import com.airbnb.mvrx.MavericksViewModelFactory
|
||||||
|
import com.airbnb.mvrx.Success
|
||||||
|
import com.airbnb.mvrx.ViewModelContext
|
||||||
|
import io.element.android.x.core.coroutine.parallelMap
|
||||||
import io.element.android.x.designsystem.components.avatar.AvatarData
|
import io.element.android.x.designsystem.components.avatar.AvatarData
|
||||||
import io.element.android.x.designsystem.components.avatar.AvatarSize
|
import io.element.android.x.designsystem.components.avatar.AvatarSize
|
||||||
import io.element.android.x.features.roomlist.model.MatrixUser
|
import io.element.android.x.features.roomlist.model.MatrixUser
|
||||||
|
|
@ -118,8 +122,8 @@ class RoomListViewModel(
|
||||||
copy(
|
copy(
|
||||||
rooms = when {
|
rooms = when {
|
||||||
it is Loading ||
|
it is Loading ||
|
||||||
// Note: this second case will prevent to handle correctly the empty case
|
// Note: this second case will prevent to handle correctly the empty case
|
||||||
(it is Success && it().isEmpty() && filter.isEmpty()) -> {
|
(it is Success && it().isEmpty() && filter.isEmpty()) -> {
|
||||||
// Show fake placeholders to avoid having empty screen
|
// Show fake placeholders to avoid having empty screen
|
||||||
Loading(RoomListRoomSummaryPlaceholders.createFakeList(size = 16))
|
Loading(RoomListRoomSummaryPlaceholders.createFakeList(size = 16))
|
||||||
}
|
}
|
||||||
|
|
@ -164,5 +168,4 @@ class RoomListViewModel(
|
||||||
.resolve(url, kind = MediaResolver.Kind.Thumbnail(size.value))
|
.resolve(url, kind = MediaResolver.Kind.Thumbnail(size.value))
|
||||||
return AvatarData(name, model, size)
|
return AvatarData(name, model, size)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
package io.element.android.x.features.roomlist.components
|
package io.element.android.x.features.roomlist.components
|
||||||
|
|
||||||
import Avatar
|
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.material.ContentAlpha
|
import androidx.compose.material.ContentAlpha
|
||||||
|
|
@ -11,9 +10,23 @@ import androidx.compose.material.icons.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.filled.Close
|
import androidx.compose.material.icons.filled.Close
|
||||||
import androidx.compose.material.icons.filled.Logout
|
import androidx.compose.material.icons.filled.Logout
|
||||||
import androidx.compose.material.icons.filled.Search
|
import androidx.compose.material.icons.filled.Search
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.MediumTopAppBar
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextField
|
||||||
|
import androidx.compose.material3.TextFieldDefaults
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
|
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
|
|
@ -24,6 +37,7 @@ import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import io.element.android.x.core.compose.LogCompositions
|
import io.element.android.x.core.compose.LogCompositions
|
||||||
import io.element.android.x.core.compose.textFieldState
|
import io.element.android.x.core.compose.textFieldState
|
||||||
|
import io.element.android.x.designsystem.components.avatar.Avatar
|
||||||
import io.element.android.x.designsystem.components.dialogs.ConfirmationDialog
|
import io.element.android.x.designsystem.components.dialogs.ConfirmationDialog
|
||||||
import io.element.android.x.features.roomlist.model.MatrixUser
|
import io.element.android.x.features.roomlist.model.MatrixUser
|
||||||
|
|
||||||
|
|
@ -35,7 +49,6 @@ fun RoomListTopBar(
|
||||||
onLogoutClicked: () -> Unit,
|
onLogoutClicked: () -> Unit,
|
||||||
scrollBehavior: TopAppBarScrollBehavior
|
scrollBehavior: TopAppBarScrollBehavior
|
||||||
) {
|
) {
|
||||||
|
|
||||||
LogCompositions(tag = "RoomListScreen", msg = "TopBar")
|
LogCompositions(tag = "RoomListScreen", msg = "TopBar")
|
||||||
var searchWidgetStateIsOpened by rememberSaveable { mutableStateOf(false) }
|
var searchWidgetStateIsOpened by rememberSaveable { mutableStateOf(false) }
|
||||||
|
|
||||||
|
|
@ -65,20 +78,20 @@ fun RoomListTopBar(
|
||||||
scrollBehavior = scrollBehavior,
|
scrollBehavior = scrollBehavior,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SearchRoomListTopBar(
|
fun SearchRoomListTopBar(
|
||||||
text: String,
|
text: String,
|
||||||
onFilterChanged: (String) -> Unit,
|
scrollBehavior: TopAppBarScrollBehavior,
|
||||||
onCloseClicked: () -> Unit,
|
modifier: Modifier = Modifier,
|
||||||
scrollBehavior: TopAppBarScrollBehavior
|
onFilterChanged: (String) -> Unit = {},
|
||||||
|
onCloseClicked: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
var filterState by textFieldState(stateValue = text)
|
var filterState by textFieldState(stateValue = text)
|
||||||
val focusRequester = remember { FocusRequester() }
|
val focusRequester = remember { FocusRequester() }
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
modifier = Modifier
|
modifier = modifier
|
||||||
.nestedScroll(scrollBehavior.nestedScrollConnection),
|
.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
title = {
|
title = {
|
||||||
TextField(
|
TextField(
|
||||||
|
|
@ -184,10 +197,13 @@ private fun DefaultRoomListTopBar(
|
||||||
)
|
)
|
||||||
// Log out confirmation dialog
|
// Log out confirmation dialog
|
||||||
ConfirmationDialog(
|
ConfirmationDialog(
|
||||||
openDialog,
|
isDisplayed = openDialog.value,
|
||||||
title = "Log out",
|
title = "Log out",
|
||||||
content = "Do you confirm you want to log out?",
|
content = "Do you confirm you want to log out?",
|
||||||
submitText = "Log out",
|
submitText = "Log out",
|
||||||
onSubmitClicked = onLogoutClicked,
|
onSubmitClicked = onLogoutClicked,
|
||||||
|
onDismiss = {
|
||||||
|
openDialog.value = false
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,23 @@
|
||||||
package io.element.android.x.features.roomlist.components
|
package io.element.android.x.features.roomlist.components
|
||||||
|
|
||||||
import Avatar
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.IntrinsicSize
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.heightIn
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.material.ripple.rememberRipple
|
import androidx.compose.material.ripple.rememberRipple
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.Immutable
|
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
import androidx.compose.ui.Alignment.Companion.CenterVertically
|
||||||
|
|
@ -29,17 +36,17 @@ import androidx.compose.ui.unit.LayoutDirection
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import com.google.accompanist.placeholder.material.placeholder
|
import com.google.accompanist.placeholder.material.placeholder
|
||||||
|
import io.element.android.x.designsystem.components.avatar.Avatar
|
||||||
import io.element.android.x.features.roomlist.model.RoomListRoomSummary
|
import io.element.android.x.features.roomlist.model.RoomListRoomSummary
|
||||||
|
|
||||||
private val minHeight = 72.dp
|
private val minHeight = 72.dp
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun RoomSummaryRow(
|
internal fun RoomSummaryRow(
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
room: RoomListRoomSummary,
|
room: RoomListRoomSummary,
|
||||||
onClick: (RoomListRoomSummary) -> Unit
|
modifier: Modifier = Modifier,
|
||||||
|
onClick: (RoomListRoomSummary) -> Unit = {},
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val clickModifier = if (room.isPlaceholder) {
|
val clickModifier = if (room.isPlaceholder) {
|
||||||
modifier
|
modifier
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -57,7 +64,6 @@ internal fun RoomSummaryRow(
|
||||||
) {
|
) {
|
||||||
DefaultRoomSummaryRow(room = room)
|
DefaultRoomSummaryRow(room = room)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
|
||||||
|
|
@ -13,4 +13,5 @@ data class RoomListRoomSummary(
|
||||||
val timestamp: String? = null,
|
val timestamp: String? = null,
|
||||||
val lastMessage: CharSequence? = null,
|
val lastMessage: CharSequence? = null,
|
||||||
val avatarData: AvatarData = AvatarData(),
|
val avatarData: AvatarData = AvatarData(),
|
||||||
val isPlaceholder: Boolean = false,)
|
val isPlaceholder: Boolean = false,
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ package io.element.android.x.features.roomlist.model
|
||||||
|
|
||||||
import io.element.android.x.designsystem.components.avatar.AvatarData
|
import io.element.android.x.designsystem.components.avatar.AvatarData
|
||||||
|
|
||||||
|
|
||||||
object RoomListRoomSummaryPlaceholders {
|
object RoomListRoomSummaryPlaceholders {
|
||||||
|
|
||||||
fun create(id: String): RoomListRoomSummary {
|
fun create(id: String): RoomListRoomSummary {
|
||||||
|
|
@ -23,6 +22,4 @@ object RoomListRoomSummaryPlaceholders {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
package io.element.android.x.features.roomlist.model
|
package io.element.android.x.features.roomlist.model
|
||||||
|
|
||||||
import io.element.android.x.designsystem.components.avatar.AvatarData
|
import io.element.android.x.designsystem.components.avatar.AvatarData
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
|
||||||
internal fun stubbedRoomSummaries(): List<RoomListRoomSummary> {
|
internal fun stubbedRoomSummaries(): ImmutableList<RoomListRoomSummary> {
|
||||||
return listOf(
|
return persistentListOf(
|
||||||
RoomListRoomSummary(
|
RoomListRoomSummary(
|
||||||
name = "Room",
|
name = "Room",
|
||||||
hasUnread = true,
|
hasUnread = true,
|
||||||
|
|
@ -22,4 +24,4 @@ internal fun stubbedRoomSummaries(): List<RoomListRoomSummary> {
|
||||||
),
|
),
|
||||||
RoomListRoomSummaryPlaceholders.create("roomId2")
|
RoomListRoomSummaryPlaceholders.create("roomId2")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
package io.element.android.x.features.roomlist
|
package io.element.android.x.features.roomlist
|
||||||
|
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
import org.junit.Assert.*
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Example local unit test, which will execute on the development machine (host).
|
* Example local unit test, which will execute on the development machine (host).
|
||||||
*
|
*
|
||||||
|
|
@ -14,4 +13,4 @@ class ExampleUnitTest {
|
||||||
fun addition_isCorrect() {
|
fun addition_isCorrect() {
|
||||||
assertEquals(4, 2 + 2)
|
assertEquals(4, 2 + 2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,7 @@ kotlin.code.style=official
|
||||||
# resources declared in the library itself and none from the library's dependencies,
|
# resources declared in the library itself and none from the library's dependencies,
|
||||||
# thereby reducing the size of the R class for that library
|
# thereby reducing the size of the R class for that library
|
||||||
android.nonTransitiveRClass=true
|
android.nonTransitiveRClass=true
|
||||||
|
|
||||||
# Dummy values for signing secrets / nightly
|
# Dummy values for signing secrets / nightly
|
||||||
signing.element.nightly.storePassword=Secret
|
signing.element.nightly.storePassword=Secret
|
||||||
signing.element.nightly.keyId=Secret
|
signing.element.nightly.keyId=Secret
|
||||||
signing.element.nightly.keyPassword=Secret
|
signing.element.nightly.keyPassword=Secret
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
# This file is referenced in ./plugins/settings.gradle.kts to generate the version catalog.
|
||||||
|
# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format
|
||||||
|
|
||||||
[versions]
|
[versions]
|
||||||
# Project
|
# Project
|
||||||
android_gradle_plugin = "7.3.1"
|
android_gradle_plugin = "7.3.1"
|
||||||
|
|
@ -37,7 +40,6 @@ test_orchestrator = "1.4.1"
|
||||||
|
|
||||||
#other
|
#other
|
||||||
mavericks = "3.0.1"
|
mavericks = "3.0.1"
|
||||||
timber = "5.0.1"
|
|
||||||
coil = "2.2.1"
|
coil = "2.2.1"
|
||||||
datetime = "0.4.0"
|
datetime = "0.4.0"
|
||||||
wysiwyg = "0.7.0.1"
|
wysiwyg = "0.7.0.1"
|
||||||
|
|
@ -46,6 +48,10 @@ showkase = "1.0.0-beta14"
|
||||||
compose_destinations = "1.7.23-beta"
|
compose_destinations = "1.7.23-beta"
|
||||||
jsoup = "1.15.3"
|
jsoup = "1.15.3"
|
||||||
|
|
||||||
|
# quality
|
||||||
|
detekt = "1.22.0"
|
||||||
|
ktlint = "11.0.0"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
# Project
|
# Project
|
||||||
android_gradle_plugin = { module = "com.android.tools.build:gradle", version.ref = "android_gradle_plugin" }
|
android_gradle_plugin = { module = "com.android.tools.build:gradle", version.ref = "android_gradle_plugin" }
|
||||||
|
|
@ -93,13 +99,12 @@ test_hamcrest = { module = "org.hamcrest:hamcrest", version.ref = "test_hamcrest
|
||||||
test_orchestrator = { module = "androidx.test:orchestrator", version.ref = "test_orchestrator" }
|
test_orchestrator = { module = "androidx.test:orchestrator", version.ref = "test_orchestrator" }
|
||||||
|
|
||||||
mavericks_compose = { module = "com.airbnb.android:mavericks-compose", version.ref = "mavericks" }
|
mavericks_compose = { module = "com.airbnb.android:mavericks-compose", version.ref = "mavericks" }
|
||||||
timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" }
|
|
||||||
coil = { module = "io.coil-kt:coil", version.ref = "coil" }
|
coil = { module = "io.coil-kt:coil", version.ref = "coil" }
|
||||||
coil_compose = { module = "io.coil-kt:coil-compose", version.ref = "coil" }
|
coil_compose = { module = "io.coil-kt:coil-compose", version.ref = "coil" }
|
||||||
datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "datetime" }
|
datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "datetime" }
|
||||||
serialization_json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization_json" }
|
serialization_json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization_json" }
|
||||||
compose_destinations = { module = "io.github.raamcosta.compose-destinations:animations-core", version.ref = "compose_destinations" }
|
compose_destinations = { module = "io.github.raamcosta.compose-destinations:animations-core", version.ref = "compose_destinations" }
|
||||||
compose_destinations_processor = {module = "io.github.raamcosta.compose-destinations:ksp", version.ref = "compose_destinations"}
|
compose_destinations_processor = { module = "io.github.raamcosta.compose-destinations:ksp", version.ref = "compose_destinations" }
|
||||||
showkase = { module = "com.airbnb.android:showkase", version.ref = "showkase" }
|
showkase = { module = "com.airbnb.android:showkase", version.ref = "showkase" }
|
||||||
showkase_processor = { module = "com.airbnb.android:showkase-processor", version.ref = "showkase" }
|
showkase_processor = { module = "com.airbnb.android:showkase-processor", version.ref = "showkase" }
|
||||||
jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" }
|
jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" }
|
||||||
|
|
@ -113,4 +118,7 @@ wysiwyg = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" }
|
||||||
android_application = { id = "com.android.application", version.ref = "android_gradle_plugin" }
|
android_application = { id = "com.android.application", version.ref = "android_gradle_plugin" }
|
||||||
android_library = { id = "com.android.library", version.ref = "android_gradle_plugin" }
|
android_library = { id = "com.android.library", version.ref = "android_gradle_plugin" }
|
||||||
kotlin_android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
kotlin_android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
||||||
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
|
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
|
||||||
|
detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
|
||||||
|
ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint" }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,21 @@
|
||||||
package io.element.android.x.core.compose
|
package io.element.android.x.core.compose
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.SideEffect
|
import androidx.compose.runtime.SideEffect
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import io.element.android.x.core.BuildConfig
|
import io.element.android.x.core.BuildConfig
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
// Note the inline function below which ensures that this function is essentially
|
// Note the inline function below which ensures that this function is essentially
|
||||||
// copied at the call site to ensure that its logging only recompositions from the
|
// copied at the call site to ensure that its logging only recompositions from the
|
||||||
// original call site.
|
// original call site.
|
||||||
@Composable
|
@Composable
|
||||||
inline fun LogCompositions(tag: String, msg: String) {
|
fun LogCompositions(tag: String, msg: String) {
|
||||||
if (BuildConfig.DEBUG) {
|
if (BuildConfig.DEBUG) {
|
||||||
val ref = remember { Ref(0) }
|
val ref = remember { Ref(0) }
|
||||||
SideEffect { ref.value++ }
|
SideEffect { ref.value++ }
|
||||||
Log.d(tag, "Compositions: $msg ${ref.value}")
|
Timber.d(tag, "Compositions: $msg ${ref.value}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Ref(var value: Int)
|
class Ref(var value: Int)
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import androidx.lifecycle.LifecycleOwner
|
||||||
fun OnLifecycleEvent(onEvent: (owner: LifecycleOwner, event: Lifecycle.Event) -> Unit) {
|
fun OnLifecycleEvent(onEvent: (owner: LifecycleOwner, event: Lifecycle.Event) -> Unit) {
|
||||||
val eventHandler = rememberUpdatedState(onEvent)
|
val eventHandler = rememberUpdatedState(onEvent)
|
||||||
val lifecycleOwner = rememberUpdatedState(LocalLifecycleOwner.current)
|
val lifecycleOwner = rememberUpdatedState(LocalLifecycleOwner.current)
|
||||||
|
|
||||||
DisposableEffect(lifecycleOwner.value) {
|
DisposableEffect(lifecycleOwner.value) {
|
||||||
val lifecycle = lifecycleOwner.value.lifecycle
|
val lifecycle = lifecycleOwner.value.lifecycle
|
||||||
val observer = LifecycleEventObserver { owner, event ->
|
val observer = LifecycleEventObserver { owner, event ->
|
||||||
|
|
@ -24,4 +24,4 @@ fun OnLifecycleEvent(onEvent: (owner: LifecycleOwner, event: Lifecycle.Event) ->
|
||||||
lifecycle.removeObserver(observer)
|
lifecycle.removeObserver(observer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
public fun textFieldState(stateValue: String): MutableState<String> =
|
public fun textFieldState(stateValue: String): MutableState<String> =
|
||||||
remember(stateValue) { mutableStateOf(stateValue) }
|
remember(stateValue) { mutableStateOf(stateValue) }
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package io.element.android.x.core.data.flow
|
package io.element.android.x.core.coroutine
|
||||||
|
|
||||||
import android.os.SystemClock
|
import android.os.SystemClock
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package io.element.android.x.core.data
|
package io.element.android.x.core.coroutine
|
||||||
|
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
|
|
@ -7,4 +7,4 @@ import kotlinx.coroutines.coroutineScope
|
||||||
// https://jivimberg.io/blog/2018/05/04/parallel-map-in-kotlin/
|
// https://jivimberg.io/blog/2018/05/04/parallel-map-in-kotlin/
|
||||||
suspend fun <A, B> Iterable<A>.parallelMap(f: suspend (A) -> B): List<B> = coroutineScope {
|
suspend fun <A, B> Iterable<A>.parallelMap(f: suspend (A) -> B): List<B> = coroutineScope {
|
||||||
map { async { f(it) } }.awaitAll()
|
map { async { f(it) } }.awaitAll()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
package io.element.android.x.core.data
|
package io.element.android.x.core.data
|
||||||
|
|
||||||
import android.util.Log
|
import timber.log.Timber
|
||||||
|
|
||||||
inline fun <A> tryOrNull(message: String? = null, operation: () -> A): A? {
|
inline fun <A> tryOrNull(message: String? = null, operation: () -> A): A? {
|
||||||
return try {
|
return try {
|
||||||
operation()
|
operation()
|
||||||
} catch (any: Throwable) {
|
} catch (any: Throwable) {
|
||||||
if (message != null) {
|
if (message != null) {
|
||||||
Log.e("TAG", message, any)
|
Timber.e("TAG", message, any)
|
||||||
}
|
}
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,18 +24,18 @@ class DimensionConverter(val resources: Resources) {
|
||||||
@Px
|
@Px
|
||||||
fun dpToPx(dp: Int): Int {
|
fun dpToPx(dp: Int): Int {
|
||||||
return TypedValue.applyDimension(
|
return TypedValue.applyDimension(
|
||||||
TypedValue.COMPLEX_UNIT_DIP,
|
TypedValue.COMPLEX_UNIT_DIP,
|
||||||
dp.toFloat(),
|
dp.toFloat(),
|
||||||
resources.displayMetrics
|
resources.displayMetrics
|
||||||
).toInt()
|
).toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Px
|
@Px
|
||||||
fun spToPx(sp: Int): Int {
|
fun spToPx(sp: Int): Int {
|
||||||
return TypedValue.applyDimension(
|
return TypedValue.applyDimension(
|
||||||
TypedValue.COMPLEX_UNIT_SP,
|
TypedValue.COMPLEX_UNIT_SP,
|
||||||
sp.toFloat(),
|
sp.toFloat(),
|
||||||
resources.displayMetrics
|
resources.displayMetrics
|
||||||
).toInt()
|
).toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,9 +35,9 @@ fun View.showKeyboard(andRequestFocus: Boolean = false) {
|
||||||
|
|
||||||
fun View.setHorizontalPadding(padding: Int) {
|
fun View.setHorizontalPadding(padding: Int) {
|
||||||
setPadding(
|
setPadding(
|
||||||
padding,
|
padding,
|
||||||
paddingTop,
|
paddingTop,
|
||||||
padding,
|
padding,
|
||||||
paddingBottom
|
paddingBottom
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,4 +12,4 @@ android {
|
||||||
implementation(libs.accompanist.systemui)
|
implementation(libs.accompanist.systemui)
|
||||||
ksp(libs.showkase.processor)
|
ksp(libs.showkase.processor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue