diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..26bef415d7 --- /dev/null +++ b/.editorconfig @@ -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 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000000..372c275efc --- /dev/null +++ b/.github/workflows/build.yml @@ -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 diff --git a/.github/workflows/danger.yml b/.github/workflows/danger.yml new file mode 100644 index 0000000000..8752f339bd --- /dev/null +++ b/.github/workflows/danger.yml @@ -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 }} diff --git a/.github/workflows/dependabot.yml b/.github/workflows/dependabot.yml new file mode 100644 index 0000000000..6a456254a9 --- /dev/null +++ b/.github/workflows/dependabot.yml @@ -0,0 +1,22 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + # Updates for Github Actions used in the repo + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + reviewers: + - "vector-im/element-x-android-reviewers" + # Updates for Gradle dependencies used in the app + - package-ecosystem: "gradle" + directory: "/" + schedule: + interval: "daily" + open-pull-requests-limit: 200 + reviewers: + - "vector-im/element-x-android-reviewers" diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml new file mode 100644 index 0000000000..2741638914 --- /dev/null +++ b/.github/workflows/quality.yml @@ -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 }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000000..02e8ab62b2 --- /dev/null +++ b/.github/workflows/tests.yml @@ -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 diff --git a/.github/workflows/triage-labelled.yml b/.github/workflows/triage-labelled.yml index 25dcc59e36..de2522c9e3 100644 --- a/.github/workflows/triage-labelled.yml +++ b/.github/workflows/triage-labelled.yml @@ -2,7 +2,7 @@ name: Move labelled issues to correct boards and columns on: issues: - types: [labeled] + types: [ labeled ] jobs: move_element_x_issues: diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000000..74709d9df5 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,125 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000000..79ee123c2b --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/README.md b/README.md index b288e273cf..82cc63ea3b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # element-x-android-poc + 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)! \ No newline at end of file +The plan is [here](https://github.com/vector-im/element-x-android-poc/issues/1)! diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 9e9a761b65..7b26039ea8 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -5,6 +5,7 @@ plugins { alias(libs.plugins.anvil) alias(libs.plugins.kapt) id("com.google.firebase.appdistribution") version "3.0.2" + id("org.jetbrains.kotlinx.knit") version "0.4.0" } android { @@ -12,7 +13,7 @@ android { defaultConfig { applicationId = "io.element.android.x" - targetSdk = 33 + targetSdk = 33 // TODO Use Versions.targetSdk versionCode = 1 versionName = "1.0" @@ -81,7 +82,6 @@ android { appId = "1:912726360885:android:e17435e0beb0303000427c" } } - } compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 @@ -111,6 +111,26 @@ android { } } +// Knit +apply { + plugin("kotlinx-knit") +} + +knit { + files = fileTree(project.rootDir) { + include( + "**/*.md", + "**/*.kt", + "*/*.kts", + ) + exclude( + "**/build/**", + "*/.gradle/**", + "*/towncrier/template.md", + "**/CHANGES.md", + ) + } +} dependencies { implementation(project(":libraries:designsystem")) @@ -134,7 +154,6 @@ dependencies { implementation(libs.androidx.activity.compose) implementation(libs.androidx.startup) implementation(libs.coil) - implementation(libs.timber) implementation(libs.mavericks.compose) implementation(libs.dagger) @@ -142,4 +161,4 @@ dependencies { implementation(libs.showkase) ksp(libs.showkase.processor) -} \ No newline at end of file +} diff --git a/app/src/main/java/io/element/android/x/Showkase.kt b/app/src/main/java/io/element/android/x/ElementRootModule.kt similarity index 78% rename from app/src/main/java/io/element/android/x/Showkase.kt rename to app/src/main/java/io/element/android/x/ElementRootModule.kt index 999cc5bc68..ea6e1e7f31 100644 --- a/app/src/main/java/io/element/android/x/Showkase.kt +++ b/app/src/main/java/io/element/android/x/ElementRootModule.kt @@ -4,4 +4,4 @@ import com.airbnb.android.showkase.annotation.ShowkaseRoot import com.airbnb.android.showkase.annotation.ShowkaseRootModule @ShowkaseRoot -class ElementRootModule : ShowkaseRootModule \ No newline at end of file +class ElementRootModule : ShowkaseRootModule diff --git a/app/src/main/java/io/element/android/x/ElementXApplication.kt b/app/src/main/java/io/element/android/x/ElementXApplication.kt index 7526b9e788..fc6c1b8b8c 100644 --- a/app/src/main/java/io/element/android/x/ElementXApplication.kt +++ b/app/src/main/java/io/element/android/x/ElementXApplication.kt @@ -30,6 +30,4 @@ class ElementXApplication : Application(), DaggerComponentOwner { initializeComponent(MavericksInitializer::class.java) } } - - } diff --git a/app/src/main/java/io/element/android/x/MainActivity.kt b/app/src/main/java/io/element/android/x/MainActivity.kt index 5dbd6e0252..d6af9a459a 100644 --- a/app/src/main/java/io/element/android/x/MainActivity.kt +++ b/app/src/main/java/io/element/android/x/MainActivity.kt @@ -19,8 +19,17 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Close -import androidx.compose.material3.* -import androidx.compose.runtime.* +import androidx.compose.material3.Button +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.Modifier import androidx.compose.ui.tooling.preview.Preview @@ -109,7 +118,6 @@ class MainActivity : ComponentActivity() { OnLifecycleEvent { _, event -> Timber.v("OnLifecycleEvent: $event") } - } @Composable @@ -171,5 +179,4 @@ class MainActivity : ComponentActivity() { fun MainContentPreview() { MainContent(startRoute = OnBoardingScreenNavigationDestination) } - -} \ No newline at end of file +} diff --git a/app/src/main/java/io/element/android/x/MainViewModel.kt b/app/src/main/java/io/element/android/x/MainViewModel.kt index 36a7b176e0..506431e593 100644 --- a/app/src/main/java/io/element/android/x/MainViewModel.kt +++ b/app/src/main/java/io/element/android/x/MainViewModel.kt @@ -50,4 +50,4 @@ class MainViewModel @AssistedInject constructor( matrixClient.startSync() } } -} \ No newline at end of file +} diff --git a/app/src/main/java/io/element/android/x/Navigation.kt b/app/src/main/java/io/element/android/x/Navigation.kt index 30b544256d..3bf0b95d27 100644 --- a/app/src/main/java/io/element/android/x/Navigation.kt +++ b/app/src/main/java/io/element/android/x/Navigation.kt @@ -7,7 +7,11 @@ import com.ramcosta.composedestinations.annotation.RootNavGraph import com.ramcosta.composedestinations.navigation.DestinationsNavigator import com.ramcosta.composedestinations.navigation.popUpTo import io.element.android.x.core.di.bindings -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.di.AppBindings import io.element.android.x.features.login.LoginScreen import io.element.android.x.features.login.changeserver.ChangeServerScreen @@ -84,6 +88,3 @@ fun RoomListScreenNavigation(navigator: DestinationsNavigator) { fun MessagesScreenNavigation(roomId: String, navigator: DestinationsNavigator) { MessagesScreen(roomId = roomId, onBackPressed = navigator::navigateUp) } - - - diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index 07d5da9cbf..0000000000 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml deleted file mode 100644 index 80e60d5f76..0000000000 --- a/app/src/main/res/drawable/ic_launcher_foreground.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml deleted file mode 100644 index beab31f753..0000000000 --- a/app/src/main/res/values/ic_launcher_background.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - #000000 - \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 46fb58517a..ab8ea28281 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -7,8 +7,78 @@ plugins { alias(libs.plugins.anvil) apply false alias(libs.plugins.kotlin.jvm) apply false alias(libs.plugins.kapt) apply false + alias(libs.plugins.detekt) + alias(libs.plugins.ktlint) } tasks.register("clean").configure { delete(rootProject.buildDir) - } \ No newline at end of file +} + +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 { + // 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", + ) + ) + } +} diff --git a/docs/usefulLinks.md b/docs/usefulLinks.md index 35ae4cf8c8..9c66616944 100644 --- a/docs/usefulLinks.md +++ b/docs/usefulLinks.md @@ -1,14 +1,22 @@ -### VersionCatalog + + + * [VersionCatalog](#versioncatalog) + * [Jetpack Compose](#jetpack-compose) + +### VersionCatalog +https://docs.gradle.org/current/userguide/platforms.html ### Jetpack Compose 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 Preview https://alexzh.com/jetpack-compose-preview/ -https://github.com/airbnb/Showkase \ No newline at end of file +https://github.com/airbnb/Showkase diff --git a/features/login/build.gradle.kts b/features/login/build.gradle.kts index 2bf855e13a..5717ba632b 100644 --- a/features/login/build.gradle.kts +++ b/features/login/build.gradle.kts @@ -23,8 +23,6 @@ dependencies { implementation(project(":libraries:elementresources")) implementation(libs.mavericks.compose) ksp(libs.showkase.processor) - implementation(libs.timber) testImplementation(libs.test.junit) androidTestImplementation(libs.test.junitext) - -} \ No newline at end of file +} diff --git a/features/login/src/androidTest/java/io/element/android/x/features/login/ExampleInstrumentedTest.kt b/features/login/src/androidTest/java/io/element/android/x/features/login/ExampleInstrumentedTest.kt index ba9eb96b15..ec5ace41e6 100644 --- a/features/login/src/androidTest/java/io/element/android/x/features/login/ExampleInstrumentedTest.kt +++ b/features/login/src/androidTest/java/io/element/android/x/features/login/ExampleInstrumentedTest.kt @@ -1,13 +1,11 @@ package io.element.android.x.features.login -import androidx.test.platform.app.InstrumentationRegistry 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.runner.RunWith -import org.junit.Assert.* - /** * Instrumented test, which will execute on an Android device. * @@ -21,4 +19,4 @@ class ExampleInstrumentedTest { val appContext = InstrumentationRegistry.getInstrumentation().targetContext assertEquals("io.element.android.x.features.login.test", appContext.packageName) } -} \ No newline at end of file +} diff --git a/features/login/src/main/AndroidManifest.xml b/features/login/src/main/AndroidManifest.xml index a5918e68ab..e100076157 100644 --- a/features/login/src/main/AndroidManifest.xml +++ b/features/login/src/main/AndroidManifest.xml @@ -1,4 +1,4 @@ - + - \ No newline at end of file + diff --git a/features/login/src/main/java/io/element/android/x/features/login/LoginScreen.kt b/features/login/src/main/java/io/element/android/x/features/login/LoginScreen.kt index 6736b98e3d..d7fe0de593 100644 --- a/features/login/src/main/java/io/element/android/x/features/login/LoginScreen.kt +++ b/features/login/src/main/java/io/element/android/x/features/login/LoginScreen.kt @@ -2,7 +2,13 @@ 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.text.KeyboardActions 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.filled.Visibility import androidx.compose.material.icons.filled.VisibilityOff -import androidx.compose.material3.* -import androidx.compose.runtime.* +import androidx.compose.material3.Button +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.Modifier import androidx.compose.ui.text.font.FontWeight @@ -56,19 +75,22 @@ fun LoginScreen( ) } - @OptIn(ExperimentalMaterial3Api::class) @Composable fun LoginContent( state: LoginViewState, formState: LoginFormState, + modifier: Modifier = Modifier, onChangeServer: () -> Unit = {}, onLoginChanged: (String) -> Unit = {}, onPasswordChanged: (String) -> Unit = {}, onSubmitClicked: () -> Unit = {}, onLoginWithSuccess: (MatrixClient) -> Unit = {}, ) { - Surface(color = MaterialTheme.colorScheme.background) { + Surface( + modifier = modifier, + color = MaterialTheme.colorScheme.background, + ) { Box( modifier = Modifier .fillMaxSize() @@ -96,7 +118,7 @@ fun LoginContent( ) // Form Column( - //modifier = Modifier.weight(1f), + // modifier = Modifier.weight(1f), ) { Box( modifier = Modifier.fillMaxWidth() diff --git a/features/login/src/main/java/io/element/android/x/features/login/LoginViewModel.kt b/features/login/src/main/java/io/element/android/x/features/login/LoginViewModel.kt index 3c39a6a139..735289edfc 100644 --- a/features/login/src/main/java/io/element/android/x/features/login/LoginViewModel.kt +++ b/features/login/src/main/java/io/element/android/x/features/login/LoginViewModel.kt @@ -66,4 +66,4 @@ class LoginViewModel @AssistedInject constructor( formState.value = formState.value.copy(login = name) setState { copy(loggedInClient = Uninitialized) } } -} \ No newline at end of file +} diff --git a/features/login/src/main/java/io/element/android/x/features/login/LoginViewState.kt b/features/login/src/main/java/io/element/android/x/features/login/LoginViewState.kt index f4d4820430..e7871dc504 100644 --- a/features/login/src/main/java/io/element/android/x/features/login/LoginViewState.kt +++ b/features/login/src/main/java/io/element/android/x/features/login/LoginViewState.kt @@ -23,5 +23,4 @@ data class LoginFormState( companion object { val Default = LoginFormState("", "") } - -} \ No newline at end of file +} diff --git a/features/login/src/main/java/io/element/android/x/features/login/changeserver/ChangeServerScreen.kt b/features/login/src/main/java/io/element/android/x/features/login/changeserver/ChangeServerScreen.kt index de03fcb868..3918d2f6c5 100644 --- a/features/login/src/main/java/io/element/android/x/features/login/changeserver/ChangeServerScreen.kt +++ b/features/login/src/main/java/io/element/android/x/features/login/changeserver/ChangeServerScreen.kt @@ -3,13 +3,27 @@ package io.element.android.x.features.login.changeserver 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.shape.RoundedCornerShape import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions 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.getValue import androidx.compose.ui.Alignment @@ -45,15 +59,18 @@ fun ChangeServerScreen( ) } - @Composable fun ChangeServerContent( state: ChangeServerViewState, + modifier: Modifier = Modifier, onChangeServer: (String) -> Unit = {}, onChangeServerSubmit: () -> Unit = {}, onChangeServerSuccess: () -> Unit = {}, ) { - Surface(color = MaterialTheme.colorScheme.background) { + Surface( + modifier = modifier, + color = MaterialTheme.colorScheme.background, + ) { val scrollState = rememberScrollState() Box( modifier = Modifier @@ -67,8 +84,7 @@ fun ChangeServerContent( state = scrollState, ) .padding(horizontal = 16.dp) - ) - { + ) { val isError = state.changeServerAction is Fail Box( modifier = Modifier @@ -101,7 +117,7 @@ fun ChangeServerContent( ) Text( 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 .fillMaxWidth() .align(Alignment.CenterHorizontally) diff --git a/features/login/src/main/java/io/element/android/x/features/login/changeserver/ChangeServerViewModel.kt b/features/login/src/main/java/io/element/android/x/features/login/changeserver/ChangeServerViewModel.kt index f625c2e75b..e4007dcb4b 100644 --- a/features/login/src/main/java/io/element/android/x/features/login/changeserver/ChangeServerViewModel.kt +++ b/features/login/src/main/java/io/element/android/x/features/login/changeserver/ChangeServerViewModel.kt @@ -48,4 +48,4 @@ class ChangeServerViewModel @AssistedInject constructor( } } } -} \ No newline at end of file +} diff --git a/features/login/src/main/java/io/element/android/x/features/login/changeserver/ChangeServerViewState.kt b/features/login/src/main/java/io/element/android/x/features/login/changeserver/ChangeServerViewState.kt index 34a7d4aeb8..8e1f907c31 100644 --- a/features/login/src/main/java/io/element/android/x/features/login/changeserver/ChangeServerViewState.kt +++ b/features/login/src/main/java/io/element/android/x/features/login/changeserver/ChangeServerViewState.kt @@ -10,4 +10,4 @@ data class ChangeServerViewState( val changeServerAction: Async = Uninitialized, ) : MavericksState { val submitEnabled = homeserver.isNotEmpty() && changeServerAction !is Loading -} \ No newline at end of file +} diff --git a/features/login/src/main/java/io/element/android/x/features/login/error/ErrorFormatter.kt b/features/login/src/main/java/io/element/android/x/features/login/error/ErrorFormatter.kt index ab862e085c..6c26a9aff1 100644 --- a/features/login/src/main/java/io/element/android/x/features/login/error/ErrorFormatter.kt +++ b/features/login/src/main/java/io/element/android/x/features/login/error/ErrorFormatter.kt @@ -3,8 +3,8 @@ package io.element.android.x.features.login.error import androidx.compose.runtime.Composable import androidx.compose.ui.res.stringResource 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.features.login.LoginFormState @Composable fun loginError( diff --git a/features/login/src/main/res/drawable/element_logo_green.xml b/features/login/src/main/res/drawable/element_logo_green.xml deleted file mode 100644 index 6e948c3536..0000000000 --- a/features/login/src/main/res/drawable/element_logo_green.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - diff --git a/features/login/src/main/res/drawable/ic_baseline_dataset_24.xml b/features/login/src/main/res/drawable/ic_baseline_dataset_24.xml index f1171cb51c..aa885cbf10 100644 --- a/features/login/src/main/res/drawable/ic_baseline_dataset_24.xml +++ b/features/login/src/main/res/drawable/ic_baseline_dataset_24.xml @@ -1,5 +1,10 @@ - - + + diff --git a/features/login/src/test/java/io/element/android/x/features/login/ExampleUnitTest.kt b/features/login/src/test/java/io/element/android/x/features/login/ExampleUnitTest.kt index bcc403cdbf..f1768db5bc 100644 --- a/features/login/src/test/java/io/element/android/x/features/login/ExampleUnitTest.kt +++ b/features/login/src/test/java/io/element/android/x/features/login/ExampleUnitTest.kt @@ -1,9 +1,8 @@ package io.element.android.x.features.login +import org.junit.Assert.assertEquals import org.junit.Test -import org.junit.Assert.* - /** * Example local unit test, which will execute on the development machine (host). * @@ -14,4 +13,4 @@ class ExampleUnitTest { fun addition_isCorrect() { assertEquals(4, 2 + 2) } -} \ No newline at end of file +} diff --git a/features/messages/build.gradle.kts b/features/messages/build.gradle.kts index 3b6c10c717..4735cd6530 100644 --- a/features/messages/build.gradle.kts +++ b/features/messages/build.gradle.kts @@ -23,7 +23,6 @@ dependencies { implementation(project(":libraries:textcomposer")) implementation(libs.mavericks.compose) implementation(libs.coil.compose) - implementation(libs.timber) implementation(libs.datetime) implementation(libs.accompanist.flowlayout) implementation(libs.androidx.recyclerview) diff --git a/features/messages/src/androidTest/java/io/element/android/x/features/messages/ExampleInstrumentedTest.kt b/features/messages/src/androidTest/java/io/element/android/x/features/messages/ExampleInstrumentedTest.kt index 5594e59678..6c7e4fce97 100644 --- a/features/messages/src/androidTest/java/io/element/android/x/features/messages/ExampleInstrumentedTest.kt +++ b/features/messages/src/androidTest/java/io/element/android/x/features/messages/ExampleInstrumentedTest.kt @@ -1,13 +1,11 @@ package io.element.android.x.features.messages -import androidx.test.platform.app.InstrumentationRegistry 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.runner.RunWith -import org.junit.Assert.* - /** * Instrumented test, which will execute on an Android device. * @@ -21,4 +19,4 @@ class ExampleInstrumentedTest { val appContext = InstrumentationRegistry.getInstrumentation().targetContext assertEquals("io.element.android.x.features.messages.test", appContext.packageName) } -} \ No newline at end of file +} diff --git a/features/messages/src/main/AndroidManifest.xml b/features/messages/src/main/AndroidManifest.xml index a5918e68ab..e100076157 100644 --- a/features/messages/src/main/AndroidManifest.xml +++ b/features/messages/src/main/AndroidManifest.xml @@ -1,4 +1,4 @@ - + - \ No newline at end of file + diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/MessageTimelineItemStateFactory.kt b/features/messages/src/main/java/io/element/android/x/features/messages/MessageTimelineItemStateFactory.kt index d52754b3b2..1dfd5712e7 100644 --- a/features/messages/src/main/java/io/element/android/x/features/messages/MessageTimelineItemStateFactory.kt +++ b/features/messages/src/main/java/io/element/android/x/features/messages/MessageTimelineItemStateFactory.kt @@ -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.MessagesItemReactionState 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.matrix.MatrixClient import io.element.android.x.matrix.media.MediaResolver import io.element.android.x.matrix.room.MatrixRoom import io.element.android.x.matrix.timeline.MatrixTimelineItem +import kotlin.system.measureTimeMillis import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.MutableStateFlow 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.MessageType import timber.log.Timber -import kotlin.system.measureTimeMillis class MessageTimelineItemStateFactory( private val client: MatrixClient, @@ -83,7 +90,6 @@ class MessageTimelineItemStateFactory( timelineItemStates.emit(newTimelineItemStates) } - private fun calculateAndApplyDiff(newTimelineItems: List) { val timeToDiff = measureTimeMillis { val diffCallback = @@ -192,7 +198,6 @@ class MessageTimelineItemStateFactory( htmlDocument = messageType.content.formatted?.toHtmlDocument() ) else -> MessagesTimelineItemUnknownContent - } } @@ -232,5 +237,4 @@ class MessageTimelineItemStateFactory( .resolve(url, kind = MediaResolver.Kind.Thumbnail(size.value)) return AvatarData(name, model, size) } - } diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/MessagesScreen.kt b/features/messages/src/main/java/io/element/android/x/features/messages/MessagesScreen.kt index 44320e3e70..a5a44e38f5 100644 --- a/features/messages/src/main/java/io/element/android/x/features/messages/MessagesScreen.kt +++ b/features/messages/src/main/java/io/element/android/x/features/messages/MessagesScreen.kt @@ -6,9 +6,26 @@ package io.element.android.x.features.messages -import Avatar 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.LazyListState 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.ArrowDownward import androidx.compose.material.rememberModalBottomSheetState -import androidx.compose.material3.* -import androidx.compose.runtime.* +import androidx.compose.material3.CircularProgressIndicator +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.Companion.End 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.PairCombinedPreviewParameter 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.features.messages.components.* -import io.element.android.x.features.messages.model.* -import io.element.android.x.features.messages.model.content.* +import io.element.android.x.features.messages.components.MessageEventBubble +import io.element.android.x.features.messages.components.MessagesReactionsView +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.MessageComposerViewState import io.element.android.x.textcomposer.MessageComposerMode 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.launch import timber.log.Timber -import java.lang.Math.random @Composable fun MessagesScreen( @@ -61,7 +116,6 @@ fun MessagesScreen( viewModel: MessagesViewModel = mavericksViewModel(argsFactory = { roomId }), composerViewModel: MessageComposerViewModel = mavericksViewModel(argsFactory = { roomId }) ) { - fun onSendMessage(textMessage: String) { viewModel.sendMessage(textMessage) composerViewModel.updateText("") @@ -88,7 +142,7 @@ fun MessagesScreen( MessagesScreenContent( roomTitle = roomTitle, roomAvatar = roomAvatar, - timelineItems = timelineItems().orEmpty(), + timelineItems = timelineItems().orEmpty().toImmutableList(), hasMoreToLoad = hasMoreToLoad, onReachedLoadMore = viewModel::loadMore, onBackPressed = onBackPressed, @@ -130,7 +184,7 @@ fun MessagesScreen( fun MessagesScreenContent( roomTitle: String?, roomAvatar: AvatarData?, - timelineItems: List, + timelineItems: ImmutableList, hasMoreToLoad: Boolean, onReachedLoadMore: () -> Unit, onBackPressed: () -> Unit, @@ -146,9 +200,11 @@ fun MessagesScreenContent( composerCanSendMessage: Boolean, composerText: StableCharSequence?, snackbarHostState: SnackbarHostState, + modifier: Modifier = Modifier, ) { LogCompositions(tag = "MessagesScreen", msg = "Content") Scaffold( + modifier = modifier, contentWindowInsets = WindowInsets.statusBars, topBar = { MessagesTopAppBar( @@ -187,7 +243,7 @@ fun MessagesScreenContent( @Composable fun MessagesContent( - timelineItems: List, + timelineItems: ImmutableList, hasMoreToLoad: Boolean, onReachedLoadMore: () -> Unit, onSendMessage: (String) -> Unit, @@ -203,7 +259,6 @@ fun MessagesContent( composerText: StableCharSequence?, modifier: Modifier = Modifier ) { - val lazyListState = rememberLazyListState() Column( modifier = modifier @@ -249,9 +304,11 @@ fun MessagesContent( fun MessagesTopAppBar( roomTitle: String?, roomAvatar: AvatarData?, - onBackPressed: () -> Unit, + modifier: Modifier = Modifier, + onBackPressed: () -> Unit = {}, ) { TopAppBar( + modifier = modifier, navigationIcon = { IconButton(onClick = onBackPressed) { Icon( @@ -282,7 +339,7 @@ fun MessagesTopAppBar( @Composable fun TimelineItems( lazyListState: LazyListState, - timelineItems: List, + timelineItems: ImmutableList, highlightedEventId: String?, modifier: Modifier = Modifier, hasMoreToLoad: Boolean = false, @@ -322,7 +379,6 @@ fun TimelineItems( onLoadMore = onReachedLoadMore ) } - } private fun MessagesTimelineItemState.key(): String { @@ -339,7 +395,6 @@ private fun MessagesTimelineItemState.contentType(): Int { } } - @Composable fun TimelineItemRow( timelineItem: MessagesTimelineItemState, @@ -426,7 +481,6 @@ fun MessageEventRow( content = messageEvent.content, modifier = contentModifier ) - else -> TODO() /* compiler issue ? */ } } MessagesReactionsView( @@ -471,8 +525,8 @@ private fun MessageSenderInformation( @Composable internal fun BoxScope.MessagesScrollHelper( lazyListState: LazyListState, - timelineItems: List, - onLoadMore: () -> Unit, + timelineItems: ImmutableList, + onLoadMore: () -> Unit = {}, ) { val coroutineScope = rememberCoroutineScope() val firstVisibleItemIndex by remember { derivedStateOf { lazyListState.firstVisibleItemIndex } } @@ -526,7 +580,6 @@ internal fun BoxScope.MessagesScrollHelper( Icon(Icons.Default.ArrowDownward, "") } } - } @Composable @@ -543,7 +596,6 @@ internal fun MessagesLoadingMoreIndicator() { color = MaterialTheme.colorScheme.primary ) } - } class MessagesItemGroupPositionToMessagesTimelineItemContentProvider : @@ -551,6 +603,7 @@ class MessagesItemGroupPositionToMessagesTimelineItemContentProvider : MessagesItemGroupPositionProvider() to MessagesTimelineItemContentProvider() ) +@Suppress("PreviewPublic") @Preview(showBackground = true) @Composable fun TimelineItemsPreview( @@ -559,7 +612,7 @@ fun TimelineItemsPreview( ) { TimelineItems( lazyListState = LazyListState(), - timelineItems = listOf( + timelineItems = persistentListOf( // 3 items (First Middle Last) with isMine = false createMessageEvent( isMine = false, diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/MessagesViewModel.kt b/features/messages/src/main/java/io/element/android/x/features/messages/MessagesViewModel.kt index 0b8fb62529..98165305f1 100644 --- a/features/messages/src/main/java/io/element/android/x/features/messages/MessagesViewModel.kt +++ b/features/messages/src/main/java/io/element/android/x/features/messages/MessagesViewModel.kt @@ -218,4 +218,4 @@ class MessagesViewModel @AssistedInject constructor( timeline.callback = null timeline.dispose() } -} \ No newline at end of file +} diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/components/MessageEventBubble.kt b/features/messages/src/main/java/io/element/android/x/features/messages/components/MessageEventBubble.kt index 47bf5f3674..51d0faf677 100644 --- a/features/messages/src/main/java/io/element/android/x/features/messages/components/MessageEventBubble.kt +++ b/features/messages/src/main/java/io/element/android/x/features/messages/components/MessageEventBubble.kt @@ -13,7 +13,13 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Shape 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 private val BUBBLE_RADIUS = 16.dp @@ -26,9 +32,9 @@ fun MessageEventBubble( interactionSource: MutableInteractionSource, isHighlighted: Boolean, modifier: Modifier = Modifier, - onClick: () -> Unit, - onLongClick: () -> Unit, - content: @Composable () -> Unit, + onClick: () -> Unit = {}, + onLongClick: () -> Unit = {}, + content: @Composable () -> Unit = {}, ) { fun bubbleShape(): Shape { return when (groupPosition) { @@ -102,4 +108,4 @@ fun MessageEventBubble( shape = bubbleShape, content = content ) -} \ No newline at end of file +} diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesReactionsView.kt b/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesReactionsView.kt index 7b62e9d6cb..0802493a67 100644 --- a/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesReactionsView.kt +++ b/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesReactionsView.kt @@ -24,7 +24,7 @@ fun MessagesReactionsView( reactionsState: MessagesItemReactionState, modifier: Modifier = Modifier, ) { - if(reactionsState.reactions.isEmpty()) return + if (reactionsState.reactions.isEmpty()) return FlowRow( modifier = modifier, 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) } } -} \ No newline at end of file +} diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemActionsSheet.kt b/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemActionsSheet.kt index 3d1b6cede9..b34c65916d 100644 --- a/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemActionsSheet.kt +++ b/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemActionsSheet.kt @@ -3,14 +3,28 @@ package io.element.android.x.features.messages.components 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.items -import androidx.compose.material.* -import androidx.compose.runtime.* +import androidx.compose.material.ExperimentalMaterialApi +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.graphics.Color -import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.unit.dp import com.airbnb.mvrx.compose.collectAsState 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.content.MessagesTimelineItemTextBasedContent import io.element.android.x.features.messages.textcomposer.MessageComposerViewModel -import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch @@ -63,7 +76,6 @@ fun TimelineItemActionsScreen( } } - ModalBottomSheetLayout( modifier = modifier, sheetState = modalBottomSheetState, @@ -71,46 +83,47 @@ fun TimelineItemActionsScreen( SheetContent( actionsSheetState = itemActionsSheetState(), onActionClicked = ::onItemActionClicked, - modifier = Modifier.navigationBarsPadding().imePadding() + modifier = Modifier + .navigationBarsPadding() + .imePadding() ) } ) {} - } @Composable private fun SheetContent( actionsSheetState: MessagesItemActionsSheetState?, - onActionClicked: (MessagesItemAction, MessagesTimelineItemState.MessageEvent) -> Unit, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, + onActionClicked: (MessagesItemAction, MessagesTimelineItemState.MessageEvent) -> Unit = { _, _ -> }, ) { if (actionsSheetState == null || actionsSheetState.actions.isEmpty()) { // Crashes if sheetContent size is zero Box(modifier = modifier.size(1.dp)) - return - } - LazyColumn( - modifier = modifier - .fillMaxWidth() - ) { - items(actionsSheetState.actions) { - ListItem( - modifier = Modifier.clickable { - onActionClicked(it, actionsSheetState.targetItem) - }, - text = { - Text( - text = it.title, - color = if (it.destructive) MaterialTheme.colors.error else Color.Unspecified, - ) - }, - icon = { - VectorIcon( - resourceId = it.icon, - tint = if (it.destructive) MaterialTheme.colors.error else LocalContentColor.current, - ) - } - ) + } else { + LazyColumn( + modifier = modifier + .fillMaxWidth() + ) { + items(actionsSheetState.actions) { + ListItem( + modifier = Modifier.clickable { + onActionClicked(it, actionsSheetState.targetItem) + }, + text = { + Text( + text = it.title, + color = if (it.destructive) MaterialTheme.colors.error else Color.Unspecified, + ) + }, + icon = { + VectorIcon( + resourceId = it.icon, + tint = if (it.destructive) MaterialTheme.colors.error else LocalContentColor.current, + ) + } + ) + } } } -} \ No newline at end of file +} diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemEncryptedView.kt b/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemEncryptedView.kt index d2b280657e..cf89c3418a 100644 --- a/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemEncryptedView.kt +++ b/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemEncryptedView.kt @@ -17,4 +17,4 @@ fun MessagesTimelineItemEncryptedView( icon = Icons.Default.Warning, modifier = modifier ) -} \ No newline at end of file +} diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemImageView.kt b/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemImageView.kt index eaac062ae2..35836505db 100644 --- a/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemImageView.kt +++ b/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemImageView.kt @@ -6,7 +6,6 @@ import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.heightIn import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable 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.layout.ContentScale import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.unit.dp import coil.compose.AsyncImage import coil.request.ImageRequest import io.element.android.x.features.messages.model.content.MessagesTimelineItemImageContent @@ -26,9 +24,9 @@ fun MessagesTimelineItemImageView( content: MessagesTimelineItemImageContent, modifier: Modifier = Modifier ) { - val widthPercent = if(content.aspectRatio > 1f){ + val widthPercent = if (content.aspectRatio > 1f) { 1f - }else { + } else { 0.7f } Box( @@ -37,7 +35,6 @@ fun MessagesTimelineItemImageView( .aspectRatio(content.aspectRatio), contentAlignment = Alignment.Center, ) { - var isLoading = rememberSaveable(content.imageMeta) { mutableStateOf(true) } val context = LocalContext.current val model = ImageRequest.Builder(context) @@ -52,4 +49,4 @@ fun MessagesTimelineItemImageView( onSuccess = { isLoading.value = false }, ) } -} \ No newline at end of file +} diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemInformativeView.kt b/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemInformativeView.kt index dbfe9ccf96..56f5723486 100644 --- a/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemInformativeView.kt +++ b/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemInformativeView.kt @@ -40,4 +40,4 @@ fun MessagesTimelineItemInformativeView( text = text ) } -} \ No newline at end of file +} diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemRedactedView.kt b/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemRedactedView.kt index bc1a4d2d10..f87ef4c18e 100644 --- a/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemRedactedView.kt +++ b/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemRedactedView.kt @@ -17,4 +17,4 @@ fun MessagesTimelineItemRedactedView( icon = Icons.Default.Delete, modifier = modifier ) -} \ No newline at end of file +} diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemTextView.kt b/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemTextView.kt index 26fd802bc5..3bbc334533 100644 --- a/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemTextView.kt +++ b/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemTextView.kt @@ -22,8 +22,8 @@ fun MessagesTimelineItemTextView( content: MessagesTimelineItemTextBasedContent, interactionSource: MutableInteractionSource, modifier: Modifier = Modifier, - onTextClicked: () -> Unit, - onTextLongClicked: () -> Unit, + onTextClicked: () -> Unit = {}, + onTextLongClicked: () -> Unit = {}, ) { val htmlDocument = content.htmlDocument if (htmlDocument != null) { @@ -74,4 +74,4 @@ private fun String.linkify( end = end ) } -} \ No newline at end of file +} diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemUnknownView.kt b/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemUnknownView.kt index 2c9344e02d..9445103c5f 100644 --- a/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemUnknownView.kt +++ b/features/messages/src/main/java/io/element/android/x/features/messages/components/MessagesTimelineItemUnknownView.kt @@ -17,4 +17,4 @@ fun MessagesTimelineItemUnknownView( icon = Icons.Default.Info, modifier = modifier ) -} \ No newline at end of file +} diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/components/html/HtmlDocument.kt b/features/messages/src/main/java/io/element/android/x/features/messages/components/html/HtmlDocument.kt index e71769b532..388435c390 100644 --- a/features/messages/src/main/java/io/element/android/x/features/messages/components/html/HtmlDocument.kt +++ b/features/messages/src/main/java/io/element/android/x/features/messages/components/html/HtmlDocument.kt @@ -9,17 +9,25 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.InlineTextContent 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.ui.Modifier import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.geometry.Offset 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.FontStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextDecoration +import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp 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.matrix.permalink.PermalinkData import io.element.android.x.matrix.permalink.PermalinkParser +import kotlinx.collections.immutable.persistentMapOf import org.jsoup.nodes.Document import org.jsoup.nodes.Element import org.jsoup.nodes.Node @@ -38,34 +47,33 @@ private const val chipId = "chip" fun HtmlDocument( document: Document, interactionSource: MutableInteractionSource, - onTextClicked: () -> Unit, - onTextLongClicked: () -> Unit, modifier: Modifier = Modifier, + onTextClicked: () -> Unit = {}, + onTextLongClicked: () -> Unit = {}, ) { HtmlBody( body = document.body(), + interactionSource = interactionSource, modifier = modifier, onTextClicked = onTextClicked, onTextLongClicked = onTextLongClicked, - interactionSource = interactionSource ) } @Composable private fun HtmlBody( body: Element, - modifier: Modifier = Modifier, - onTextClicked: () -> Unit, - onTextLongClicked: () -> Unit, interactionSource: MutableInteractionSource, + modifier: Modifier = Modifier, + onTextClicked: () -> Unit = {}, + onTextLongClicked: () -> Unit = {}, ) { - @Composable fun NodesFlowRode( nodes: Iterator, - onTextClicked: () -> Unit, - onTextLongClicked: () -> Unit, interactionSource: MutableInteractionSource, + onTextClicked: () -> Unit = {}, + onTextLongClicked: () -> Unit = {}, ) = FlowRow( mainAxisSpacing = 2.dp, crossAxisSpacing = 8.dp, @@ -106,9 +114,9 @@ private fun HtmlBody( while (nodesIterator.hasNext()) { NodesFlowRode( nodes = nodesIterator, + interactionSource = interactionSource, onTextClicked = onTextClicked, onTextLongClicked = onTextLongClicked, - interactionSource = interactionSource ) } } @@ -125,10 +133,10 @@ private fun Element.isInline(): Boolean { @Composable private fun HtmlBlock( element: Element, - modifier: Modifier = Modifier, - onTextClicked: () -> Unit, - onTextLongClicked: () -> Unit, interactionSource: MutableInteractionSource, + modifier: Modifier = Modifier, + onTextClicked: () -> Unit = {}, + onTextLongClicked: () -> Unit = {}, ) { val blockModifier = modifier .padding(top = 4.dp) @@ -183,10 +191,10 @@ private fun HtmlBlock( @Composable private fun HtmlInline( element: Element, - modifier: Modifier = Modifier, - onTextClicked: () -> Unit, - onTextLongClicked: () -> Unit, interactionSource: MutableInteractionSource, + modifier: Modifier = Modifier, + onTextClicked: () -> Unit = {}, + onTextLongClicked: () -> Unit = {}, ) { Box(modifier) { val styledText = buildAnnotatedString { @@ -202,7 +210,10 @@ private fun HtmlInline( } @Composable -private fun HtmlPreformatted(pre: Element, modifier: Modifier = Modifier) { +private fun HtmlPreformatted( + pre: Element, + modifier: Modifier = Modifier +) { val isCode = pre.firstElementChild()?.normalName() == "code" val backgroundColor = if (isCode) MaterialTheme.colorScheme.codeBackground() else Color.Unspecified @@ -221,9 +232,10 @@ private fun HtmlPreformatted(pre: Element, modifier: Modifier = Modifier) { @Composable private fun HtmlParagraph( paragraph: Element, - modifier: Modifier = Modifier, - onTextClicked: () -> Unit, onTextLongClicked: () -> Unit, interactionSource: MutableInteractionSource, + modifier: Modifier = Modifier, + onTextClicked: () -> Unit = {}, + onTextLongClicked: () -> Unit = {}, ) { Box(modifier) { val styledText = buildAnnotatedString { @@ -239,9 +251,10 @@ private fun HtmlParagraph( @Composable private fun HtmlBlockquote( blockquote: Element, - modifier: Modifier = Modifier, - onTextClicked: () -> Unit, onTextLongClicked: () -> Unit, interactionSource: MutableInteractionSource, + modifier: Modifier = Modifier, + onTextClicked: () -> Unit = {}, + onTextLongClicked: () -> Unit = {}, ) { val color = MaterialTheme.colorScheme.onBackground Box( @@ -268,13 +281,13 @@ private fun HtmlBlockquote( } } - @Composable private fun HtmlHeading( heading: Element, - modifier: Modifier = Modifier, - onTextClicked: () -> Unit, onTextLongClicked: () -> Unit, interactionSource: MutableInteractionSource, + modifier: Modifier = Modifier, + onTextClicked: () -> Unit = {}, + onTextLongClicked: () -> Unit = {}, ) { val style = when (heading.normalName()) { "h1" -> MaterialTheme.typography.headlineLarge.copy(fontSize = 30.sp) @@ -304,9 +317,10 @@ private fun HtmlHeading( @Composable private fun HtmlMxReply( mxReply: Element, - modifier: Modifier = Modifier, - onTextClicked: () -> Unit, onTextLongClicked: () -> Unit, interactionSource: MutableInteractionSource, + modifier: Modifier = Modifier, + onTextClicked: () -> Unit = {}, + onTextLongClicked: () -> Unit = {}, ) { val blockquote = mxReply.childNodes().firstOrNull() ?: return val shape = RoundedCornerShape(12.dp) @@ -356,9 +370,10 @@ private fun HtmlMxReply( @Composable private fun HtmlOrderedList( orderedList: Element, - modifier: Modifier = Modifier, - onTextClicked: () -> Unit, onTextLongClicked: () -> Unit, interactionSource: MutableInteractionSource, + modifier: Modifier = Modifier, + onTextClicked: () -> Unit = {}, + onTextLongClicked: () -> Unit = {}, ) { var number = 1 val delimiter = "." @@ -381,9 +396,10 @@ private fun HtmlOrderedList( @Composable private fun HtmlUnorderedList( unorderedList: Element, - modifier: Modifier = Modifier, - onTextClicked: () -> Unit, onTextLongClicked: () -> Unit, interactionSource: MutableInteractionSource, + modifier: Modifier = Modifier, + onTextClicked: () -> Unit = {}, + onTextLongClicked: () -> Unit = {}, ) { val marker = "・" HtmlListItems( @@ -402,14 +418,14 @@ private fun HtmlUnorderedList( } } - @Composable private fun HtmlListItems( list: Element, - modifier: Modifier = Modifier, - onTextClicked: () -> Unit, onTextLongClicked: () -> Unit, interactionSource: MutableInteractionSource, - content: @Composable (node: TextNode) -> Unit + modifier: Modifier = Modifier, + onTextClicked: () -> Unit = {}, + onTextLongClicked: () -> Unit = {}, + content: @Composable (node: TextNode) -> Unit = {} ) { Column(modifier = modifier) { for (node in list.children()) { @@ -420,13 +436,12 @@ private fun HtmlListItems( } is Element -> HtmlBlock( element = innerNode, - modifier = modifier.padding(start = 4.dp), + modifier = Modifier.padding(start = 4.dp), onTextClicked = onTextClicked, onTextLongClicked = onTextLongClicked, interactionSource = interactionSource ) } } - } } } @@ -439,7 +454,6 @@ private fun AnnotatedString.Builder.appendInlineChildrenElements( childNodes: List, colors: ColorScheme ) { - for (node in childNodes) { when (node) { is TextNode -> { @@ -452,7 +466,6 @@ private fun AnnotatedString.Builder.appendInlineChildrenElements( } } - private fun AnnotatedString.Builder.appendInlineElement(element: Element, colors: ColorScheme) { when (element.normalName()) { "br" -> { @@ -490,7 +503,6 @@ private fun AnnotatedString.Builder.appendInlineElement(element: Element, colors appendInlineChildrenElements(element.childNodes(), colors) } } - } private fun AnnotatedString.Builder.appendLink(link: Element) { @@ -521,13 +533,13 @@ private fun AnnotatedString.Builder.appendLink(link: Element) { @Composable private fun HtmlText( text: AnnotatedString, + interactionSource: MutableInteractionSource, modifier: Modifier = Modifier, style: TextStyle = LocalTextStyle.current, - onClick: () -> Unit, - onLongClick: () -> Unit, - interactionSource: MutableInteractionSource, + onClick: () -> Unit = {}, + onLongClick: () -> Unit = {}, ) { - val inlineContentMap = emptyMap() + val inlineContentMap = persistentMapOf() ClickableLinkText( text = text, linkAnnotationTag = "URL", @@ -539,4 +551,3 @@ private fun HtmlText( onLongClick = onLongClick ) } - diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/diff/CacheInvalidator.kt b/features/messages/src/main/java/io/element/android/x/features/messages/diff/CacheInvalidator.kt index 4940ea6046..542bd98b8d 100644 --- a/features/messages/src/main/java/io/element/android/x/features/messages/diff/CacheInvalidator.kt +++ b/features/messages/src/main/java/io/element/android/x/features/messages/diff/CacheInvalidator.kt @@ -37,5 +37,4 @@ internal class CacheInvalidator(private val itemStatesCache: MutableList true else -> false } - } internal class MessagesItemGroupPositionProvider : PreviewParameterProvider { @@ -22,4 +21,4 @@ internal class MessagesItemGroupPositionProvider : PreviewParameterProvider ) + @Stable data class AggregatedReaction( val key: String, val count: String, val isHighlighted: Boolean = false -) \ No newline at end of file +) diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/model/MessagesTimelineItemState.kt b/features/messages/src/main/java/io/element/android/x/features/messages/model/MessagesTimelineItemState.kt index e194e9a1a4..fd4bf88f18 100644 --- a/features/messages/src/main/java/io/element/android/x/features/messages/model/MessagesTimelineItemState.kt +++ b/features/messages/src/main/java/io/element/android/x/features/messages/model/MessagesTimelineItemState.kt @@ -23,11 +23,5 @@ sealed interface MessagesTimelineItemState { val showSenderInformation = groupPosition.isNew() && !isMine val safeSenderName: String = senderDisplayName ?: senderId - } - - } - - - diff --git a/features/messages/src/main/java/io/element/android/x/features/messages/model/content/MessagesTimelineItemContent.kt b/features/messages/src/main/java/io/element/android/x/features/messages/model/content/MessagesTimelineItemContent.kt index 57c6edd330..8c758347f8 100644 --- a/features/messages/src/main/java/io/element/android/x/features/messages/model/content/MessagesTimelineItemContent.kt +++ b/features/messages/src/main/java/io/element/android/x/features/messages/model/content/MessagesTimelineItemContent.kt @@ -2,8 +2,6 @@ package io.element.android.x.features.messages.model.content import androidx.compose.ui.tooling.preview.PreviewParameterProvider import org.matrix.rustcomponents.sdk.EncryptedMessage -import org.matrix.rustcomponents.sdk.FormattedBody -import org.matrix.rustcomponents.sdk.MessageFormat sealed interface MessagesTimelineItemContent @@ -28,4 +26,4 @@ class MessagesTimelineItemContentProvider : PreviewParameterProvider MutableList.invalidateLast() { if (indexOfLast > 0) { set(indexOfLast - 1, null) } -} \ No newline at end of file +} diff --git a/features/messages/src/test/java/io/element/android/x/features/messages/ExampleUnitTest.kt b/features/messages/src/test/java/io/element/android/x/features/messages/ExampleUnitTest.kt index d1fddda9b7..01e16c5949 100644 --- a/features/messages/src/test/java/io/element/android/x/features/messages/ExampleUnitTest.kt +++ b/features/messages/src/test/java/io/element/android/x/features/messages/ExampleUnitTest.kt @@ -1,9 +1,8 @@ package io.element.android.x.features.messages +import org.junit.Assert.assertEquals import org.junit.Test -import org.junit.Assert.* - /** * Example local unit test, which will execute on the development machine (host). * @@ -14,4 +13,4 @@ class ExampleUnitTest { fun addition_isCorrect() { assertEquals(4, 2 + 2) } -} \ No newline at end of file +} diff --git a/features/onboarding/build.gradle.kts b/features/onboarding/build.gradle.kts index b878aed3c7..a808aa7d8d 100644 --- a/features/onboarding/build.gradle.kts +++ b/features/onboarding/build.gradle.kts @@ -12,10 +12,9 @@ dependencies { implementation(project(":libraries:elementresources")) implementation(project(":libraries:designsystem")) implementation(libs.mavericks.compose) - implementation(libs.timber) implementation(libs.accompanist.pager) implementation(libs.accompanist.pagerindicator) testImplementation(libs.test.junit) androidTestImplementation(libs.test.junitext) ksp(libs.showkase.processor) -} \ No newline at end of file +} diff --git a/features/onboarding/src/androidTest/java/io/element/android/x/features/login/ExampleInstrumentedTest.kt b/features/onboarding/src/androidTest/java/io/element/android/x/features/login/ExampleInstrumentedTest.kt index ba9eb96b15..ec5ace41e6 100644 --- a/features/onboarding/src/androidTest/java/io/element/android/x/features/login/ExampleInstrumentedTest.kt +++ b/features/onboarding/src/androidTest/java/io/element/android/x/features/login/ExampleInstrumentedTest.kt @@ -1,13 +1,11 @@ package io.element.android.x.features.login -import androidx.test.platform.app.InstrumentationRegistry 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.runner.RunWith -import org.junit.Assert.* - /** * Instrumented test, which will execute on an Android device. * @@ -21,4 +19,4 @@ class ExampleInstrumentedTest { val appContext = InstrumentationRegistry.getInstrumentation().targetContext assertEquals("io.element.android.x.features.login.test", appContext.packageName) } -} \ No newline at end of file +} diff --git a/features/onboarding/src/main/AndroidManifest.xml b/features/onboarding/src/main/AndroidManifest.xml index a5918e68ab..e100076157 100644 --- a/features/onboarding/src/main/AndroidManifest.xml +++ b/features/onboarding/src/main/AndroidManifest.xml @@ -1,4 +1,4 @@ - + - \ No newline at end of file + diff --git a/features/onboarding/src/main/java/io/element/android/x/features/onboarding/OnBoardingScreen.kt b/features/onboarding/src/main/java/io/element/android/x/features/onboarding/OnBoardingScreen.kt index 8a1b4bfa39..55d3375a4a 100644 --- a/features/onboarding/src/main/java/io/element/android/x/features/onboarding/OnBoardingScreen.kt +++ b/features/onboarding/src/main/java/io/element/android/x/features/onboarding/OnBoardingScreen.kt @@ -3,12 +3,24 @@ package io.element.android.x.features.onboarding 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.MaterialTheme import androidx.compose.material3.Surface 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.Modifier import androidx.compose.ui.res.painterResource @@ -42,19 +54,20 @@ fun OnBoardingScreen( ) } - @OptIn(ExperimentalPagerApi::class) @Composable fun OnBoardingContent( state: OnBoardingViewState, - onPageChanged: (Int) -> Unit, - onSignUp: () -> Unit, - onSignIn: () -> Unit, + modifier: Modifier = Modifier, + onPageChanged: (Int) -> Unit = {}, + onSignUp: () -> Unit = {}, + onSignIn: () -> Unit = {}, ) { val carrouselState = remember { SplashCarouselStateFactory().create() } val nbOfPages = carrouselState.items.size var key by remember { mutableStateOf(false) } Surface( + modifier = modifier, color = MaterialTheme.colorScheme.background, ) { Box( @@ -125,8 +138,11 @@ fun OnBoardingContent( @Composable fun OnBoardingPage( item: SplashCarouselState.Item, + modifier: Modifier = Modifier, ) { - Box { + Box( + modifier = modifier, + ) { /* Image( painterResource(id = item.pageBackground), @@ -164,4 +180,4 @@ fun OnBoardingPage( ) } } -} \ No newline at end of file +} diff --git a/features/onboarding/src/main/java/io/element/android/x/features/onboarding/OnBoardingViewModel.kt b/features/onboarding/src/main/java/io/element/android/x/features/onboarding/OnBoardingViewModel.kt index 0749c4a50d..b1f708b126 100644 --- a/features/onboarding/src/main/java/io/element/android/x/features/onboarding/OnBoardingViewModel.kt +++ b/features/onboarding/src/main/java/io/element/android/x/features/onboarding/OnBoardingViewModel.kt @@ -12,4 +12,4 @@ class OnBoardingViewModel(initialState: OnBoardingViewState) : ) } } -} \ No newline at end of file +} diff --git a/features/onboarding/src/main/java/io/element/android/x/features/onboarding/SplashCarouselState.kt b/features/onboarding/src/main/java/io/element/android/x/features/onboarding/SplashCarouselState.kt index f9b0bb9dfb..e21ccf9058 100644 --- a/features/onboarding/src/main/java/io/element/android/x/features/onboarding/SplashCarouselState.kt +++ b/features/onboarding/src/main/java/io/element/android/x/features/onboarding/SplashCarouselState.kt @@ -20,12 +20,12 @@ import androidx.annotation.DrawableRes import androidx.annotation.StringRes data class SplashCarouselState( - val items: List + val items: List ) { data class Item( - @StringRes val title: Int, - @StringRes val body: Int, - @DrawableRes val image: Int, - @DrawableRes val pageBackground: Int + @StringRes val title: Int, + @StringRes val body: Int, + @DrawableRes val image: Int, + @DrawableRes val pageBackground: Int ) } diff --git a/features/onboarding/src/main/java/io/element/android/x/features/onboarding/SplashCarouselStateFactory.kt b/features/onboarding/src/main/java/io/element/android/x/features/onboarding/SplashCarouselStateFactory.kt index e80f591062..04f605279d 100644 --- a/features/onboarding/src/main/java/io/element/android/x/features/onboarding/SplashCarouselStateFactory.kt +++ b/features/onboarding/src/main/java/io/element/android/x/features/onboarding/SplashCarouselStateFactory.kt @@ -3,7 +3,7 @@ package io.element.android.x.features.onboarding import androidx.annotation.DrawableRes import io.element.android.x.element.resources.R as ElementR -class SplashCarouselStateFactory() { +class SplashCarouselStateFactory { fun create(): SplashCarouselState { val lightTheme = true fun background(@DrawableRes lightDrawable: Int) = diff --git a/features/onboarding/src/test/java/io/element/android/x/features/login/ExampleUnitTest.kt b/features/onboarding/src/test/java/io/element/android/x/features/login/ExampleUnitTest.kt index bcc403cdbf..f1768db5bc 100644 --- a/features/onboarding/src/test/java/io/element/android/x/features/login/ExampleUnitTest.kt +++ b/features/onboarding/src/test/java/io/element/android/x/features/login/ExampleUnitTest.kt @@ -1,9 +1,8 @@ package io.element.android.x.features.login +import org.junit.Assert.assertEquals import org.junit.Test -import org.junit.Assert.* - /** * Example local unit test, which will execute on the development machine (host). * @@ -14,4 +13,4 @@ class ExampleUnitTest { fun addition_isCorrect() { assertEquals(4, 2 + 2) } -} \ No newline at end of file +} diff --git a/features/roomlist/build.gradle.kts b/features/roomlist/build.gradle.kts index 6b54bb4811..6eb99fa7a3 100644 --- a/features/roomlist/build.gradle.kts +++ b/features/roomlist/build.gradle.kts @@ -20,10 +20,9 @@ dependencies { implementation(project(":libraries:matrix")) implementation(project(":libraries:designsystem")) implementation(libs.mavericks.compose) - implementation(libs.timber) implementation(libs.datetime) implementation(libs.accompanist.placeholder) testImplementation(libs.test.junit) androidTestImplementation(libs.test.junitext) ksp(libs.showkase.processor) -} \ No newline at end of file +} diff --git a/features/roomlist/src/androidTest/java/io/element/android/x/features/roomlist/ExampleInstrumentedTest.kt b/features/roomlist/src/androidTest/java/io/element/android/x/features/roomlist/ExampleInstrumentedTest.kt index 8b9c88c9c3..c16a44bebb 100644 --- a/features/roomlist/src/androidTest/java/io/element/android/x/features/roomlist/ExampleInstrumentedTest.kt +++ b/features/roomlist/src/androidTest/java/io/element/android/x/features/roomlist/ExampleInstrumentedTest.kt @@ -1,13 +1,11 @@ package io.element.android.x.features.roomlist -import androidx.test.platform.app.InstrumentationRegistry 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.runner.RunWith -import org.junit.Assert.* - /** * Instrumented test, which will execute on an Android device. * @@ -21,4 +19,4 @@ class ExampleInstrumentedTest { val appContext = InstrumentationRegistry.getInstrumentation().targetContext assertEquals("io.element.android.x.features.roomlist.test", appContext.packageName) } -} \ No newline at end of file +} diff --git a/features/roomlist/src/main/AndroidManifest.xml b/features/roomlist/src/main/AndroidManifest.xml index a5918e68ab..e100076157 100644 --- a/features/roomlist/src/main/AndroidManifest.xml +++ b/features/roomlist/src/main/AndroidManifest.xml @@ -1,4 +1,4 @@ - + - \ No newline at end of file + diff --git a/features/roomlist/src/main/java/io/element/android/x/features/roomlist/LastMessageFormatter.kt b/features/roomlist/src/main/java/io/element/android/x/features/roomlist/LastMessageFormatter.kt index 4cd35efc15..d06eb20fbc 100644 --- a/features/roomlist/src/main/java/io/element/android/x/features/roomlist/LastMessageFormatter.kt +++ b/features/roomlist/src/main/java/io/element/android/x/features/roomlist/LastMessageFormatter.kt @@ -2,12 +2,18 @@ package io.element.android.x.features.roomlist import android.text.format.DateFormat import android.text.format.DateUtils -import kotlinx.datetime.* -import kotlinx.datetime.TimeZone import java.time.Period import java.time.format.DateTimeFormatter -import java.util.* +import java.util.Locale 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( private val clock: Clock = Clock.System, @@ -29,7 +35,6 @@ class LastMessageFormatter( DateTimeFormatter.ofPattern(pattern) } - fun format(timestamp: Long?): String { if (timestamp == null) return "" val now: Instant = clock.now() @@ -77,6 +82,4 @@ class LastMessageFormatter( DateUtils.FORMAT_SHOW_WEEKDAY ).toString() } - - -} \ No newline at end of file +} diff --git a/features/roomlist/src/main/java/io/element/android/x/features/roomlist/RoomListScreen.kt b/features/roomlist/src/main/java/io/element/android/x/features/roomlist/RoomListScreen.kt index 148cfd0ecc..dff4871efe 100644 --- a/features/roomlist/src/main/java/io/element/android/x/features/roomlist/RoomListScreen.kt +++ b/features/roomlist/src/main/java/io/element/android/x/features/roomlist/RoomListScreen.kt @@ -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.stubbedRoomSummaries import io.element.android.x.matrix.core.RoomId +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList @Composable fun RoomListScreen( @@ -53,7 +55,7 @@ fun RoomListScreen( val roomSummaries by viewModel.collectAsState(RoomListViewState::rooms) val matrixUser by viewModel.collectAsState(RoomListViewState::user) RoomListContent( - roomSummaries = roomSummaries().orEmpty(), + roomSummaries = roomSummaries().orEmpty().toImmutableList(), matrixUser = matrixUser(), onRoomClicked = onRoomClicked, onLogoutClicked = viewModel::logout, @@ -66,16 +68,16 @@ fun RoomListScreen( @Composable fun RoomListContent( - roomSummaries: List, + roomSummaries: ImmutableList, matrixUser: MatrixUser?, - onRoomClicked: (RoomId) -> Unit, filter: String, - onFilterChanged: (String) -> Unit, - onLogoutClicked: () -> Unit, - onScrollOver: (IntRange) -> Unit, isLoginOut: Boolean, + modifier: Modifier = Modifier, + onRoomClicked: (RoomId) -> Unit = {}, + onFilterChanged: (String) -> Unit = {}, + onLogoutClicked: () -> Unit = {}, + onScrollOver: (IntRange) -> Unit = {}, ) { - fun onRoomClicked(room: RoomListRoomSummary) { onRoomClicked(room.roomId) } @@ -104,7 +106,7 @@ fun RoomListContent( } Scaffold( - modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), + modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection), topBar = { RoomListTopBar( matrixUser = matrixUser, @@ -133,7 +135,7 @@ fun RoomListContent( } ) if (isLoginOut) { - ProgressDialog("Login out...") + ProgressDialog(text = "Login out...") } } @@ -176,4 +178,3 @@ fun PreviewableDarkRoomListContent() { ) } } - diff --git a/features/roomlist/src/main/java/io/element/android/x/features/roomlist/RoomListViewModel.kt b/features/roomlist/src/main/java/io/element/android/x/features/roomlist/RoomListViewModel.kt index 3eaf231818..5137f83761 100644 --- a/features/roomlist/src/main/java/io/element/android/x/features/roomlist/RoomListViewModel.kt +++ b/features/roomlist/src/main/java/io/element/android/x/features/roomlist/RoomListViewModel.kt @@ -4,17 +4,15 @@ import com.airbnb.mvrx.* import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.x.anvilannotations.ContributesViewModel -import io.element.android.x.core.data.parallelMap +import io.element.android.x.core.coroutine.parallelMap import io.element.android.x.core.di.daggerMavericksViewModelFactory import io.element.android.x.designsystem.components.avatar.AvatarData import io.element.android.x.designsystem.components.avatar.AvatarSize -import io.element.android.x.di.AppScope import io.element.android.x.di.SessionScope import io.element.android.x.features.roomlist.model.MatrixUser import io.element.android.x.features.roomlist.model.RoomListRoomSummary import io.element.android.x.features.roomlist.model.RoomListRoomSummaryPlaceholders import io.element.android.x.features.roomlist.model.RoomListViewState -import io.element.android.x.matrix.Matrix import io.element.android.x.matrix.MatrixClient import io.element.android.x.matrix.media.MediaResolver import io.element.android.x.matrix.room.RoomSummary @@ -112,8 +110,8 @@ class RoomListViewModel @AssistedInject constructor( copy( rooms = when { it is Loading || - // Note: this second case will prevent to handle correctly the empty case - (it is Success && it().isEmpty() && filter.isEmpty()) -> { + // Note: this second case will prevent to handle correctly the empty case + (it is Success && it().isEmpty() && filter.isEmpty()) -> { // Show fake placeholders to avoid having empty screen Loading(RoomListRoomSummaryPlaceholders.createFakeList(size = 16)) } @@ -158,5 +156,4 @@ class RoomListViewModel @AssistedInject constructor( .resolve(url, kind = MediaResolver.Kind.Thumbnail(size.value)) return AvatarData(name, model, size) } - -} \ No newline at end of file +} diff --git a/features/roomlist/src/main/java/io/element/android/x/features/roomlist/components/RoomListTopBar.kt b/features/roomlist/src/main/java/io/element/android/x/features/roomlist/components/RoomListTopBar.kt index 95b7744f5c..667357cf73 100644 --- a/features/roomlist/src/main/java/io/element/android/x/features/roomlist/components/RoomListTopBar.kt +++ b/features/roomlist/src/main/java/io/element/android/x/features/roomlist/components/RoomListTopBar.kt @@ -2,7 +2,6 @@ package io.element.android.x.features.roomlist.components -import Avatar import androidx.activity.compose.BackHandler import androidx.compose.foundation.layout.fillMaxWidth 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.Logout import androidx.compose.material.icons.filled.Search -import androidx.compose.material3.* -import androidx.compose.runtime.* +import androidx.compose.material3.ExperimentalMaterial3Api +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.setValue import androidx.compose.ui.Modifier 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 io.element.android.x.core.compose.LogCompositions 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.features.roomlist.model.MatrixUser @@ -35,7 +49,6 @@ fun RoomListTopBar( onLogoutClicked: () -> Unit, scrollBehavior: TopAppBarScrollBehavior ) { - LogCompositions(tag = "RoomListScreen", msg = "TopBar") var searchWidgetStateIsOpened by rememberSaveable { mutableStateOf(false) } @@ -65,20 +78,20 @@ fun RoomListTopBar( scrollBehavior = scrollBehavior, ) } - } @Composable fun SearchRoomListTopBar( text: String, - onFilterChanged: (String) -> Unit, - onCloseClicked: () -> Unit, - scrollBehavior: TopAppBarScrollBehavior + scrollBehavior: TopAppBarScrollBehavior, + modifier: Modifier = Modifier, + onFilterChanged: (String) -> Unit = {}, + onCloseClicked: () -> Unit = {}, ) { var filterState by textFieldState(stateValue = text) val focusRequester = remember { FocusRequester() } TopAppBar( - modifier = Modifier + modifier = modifier .nestedScroll(scrollBehavior.nestedScrollConnection), title = { TextField( @@ -184,10 +197,13 @@ private fun DefaultRoomListTopBar( ) // Log out confirmation dialog ConfirmationDialog( - openDialog, + isDisplayed = openDialog.value, title = "Log out", content = "Do you confirm you want to log out?", submitText = "Log out", onSubmitClicked = onLogoutClicked, + onDismiss = { + openDialog.value = false + } ) } diff --git a/features/roomlist/src/main/java/io/element/android/x/features/roomlist/components/RoomSummaryRow.kt b/features/roomlist/src/main/java/io/element/android/x/features/roomlist/components/RoomSummaryRow.kt index 5cdee76523..a83d2cd067 100644 --- a/features/roomlist/src/main/java/io/element/android/x/features/roomlist/components/RoomSummaryRow.kt +++ b/features/roomlist/src/main/java/io/element/android/x/features/roomlist/components/RoomSummaryRow.kt @@ -1,16 +1,23 @@ package io.element.android.x.features.roomlist.components -import Avatar import androidx.compose.foundation.background import androidx.compose.foundation.clickable 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.material.ripple.rememberRipple import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.Immutable import androidx.compose.runtime.remember import androidx.compose.ui.Alignment 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.sp 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 private val minHeight = 72.dp @Composable internal fun RoomSummaryRow( - modifier: Modifier = Modifier, room: RoomListRoomSummary, - onClick: (RoomListRoomSummary) -> Unit + modifier: Modifier = Modifier, + onClick: (RoomListRoomSummary) -> Unit = {}, ) { - val clickModifier = if (room.isPlaceholder) { modifier } else { @@ -57,7 +64,6 @@ internal fun RoomSummaryRow( ) { DefaultRoomSummaryRow(room = room) } - } @Composable diff --git a/features/roomlist/src/main/java/io/element/android/x/features/roomlist/model/RoomListRoomSummary.kt b/features/roomlist/src/main/java/io/element/android/x/features/roomlist/model/RoomListRoomSummary.kt index 98e2200df6..893824756f 100644 --- a/features/roomlist/src/main/java/io/element/android/x/features/roomlist/model/RoomListRoomSummary.kt +++ b/features/roomlist/src/main/java/io/element/android/x/features/roomlist/model/RoomListRoomSummary.kt @@ -13,4 +13,5 @@ data class RoomListRoomSummary( val timestamp: String? = null, val lastMessage: CharSequence? = null, val avatarData: AvatarData = AvatarData(), - val isPlaceholder: Boolean = false,) + val isPlaceholder: Boolean = false, +) diff --git a/features/roomlist/src/main/java/io/element/android/x/features/roomlist/model/RoomListRoomSummaryPlaceholders.kt b/features/roomlist/src/main/java/io/element/android/x/features/roomlist/model/RoomListRoomSummaryPlaceholders.kt index 1be8c07b2d..645114507f 100644 --- a/features/roomlist/src/main/java/io/element/android/x/features/roomlist/model/RoomListRoomSummaryPlaceholders.kt +++ b/features/roomlist/src/main/java/io/element/android/x/features/roomlist/model/RoomListRoomSummaryPlaceholders.kt @@ -2,7 +2,6 @@ package io.element.android.x.features.roomlist.model import io.element.android.x.designsystem.components.avatar.AvatarData - object RoomListRoomSummaryPlaceholders { fun create(id: String): RoomListRoomSummary { @@ -23,6 +22,4 @@ object RoomListRoomSummaryPlaceholders { } } } - } - diff --git a/features/roomlist/src/main/java/io/element/android/x/features/roomlist/model/stubbed.kt b/features/roomlist/src/main/java/io/element/android/x/features/roomlist/model/stubbed.kt index 4c8844b13b..7813171e45 100644 --- a/features/roomlist/src/main/java/io/element/android/x/features/roomlist/model/stubbed.kt +++ b/features/roomlist/src/main/java/io/element/android/x/features/roomlist/model/stubbed.kt @@ -1,9 +1,11 @@ package io.element.android.x.features.roomlist.model import io.element.android.x.designsystem.components.avatar.AvatarData +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf -internal fun stubbedRoomSummaries(): List { - return listOf( +internal fun stubbedRoomSummaries(): ImmutableList { + return persistentListOf( RoomListRoomSummary( name = "Room", hasUnread = true, @@ -22,4 +24,4 @@ internal fun stubbedRoomSummaries(): List { ), RoomListRoomSummaryPlaceholders.create("roomId2") ) -} \ No newline at end of file +} diff --git a/features/roomlist/src/test/java/io/element/android/x/features/roomlist/ExampleUnitTest.kt b/features/roomlist/src/test/java/io/element/android/x/features/roomlist/ExampleUnitTest.kt index 39034b2cb2..38bdf65d63 100644 --- a/features/roomlist/src/test/java/io/element/android/x/features/roomlist/ExampleUnitTest.kt +++ b/features/roomlist/src/test/java/io/element/android/x/features/roomlist/ExampleUnitTest.kt @@ -1,9 +1,8 @@ package io.element.android.x.features.roomlist +import org.junit.Assert.assertEquals import org.junit.Test -import org.junit.Assert.* - /** * Example local unit test, which will execute on the development machine (host). * @@ -14,4 +13,4 @@ class ExampleUnitTest { fun addition_isCorrect() { assertEquals(4, 2 + 2) } -} \ No newline at end of file +} diff --git a/gradle.properties b/gradle.properties index c4b415660b..9caae7208e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -21,8 +21,7 @@ kotlin.code.style=official # resources declared in the library itself and none from the library's dependencies, # thereby reducing the size of the R class for that library android.nonTransitiveRClass=true - # Dummy values for signing secrets / nightly signing.element.nightly.storePassword=Secret signing.element.nightly.keyId=Secret -signing.element.nightly.keyPassword=Secret \ No newline at end of file +signing.element.nightly.keyPassword=Secret diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 704c0236ac..6b62ade122 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -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] # Project android_gradle_plugin = "7.3.1" @@ -39,7 +42,6 @@ test_orchestrator = "1.4.1" #other mavericks = "3.0.1" -timber = "5.0.1" coil = "2.2.1" datetime = "0.4.0" wysiwyg = "0.7.0.1" @@ -52,6 +54,10 @@ jsoup = "1.15.3" dagger = "2.43" anvil = "2.4.2" +# quality +detekt = "1.22.0" +ktlint = "11.0.0" + [libraries] # Project android_gradle_plugin = { module = "com.android.tools.build:gradle", version.ref = "android_gradle_plugin" } @@ -102,13 +108,12 @@ test_orchestrator = { module = "androidx.test:orchestrator", version.ref = "test # Others 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_compose = { module = "io.coil-kt:coil-compose", version.ref = "coil" } datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "datetime" } 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_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_processor = { module = "com.airbnb.android:showkase-processor", version.ref = "showkase" } jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" } @@ -133,4 +138,6 @@ kotlin_android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlin_jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } kapt = {id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin"} ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } -anvil = {id = "com.squareup.anvil", version.ref = "anvil"} \ No newline at end of file +anvil = {id = "com.squareup.anvil", version.ref = "anvil"} +detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } +ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint" } diff --git a/libraries/core/src/main/java/io/element/android/x/core/compose/LogCompositions.kt b/libraries/core/src/main/java/io/element/android/x/core/compose/LogCompositions.kt index 7ab910b135..16f57ab409 100644 --- a/libraries/core/src/main/java/io/element/android/x/core/compose/LogCompositions.kt +++ b/libraries/core/src/main/java/io/element/android/x/core/compose/LogCompositions.kt @@ -1,22 +1,21 @@ package io.element.android.x.core.compose -import android.util.Log import androidx.compose.runtime.Composable import androidx.compose.runtime.SideEffect import androidx.compose.runtime.remember import io.element.android.x.core.BuildConfig - +import timber.log.Timber // 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 // original call site. @Composable -inline fun LogCompositions(tag: String, msg: String) { +fun LogCompositions(tag: String, msg: String) { if (BuildConfig.DEBUG) { val ref = remember { Ref(0) } SideEffect { ref.value++ } - Log.d(tag, "Compositions: $msg ${ref.value}") + Timber.d(tag, "Compositions: $msg ${ref.value}") } } -class Ref(var value: Int) \ No newline at end of file +class Ref(var value: Int) diff --git a/libraries/core/src/main/java/io/element/android/x/core/compose/OnLifecycleEvent.kt b/libraries/core/src/main/java/io/element/android/x/core/compose/OnLifecycleEvent.kt index 310e85a061..c022703236 100644 --- a/libraries/core/src/main/java/io/element/android/x/core/compose/OnLifecycleEvent.kt +++ b/libraries/core/src/main/java/io/element/android/x/core/compose/OnLifecycleEvent.kt @@ -12,7 +12,7 @@ import androidx.lifecycle.LifecycleOwner fun OnLifecycleEvent(onEvent: (owner: LifecycleOwner, event: Lifecycle.Event) -> Unit) { val eventHandler = rememberUpdatedState(onEvent) val lifecycleOwner = rememberUpdatedState(LocalLifecycleOwner.current) - + DisposableEffect(lifecycleOwner.value) { val lifecycle = lifecycleOwner.value.lifecycle val observer = LifecycleEventObserver { owner, event -> @@ -24,4 +24,4 @@ fun OnLifecycleEvent(onEvent: (owner: LifecycleOwner, event: Lifecycle.Event) -> lifecycle.removeObserver(observer) } } -} \ No newline at end of file +} diff --git a/libraries/core/src/main/java/io/element/android/x/core/compose/Previews.kt b/libraries/core/src/main/java/io/element/android/x/core/compose/PairCombinedPreviewParameter.kt similarity index 100% rename from libraries/core/src/main/java/io/element/android/x/core/compose/Previews.kt rename to libraries/core/src/main/java/io/element/android/x/core/compose/PairCombinedPreviewParameter.kt diff --git a/libraries/core/src/main/java/io/element/android/x/core/compose/TextFieldLocalState.kt b/libraries/core/src/main/java/io/element/android/x/core/compose/TextFieldLocalState.kt index 188d99260d..0b3067968c 100644 --- a/libraries/core/src/main/java/io/element/android/x/core/compose/TextFieldLocalState.kt +++ b/libraries/core/src/main/java/io/element/android/x/core/compose/TextFieldLocalState.kt @@ -5,7 +5,6 @@ import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember - @Composable public fun textFieldState(stateValue: String): MutableState = - remember(stateValue) { mutableStateOf(stateValue) } \ No newline at end of file + remember(stateValue) { mutableStateOf(stateValue) } diff --git a/libraries/core/src/main/java/io/element/android/x/core/coroutine/TimingOperators.kt b/libraries/core/src/main/java/io/element/android/x/core/coroutine/TimingOperators.kt index 67e187b746..c29cb79d9e 100644 --- a/libraries/core/src/main/java/io/element/android/x/core/coroutine/TimingOperators.kt +++ b/libraries/core/src/main/java/io/element/android/x/core/coroutine/TimingOperators.kt @@ -1,4 +1,4 @@ -package io.element.android.x.core.data.flow +package io.element.android.x.core.coroutine import android.os.SystemClock import kotlinx.coroutines.CoroutineScope diff --git a/libraries/core/src/main/java/io/element/android/x/core/coroutine/pmap.kt b/libraries/core/src/main/java/io/element/android/x/core/coroutine/pmap.kt index 36790dd426..90d2b38984 100644 --- a/libraries/core/src/main/java/io/element/android/x/core/coroutine/pmap.kt +++ b/libraries/core/src/main/java/io/element/android/x/core/coroutine/pmap.kt @@ -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.awaitAll @@ -7,4 +7,4 @@ import kotlinx.coroutines.coroutineScope // https://jivimberg.io/blog/2018/05/04/parallel-map-in-kotlin/ suspend fun Iterable.parallelMap(f: suspend (A) -> B): List = coroutineScope { map { async { f(it) } }.awaitAll() -} \ No newline at end of file +} diff --git a/libraries/core/src/main/java/io/element/android/x/core/data/Try.kt b/libraries/core/src/main/java/io/element/android/x/core/data/Try.kt index 6c3cfa8599..d6a4148ee1 100644 --- a/libraries/core/src/main/java/io/element/android/x/core/data/Try.kt +++ b/libraries/core/src/main/java/io/element/android/x/core/data/Try.kt @@ -1,13 +1,13 @@ package io.element.android.x.core.data -import android.util.Log +import timber.log.Timber inline fun tryOrNull(message: String? = null, operation: () -> A): A? { return try { operation() } catch (any: Throwable) { if (message != null) { - Log.e("TAG", message, any) + Timber.e("TAG", message, any) } null } diff --git a/libraries/core/src/main/java/io/element/android/x/core/ui/DimensionConverter.kt b/libraries/core/src/main/java/io/element/android/x/core/ui/DimensionConverter.kt index 7564f77f14..bdca1eefd0 100644 --- a/libraries/core/src/main/java/io/element/android/x/core/ui/DimensionConverter.kt +++ b/libraries/core/src/main/java/io/element/android/x/core/ui/DimensionConverter.kt @@ -24,18 +24,18 @@ class DimensionConverter(val resources: Resources) { @Px fun dpToPx(dp: Int): Int { return TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, - dp.toFloat(), - resources.displayMetrics + TypedValue.COMPLEX_UNIT_DIP, + dp.toFloat(), + resources.displayMetrics ).toInt() } @Px fun spToPx(sp: Int): Int { return TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_SP, - sp.toFloat(), - resources.displayMetrics + TypedValue.COMPLEX_UNIT_SP, + sp.toFloat(), + resources.displayMetrics ).toInt() } diff --git a/libraries/core/src/main/java/io/element/android/x/core/ui/View.kt b/libraries/core/src/main/java/io/element/android/x/core/ui/View.kt index e9c0542c09..a240a4d10c 100644 --- a/libraries/core/src/main/java/io/element/android/x/core/ui/View.kt +++ b/libraries/core/src/main/java/io/element/android/x/core/ui/View.kt @@ -35,9 +35,9 @@ fun View.showKeyboard(andRequestFocus: Boolean = false) { fun View.setHorizontalPadding(padding: Int) { setPadding( - padding, - paddingTop, - padding, - paddingBottom + padding, + paddingTop, + padding, + paddingBottom ) } diff --git a/libraries/designsystem/build.gradle.kts b/libraries/designsystem/build.gradle.kts index c132b472c3..2fb20b4f6c 100644 --- a/libraries/designsystem/build.gradle.kts +++ b/libraries/designsystem/build.gradle.kts @@ -12,4 +12,4 @@ android { implementation(libs.accompanist.systemui) ksp(libs.showkase.processor) } -} \ No newline at end of file +} diff --git a/libraries/designsystem/src/main/AndroidManifest.xml b/libraries/designsystem/src/main/AndroidManifest.xml index a5918e68ab..e100076157 100644 --- a/libraries/designsystem/src/main/AndroidManifest.xml +++ b/libraries/designsystem/src/main/AndroidManifest.xml @@ -1,4 +1,4 @@ - + - \ No newline at end of file + diff --git a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/Color.kt b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/Color.kt index 0bc41fb0d3..6bf9aaca92 100644 --- a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/Color.kt +++ b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/Color.kt @@ -5,6 +5,7 @@ import com.airbnb.android.showkase.annotation.ShowkaseColor @ShowkaseColor(name = "LightGrey", group = "Material Design") val LightGrey = Color(0x993C3C43) + @ShowkaseColor(name = "DarkGrey", group = "Material Design") val DarkGrey = Color(0x99EBEBF5) @@ -37,7 +38,8 @@ val Vermilion = Color(0xFFFF5B55) // TODO Update color val MessageHighlightLight = Azure + // TODO Update color val MessageHighlightDark = Azure -val LinkColor = Color(0xFF054F6E) \ No newline at end of file +val LinkColor = Color(0xFF054F6E) diff --git a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/Theme.kt b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/Theme.kt index 2f757fa11b..2e72ebe4ee 100644 --- a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/Theme.kt +++ b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/Theme.kt @@ -2,7 +2,11 @@ package io.element.android.x.designsystem import android.os.Build import androidx.compose.foundation.isSystemInDarkTheme -import androidx.compose.material3.* +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.SideEffect @@ -42,8 +46,9 @@ private val LightColorScheme = lightColorScheme( onTertiary = Color.White, onBackground = Color(0xFF1C1B1F), onSurface = Color(0xFF1C1B1F), - */ + */ ) +@Suppress("CompositionLocalAllowlist") val LocalIsDarkTheme = compositionLocalOf { error("Not defined") } @Composable @@ -81,7 +86,4 @@ fun ElementXTheme( content = content ) } - } - - diff --git a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/Type.kt b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/Type.kt index 3cfdcf85f3..da25eb21ef 100644 --- a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/Type.kt +++ b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/Type.kt @@ -9,7 +9,6 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.sp import com.airbnb.android.showkase.annotation.ShowkaseTypography - @ShowkaseTypography(name = "Body Large", group = "Element") val bodyLarge = TextStyle( fontFamily = FontFamily.Default, @@ -47,7 +46,7 @@ val Typography = Typography( lineHeight = 16.sp, letterSpacing = 0.5.sp ) - */ + */ ) object ElementTextStyles { @@ -231,6 +230,4 @@ object ElementTextStyles { textAlign = TextAlign.Center ) } - - -} \ No newline at end of file +} diff --git a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/Icons.kt b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/VectorIcons.kt similarity index 99% rename from libraries/designsystem/src/main/java/io/element/android/x/designsystem/Icons.kt rename to libraries/designsystem/src/main/java/io/element/android/x/designsystem/VectorIcons.kt index bd1d941e3e..0f6be4989d 100644 --- a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/Icons.kt +++ b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/VectorIcons.kt @@ -8,4 +8,4 @@ object VectorIcons { val Delete = R.drawable.ic_baseline_delete_outline_24 val Reply = R.drawable.ic_baseline_reply_24 val Edit = R.drawable.ic_baseline_edit_24 -} \ No newline at end of file +} diff --git a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/ClickableLinkText.kt b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/ClickableLinkText.kt index 39edb34689..0efdb52771 100644 --- a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/ClickableLinkText.kt +++ b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/ClickableLinkText.kt @@ -16,6 +16,8 @@ import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.TextLayoutResult import androidx.compose.ui.text.TextStyle +import kotlinx.collections.immutable.ImmutableMap +import kotlinx.collections.immutable.persistentMapOf @Composable fun ClickableLinkText( @@ -26,7 +28,7 @@ fun ClickableLinkText( interactionSource: MutableInteractionSource, modifier: Modifier = Modifier, style: TextStyle = LocalTextStyle.current, - inlineContent: Map = mapOf(), + inlineContent: ImmutableMap = persistentMapOf(), ) { val uriHandler = LocalUriHandler.current val layoutResult = remember { mutableStateOf(null) } @@ -56,7 +58,6 @@ fun ClickableLinkText( uriHandler.openUri(linkAnnotations.first().item) } } - } } Text( @@ -69,4 +70,3 @@ fun ClickableLinkText( inlineContent = inlineContent ) } - diff --git a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/ProgressDialog.kt b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/ProgressDialog.kt index a01c2eeddc..885fff2a61 100644 --- a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/ProgressDialog.kt +++ b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/ProgressDialog.kt @@ -18,14 +18,18 @@ import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties @Composable -fun ProgressDialog(text: String? = null, onDismiss: () -> Unit = {}) { +fun ProgressDialog( + modifier: Modifier = Modifier, + text: String? = null, + onDismiss: () -> Unit = {}, +) { Dialog( onDismissRequest = onDismiss, properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false) ) { Box( contentAlignment = Alignment.Center, - modifier = Modifier + modifier = modifier .fillMaxWidth() .background( color = MaterialTheme.colorScheme.onBackground, @@ -52,5 +56,5 @@ fun ProgressDialog(text: String? = null, onDismiss: () -> Unit = {}) { @Composable @Preview fun ProgressDialogPreview() { - ProgressDialog("test dialog content") -} \ No newline at end of file + ProgressDialog(text = "test dialog content") +} diff --git a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/VectorButton.kt b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/VectorButton.kt index 70198103eb..df1939e9af 100644 --- a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/VectorButton.kt +++ b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/VectorButton.kt @@ -5,7 +5,6 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier - @Composable fun VectorButton(text: String, enabled: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) { Button( diff --git a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/VectorTextField.kt b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/VectorTextField.kt deleted file mode 100644 index 53ffa2739a..0000000000 --- a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/VectorTextField.kt +++ /dev/null @@ -1,19 +0,0 @@ -package io.element.android.x.designsystem.components - -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.OutlinedTextField -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier - - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun VectorTextField(value: String, onValueChange: (String) -> Unit, isError: Boolean = false) { - OutlinedTextField( - value = value, - onValueChange = onValueChange, - modifier = Modifier.fillMaxWidth(), - isError = isError - ) -} diff --git a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/avatar/Avatar.kt b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/avatar/Avatar.kt index c5eb17164a..cdd1e4bb5b 100644 --- a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/avatar/Avatar.kt +++ b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/avatar/Avatar.kt @@ -1,4 +1,5 @@ -import android.util.Log +package io.element.android.x.designsystem.components.avatar + import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.size @@ -16,7 +17,7 @@ import androidx.compose.ui.unit.sp import coil.compose.AsyncImage import io.element.android.x.designsystem.AvatarGradientEnd import io.element.android.x.designsystem.AvatarGradientStart -import io.element.android.x.designsystem.components.avatar.AvatarData +import timber.log.Timber @Composable fun Avatar(avatarData: AvatarData, modifier: Modifier = Modifier) { @@ -44,7 +45,7 @@ private fun ImageAvatar( AsyncImage( model = avatarData.model, onError = { - Log.e("TAG", "Error $it\n${it.result}", it.result.throwable) + Timber.e("TAG", "Error $it\n${it.result}", it.result.throwable) }, contentDescription = null, contentScale = ContentScale.Crop, @@ -52,7 +53,6 @@ private fun ImageAvatar( ) } - @Composable private fun InitialsAvatar( initials: String, @@ -77,5 +77,3 @@ private fun InitialsAvatar( ) } } - - diff --git a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/avatar/AvatarData.kt b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/avatar/AvatarData.kt index ce1fd06dba..34892867ce 100644 --- a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/avatar/AvatarData.kt +++ b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/avatar/AvatarData.kt @@ -30,5 +30,4 @@ data class AvatarData( result = 31 * result + size.value return result } - -} \ No newline at end of file +} diff --git a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/avatar/AvatarSize.kt b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/avatar/AvatarSize.kt index 764b547dca..d7834fd352 100644 --- a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/avatar/AvatarSize.kt +++ b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/avatar/AvatarSize.kt @@ -8,4 +8,4 @@ enum class AvatarSize(val value: Int) { BIG(48); val dp = value.dp -} \ No newline at end of file +} diff --git a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/dialogs/ConfirmationDialog.kt b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/dialogs/ConfirmationDialog.kt index 1161fcb5f3..fb43ccd3ce 100644 --- a/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/dialogs/ConfirmationDialog.kt +++ b/libraries/designsystem/src/main/java/io/element/android/x/designsystem/components/dialogs/ConfirmationDialog.kt @@ -8,25 +8,24 @@ import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @Composable fun ConfirmationDialog( - isDisplayed: MutableState, + isDisplayed: Boolean, title: String, content: String, + modifier: Modifier = Modifier, submitText: String = "OK", cancelText: String = "Cancel", onSubmitClicked: () -> Unit = {}, onDismiss: () -> Unit = {}, ) { - if (!isDisplayed.value) return + if (!isDisplayed) return AlertDialog( + modifier = modifier, onDismissRequest = onDismiss, title = { Text(text = title) @@ -42,11 +41,10 @@ fun ConfirmationDialog( Button( modifier = Modifier.fillMaxWidth(), onClick = { - isDisplayed.value = false onDismiss() onSubmitClicked() - }) - { + } + ) { Text(submitText) } } @@ -59,7 +57,6 @@ fun ConfirmationDialog( Button( modifier = Modifier.fillMaxWidth(), onClick = { - isDisplayed.value = false onDismiss() }) { Text(cancelText) @@ -73,8 +70,8 @@ fun ConfirmationDialog( @Preview fun ConfirmationDialogPreview() { ConfirmationDialog( - isDisplayed = remember { mutableStateOf(true) }, + isDisplayed = true, title = "Title", content = "Content", ) -} \ No newline at end of file +} diff --git a/libraries/designsystem/src/main/res/drawable/ic_baseline_delete_outline_24.xml b/libraries/designsystem/src/main/res/drawable/ic_baseline_delete_outline_24.xml index ef36649125..33b26af516 100644 --- a/libraries/designsystem/src/main/res/drawable/ic_baseline_delete_outline_24.xml +++ b/libraries/designsystem/src/main/res/drawable/ic_baseline_delete_outline_24.xml @@ -1,5 +1,10 @@ - - + + diff --git a/libraries/designsystem/src/main/res/drawable/ic_baseline_edit_24.xml b/libraries/designsystem/src/main/res/drawable/ic_baseline_edit_24.xml index 1c9bd3e6bd..7aeb747672 100644 --- a/libraries/designsystem/src/main/res/drawable/ic_baseline_edit_24.xml +++ b/libraries/designsystem/src/main/res/drawable/ic_baseline_edit_24.xml @@ -1,5 +1,10 @@ - - + + diff --git a/libraries/designsystem/src/main/res/drawable/ic_baseline_reply_24.xml b/libraries/designsystem/src/main/res/drawable/ic_baseline_reply_24.xml index c5fba99883..7555e22d54 100644 --- a/libraries/designsystem/src/main/res/drawable/ic_baseline_reply_24.xml +++ b/libraries/designsystem/src/main/res/drawable/ic_baseline_reply_24.xml @@ -1,5 +1,11 @@ - - + + diff --git a/libraries/designsystem/src/main/res/drawable/ic_content_arrow_forward.xml b/libraries/designsystem/src/main/res/drawable/ic_content_arrow_forward.xml index 8d3848e661..2927820a2b 100644 --- a/libraries/designsystem/src/main/res/drawable/ic_content_arrow_forward.xml +++ b/libraries/designsystem/src/main/res/drawable/ic_content_arrow_forward.xml @@ -1,5 +1,11 @@ - - + + diff --git a/libraries/designsystem/src/main/res/drawable/ic_content_copy.xml b/libraries/designsystem/src/main/res/drawable/ic_content_copy.xml index bac0f6001a..4b70c6f537 100644 --- a/libraries/designsystem/src/main/res/drawable/ic_content_copy.xml +++ b/libraries/designsystem/src/main/res/drawable/ic_content_copy.xml @@ -1,5 +1,10 @@ - - + + diff --git a/libraries/elementresources/build.gradle.kts b/libraries/elementresources/build.gradle.kts index bc26e32933..aea3268bf4 100644 --- a/libraries/elementresources/build.gradle.kts +++ b/libraries/elementresources/build.gradle.kts @@ -8,4 +8,4 @@ android { dependencies { implementation("com.google.android.material:material:1.7.0") -} \ No newline at end of file +} diff --git a/libraries/elementresources/src/main/AndroidManifest.xml b/libraries/elementresources/src/main/AndroidManifest.xml index 8bdb7e14b3..e100076157 100644 --- a/libraries/elementresources/src/main/AndroidManifest.xml +++ b/libraries/elementresources/src/main/AndroidManifest.xml @@ -1,4 +1,4 @@ - + diff --git a/libraries/elementresources/src/main/res/color/button_background_tint_selector.xml b/libraries/elementresources/src/main/res/color/button_background_tint_selector.xml deleted file mode 100644 index 57135b1eb9..0000000000 --- a/libraries/elementresources/src/main/res/color/button_background_tint_selector.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/libraries/elementresources/src/main/res/color/color_primary_alpha25.xml b/libraries/elementresources/src/main/res/color/color_primary_alpha25.xml deleted file mode 100644 index 5afa385f3c..0000000000 --- a/libraries/elementresources/src/main/res/color/color_primary_alpha25.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/libraries/elementresources/src/main/res/drawable/bg_send.xml b/libraries/elementresources/src/main/res/drawable/bg_send.xml deleted file mode 100644 index 06090b3f96..0000000000 --- a/libraries/elementresources/src/main/res/drawable/bg_send.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/libraries/elementresources/src/main/res/drawable/ic_attachment.xml b/libraries/elementresources/src/main/res/drawable/ic_attachment.xml deleted file mode 100644 index 8f2deff482..0000000000 --- a/libraries/elementresources/src/main/res/drawable/ic_attachment.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - diff --git a/libraries/elementresources/src/main/res/drawable/ic_close_round.xml b/libraries/elementresources/src/main/res/drawable/ic_close_round.xml deleted file mode 100644 index 413a233b56..0000000000 --- a/libraries/elementresources/src/main/res/drawable/ic_close_round.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - diff --git a/libraries/elementresources/src/main/res/drawable/ic_composer_bold.xml b/libraries/elementresources/src/main/res/drawable/ic_composer_bold.xml deleted file mode 100644 index 3d9a10d16b..0000000000 --- a/libraries/elementresources/src/main/res/drawable/ic_composer_bold.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/libraries/elementresources/src/main/res/drawable/ic_composer_full_screen.xml b/libraries/elementresources/src/main/res/drawable/ic_composer_full_screen.xml deleted file mode 100644 index 394dc52279..0000000000 --- a/libraries/elementresources/src/main/res/drawable/ic_composer_full_screen.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/libraries/elementresources/src/main/res/drawable/ic_composer_italic.xml b/libraries/elementresources/src/main/res/drawable/ic_composer_italic.xml deleted file mode 100644 index faa4f89cd4..0000000000 --- a/libraries/elementresources/src/main/res/drawable/ic_composer_italic.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/libraries/elementresources/src/main/res/drawable/ic_composer_strikethrough.xml b/libraries/elementresources/src/main/res/drawable/ic_composer_strikethrough.xml deleted file mode 100644 index 3970c95381..0000000000 --- a/libraries/elementresources/src/main/res/drawable/ic_composer_strikethrough.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - diff --git a/libraries/elementresources/src/main/res/drawable/ic_composer_underlined.xml b/libraries/elementresources/src/main/res/drawable/ic_composer_underlined.xml deleted file mode 100644 index fe18d60185..0000000000 --- a/libraries/elementresources/src/main/res/drawable/ic_composer_underlined.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - diff --git a/libraries/elementresources/src/main/res/drawable/ic_edit.xml b/libraries/elementresources/src/main/res/drawable/ic_edit.xml deleted file mode 100644 index 33214d4246..0000000000 --- a/libraries/elementresources/src/main/res/drawable/ic_edit.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - diff --git a/libraries/elementresources/src/main/res/drawable/ic_send.xml b/libraries/elementresources/src/main/res/drawable/ic_send.xml deleted file mode 100644 index 9f10eca84a..0000000000 --- a/libraries/elementresources/src/main/res/drawable/ic_send.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/libraries/elementresources/src/main/res/transition/image_preview_transition.xml b/libraries/elementresources/src/main/res/transition/image_preview_transition.xml deleted file mode 100644 index c1af6d7973..0000000000 --- a/libraries/elementresources/src/main/res/transition/image_preview_transition.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - diff --git a/libraries/elementresources/src/main/res/values/attrs_room_message_colors.xml b/libraries/elementresources/src/main/res/values/attrs_room_message_colors.xml deleted file mode 100644 index 68b64c21b0..0000000000 --- a/libraries/elementresources/src/main/res/values/attrs_room_message_colors.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/libraries/elementresources/src/main/res/values/colors_message_bubble.xml b/libraries/elementresources/src/main/res/values/colors_message_bubble.xml deleted file mode 100644 index 7ac68574b6..0000000000 --- a/libraries/elementresources/src/main/res/values/colors_message_bubble.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - #E8EDF4 - #21262C - - #E7F8F3 - #133A34 - \ No newline at end of file diff --git a/libraries/elementresources/src/main/res/values/style_action_button.xml b/libraries/elementresources/src/main/res/values/style_action_button.xml deleted file mode 100644 index 0a3c73622f..0000000000 --- a/libraries/elementresources/src/main/res/values/style_action_button.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/libraries/elementresources/src/main/res/values/style_snackbar.xml b/libraries/elementresources/src/main/res/values/style_snackbar.xml deleted file mode 100644 index d15f846d8f..0000000000 --- a/libraries/elementresources/src/main/res/values/style_snackbar.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - diff --git a/libraries/elementresources/src/main/res/values/styles_action_mode.xml b/libraries/elementresources/src/main/res/values/styles_action_mode.xml deleted file mode 100644 index f6e6079633..0000000000 --- a/libraries/elementresources/src/main/res/values/styles_action_mode.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/libraries/elementresources/src/main/res/values/styles_alert_dialog.xml b/libraries/elementresources/src/main/res/values/styles_alert_dialog.xml deleted file mode 100644 index 69abc85c39..0000000000 --- a/libraries/elementresources/src/main/res/values/styles_alert_dialog.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/libraries/elementresources/src/main/res/values/styles_app_bar_layout.xml b/libraries/elementresources/src/main/res/values/styles_app_bar_layout.xml deleted file mode 100644 index 973a2c5e4a..0000000000 --- a/libraries/elementresources/src/main/res/values/styles_app_bar_layout.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/libraries/elementresources/src/main/res/values/styles_bottom_sheet.xml b/libraries/elementresources/src/main/res/values/styles_bottom_sheet.xml index f6c30040d9..a48071cb71 100644 --- a/libraries/elementresources/src/main/res/values/styles_bottom_sheet.xml +++ b/libraries/elementresources/src/main/res/values/styles_bottom_sheet.xml @@ -1,62 +1,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libraries/elementresources/src/main/res/values/styles_devices_management.xml b/libraries/elementresources/src/main/res/values/styles_devices_management.xml deleted file mode 100644 index 6b42b85ffd..0000000000 --- a/libraries/elementresources/src/main/res/values/styles_devices_management.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - diff --git a/libraries/elementresources/src/main/res/values/styles_edit_text.xml b/libraries/elementresources/src/main/res/values/styles_edit_text.xml index 94f4d86160..a4458d8e4e 100644 --- a/libraries/elementresources/src/main/res/values/styles_edit_text.xml +++ b/libraries/elementresources/src/main/res/values/styles_edit_text.xml @@ -1,16 +1,6 @@ - - diff --git a/libraries/elementresources/src/main/res/values/styles_jump_to_unread.xml b/libraries/elementresources/src/main/res/values/styles_jump_to_unread.xml deleted file mode 100644 index 21f0ebd5d4..0000000000 --- a/libraries/elementresources/src/main/res/values/styles_jump_to_unread.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/libraries/elementresources/src/main/res/values/styles_location.xml b/libraries/elementresources/src/main/res/values/styles_location.xml deleted file mode 100644 index ee893046ba..0000000000 --- a/libraries/elementresources/src/main/res/values/styles_location.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/libraries/elementresources/src/main/res/values/styles_login.xml b/libraries/elementresources/src/main/res/values/styles_login.xml deleted file mode 100644 index ab2cb44c5a..0000000000 --- a/libraries/elementresources/src/main/res/values/styles_login.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/libraries/elementresources/src/main/res/values/styles_popup.xml b/libraries/elementresources/src/main/res/values/styles_popup.xml deleted file mode 100644 index 2aad848989..0000000000 --- a/libraries/elementresources/src/main/res/values/styles_popup.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/libraries/elementresources/src/main/res/values/styles_text_input_layout.xml b/libraries/elementresources/src/main/res/values/styles_text_input_layout.xml deleted file mode 100644 index 4e7a687a7a..0000000000 --- a/libraries/elementresources/src/main/res/values/styles_text_input_layout.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/libraries/elementresources/src/main/res/values/styles_text_view.xml b/libraries/elementresources/src/main/res/values/styles_text_view.xml deleted file mode 100644 index 0dcaf30f48..0000000000 --- a/libraries/elementresources/src/main/res/values/styles_text_view.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libraries/elementresources/src/main/res/values/styles_timeline.xml b/libraries/elementresources/src/main/res/values/styles_timeline.xml deleted file mode 100644 index 9cae19d6b2..0000000000 --- a/libraries/elementresources/src/main/res/values/styles_timeline.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - diff --git a/libraries/elementresources/src/main/res/values/styles_toolbar.xml b/libraries/elementresources/src/main/res/values/styles_toolbar.xml deleted file mode 100644 index 893de92aae..0000000000 --- a/libraries/elementresources/src/main/res/values/styles_toolbar.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/libraries/elementresources/src/main/res/values/styles_voice_broadcast.xml b/libraries/elementresources/src/main/res/values/styles_voice_broadcast.xml deleted file mode 100644 index eb85378141..0000000000 --- a/libraries/elementresources/src/main/res/values/styles_voice_broadcast.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - diff --git a/libraries/elementresources/src/main/res/values/text_appearances.xml b/libraries/elementresources/src/main/res/values/text_appearances.xml deleted file mode 100644 index 570d26fdfd..0000000000 --- a/libraries/elementresources/src/main/res/values/text_appearances.xml +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libraries/elementresources/src/main/res/values/theme_light.xml b/libraries/elementresources/src/main/res/values/theme_light.xml index 1e391e2c85..81839a70c1 100644 --- a/libraries/elementresources/src/main/res/values/theme_light.xml +++ b/libraries/elementresources/src/main/res/values/theme_light.xml @@ -26,20 +26,8 @@ @color/vctr_waiting_background_color_light @color/vctr_chat_effect_snow_background_light @color/element_background_light - @color/vctr_message_bubble_inbound_light - @color/vctr_message_bubble_outbound_light @color/vctr_badge_color_border_light - - #61708B - ?colorError - @color/element_content_primary_light - #FF61708b - @color/palette_element_green - @color/element_content_secondary_light - #FFEEEEEE - #FF000000 - @color/vctr_presence_indicator_offline_light @color/vctr_presence_indicator_online_light @@ -67,36 +55,7 @@ @color/element_background_light ?vctr_content_primary - - @style/TextAppearance.Vector.Button - @style/TextAppearance.Vector.Caption - - @style/TextAppearance.Vector.Body - - @style/TextAppearance.Vector.Subtitle - @style/TextAppearance.Vector.Body - @style/TextAppearance.Vector.Body - - - @style/Widget.Vector.TextView.Body - @style/Widget.Vector.Button - @style/Widget.Vector.Toolbar - - @style/Widget.Vector.TextInputLayout - @style/Widget.Vector.AppBarLayout - @style/Widget.Vector.PopupMenu - @style/Widget.Vector.SnackBar - @style/Widget.Vector.SnackBar.Button - @style/Widget.Vector.SnackBar.TextView - @style/Widget.Vector.ActionMode - - @style/Theme.Vector.BottomSheetDialog.Light - @style/ThemeOverlay.Vector.MaterialAlertDialog - @color/element_link_light @@ -132,10 +91,6 @@ true - - @transition/image_preview_transition - @transition/image_preview_transition - - @style/Widget.Vector.JumpToUnread.Light - @color/vctr_live_location_light @@ -166,4 +117,4 @@ @color/vctr_rich_text_editor_menu_button_background_light - \ No newline at end of file + diff --git a/libraries/matrix/build.gradle.kts b/libraries/matrix/build.gradle.kts index 591f5b012d..fa9d9802e1 100644 --- a/libraries/matrix/build.gradle.kts +++ b/libraries/matrix/build.gradle.kts @@ -16,9 +16,8 @@ dependencies { api(project(":libraries:rustsdk")) implementation(project(":libraries:di")) implementation(project(":libraries:core")) - implementation(libs.timber) implementation("net.java.dev.jna:jna:5.12.1@aar") implementation(libs.coil.compose) implementation(libs.androidx.datastore.preferences) implementation(libs.serialization.json) -} \ No newline at end of file +} diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/Matrix.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/Matrix.kt index 31e13261dc..dd59606a15 100644 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/Matrix.kt +++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/Matrix.kt @@ -13,7 +13,7 @@ import io.element.android.x.matrix.util.logError import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.asCoroutineDispatcher -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.withContext import org.matrix.rustcomponents.sdk.AuthenticationService import org.matrix.rustcomponents.sdk.Client @@ -101,4 +101,4 @@ class Matrix @Inject constructor( baseDirectory = baseDirectory, ) } -} \ No newline at end of file +} diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/MatrixClient.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/MatrixClient.kt index 81a0f408f5..db16d9f706 100644 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/MatrixClient.kt +++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/MatrixClient.kt @@ -10,13 +10,19 @@ import io.element.android.x.matrix.room.RoomSummaryDataSource import io.element.android.x.matrix.room.RustRoomSummaryDataSource import io.element.android.x.matrix.session.SessionStore import io.element.android.x.matrix.sync.SlidingSyncObserverProxy -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.withContext -import org.matrix.rustcomponents.sdk.* -import timber.log.Timber import java.io.Closeable import java.io.File import java.util.concurrent.atomic.AtomicBoolean +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.withContext +import org.matrix.rustcomponents.sdk.Client +import org.matrix.rustcomponents.sdk.ClientDelegate +import org.matrix.rustcomponents.sdk.MediaSource +import org.matrix.rustcomponents.sdk.RequiredState +import org.matrix.rustcomponents.sdk.SlidingSyncMode +import org.matrix.rustcomponents.sdk.SlidingSyncViewBuilder +import org.matrix.rustcomponents.sdk.StoppableSpawn +import timber.log.Timber class MatrixClient internal constructor( private val client: Client, @@ -60,7 +66,7 @@ class MatrixClient internal constructor( .slidingSync() .homeserver("https://slidingsync.lab.element.dev") .withCommonExtensions() - //.coldCache("ElementX") + // .coldCache("ElementX") .addView(slidingSyncView) .build() @@ -148,6 +154,7 @@ class MatrixClient internal constructor( } } + @OptIn(ExperimentalUnsignedTypes::class) suspend fun loadMediaContentForSource(source: MediaSource): Result = withContext(dispatchers.io) { runCatching { @@ -155,6 +162,7 @@ class MatrixClient internal constructor( } } + @OptIn(ExperimentalUnsignedTypes::class) suspend fun loadMediaThumbnailForSource( source: MediaSource, width: Long, diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/RoomWrapper.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/RoomWrapper.kt deleted file mode 100644 index 90aaaa6251..0000000000 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/RoomWrapper.kt +++ /dev/null @@ -1,15 +0,0 @@ -package io.element.android.x.matrix - -import android.util.Log -import org.matrix.rustcomponents.sdk.Client -import org.matrix.rustcomponents.sdk.Room - -class RoomWrapper( - private val client: Client -) { - fun getRoom(roomId: String): Room? { - val rooms = client.rooms() - Log.d(LOG_TAG, "We have ${rooms.size} rooms") - return rooms.firstOrNull { it.id() == roomId } - } -} \ No newline at end of file diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/core/EventId.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/core/EventId.kt index ee90c7d1d0..bcc6801a1f 100644 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/core/EventId.kt +++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/core/EventId.kt @@ -3,4 +3,4 @@ package io.element.android.x.matrix.core import java.io.Serializable @JvmInline -value class EventId(val value: String) : Serializable \ No newline at end of file +value class EventId(val value: String) : Serializable diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/core/MatrixPatterns.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/core/MatrixPatterns.kt index ab516d8ba8..e73cf2b024 100644 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/core/MatrixPatterns.kt +++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/core/MatrixPatterns.kt @@ -80,15 +80,15 @@ object MatrixPatterns { // list of patterns to find some matrix item. val MATRIX_PATTERNS = listOf( - PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID, - PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS, - PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID, - PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ALIAS, - PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER, - PATTERN_CONTAIN_MATRIX_ALIAS, - PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER, - PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER, - PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER + PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID, + PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS, + PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID, + PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ALIAS, + PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER, + PATTERN_CONTAIN_MATRIX_ALIAS, + PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER, + PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER, + PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER ) /** @@ -129,9 +129,9 @@ object MatrixPatterns { */ fun isEventId(str: String?): Boolean { return str != null && - (str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER || - str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V3 || - str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V4) + (str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER || + str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V3 || + str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V4) } /** diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/core/RoomId.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/core/RoomId.kt index cea9a9e8d6..3369cab78a 100644 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/core/RoomId.kt +++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/core/RoomId.kt @@ -3,4 +3,4 @@ package io.element.android.x.matrix.core import java.io.Serializable @JvmInline -value class RoomId(val value: String): Serializable \ No newline at end of file +value class RoomId(val value: String) : Serializable diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/core/UserId.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/core/UserId.kt index 3c499f8487..cf34ba13c8 100644 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/core/UserId.kt +++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/core/UserId.kt @@ -3,4 +3,4 @@ package io.element.android.x.matrix.core import java.io.Serializable @JvmInline -value class UserId(val value: String): Serializable \ No newline at end of file +value class UserId(val value: String) : Serializable diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/media/MediaFetcher.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/media/MediaFetcher.kt index 442af55bf7..3789fcad42 100644 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/media/MediaFetcher.kt +++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/media/MediaFetcher.kt @@ -36,4 +36,4 @@ internal class MediaFetcher( ) } } -} \ No newline at end of file +} diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/media/MediaKeyer.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/media/MediaKeyer.kt index 4bc77018fa..03f244cc14 100644 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/media/MediaKeyer.kt +++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/media/MediaKeyer.kt @@ -7,4 +7,4 @@ internal class MediaKeyer : Keyer { override fun key(data: MediaResolver.Meta, options: Options): String? { return "${data.source.url()}_${data.kind}" } -} \ No newline at end of file +} diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/media/MediaResolver.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/media/MediaResolver.kt index 949ce02cf4..8a1991298c 100644 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/media/MediaResolver.kt +++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/media/MediaResolver.kt @@ -24,7 +24,6 @@ interface MediaResolver { suspend fun resolve(meta: Meta): ByteArray? } - internal class RustMediaResolver(private val client: MatrixClient) : MediaResolver { override suspend fun resolve(url: String?, kind: MediaResolver.Kind): ByteArray? { @@ -43,6 +42,4 @@ internal class RustMediaResolver(private val client: MatrixClient) : MediaResolv ) }.getOrNull() } - - -} \ No newline at end of file +} diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/permalink/PermalinkParser.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/permalink/PermalinkParser.kt index e1f878d331..d23c3d3d4f 100644 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/permalink/PermalinkParser.kt +++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/permalink/PermalinkParser.kt @@ -3,8 +3,8 @@ package io.element.android.x.matrix.permalink import android.net.Uri import android.net.UrlQuerySanitizer import io.element.android.x.matrix.core.MatrixPatterns -import timber.log.Timber import java.net.URLDecoder +import timber.log.Timber /** * This class turns a uri to a [PermalinkData]. @@ -43,12 +43,12 @@ object PermalinkParser { // we are limiting to 2 params val params = safeFragment - .split(MatrixPatterns.SEP_REGEX) - .filter { it.isNotEmpty() } - .take(2) + .split(MatrixPatterns.SEP_REGEX) + .filter { it.isNotEmpty() } + .take(2) val decodedParams = params - .map { URLDecoder.decode(it, "UTF-8") } + .map { URLDecoder.decode(it, "UTF-8") } val identifier = params.getOrNull(0) val decodedIdentifier = decodedParams.getOrNull(0) @@ -61,10 +61,10 @@ object PermalinkParser { } MatrixPatterns.isRoomAlias(decodedIdentifier) -> { PermalinkData.RoomLink( - roomIdOrAlias = decodedIdentifier, - isRoomAlias = true, - eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) }, - viaParameters = viaQueryParameters + roomIdOrAlias = decodedIdentifier, + isRoomAlias = true, + eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) }, + viaParameters = viaQueryParameters ) } else -> PermalinkData.FallbackLink(uri, MatrixPatterns.isGroupId(identifier)) @@ -83,16 +83,16 @@ object PermalinkParser { val token = signValidUri.getQueryParameter("token") ?: throw IllegalArgumentException() val privateKey = signValidUri.getQueryParameter("private_key") ?: throw IllegalArgumentException() PermalinkData.RoomEmailInviteLink( - roomId = identifier, - email = email!!, - signUrl = signUrl!!, - roomName = paramList.firstOrNull { it.first == "room_name" }?.second, - inviterName = paramList.firstOrNull { it.first == "inviter_name" }?.second, - roomAvatarUrl = paramList.firstOrNull { it.first == "room_avatar_url" }?.second, - roomType = paramList.firstOrNull { it.first == "room_type" }?.second, - identityServer = identityServerHost, - token = token, - privateKey = privateKey + roomId = identifier, + email = email!!, + signUrl = signUrl!!, + roomName = paramList.firstOrNull { it.first == "room_name" }?.second, + inviterName = paramList.firstOrNull { it.first == "inviter_name" }?.second, + roomAvatarUrl = paramList.firstOrNull { it.first == "room_avatar_url" }?.second, + roomType = paramList.firstOrNull { it.first == "room_type" }?.second, + identityServer = identityServerHost, + token = token, + privateKey = privateKey ) } catch (failure: Throwable) { Timber.i("## Permalink: Failed to parse permalink $signUrl") @@ -100,29 +100,29 @@ object PermalinkParser { } } else { PermalinkData.RoomLink( - roomIdOrAlias = identifier, - isRoomAlias = false, - eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) }, - viaParameters = viaQueryParameters + roomIdOrAlias = identifier, + isRoomAlias = false, + eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) }, + viaParameters = viaQueryParameters ) } } private fun safeExtractParams(fragment: String) = - fragment.substringAfter("?").split('&').mapNotNull { - val splitNameValue = it.split("=") - if (splitNameValue.size == 2) { - Pair(splitNameValue[0], URLDecoder.decode(splitNameValue[1], "UTF-8")) - } else null - } + fragment.substringAfter("?").split('&').mapNotNull { + val splitNameValue = it.split("=") + if (splitNameValue.size == 2) { + Pair(splitNameValue[0], URLDecoder.decode(splitNameValue[1], "UTF-8")) + } else null + } private fun String.getViaParameters(): List { return UrlQuerySanitizer(this) - .parameterList - .filter { - it.mParameter == "via" - }.map { - URLDecoder.decode(it.mValue, "UTF-8") - } + .parameterList + .filter { + it.mParameter == "via" + }.map { + URLDecoder.decode(it.mValue, "UTF-8") + } } } diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/room/MatrixRoom.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/room/MatrixRoom.kt index 940c3018cf..3bf8b79003 100644 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/room/MatrixRoom.kt +++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/room/MatrixRoom.kt @@ -9,7 +9,11 @@ import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.withContext -import org.matrix.rustcomponents.sdk.* +import org.matrix.rustcomponents.sdk.Room +import org.matrix.rustcomponents.sdk.SlidingSyncRoom +import org.matrix.rustcomponents.sdk.UpdateSummary +import org.matrix.rustcomponents.sdk.genTransactionId +import org.matrix.rustcomponents.sdk.messageEventContentFromMarkdown class MatrixRoom( private val slidingSyncUpdateFlow: Flow, @@ -84,7 +88,7 @@ class MatrixRoom( suspend fun editMessage(originalEventId: String, message: String): Result = withContext(coroutineDispatchers.io) { val transactionId = genTransactionId() - val content = messageEventContentFromMarkdown(message) + // val content = messageEventContentFromMarkdown(message) runCatching { room.edit(/* TODO use content */ message, originalEventId, transactionId) } @@ -92,16 +96,16 @@ class MatrixRoom( suspend fun replyMessage(eventId: String, message: String): Result = withContext(coroutineDispatchers.io) { val transactionId = genTransactionId() - val content = messageEventContentFromMarkdown(message) + // val content = messageEventContentFromMarkdown(message) runCatching { room.sendReply(/* TODO use content */ message, eventId, transactionId) } } - suspend fun redactEvent(eventId: String, reason: String? = null, ) = withContext(coroutineDispatchers.io) { + suspend fun redactEvent(eventId: String, reason: String? = null) = withContext(coroutineDispatchers.io) { val transactionId = genTransactionId() runCatching { room.redact(eventId, reason, transactionId) } } -} \ No newline at end of file +} diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/room/RoomListenerFlows.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/room/RoomListenerFlows.kt index 691798b6e3..4634e6df12 100644 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/room/RoomListenerFlows.kt +++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/room/RoomListenerFlows.kt @@ -9,7 +9,6 @@ import org.matrix.rustcomponents.sdk.Room import org.matrix.rustcomponents.sdk.TimelineDiff import org.matrix.rustcomponents.sdk.TimelineListener - fun Room.timelineDiff(scope: CoroutineScope): Flow = callbackFlow { val listener = object : TimelineListener { override fun onUpdate(update: TimelineDiff) { @@ -22,6 +21,4 @@ fun Room.timelineDiff(scope: CoroutineScope): Flow = callbackFlow awaitClose { removeTimeline() } - } - diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/room/RoomSummary.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/room/RoomSummary.kt index ff4a01eaf0..580a64e081 100644 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/room/RoomSummary.kt +++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/room/RoomSummary.kt @@ -2,7 +2,6 @@ package io.element.android.x.matrix.room import io.element.android.x.matrix.core.RoomId - sealed interface RoomSummary { data class Empty(val identifier: String) : RoomSummary data class Filled(val details: RoomSummaryDetails) : RoomSummary @@ -13,7 +12,6 @@ sealed interface RoomSummary { is Filled -> details.roomId.value } } - } data class RoomSummaryDetails( diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/room/RoomSummaryDataSource.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/room/RoomSummaryDataSource.kt index 91af2c5eca..03e9422157 100644 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/room/RoomSummaryDataSource.kt +++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/room/RoomSummaryDataSource.kt @@ -3,12 +3,28 @@ package io.element.android.x.matrix.room import io.element.android.x.core.coroutine.CoroutineDispatchers import io.element.android.x.matrix.sync.roomListDiff import io.element.android.x.matrix.sync.state -import kotlinx.coroutines.* -import kotlinx.coroutines.flow.* -import org.matrix.rustcomponents.sdk.* -import timber.log.Timber import java.io.Closeable -import java.util.* +import java.util.Collections +import java.util.UUID +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel +import kotlinx.coroutines.cancelChildren +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.sample +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.matrix.rustcomponents.sdk.RoomListEntry +import org.matrix.rustcomponents.sdk.SlidingSync +import org.matrix.rustcomponents.sdk.SlidingSyncState +import org.matrix.rustcomponents.sdk.SlidingSyncView +import org.matrix.rustcomponents.sdk.SlidingSyncViewRoomsListDiff +import org.matrix.rustcomponents.sdk.UpdateSummary +import timber.log.Timber interface RoomSummaryDataSource { fun roomSummaries(): Flow> @@ -56,7 +72,6 @@ internal class RustRoomSummaryDataSource( Timber.v("New sliding sync state: $slidingSyncState") state.value = slidingSyncState }.launchIn(coroutineScope) - } fun stopSync() { @@ -67,6 +82,7 @@ internal class RustRoomSummaryDataSource( coroutineScope.cancel() } + @OptIn(FlowPreview::class) override fun roomSummaries(): Flow> { return roomSummaries.sample(50) } @@ -95,7 +111,6 @@ internal class RustRoomSummaryDataSource( } private fun MutableList.applyDiff(diff: SlidingSyncViewRoomsListDiff) { - fun MutableList.fillUntil(untilIndex: Int) { repeat((size - 1 until untilIndex).count()) { add(buildEmptyRoomSummary()) @@ -163,4 +178,4 @@ internal class RustRoomSummaryDataSource( else -> false } } -} \ No newline at end of file +} diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/room/RoomSummaryDetailsFactory.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/room/RoomSummaryDetailsFactory.kt index 0427987bd5..8f9c4a471b 100644 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/room/RoomSummaryDetailsFactory.kt +++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/room/RoomSummaryDetailsFactory.kt @@ -7,7 +7,7 @@ import org.matrix.rustcomponents.sdk.SlidingSyncRoom class RoomSummaryDetailsFactory(private val roomMessageFactory: RoomMessageFactory = RoomMessageFactory()) { - fun create(slidingSyncRoom: SlidingSyncRoom, room: Room?): RoomSummaryDetails{ + fun create(slidingSyncRoom: SlidingSyncRoom, room: Room?): RoomSummaryDetails { val latestRoomMessage = slidingSyncRoom.latestRoomMessage()?.let { roomMessageFactory.create(it) } @@ -17,14 +17,13 @@ class RoomSummaryDetailsFactory(private val roomMessageFactory: RoomMessageFacto else -> "${latestRoomMessage.sender.value}: ${latestRoomMessage.body}" } return RoomSummaryDetails( - roomId = RoomId(slidingSyncRoom.roomId()), - name = slidingSyncRoom.name() ?: slidingSyncRoom.roomId(), - isDirect = slidingSyncRoom.isDm() ?: false, - avatarURLString = room?.avatarUrl(), - unreadNotificationCount = slidingSyncRoom.unreadNotifications().notificationCount().toInt(), - lastMessage = computedLastMessage, - lastMessageTimestamp = latestRoomMessage?.originServerTs + roomId = RoomId(slidingSyncRoom.roomId()), + name = slidingSyncRoom.name() ?: slidingSyncRoom.roomId(), + isDirect = slidingSyncRoom.isDm() ?: false, + avatarURLString = room?.avatarUrl(), + unreadNotificationCount = slidingSyncRoom.unreadNotifications().notificationCount().toInt(), + lastMessage = computedLastMessage, + lastMessageTimestamp = latestRoomMessage?.originServerTs ) } - -} \ No newline at end of file +} diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/room/message/RoomMessageFactory.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/room/message/RoomMessageFactory.kt index 7c82c42472..4bcb86eefb 100644 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/room/message/RoomMessageFactory.kt +++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/room/message/RoomMessageFactory.kt @@ -14,5 +14,4 @@ class RoomMessageFactory { originServerTs = eventTimelineItem.originServerTs()?.toLong() ?: 0L ) } - -} \ No newline at end of file +} diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/session/SessionStore.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/session/SessionStore.kt index a30c5b4ebc..288e181b78 100644 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/session/SessionStore.kt +++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/session/SessionStore.kt @@ -10,7 +10,8 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.map import kotlinx.serialization.Serializable -import kotlinx.serialization.* +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import org.matrix.rustcomponents.sdk.Session @@ -73,4 +74,4 @@ internal class SessionStore( suspend fun reset() { store.edit { it.clear() } } -} \ No newline at end of file +} diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/sync/SlidingSyncObserverProxy.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/sync/SlidingSyncObserverProxy.kt index b5365cdf9a..88f8175d86 100644 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/sync/SlidingSyncObserverProxy.kt +++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/sync/SlidingSyncObserverProxy.kt @@ -11,6 +11,7 @@ import org.matrix.rustcomponents.sdk.UpdateSummary // Sounds like a reasonable buffer size before it suspends emitting new items. private const val BUFFER_SIZE = 64 + class SlidingSyncObserverProxy( private val coroutineScope: CoroutineScope, private val coroutineDispatchers: CoroutineDispatchers @@ -26,5 +27,4 @@ class SlidingSyncObserverProxy( updateSummaryMutableFlow.emit(summary) } } - -} \ No newline at end of file +} diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/sync/SlidingSyncViewFlows.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/sync/SlidingSyncViewFlows.kt index 8eaa386390..7cf137c063 100644 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/sync/SlidingSyncViewFlows.kt +++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/sync/SlidingSyncViewFlows.kt @@ -1,10 +1,15 @@ package io.element.android.x.matrix.sync +import io.element.android.x.matrix.util.mxCallbackFlow import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.launch -import mxCallbackFlow -import org.matrix.rustcomponents.sdk.* +import org.matrix.rustcomponents.sdk.SlidingSyncState +import org.matrix.rustcomponents.sdk.SlidingSyncView +import org.matrix.rustcomponents.sdk.SlidingSyncViewRoomListObserver +import org.matrix.rustcomponents.sdk.SlidingSyncViewRoomsCountObserver +import org.matrix.rustcomponents.sdk.SlidingSyncViewRoomsListDiff +import org.matrix.rustcomponents.sdk.SlidingSyncViewStateObserver fun SlidingSyncView.roomListDiff(scope: CoroutineScope): Flow = mxCallbackFlow { diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/timeline/MatrixTimeline.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/timeline/MatrixTimeline.kt index c987716104..41c06c1a9d 100644 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/timeline/MatrixTimeline.kt +++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/timeline/MatrixTimeline.kt @@ -2,15 +2,21 @@ package io.element.android.x.matrix.timeline import io.element.android.x.core.coroutine.CoroutineDispatchers import io.element.android.x.matrix.room.MatrixRoom +import java.util.Collections import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.sample import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import org.matrix.rustcomponents.sdk.* +import org.matrix.rustcomponents.sdk.PaginationOutcome +import org.matrix.rustcomponents.sdk.Room +import org.matrix.rustcomponents.sdk.SlidingSyncRoom +import org.matrix.rustcomponents.sdk.TimelineChange +import org.matrix.rustcomponents.sdk.TimelineDiff +import org.matrix.rustcomponents.sdk.TimelineListener import timber.log.Timber -import java.util.* class MatrixTimeline( private val matrixRoom: MatrixRoom, @@ -31,7 +37,7 @@ class MatrixTimeline( private val timelineItems: MutableStateFlow> = MutableStateFlow(emptyList()) - + @OptIn(FlowPreview::class) fun timelineItems(): Flow> { return timelineItems.sample(50) } @@ -41,7 +47,6 @@ class MatrixTimeline( return paginationOutcome.value.moreMessages } - private fun MutableList.applyDiff(diff: TimelineDiff) { when (diff.change()) { TimelineChange.PUSH -> { @@ -140,5 +145,4 @@ class MatrixTimeline( } } } - -} \ No newline at end of file +} diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/tracing/TracingConfiguration.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/tracing/TracingConfiguration.kt index 947bff09f5..de5ae950bb 100644 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/tracing/TracingConfiguration.kt +++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/tracing/TracingConfiguration.kt @@ -9,7 +9,6 @@ data class TracingConfiguration( targets.map { "${it.key.filter}=${it.value.filter}" }.joinToString(separator = ",") }" - sealed class Target(open val filter: String) { object Hyper : Target("hyper") object Sled : Target("sled") @@ -31,7 +30,6 @@ data class TracingConfiguration( object Debug : LogLevel("debug") object Error : LogLevel("error") } - } fun setupTracing(tracingConfiguration: TracingConfiguration) { @@ -47,4 +45,4 @@ object TracingConfigurations { TracingConfiguration.Target.Sled to TracingConfiguration.LogLevel.Warn ) ) -} \ No newline at end of file +} diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/util/CallbackFlow.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/util/CallbackFlow.kt index 23bb5f6fbc..842da90e3e 100644 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/util/CallbackFlow.kt +++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/util/CallbackFlow.kt @@ -1,6 +1,5 @@ -@file:OptIn(ExperimentalCoroutinesApi::class) +package io.element.android.x.matrix.util -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.ProducerScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.callbackFlow @@ -12,4 +11,4 @@ internal fun mxCallbackFlow(block: suspend ProducerScope.() -> StoppableS awaitClose { token.cancel() } - } \ No newline at end of file + } diff --git a/libraries/matrix/src/main/java/io/element/android/x/matrix/util/Error.kt b/libraries/matrix/src/main/java/io/element/android/x/matrix/util/Error.kt index c7f4e6ac12..db44533b73 100644 --- a/libraries/matrix/src/main/java/io/element/android/x/matrix/util/Error.kt +++ b/libraries/matrix/src/main/java/io/element/android/x/matrix/util/Error.kt @@ -12,4 +12,4 @@ fun logError(throwable: Throwable) { Timber.e("Error", throwable) } } -} \ No newline at end of file +} diff --git a/libraries/textcomposer/src/main/AndroidManifest.xml b/libraries/textcomposer/src/main/AndroidManifest.xml index 8bdb7e14b3..e100076157 100644 --- a/libraries/textcomposer/src/main/AndroidManifest.xml +++ b/libraries/textcomposer/src/main/AndroidManifest.xml @@ -1,4 +1,4 @@ - + diff --git a/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/MessageComposerMode.kt b/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/MessageComposerMode.kt index 617eeef499..bf5b556525 100644 --- a/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/MessageComposerMode.kt +++ b/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/MessageComposerMode.kt @@ -34,7 +34,6 @@ sealed interface MessageComposerMode { override val defaultContent: CharSequence ) : Special(eventId, defaultContent) - val relatedEventId: String? get() = when (this) { is Normal -> null @@ -42,7 +41,4 @@ sealed interface MessageComposerMode { is Quote -> eventId is Reply -> eventId } - - } - diff --git a/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/RichTextComposerLayout.kt b/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/RichTextComposerLayout.kt index 34cc3065b1..eb51388ca3 100644 --- a/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/RichTextComposerLayout.kt +++ b/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/RichTextComposerLayout.kt @@ -45,12 +45,12 @@ import io.element.android.wysiwyg.inputhandlers.models.InlineFormat import io.element.android.x.core.ui.DimensionConverter import io.element.android.x.core.ui.hideKeyboard import io.element.android.x.core.ui.showKeyboard +import io.element.android.x.element.resources.R as ElementR import io.element.android.x.textcomposer.databinding.ComposerRichTextLayoutBinding import io.element.android.x.textcomposer.databinding.ViewRichTextMenuButtonBinding import io.element.android.x.textcomposer.tools.setTextIfDifferent import uniffi.wysiwyg_composer.ActionState import uniffi.wysiwyg_composer.ComposerAction -import io.element.android.x.element.resources.R as ElementR // Imported from Element Android class RichTextComposerLayout @JvmOverloads constructor( @@ -247,28 +247,28 @@ class RichTextComposerLayout @JvmOverloads constructor( private fun setupRichTextMenu() { addRichTextMenuItem( - ElementR.drawable.ic_composer_bold, + R.drawable.ic_composer_bold, ElementR.string.rich_text_editor_format_bold, ComposerAction.BOLD ) { views.richTextComposerEditText.toggleInlineFormat(InlineFormat.Bold) } addRichTextMenuItem( - ElementR.drawable.ic_composer_italic, + R.drawable.ic_composer_italic, ElementR.string.rich_text_editor_format_italic, ComposerAction.ITALIC ) { views.richTextComposerEditText.toggleInlineFormat(InlineFormat.Italic) } addRichTextMenuItem( - ElementR.drawable.ic_composer_underlined, + R.drawable.ic_composer_underlined, ElementR.string.rich_text_editor_format_underline, ComposerAction.UNDERLINE ) { views.richTextComposerEditText.toggleInlineFormat(InlineFormat.Underline) } addRichTextMenuItem( - ElementR.drawable.ic_composer_strikethrough, + R.drawable.ic_composer_strikethrough, ElementR.string.rich_text_editor_format_strikethrough, ComposerAction.STRIKE_THROUGH ) { @@ -485,7 +485,7 @@ class RichTextComposerLayout @JvmOverloads constructor( } else { views.composerModeGroup.isGone = true (mode as? MessageComposerMode.Normal)?.content?.let { text -> - // TODO: un-comment once we update to a version of the lib > 0.8.0 + // TODO un-comment once we update to a version of the lib > 0.8.0 /* if (isTextFormattingEnabled) { replaceFormattedContent(text) diff --git a/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/TextComposer.kt b/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/TextComposer.kt index 870fe1e657..6efa2e633b 100644 --- a/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/TextComposer.kt +++ b/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/TextComposer.kt @@ -22,81 +22,81 @@ import io.element.android.x.element.resources.R as ElementR @Composable fun TextComposer( - onSendMessage: (String) -> Unit, - modifier: Modifier = Modifier, fullscreen: Boolean, - onFullscreenToggle: () -> Unit, + composerText: String?, composerMode: MessageComposerMode, - onCloseSpecialMode: () -> Unit, - onComposerTextChange: (CharSequence) -> Unit, composerCanSendMessage: Boolean, - composerText: String?, + modifier: Modifier = Modifier, + onSendMessage: (String) -> Unit = {}, + onFullscreenToggle: () -> Unit = {}, + onCloseSpecialMode: () -> Unit = {}, + onComposerTextChange: (CharSequence) -> Unit = {}, ) { if (LocalInspectionMode.current) { FakeComposer(modifier) - return - } + } else { + val isInDarkMode = isSystemInDarkTheme() + AndroidView( + modifier = modifier, + factory = { context -> + RichTextComposerLayout(context).apply { + // Sets up listeners for View -> Compose communication + this.callback = object : Callback { + override fun onRichContentSelected(contentUri: Uri): Boolean { + return false + } - val isInDarkMode = isSystemInDarkTheme() - AndroidView( - modifier = modifier, - factory = { context -> - RichTextComposerLayout(context).apply { - // Sets up listeners for View -> Compose communication - this.callback = object : Callback { - override fun onRichContentSelected(contentUri: Uri): Boolean { - return false - } + override fun onTextChanged(text: CharSequence) { + onComposerTextChange(text) + } - override fun onTextChanged(text: CharSequence) { - onComposerTextChange(text) - } + override fun onCloseRelatedMessage() { + onCloseSpecialMode() + } - override fun onCloseRelatedMessage() { - onCloseSpecialMode() - } + override fun onSendMessage(text: CharSequence) { + // text contains markdown. + onSendMessage(text.toString()) + } - override fun onSendMessage(text: CharSequence) { - // text contains markdown. - onSendMessage(text.toString()) - } + override fun onAddAttachment() { + } - override fun onAddAttachment() { - } + override fun onExpandOrCompactChange() { + } - override fun onExpandOrCompactChange() { + override fun onFullScreenModeChanged() { + onFullscreenToggle() + } } - - override fun onFullScreenModeChanged() { - onFullscreenToggle() + setFullScreen(fullscreen, animated = false, manageKeyboard = true) + (this as MessageComposerView).apply { + setup(isInDarkMode, composerMode) } - - } - setFullScreen(fullscreen, animated = false, manageKeyboard = true) - (this as MessageComposerView).apply { - setup(isInDarkMode, composerMode) } - } - }, - update = { view -> - // View's been inflated or state read in this block has been updated - // Add logic here if necessary + }, + update = { view -> + // View's been inflated or state read in this block has been updated + // Add logic here if necessary - // As selectedItem is read here, AndroidView will recompose - // whenever the state changes - // Example of Compose -> View communication - val messageComposerView = (view as MessageComposerView) - view.setFullScreen(fullscreen, animated = false, manageKeyboard = false) - messageComposerView.renderComposerMode(composerMode) - messageComposerView.sendButton.isInvisible = !composerCanSendMessage - messageComposerView.setTextIfDifferent(composerText ?: "") - messageComposerView.editText.requestFocus() - } - ) + // As selectedItem is read here, AndroidView will recompose + // whenever the state changes + // Example of Compose -> View communication + val messageComposerView = (view as MessageComposerView) + view.setFullScreen(fullscreen, animated = false, manageKeyboard = false) + messageComposerView.renderComposerMode(composerMode) + messageComposerView.sendButton.isInvisible = !composerCanSendMessage + messageComposerView.setTextIfDifferent(composerText ?: "") + messageComposerView.editText.requestFocus() + } + ) + } } @Composable -private fun FakeComposer(modifier: Modifier) { +private fun FakeComposer( + modifier: Modifier = Modifier, +) { // AndroidView is not Available in this mode, just render a Text Box( modifier = modifier diff --git a/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/tools/ViewExtensions.kt b/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/tools/ViewExtensions.kt index 649221c2bd..fa0a218d19 100644 --- a/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/tools/ViewExtensions.kt +++ b/libraries/textcomposer/src/main/java/io/element/android/x/textcomposer/tools/ViewExtensions.kt @@ -1,7 +1,11 @@ package io.element.android.x.textcomposer.tools import android.view.ViewGroup -import androidx.transition.* +import androidx.transition.ChangeBounds +import androidx.transition.Fade +import androidx.transition.Transition +import androidx.transition.TransitionManager +import androidx.transition.TransitionSet fun ViewGroup.animateLayoutChange(animationDuration: Long, transitionComplete: (() -> Unit)? = null) { val transition = TransitionSet().apply { diff --git a/libraries/elementresources/src/main/res/color/selector_rich_text_menu_icon.xml b/libraries/textcomposer/src/main/res/color/selector_rich_text_menu_icon.xml similarity index 100% rename from libraries/elementresources/src/main/res/color/selector_rich_text_menu_icon.xml rename to libraries/textcomposer/src/main/res/color/selector_rich_text_menu_icon.xml diff --git a/libraries/textcomposer/src/main/res/drawable/bg_composer_rich_bottom_sheet.xml b/libraries/textcomposer/src/main/res/drawable/bg_composer_rich_bottom_sheet.xml deleted file mode 100644 index 47364373f7..0000000000 --- a/libraries/textcomposer/src/main/res/drawable/bg_composer_rich_bottom_sheet.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/libraries/elementresources/src/main/res/drawable/bg_rich_text_menu_button.xml b/libraries/textcomposer/src/main/res/drawable/bg_rich_text_menu_button.xml similarity index 100% rename from libraries/elementresources/src/main/res/drawable/bg_rich_text_menu_button.xml rename to libraries/textcomposer/src/main/res/drawable/bg_rich_text_menu_button.xml diff --git a/libraries/textcomposer/src/main/res/drawable/bottomsheet_handle.xml b/libraries/textcomposer/src/main/res/drawable/bottomsheet_handle.xml index 89ccf57ed0..f1bb917c61 100644 --- a/libraries/textcomposer/src/main/res/drawable/bottomsheet_handle.xml +++ b/libraries/textcomposer/src/main/res/drawable/bottomsheet_handle.xml @@ -1,6 +1,7 @@ - - + + diff --git a/libraries/textcomposer/src/main/res/drawable/ic_composer_bold.xml b/libraries/textcomposer/src/main/res/drawable/ic_composer_bold.xml new file mode 100644 index 0000000000..17adfc3d35 --- /dev/null +++ b/libraries/textcomposer/src/main/res/drawable/ic_composer_bold.xml @@ -0,0 +1,10 @@ + + + diff --git a/libraries/textcomposer/src/main/res/drawable/ic_composer_collapse.xml b/libraries/textcomposer/src/main/res/drawable/ic_composer_collapse.xml index 724a833761..3e24b2d62e 100644 --- a/libraries/textcomposer/src/main/res/drawable/ic_composer_collapse.xml +++ b/libraries/textcomposer/src/main/res/drawable/ic_composer_collapse.xml @@ -5,5 +5,5 @@ android:viewportHeight="20"> + android:pathData="M10.708,10Q10.438,10 10.219,9.781Q10,9.562 10,9.292V4.542Q10,4.354 10.146,4.219Q10.292,4.083 10.458,4.083Q10.646,4.083 10.781,4.219Q10.917,4.354 10.917,4.542V8.438L16.375,3Q16.5,2.854 16.688,2.854Q16.875,2.854 17,3Q17.146,3.125 17.146,3.312Q17.146,3.5 17,3.625L11.562,9.083H15.458Q15.646,9.083 15.781,9.229Q15.917,9.375 15.917,9.542Q15.917,9.729 15.781,9.865Q15.646,10 15.458,10ZM3,17Q2.854,16.875 2.854,16.688Q2.854,16.5 3,16.375L8.438,10.917H4.542Q4.354,10.917 4.219,10.771Q4.083,10.625 4.083,10.458Q4.083,10.271 4.219,10.135Q4.354,10 4.542,10H9.292Q9.562,10 9.781,10.219Q10,10.438 10,10.708V15.458Q10,15.646 9.854,15.781Q9.708,15.917 9.542,15.917Q9.354,15.917 9.219,15.781Q9.083,15.646 9.083,15.458V11.562L3.625,17Q3.5,17.146 3.312,17.146Q3.125,17.146 3,17Z" /> diff --git a/libraries/textcomposer/src/main/res/drawable/ic_composer_full_screen.xml b/libraries/textcomposer/src/main/res/drawable/ic_composer_full_screen.xml index de1862c09b..4c88f9063c 100644 --- a/libraries/textcomposer/src/main/res/drawable/ic_composer_full_screen.xml +++ b/libraries/textcomposer/src/main/res/drawable/ic_composer_full_screen.xml @@ -1,9 +1,9 @@ + android:width="48dp" + android:height="48dp" + android:viewportWidth="48" + android:viewportHeight="48"> + android:pathData="M17.125,31.5C16.944,31.5 16.795,31.441 16.677,31.323C16.559,31.205 16.5,31.056 16.5,30.875V25.875C16.5,25.694 16.559,25.545 16.677,25.427C16.795,25.309 16.944,25.25 17.125,25.25C17.306,25.25 17.455,25.309 17.573,25.427C17.691,25.545 17.75,25.694 17.75,25.875V29.375L29.375,17.75H25.875C25.694,17.75 25.545,17.691 25.427,17.573C25.309,17.455 25.25,17.306 25.25,17.125C25.25,16.944 25.309,16.795 25.427,16.677C25.545,16.559 25.694,16.5 25.875,16.5H30.875C31.056,16.5 31.205,16.559 31.323,16.677C31.441,16.795 31.5,16.944 31.5,17.125V22.125C31.5,22.306 31.441,22.455 31.323,22.573C31.205,22.691 31.056,22.75 30.875,22.75C30.694,22.75 30.545,22.691 30.427,22.573C30.309,22.455 30.25,22.306 30.25,22.125V18.625L18.625,30.25H22.125C22.306,30.25 22.455,30.309 22.573,30.427C22.691,30.545 22.75,30.694 22.75,30.875C22.75,31.056 22.691,31.205 22.573,31.323C22.455,31.441 22.306,31.5 22.125,31.5H17.125Z" + android:fillColor="#C1C6CD" /> diff --git a/libraries/textcomposer/src/main/res/drawable/ic_composer_italic.xml b/libraries/textcomposer/src/main/res/drawable/ic_composer_italic.xml new file mode 100644 index 0000000000..97050d52f9 --- /dev/null +++ b/libraries/textcomposer/src/main/res/drawable/ic_composer_italic.xml @@ -0,0 +1,10 @@ + + + diff --git a/libraries/textcomposer/src/main/res/drawable/ic_composer_rich_text_editor_close.xml b/libraries/textcomposer/src/main/res/drawable/ic_composer_rich_text_editor_close.xml index c461470de5..44343de281 100644 --- a/libraries/textcomposer/src/main/res/drawable/ic_composer_rich_text_editor_close.xml +++ b/libraries/textcomposer/src/main/res/drawable/ic_composer_rich_text_editor_close.xml @@ -3,7 +3,7 @@ android:height="12dp" android:viewportWidth="12" android:viewportHeight="12"> - + diff --git a/libraries/textcomposer/src/main/res/drawable/ic_composer_rich_text_editor_edit.xml b/libraries/textcomposer/src/main/res/drawable/ic_composer_rich_text_editor_edit.xml index 4556974221..a5ef981c5b 100644 --- a/libraries/textcomposer/src/main/res/drawable/ic_composer_rich_text_editor_edit.xml +++ b/libraries/textcomposer/src/main/res/drawable/ic_composer_rich_text_editor_edit.xml @@ -3,10 +3,10 @@ android:height="12dp" android:viewportWidth="12" android:viewportHeight="12"> - - + + diff --git a/libraries/textcomposer/src/main/res/drawable/ic_composer_rich_text_save.xml b/libraries/textcomposer/src/main/res/drawable/ic_composer_rich_text_save.xml index f270d6f8ae..e447fdc6af 100644 --- a/libraries/textcomposer/src/main/res/drawable/ic_composer_rich_text_save.xml +++ b/libraries/textcomposer/src/main/res/drawable/ic_composer_rich_text_save.xml @@ -3,14 +3,14 @@ android:height="36dp" android:viewportWidth="36" android:viewportHeight="36"> - - + + diff --git a/libraries/textcomposer/src/main/res/drawable/ic_composer_strikethrough.xml b/libraries/textcomposer/src/main/res/drawable/ic_composer_strikethrough.xml new file mode 100644 index 0000000000..505558409a --- /dev/null +++ b/libraries/textcomposer/src/main/res/drawable/ic_composer_strikethrough.xml @@ -0,0 +1,12 @@ + + + + diff --git a/libraries/textcomposer/src/main/res/drawable/ic_composer_underlined.xml b/libraries/textcomposer/src/main/res/drawable/ic_composer_underlined.xml new file mode 100644 index 0000000000..296e16f3d8 --- /dev/null +++ b/libraries/textcomposer/src/main/res/drawable/ic_composer_underlined.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/libraries/textcomposer/src/main/res/drawable/ic_quote.xml b/libraries/textcomposer/src/main/res/drawable/ic_quote.xml index 0689651f1d..e287c9296d 100644 --- a/libraries/textcomposer/src/main/res/drawable/ic_quote.xml +++ b/libraries/textcomposer/src/main/res/drawable/ic_quote.xml @@ -3,12 +3,12 @@ android:height="14dp" android:viewportWidth="20" android:viewportHeight="14"> - + diff --git a/libraries/textcomposer/src/main/res/drawable/ic_reply.xml b/libraries/textcomposer/src/main/res/drawable/ic_reply.xml index f23730624f..80eeab00c9 100644 --- a/libraries/textcomposer/src/main/res/drawable/ic_reply.xml +++ b/libraries/textcomposer/src/main/res/drawable/ic_reply.xml @@ -1,11 +1,20 @@ - - + - + + android:strokeColor="#000000" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="2" /> diff --git a/libraries/textcomposer/src/main/res/drawable/ic_rich_composer_add.xml b/libraries/textcomposer/src/main/res/drawable/ic_rich_composer_add.xml index 3a90a40902..9dc6ed03e9 100644 --- a/libraries/textcomposer/src/main/res/drawable/ic_rich_composer_add.xml +++ b/libraries/textcomposer/src/main/res/drawable/ic_rich_composer_add.xml @@ -3,13 +3,13 @@ android:height="36dp" android:viewportWidth="36" android:viewportHeight="36"> - - + + diff --git a/libraries/textcomposer/src/main/res/drawable/ic_rich_composer_send.xml b/libraries/textcomposer/src/main/res/drawable/ic_rich_composer_send.xml index 0f99c1670e..18afb70d6d 100644 --- a/libraries/textcomposer/src/main/res/drawable/ic_rich_composer_send.xml +++ b/libraries/textcomposer/src/main/res/drawable/ic_rich_composer_send.xml @@ -3,10 +3,10 @@ android:height="36dp" android:viewportWidth="36" android:viewportHeight="36"> - - + + diff --git a/libraries/textcomposer/src/main/res/layout/composer_rich_text_layout.xml b/libraries/textcomposer/src/main/res/layout/composer_rich_text_layout.xml index d099c72cab..0e82ca381b 100644 --- a/libraries/textcomposer/src/main/res/layout/composer_rich_text_layout.xml +++ b/libraries/textcomposer/src/main/res/layout/composer_rich_text_layout.xml @@ -81,7 +81,8 @@ app:layout_constraintStart_toStartOf="@id/composerEditTextOuterBorder" app:tint="?vctr_content_tertiary" /> - - - .androidConfig() { +fun CommonExtension<*, *, *, *>.androidConfig(project: Project) { defaultConfig { compileSdk = Versions.compileSdk minSdk = Versions.minSdk @@ -18,6 +19,12 @@ fun CommonExtension<*, *, *, *>.androidConfig() { testOptions { unitTests.isReturnDefaultValues = true } + + lint { + lintConfig = File("${project.rootDir}/tools/lint/lint.xml") + checkDependencies = true + abortOnError = true + } } fun CommonExtension<*, *, *, *>.composeConfig() { @@ -35,5 +42,11 @@ fun CommonExtension<*, *, *, *>.composeConfig() { add("META-INF/LGPL2.1") } } + + lint { + // Extra rules for compose + error.add("ComposableLambdaParameterNaming") + error.add("ComposableLambdaParameterPosition") + } } diff --git a/plugins/src/main/java/extension/DependencyHandleScope.kt b/plugins/src/main/java/extension/DependencyHandleScope.kt index 09fdd1bb23..d45fec0c94 100644 --- a/plugins/src/main/java/extension/DependencyHandleScope.kt +++ b/plugins/src/main/java/extension/DependencyHandleScope.kt @@ -5,8 +5,17 @@ import gradle.kotlin.dsl.accessors._4b7ad2363fc1fce7c774e054dc9a9300.debugImplem import gradle.kotlin.dsl.accessors._4b7ad2363fc1fce7c774e054dc9a9300.implementation import org.gradle.kotlin.dsl.DependencyHandlerScope +/** + * Dependencies used by all the modules + */ +fun DependencyHandlerScope.commonDependencies() { + implementation("com.jakewharton.timber:timber:5.0.1") +} -fun DependencyHandlerScope.composeDependencies(){ +/** + * Dependencies used by all the modules with composable items + */ +fun DependencyHandlerScope.composeDependencies() { val composeBom = platform("androidx.compose:compose-bom:2022.11.00") implementation(composeBom) androidTestImplementation(composeBom) @@ -22,5 +31,6 @@ fun DependencyHandlerScope.composeDependencies(){ debugImplementation("androidx.compose.ui:ui-tooling") debugImplementation("androidx.compose.ui:ui-test-manifest") implementation("com.airbnb.android:showkase:1.0.0-beta14") + implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.5") } diff --git a/plugins/src/main/java/io.element.android-compose-application.gradle.kts b/plugins/src/main/java/io.element.android-compose-application.gradle.kts index 8814bb7682..807ac5245d 100644 --- a/plugins/src/main/java/io.element.android-compose-application.gradle.kts +++ b/plugins/src/main/java/io.element.android-compose-application.gradle.kts @@ -1,4 +1,8 @@ +/** + * This will generate the plugin "io.element.android-compose-application", used only in the module `app`. + */ import extension.androidConfig +import extension.commonDependencies import extension.composeConfig import extension.composeDependencies @@ -8,10 +12,11 @@ plugins { } android { - androidConfig() + androidConfig(project) composeConfig() } dependencies { + commonDependencies() composeDependencies() } diff --git a/plugins/src/main/java/io.element.android-compose-library.gradle.kts b/plugins/src/main/java/io.element.android-compose-library.gradle.kts index 736b47140a..fdb73e897e 100644 --- a/plugins/src/main/java/io.element.android-compose-library.gradle.kts +++ b/plugins/src/main/java/io.element.android-compose-library.gradle.kts @@ -1,4 +1,8 @@ +/** + * This will generate the plugin "io.element.android-compose-library", used in android library with compose modules. + */ import extension.androidConfig +import extension.commonDependencies import extension.composeConfig import extension.composeDependencies @@ -7,12 +11,12 @@ plugins { id("kotlin-android") } - android { - androidConfig() + androidConfig(project) composeConfig() } dependencies { + commonDependencies() composeDependencies() } diff --git a/plugins/src/main/java/io.element.android-library.gradle.kts b/plugins/src/main/java/io.element.android-library.gradle.kts index 4283de3fa2..ed74db1f96 100644 --- a/plugins/src/main/java/io.element.android-library.gradle.kts +++ b/plugins/src/main/java/io.element.android-library.gradle.kts @@ -1,4 +1,8 @@ +/** + * This will generate the plugin "io.element.android-library", used in android library without compose modules. + */ import extension.androidConfig +import extension.commonDependencies plugins { id("com.android.library") @@ -6,5 +10,9 @@ plugins { } android { - androidConfig() + androidConfig(project) +} + +dependencies { + commonDependencies() } diff --git a/tools/danger/dangerfile-lint.js b/tools/danger/dangerfile-lint.js new file mode 100644 index 0000000000..b0531fef9b --- /dev/null +++ b/tools/danger/dangerfile-lint.js @@ -0,0 +1,29 @@ +import { schedule } from 'danger' + +/** + * Ref and documentation: https://github.com/damian-burke/danger-plugin-lint-report + * This file will check all the error in XML Checkstyle format. + * It covers, lint, ktlint, and detekt errors + */ + +const reporter = require("danger-plugin-lint-report") +schedule(reporter.scan({ + /** + * File mask used to find XML checkstyle reports. + */ + fileMask: "**/reports/**/**.xml", + /** + * If set to true, the severity will be used to switch between the different message formats (message, warn, fail). + */ + reportSeverity: true, + /** + * If set to true, only issues will be reported that are contained in the current changeset (line comparison). + * If set to false, all issues that are in modified files will be reported. + */ + requireLineModification: false, + /** + * Optional: Sets a prefix foreach violation message. + * This can be useful if there are multiple reports being parsed to make them distinguishable. + */ + // outputPrefix?: "" +})) diff --git a/tools/danger/dangerfile.js b/tools/danger/dangerfile.js new file mode 100644 index 0000000000..a9be0171d7 --- /dev/null +++ b/tools/danger/dangerfile.js @@ -0,0 +1,128 @@ +const {danger, warn} = require('danger') + +/** + * Note: if you update the checks in this file, please also update the file ./docs/danger.md + */ + +// Useful to see what we got in danger object +// warn(JSON.stringify(danger)) + +const pr = danger.github.pr +const github = danger.github +// User who has created the PR. +const user = pr.user.login +const modified = danger.git.modified_files +const created = danger.git.created_files +const editedFiles = [...modified, ...created] + +// Check that the PR has a description +if (pr.body.length == 0) { + warn("Please provide a description for this PR.") +} + +// Warn when there is a big PR +if (editedFiles.length > 50) { + message("This pull request seems relatively large. Please consider splitting it into multiple smaller ones.") +} + +// Request a changelog for each PR +const changelogAllowList = [ + "dependabot[bot]", +] + +const requiresChangelog = !changelogAllowList.includes(user) + +if (requiresChangelog) { + const changelogFiles = editedFiles.filter(file => file.startsWith("changelog.d/")) + + if (changelogFiles.length == 0) { + warn("Please add a changelog. See instructions [here](https://github.com/vector-im/element-android/blob/develop/CONTRIBUTING.md#changelog)") + } else { + const validTowncrierExtensions = [ + "bugfix", + "doc", + "feature", + "misc", + "sdk", + "wip", + ] + if (!changelogFiles.every(file => validTowncrierExtensions.includes(file.split(".").pop()))) { + fail("Invalid extension for changelog. See instructions [here](https://github.com/vector-im/element-android/blob/develop/CONTRIBUTING.md#changelog)") + } + } +} + +// check that frozen classes have not been modified +const frozenClasses = [ +] + +frozenClasses.forEach(frozen => { + if (editedFiles.some(file => file.endsWith(frozen))) { + fail("Frozen class `" + frozen + "` has been modified. Please do not modify frozen class.") + } + } +) + +// Check for a sign-off +const signOff = "Signed-off-by:" + +// Please add new names following the alphabetical order. +const allowList = [ + "amitkma", + "aringenbach", + "BillCarsonFr", + "bmarty", + "Claire1817", + "dependabot[bot]", + "ericdecanini", + "fedrunov", + "Florian14", + "ganfra", + "jmartinesp", + "jonnyandrew", + "kittykat", + "langleyd", + "MadLittleMods", + "manuroe", + "mnaturel", + "onurays", + "ouchadam", + "stefanceriu", + "yostyle", +] + +const requiresSignOff = !allowList.includes(user) + +if (requiresSignOff) { + const hasPRBodySignOff = pr.body.includes(signOff) + const hasCommitSignOff = danger.git.commits.every(commit => commit.message.includes(signOff)) + if (!hasPRBodySignOff && !hasCommitSignOff) { + fail("Please add a sign-off to either the PR description or to the commits themselves. See instructions [here](https://matrix-org.github.io/synapse/latest/development/contributing_guide.html#sign-off).") + } +} + +// Check for screenshots on view changes +const hasChangedViews = editedFiles.filter(file => file.includes("/layout")).length > 0 +if (hasChangedViews) { + if (!pr.body.includes("user-images")) { + warn("You seem to have made changes to views. Please consider adding screenshots.") + } +} + +// Check for pngs on resources +const hasPngs = editedFiles.filter(file => file.toLowerCase().endsWith(".png")).length > 0 +if (hasPngs) { + warn("You seem to have made changes to some images. Please consider using an vector drawable.") +} + +// Check for reviewers +if (github.requested_reviewers.users.length == 0 && !pr.draft) { + warn("Please add a reviewer to your PR.") +} + +// Check that translations have not been modified by developers +if (user != "RiotTranslateBot") { + if (editedFiles.some(file => file.endsWith("strings.xml") && !file.endsWith("values/strings.xml"))) { + fail("Some translation files have been edited. Only user `RiotTranslateBot` (i.e. translations coming from Weblate) is allowed to do that.\nPlease read more about translations management [in the doc](https://github.com/vector-im/element-android/blob/develop/CONTRIBUTING.md#internationalisation).") + } +} diff --git a/tools/detekt/detekt.yml b/tools/detekt/detekt.yml new file mode 100644 index 0000000000..6659692329 --- /dev/null +++ b/tools/detekt/detekt.yml @@ -0,0 +1,150 @@ +# Default rules: https://github.com/detekt/detekt/blob/main/detekt-core/src/main/resources/default-detekt-config.yml + +style: + MaxLineLength: + # Default is 120 + maxLineLength: 160 + MagicNumber: + active: false + ReturnCount: + active: false + UnnecessaryAbstractClass: + active: false + FunctionOnlyReturningConstant: + active: false + UnusedPrivateMember: + # TODO Enable it + active: false + ThrowsCount: + active: false + LoopWithTooManyJumpStatements: + active: false + SerialVersionUIDInSerializableClass: + active: false + ProtectedMemberInFinalClass: + active: false + UseCheckOrError: + active: false + +empty-blocks: + EmptyFunctionBlock: + active: false + EmptySecondaryConstructor: + active: false + +potential-bugs: + ImplicitDefaultLocale: + active: false + +exceptions: + TooGenericExceptionCaught: + active: false + SwallowedException: + active: false + ThrowingExceptionsWithoutMessageOrCause: + active: false + TooGenericExceptionThrown: + active: false + InstanceOfCheckForException: + active: false + +complexity: + TooManyFunctions: + active: false + LongMethod: + active: false + LongParameterList: + active: false + CyclomaticComplexMethod: + active: false + NestedBlockDepth: + active: false + ComplexCondition: + active: false + LargeClass: + active: false + +naming: + VariableNaming: + # TODO Enable it + active: false + TopLevelPropertyNaming: + # TODO Enable it + active: false + FunctionNaming: + active: true + ignoreAnnotated: ['Composable'] + +performance: + SpreadOperator: + active: false + +# Note: all rules for `comments` are disabled by default, but I put them here to be aware of their existence +comments: + AbsentOrWrongFileLicense: + active: false + licenseTemplateFile: 'license.template' + licenseTemplateIsRegex: false + CommentOverPrivateFunction: + active: false + CommentOverPrivateProperty: + active: false + DeprecatedBlockTag: + active: true + EndOfSentenceFormat: + active: true + OutdatedDocumentation: + active: true + UndocumentedPublicClass: + active: false + UndocumentedPublicFunction: + active: false + UndocumentedPublicProperty: + active: false + +TwitterCompose: + CompositionLocalAllowlist: + active: true + # You can optionally define a list of CompositionLocals that are allowed here + # allowedCompositionLocals: LocalSomething,LocalSomethingElse + CompositionLocalNaming: + active: true + ContentEmitterReturningValues: + active: true + # You can optionally add your own composables here + # contentEmitters: MyComposable,MyOtherComposable + ModifierComposable: + active: true + ModifierMissing: + active: true + ModifierReused: + active: true + ModifierWithoutDefault: + active: true + MultipleEmitters: + active: true + # You can optionally add your own composables here + # contentEmitters: MyComposable,MyOtherComposable + MutableParams: + active: true + ComposableNaming: + active: true + # You can optionally disable the checks in this rule for regex matches against the composable name (e.g. molecule presenters) + # allowedComposableFunctionNames: .*Presenter,.*MoleculePresenter + ComposableParamOrder: + active: true + PreviewNaming: + active: true + PreviewPublic: + active: true + # You can optionally disable that only previews with @PreviewParameter are flagged + previewPublicOnlyIfParams: false + RememberMissing: + active: true + UnstableCollections: + active: true + ViewModelForwarding: + ## TODO Set to true later + active: false + ViewModelInjection: + active: true diff --git a/tools/lint/lint.xml b/tools/lint/lint.xml new file mode 100644 index 0000000000..816fcb633a --- /dev/null +++ b/tools/lint/lint.xml @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +