diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..09135068f --- /dev/null +++ b/.editorconfig @@ -0,0 +1,358 @@ +root = true + +[*] +# charset = utf-8 +# end_of_line = lf +# indent_size = 4 +# indent_style = space +# insert_final_newline = false +# max_line_length = 100 +# tab_width = 4 +# ij_continuation_indent_size = 8 +# ij_formatter_off_tag = @formatter:off +# ij_formatter_on_tag = @formatter:on +# ij_formatter_tags_enabled = false +# ij_smart_tabs = false +# ij_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_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_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.**,|,*,|,$*,| +# 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_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_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_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_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_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 + +[{*.htm,*.shtm,*.sht,*.shtml,*.html}] +# 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 + +[{*.jhm,*.xslt,*.rng,*.xsl,*.xsd,*.ant,*.tld,*.fxml,*.wsdl,*.jrxml,*.xml,*.jnlp,*.xul}] +# ij_continuation_indent_size = 4 +# ij_xml_block_comment_at_first_column = true +# ij_xml_keep_indents_on_empty_lines = false +# ij_xml_line_comment_at_first_column = true +# ij_xml_use_custom_settings = true +# ij_continuation_indent_size = 4 +# ij_xml_block_comment_at_first_column = true +# ij_xml_keep_indents_on_empty_lines = false +# ij_xml_line_comment_at_first_column = true +# ij_xml_use_custom_settings = true + +[{*.kt,*.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_assignment_wrap = normal +# ij_kotlin_blank_lines_after_class_header = 0 +# ij_kotlin_blank_lines_around_block_when_branches = 0 +# ij_kotlin_block_comment_at_first_column = true +# ij_kotlin_call_parameters_new_line_after_left_paren = true +# ij_kotlin_call_parameters_right_paren_on_new_line = true +# ij_kotlin_call_parameters_wrap = on_every_item +# ij_kotlin_catch_on_new_line = false +# ij_kotlin_class_annotation_wrap = split_into_lines +# ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL +# ij_kotlin_continuation_indent_for_chained_calls = false +# ij_kotlin_continuation_indent_for_expression_bodies = false +# ij_kotlin_continuation_indent_in_argument_lists = false +# ij_kotlin_continuation_indent_in_elvis = false +# ij_kotlin_continuation_indent_in_if_conditions = false +# ij_kotlin_continuation_indent_in_parameter_lists = false +# ij_kotlin_continuation_indent_in_supertype_lists = false +# ij_kotlin_else_on_new_line = false +# ij_kotlin_enum_constants_wrap = off +# ij_kotlin_extends_list_wrap = normal +# ij_kotlin_field_annotation_wrap = split_into_lines +# ij_kotlin_finally_on_new_line = false +# ij_kotlin_if_rparen_on_new_line = true +# ij_kotlin_import_nested_classes = false +# ij_kotlin_insert_whitespaces_in_simple_one_line_method = true +# ij_kotlin_keep_blank_lines_before_right_brace = 2 +# ij_kotlin_keep_blank_lines_in_code = 2 +# ij_kotlin_keep_blank_lines_in_declarations = 2 +# ij_kotlin_keep_first_column_comment = true +# ij_kotlin_keep_indents_on_empty_lines = false +# ij_kotlin_keep_line_breaks = true +# ij_kotlin_lbrace_on_next_line = false +# ij_kotlin_line_comment_add_space = false +# ij_kotlin_line_comment_at_first_column = true +# ij_kotlin_method_annotation_wrap = split_into_lines +# ij_kotlin_method_call_chain_wrap = normal +# ij_kotlin_method_parameters_new_line_after_left_paren = true +# ij_kotlin_method_parameters_right_paren_on_new_line = true +# ij_kotlin_method_parameters_wrap = on_every_item +# ij_kotlin_name_count_to_use_star_import = 5 +# ij_kotlin_name_count_to_use_star_import_for_members = 3 +# ij_kotlin_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_variable_annotation_wrap = off +# ij_kotlin_while_on_new_line = false +# ij_kotlin_wrap_elvis_expressions = 1 +# ij_kotlin_wrap_expression_body_functions = 1 +# ij_kotlin_wrap_first_method_in_call_chain = false diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..411c07777 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +* text=auto eol=lf + +*.bat text eol=crlf +*.jar binary diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..3ee2b591b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,51 @@ +--- +name: Bug report +about: Create a report to help us improve. Please write in English only. +title: '' +labels: bug +assignees: '' + +--- + + + +**Have you read the [FAQ](https://github.com/RetroMusicPlayer/RetroMusicPlayer/blob/master/FAQ.md)?** +[Yes/No] + +**Has the bug already been reported? Please search in GitHub issue tab before creating an issue.** +[Yes/No] + +**Describe the bug** +A clear and concise description of what the bug is. + +**How To Reproduce** +Steps to reproduce the behavior: +1. +2. +3. +4. + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Crash log** +If the app is crashing, add a crash log +
+ Click to view logs +PASTE YOUR LOGS HERE. +
+ +**Device info:** + - Device: [e.g. OnePlus 7] + - Android version: [e.g. Android 9] + - App version [e.g. 3.5.300_0517] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..0f15789f4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,26 @@ +--- +name: Feature request +about: Suggest an idea for this project. Please write in English only. +title: '' +labels: enhancement +assignees: '' + +--- + + + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml new file mode 100644 index 000000000..e450294c1 --- /dev/null +++ b/.github/workflows/android.yml @@ -0,0 +1,34 @@ +name: Android CI + +on: + push: + branches: [ dev ] + pull_request: + branches: [ dev ] + +jobs: + check: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v3 + - uses: gradle/wrapper-validation-action@v1 + - uses: actions/setup-java@v3 + with: + distribution: 'zulu' + java-version: 17 + - uses: gradle/gradle-build-action@v2 + - name: Lint Android + run: ./gradlew lint + + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'zulu' + - uses: gradle/gradle-build-action@v2 + - name: Build + run: ./gradlew app:assemble diff --git a/.gitignore b/.gitignore index 37f05b7f5..6a32941f0 100644 --- a/.gitignore +++ b/.gitignore @@ -38,8 +38,4 @@ obj/ captures app/normal/release/ /models/ - -app/font/ -app/src/debug/ -/app/nofont/ -/crowdin.properties +/app/release/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..2775d78f3 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,35 @@ +# Contributing + +## Using the issue tracker +The [issue tracker](https://github.com/RetroMusicPlayer/RetroMusicPlayer/issues) is the preferred channel for bug reports, feature requests and submitting pull requests, but please follow these rules: + +* Please **do not** derail or troll issues. Keep the discussion on topic and respect the opinions of others. + +* Please **do not** post comments consisting solely of "+1" or "👍". Use [GitHub's "reactions" feature](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments) instead. + +* Please **do not** write [enhancement]/[bug]/[feature request] or similar stuff in the title of issues, as there are labels for that purpose that will be added by devs or collaborators. + +## Bug reports +A bug is a _demonstrable problem_. Good bug reports are extremely helpful, so thanks! + +Guidelines for bug reports: + +* Use the GitHub issue search, check if the issue has already been reported both in the open issues and in the closed ones, if there are some missing details, add them in issue comments, without creating a new one +* Check if the issue has been fixed — try to reproduce it using the latest available build +* Isolate the problem — ideally create a reproducible scenario and a live example +* Do not report multiple bugs in a single ticket, otherwise it will be confusing. + +A good bug report shouldn't leave others needing to chase you up for more information. Please try to be as detailed as possible in your report. + + +## Feature requests +Feature requests are welcome, please make sure to be as detailed as possible and use screenshots, videos, GIFs, to demonstrate it better, if possible. + + +## Pull requests +**Please ask first** before embarking on any significant pull request (e.g. implementing features, refactoring code), otherwise you risk spending a lot of time working on something that developers might not want to merge into the project. To avoid that, you can join the official [Telegram group](https://t.me/retromusicapp) or open an issue. + +## License +By contributing your code, you agree to license your contribution under the [GNU General Public License](https://github.com/RetroMusicPlayer/RetroMusicPlayer/blob/master/LICENSE.md). + +Please note we have a code of conduct, please follow it in all your interactions with the project. diff --git a/FAQ.md b/FAQ.md index e4c87a781..8223a2c7a 100644 --- a/FAQ.md +++ b/FAQ.md @@ -1,80 +1,157 @@ -#### Q: How do I get the beta version of Retro Music? +## **Q: How do I get the beta version of Retro Music?** You can opt-in for the beta build by clicking on this link: https://play.google.com/apps/testing/code.name.monkey.retromusic -#### Q: How do I use offline synced lyrics? -There are two methods for how to get offline synced lyrics. +___ -#### Method 1:- -##### STEP 1: -Find the time stamped lyrics for your songs which don't have lyrics already. A time stamped lyrics looks like this, "[00:04:02] Some lyrics text" for example. -##### STEP 2: -Copy these time stamped lyrics. -##### STEP 3: +## **Q: How to restore my purchases?** +Make sure to switch and use your account in the Play Store app through which you purchased before installing Retro Music. The Google account used to install the app is also used to purchase/restore the pro license. + +If you've already installed the app, remove all other accounts except the one from which you purchased premium, and then restore the purchase. + +___ + +## Q: **How do I use offline synced lyrics?** +There are three methods for adding offline synced lyrics in Retro Music. + +### ***Method 1:-*** +#### STEP 1: +Find the time-stamped lyrics for your songs that don't have lyrics already. A time-stamped lyric looks like this, "[00:04:02] Some lyrics text" for example. +#### STEP 2: +Copy these time-stamped lyrics. +#### STEP 3: Open retro music and head to the song synced lyrics editor. -##### STEP 4: +#### STEP 4: Paste the lyrics there normally and exit the editor -##### STEP 5: -Open lyrics and you should see your time stamped lyrics there. +#### STEP 5: +Open lyrics and you should see your time-stamped lyrics there. -#### Method 2:- -##### STEP 1: -Find the ".lrc" files for your songs which doesn't have lyrics already. -##### STEP 2: -A ".lrc" is like a text file which contains the time stamped lyrics for example, "[00:04:02] Some lyrics text" -##### STEP 3: +### ***Method 2:-*** +#### STEP 1: +Download the time-stamped lyrics for your songs that don't have lyrics already. You can find ".lrc" files for popular songs at either of the websites given below. A time-stamped lyric looks like this, "[00:04:02] Some lyrics text" for example. +#### STEP 2: +A ".lrc" is like a text file that contains the time-stamped lyrics for example, "[00:04:02] Some lyrics text". Save your time-stamped lyrics are ".lrc" file. +#### STEP 3: Now you have to rename the file you created in this way: - .lrc or for better matching copy the and the from the tag editor and then rename the file. -##### STEP 4: -You have to copy or move this file into a location on the SD Card: whatever_sdcard/RetroMusic/lyrics/ and paste it there. -Finally you will be able to see the lyrics working. +### STEP 4: +Now paste the LRC files to the following path: /sdcard/Retromusic/lyrics/ +Here sdcard is your internal storage. -> If you want to skip to particular time stamp, simply scroll to the time stamp from where you want to start from and a 'Play' icon will appear left to the particular stamp. Tap on play button to play from there. +### ***Method 3:- (Requires third-party app)*** +#### STEP 1: +Download automatag or autotagger from Play Store. +#### STEP 2: +Find the time-stamped lyrics for your songs that don't have lyrics already. You can find ".lrc" files for popular songs at either of the websites given below. A time-stamped lyric looks like this, "[00:04:02] Some lyrics text" for example. +#### STEP 3: +Find your song to edit and paste the synced lyrics. +> These apps add those synced lyrics in the music file itself instead of creating a ".lrc file for it." +**Lyrics Website Links:** +- https://www.lyricsify.com/ +- https://www.syair.info -#### Q: Why isn't the artist's image downloading? -Last.fm has disabled the download of artist's images for the time being, whether functionality for this will be restored in future is uncertain. +**Some Important Notes:** +- If you want to skip to a particular timestamp, simply scroll to the time stamp from where you want to start and a 'Play' icon will appear left to the particular stamp. Tap on the play button to play from there. +- When you save lyrics by pasting lyrics in lyrics editor, close the lyrics and open again for lyrics to show. +- For those who are having difficulty in making the synced lyrics work, we have a short tutorial video on it. Hope this helps you. {[Link in the note or here](https://youtu.be/1oIOTGWhNMY)} -#### Q: How do I change the theme? +___ + +## **Q: How do I change the theme?** Settings -> Look and feel -> Select your theme. +___ -#### Q: Why aren't last added songs showing? +## **Q: Equalizer is very laggy and unstable or I am getting a "No equalizer found" error. Why?** +- The Retro music in-built equalizer was removed updates ago so the only equalizer you will have by your OEM or Android native equalizer which isn't made by us and have no control over them. So you can report those issues to your OEM so that they can provide a fix in the next updates. + +- If you are seeing "No Equalizer Found" in your device, this means your device doesn't have a stock equalizer "MusicFx" Equalizer. You can try using this one. It's made by AEX ROM developers. + +https://drive.google.com/file/d/1_1bpsn6roeEyElGKikbU39lVKUH8O3xp/view?**usp=drivesdk + +___ + +## **Q: Why aren't last added songs showing?** Settings -> Other -> Last added playlist interval -> Select an option from the list. +___ -#### Q: How do I enable fullscreen lockscreen controls? +## **Q: How do I enable fullscreen lock screen controls?** Settings -> Personalize -> Fullscreen controls -> Enable (this will only be visible when songs are playing from Retro Music). +___ -#### Q: Why are gallery or random pictures showing up as album art? +## **Q: Why are my gallery or random pictures showing up as album art?** Settings -> Images -> Ignore media store covers -> Enable +___ -#### Q: Which file types are supported? +## **Q: Which file types are supported?** Retro Music uses the native media player that comes with your Android phone, so as long as a file type is supported by your phone, it's supported by Retro Music. +___ -#### Q: Why is my device slowing down when I'm using the app? +## **Q: Why is my device slowing down when I'm using the app?** Retro Music is image intensive, it keeps images in the cache for quick loading. +___ -#### Q: The title "Retro Music" is showing on the top of the app, how can i fix this? +## **Q: The title "Retro Music" is showing on the top of the app, how can I fix this?** Clear the app's cache and data. +___ -##### Q: My app is crashing, how do i fix this? (Sorry, settings have changed internally) -Reinstalling the app should fix this issue. +## **Q: My app is crashing, how do I fix this?** (Sorry, settings have changed internally) +Please try to clear the data of the app. If it doesn't work, reinstalling fresh from the play store should help. +___ -##### Q: Why has all the text gone white/dissapeared? +## **Q: Why has all the text gone white/disappeared?** Change the theme to Black or Dark and change it back to what you had before. +___ -##### Q: Why some of my songs are not showing in my library? -Try checking up if those songs are not less than 30 seconds, if so head to settings -> other -> filter song duration. Put this to zero and see the songs should start appearimg in the library. -If this doesn't work out for you, re-scanning the media folder should help and subsquently rebooting the device to refresh media store. -At last resort, If nothing worked and your audio files are stored in SD card. Try moving them to internal memory then back to SD card. +## **Q: Why some of my songs are not showing in my library?** +- Try checking up if those songs are not less than 30 seconds, if so head to settings -> other -> filter song duration. Put this to zero and see the songs that should start appearing in the library. -##### Q: Why my playlist/playlist songs keep disappearing? -Playlist/Playlist songs disappearing is based on android media store system. Save those playlist as file(Tap on three dot menu next to available playlist and save as file) and it should get fixed. +- If this doesn't work out for you, re-scanning the media folder should help and subsequently rebooting the device to refresh the media store. -##### Q: Why does my library shows song files twice or no song at all? -If you are seeing duplication of songs in the library or no songs at all, then it's because of Media Store issue which got affected by some other app. -To fix this: -• Head to your device settings -• Open up "Apps & notifications" (This name depends from ROM to ROM) -• Find 'Media storage' app and clear storage (both data and cache) of it. -• Then open Retro Music app and manually scan your music from your storage. -• Reboot the device to refresh media store (Not sure if this is necessary) +- At last, resort, If nothing worked and your audio files are stored in SD card. Try moving them to internal memory then back to SD card. -NOTE: Don't panic when you will open Retro Music and see "Zero" songs there in the library. It's because you cleared Media Store which is responsible for recognising files on your device. +___ + +## **Q: Why does my library shows song files twice or no song at all?** +If you are seeing duplication of songs in the library or no songs at all, then it's because of the Media Store issue which got affected by some other app. + +***To fix this:*** +1. Head to your device settings + +1. Open up "Apps & notifications" (This name depends from ROM to ROM) + +1. Find the 'Media storage' app and clear storage (both data and cache) of it. + +1. Then open the Retro Music app and manually scan your music from your storage. + +1. Reboot the device to refresh the media store (Not sure if this is necessary) + +**NOTE:** Don't panic when you will open Retro Music and see "Zero" songs there in the library. It's because you cleared Media Store which is responsible for recognising files on your device. +___ + +## **Q: I can't find the folder menu anymore after the latest update?** +Head to settings -> personalise. And select folders from "library categories". If there is no option of folders, tap on reset and select folders. +___ + +## **Q: After updating the app to the latest version, the font got removed. Why?** +- Retro Music's font has now been replaced with system font, which means the default font your system uses will be used by Retro Music too. It fixes all font-related issues you used to face/are facing in the app. + +- With the recent Retro Music v5 release, we have a built-in optional font "Manrope font" which you can toggle from Settings > Look & Feel > Toggle "Use manrope font". + +- If you think the font looks ugly, then you just need to change the default font from your Android settings (or use any Magisk module). If you can't, there's nothing we can do about it. +___ + +## **Q: How to export playlist?** +- ***From Retro Music:*** + +Head to the playlists tab > tap on the three-dot menu on the playlist you want to export > save as a file. + +- ***From Other Music Players:*** + +In your built-in music player, there should be an option to save that playlist as a file. Save them and import them from the file manager by opening it into retro music. + +> Note that such playlist must be of your offline music only since retro music is an offline music player, not an online music player. So if your playlist is of online music, it can't be opened on other offline players nor can be exported +___ + +## **Q: How to restore/import playlist?** +Retro Music will automatically detect any playlist file when that playlist file is stored in internal storage/Playlist. However, if it doesn't, just open any "File manager" and open that playlist file with Retro Music. + +For restoring playlists successfully, the location of songs must be the same in both the "Playlist" file and in your storage. For example, If your music is in "Internal storage/Music" and the playlist file has songs location "Internal storage/Songs". Then it will not be going to work since both these locations are different. \ No newline at end of file diff --git a/README.md b/README.md index 632a710f2..ca4bd8b1b 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,97 @@ -# Retro Music Player +# Metro -[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://github.com/h4h13/RetroMusicPlayer/blob/master/LICENSE.txt) +Material Design music player for Android music lovers -**Android Material Design music player** +## Downloads -Retro Music is an open source, local music player for Android. +[Get it on F-Droid](https://f-droid.org/en/packages/io.github.muntashirakon.Music/) -#### Features +## Differences between Metro and [RetroMusicPlayer](https://github.com/h4h13/RetroMusicPlayer) +- Google Play libraries removed (fully libre) +- Pro features available for free +- Fully offline (INTERNET permission removed) +- Bug fixes +- Minor differences in UI -- Local playback only (based on the MediaStore) -- Sleep timer -- Folder browser -- Home screen widgets -- Themes (Just Black, Kinda Dark, Clearly White) -- Now playing themes -- Volume controls -- Blacklist -- Album artist support +## 📱 Screenshots +### App Themes +| | | | +|:---:|:---:|:---:| +|Clearly white| Kinda dark | Just black| -#### Download +### Player screen +| | | | | | +|:---:|:---:|:---:|:---:|:---:| +| Home | Songs | Albums | Artists | Settings | -Get it on Google Play +### Synced lyrics screen (Over Cover) +| | | | +|:---:|:---:|:---:| +| Synced Over Cover light | Synced Over Cover dark | Synced Over Cover black | -#### Translations -Help us translate the app to your language [here](http://monkeycodeapp.oneskyapp.com/collaboration/project?id=238534). +### Synced lyrics screen (Replace Cover) +| | | | +|:---:|:---:|:---:| +| Synced Replace Cover light | Synced Replace Cover dark | Synced Replace Cover black | + +### 10+ Now playing themes +| || | | | +|:-----: |:-----: |:-----: |:-----: |:-----: | +| Normal | Fit | Flat | Color | Material | + +| || | | | +|:-----: |:-----: |:-----: |:-----: |:-----: | +| Classic | Adaptive | Blur | Tiny | Peek | + +## 🧭 Navigation never made easier +Self-explanatory interface without overloaded menus. + +## 🎨 Colorful +You can choose between three different main themes: Clearly White, Kinda +Dark and Just Black for AMOLED displays. Select your favorite accent +color from a color palette. + +## 🏠 Home +Where you can view your recently/top played artists, albums and +favorite songs. No other music player has this feature. + +## 📦 Included Features +- Base 3 themes (Clearly White, Kinda Dark and Just Black) +- Choose from 10+ now playing themes +- Driving Mode +- Headset/Bluetooth support +- Music duration filter +- Android auto support +- Wallpaper accent picker on Android 8.1+ +- Material You support on Android 12+ +- Monet themed icon support on Android 13+ +- Folder support - Play songs by folder +- Gapless playback +- Volume controls +- Carousel effect for album covers +- Home screen widgets +- Lock screen playback controls +- Lyrics screen (download and sync with music) +- Sleep timer +- Easy drag to sort playlist & play queue +- Tag editor +- Create, edit and import playlists +- Playing queue with reorder +- User profile +- 30+ languages support +- Browse and play your music by songs, albums, artists, playlists and + genre +- Smart Auto Playlists - Recently played, most played and history +- Build your playlist on the go + +We are trying our best to bring you the best user experience. The app is regularly being updated for bug fixes and new features. + +## 🗂️ License + +Metro is released under the GNU General Public License v3.0 +(GPLv3), which can be found [here](LICENSE.md) -#### License - -Retro Music Player is released under the GNU General Public License v3.0 (GPLv3), which can be found here: [License](LICENSE.md) - -#### FAQ [Here](FAQ.md) - -#### Change-Log and Release [Here](https://github.com/h4h13/RetroMusicPlayer/releases) - +> Please note: Metro is an offline music player app. It doesn't support music downloading or online music streaming. diff --git a/app/build.gradle b/app/build.gradle index 39eba04b7..cb394ecda 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,51 +1,30 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' -apply plugin: 'kotlin-kapt' -apply plugin: "ru.cleverpumpkin.proguard-dictionaries-generator" - -proguardDictionaries { - dictionaryNames = [ - "build/class-dictionary", - "build/package-dictionary", - "build/obfuscation-dictionary" - ] -} +apply plugin: "androidx.navigation.safeargs.kotlin" +apply plugin: 'kotlin-parcelize' +apply plugin: 'com.google.devtools.ksp' android { - compileSdkVersion 29 - buildToolsVersion = '29.0.3' + compileSdk 33 + namespace "code.name.monkey.retromusic" defaultConfig { - minSdkVersion 21 - targetSdkVersion 29 + minSdk 21 + targetSdk 33 - renderscriptTargetApi 29 //must match target sdk and build tools vectorDrawables.useSupportLibrary = true - applicationId "code.name.monkey.retromusic" - versionCode 417 - versionName '3.5.100' + applicationId 'io.github.muntashirakon.Music' + versionCode 10603 + versionName '6.1.0' multiDexEnabled true - - buildConfigField("String", "GOOGLE_PLAY_LICENSING_KEY", "\"${getProperty(getProperties('../public.properties'), 'GOOGLE_PLAY_LICENSE_KEY')}\"") - } - signingConfigs { - release { - Properties properties = getProperties('/Users/hemanths/Desktop/KeepSafe/retro.properties') - storeFile file(getProperty(properties, 'storeFile')) - keyAlias getProperty(properties, 'keyAlias') - storePassword getProperty(properties, 'storePassword') - keyPassword getProperty(properties, 'keyPassword') - } } buildTypes { release { - minifyEnabled true shrinkResources true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - signingConfig signingConfigs.release + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } debug { applicationIdSuffix '.debug' @@ -53,135 +32,101 @@ android { } } - - flavorDimensions "default" - - productFlavors { - normal { - versionCode defaultConfig.versionCode + 10000 - versionName defaultConfig.versionName + "_" + getDate() - dimension "default" - } - font { - versionCode defaultConfig.versionCode + 10000 - versionName defaultConfig.versionName + "_" + getDate() - dimension "default" - } - nofont { - versionCode defaultConfig.versionCode + 10000 - versionName defaultConfig.versionName + "_" + getDate() - dimension "default" - } + buildFeatures { + viewBinding true } - packagingOptions { - exclude 'META-INF/LICENSE' - exclude 'META-INF/NOTICE' - exclude 'META-INF/java.properties' + resources { + excludes += ['META-INF/LICENSE', 'META-INF/NOTICE', 'META-INF/java.properties'] + } } - lintOptions { - disable 'MissingTranslation' - disable 'InvalidPackage' - abortOnError false + lint { + abortOnError true + warning 'ImpliedQuantity', 'Instantiatable', 'MissingQuantity', 'MissingTranslation' } compileOptions { - sourceCompatibility '1.8' - targetCompatibility '1.8' + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 } - - - configurations.all { + kotlinOptions { + jvmTarget = "1.8" + } + dependenciesInfo { + includeInApk = false + includeInBundle = false + } + configurations.configureEach { resolutionStrategy.force 'com.google.code.findbugs:jsr305:1.3.9' } - androidExtensions { - experimental = true - } - kapt { - generateStubs = true - } - -} - -def getProperties(String fileName) { - final Properties properties = new Properties() - def file = file(fileName) - if (file.exists()) { - file.withInputStream { stream -> properties.load(stream) } - } - return properties -} - -static def getProperty(Properties properties, String name) { - return properties.getProperty(name) ?: "$name missing" -} - -static def getDate() { - new Date().format('MMdd') } dependencies { - implementation fileTree(include: ['*.jar'], dir: 'libs') implementation project(':appthemehelper') - implementation project(':fonts') - implementation 'androidx.multidex:multidex:2.0.1' - implementation "androidx.gridlayout:gridlayout:1.0.0" - implementation "androidx.cardview:cardview:1.0.0" - implementation "androidx.palette:palette:1.0.0" + + implementation "androidx.appcompat:appcompat:$appcompat_version" + implementation 'androidx.annotation:annotation:1.6.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation 'androidx.recyclerview:recyclerview:1.3.0' + implementation "androidx.preference:preference-ktx:$preference_version" + implementation "androidx.core:core-ktx:$core_version" implementation 'androidx.palette:palette-ktx:1.0.0' - implementation "androidx.viewpager2:viewpager2:1.1.0-alpha01" - implementation 'androidx.appcompat:appcompat:1.1.0' - implementation 'androidx.annotation:annotation:1.1.0' - implementation 'androidx.preference:preference:1.1.0' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - implementation 'androidx.core:core-ktx:1.2.0' - implementation 'androidx.fragment:fragment:1.2.4' - implementation 'androidx.recyclerview:recyclerview:1.1.0' + implementation 'androidx.mediarouter:mediarouter:1.3.1' - implementation 'com.google.android.material:material:1.2.0-alpha06' + implementation "androidx.navigation:navigation-runtime-ktx:$navigation_version" + implementation "androidx.navigation:navigation-fragment-ktx:$navigation_version" + implementation "androidx.navigation:navigation-ui-ktx:$navigation_version" - def retrofit_version = "2.6.2" + def room_version = '2.5.1' + implementation "androidx.room:room-runtime:$room_version" + implementation "androidx.room:room-ktx:$room_version" + ksp "androidx.room:room-compiler:$room_version" + + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" + implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" + + implementation "androidx.core:core-splashscreen:1.0.0" + + implementation "com.google.android.material:material:$mdc_version" + + def retrofit_version = '2.9.0' implementation "com.squareup.retrofit2:retrofit:$retrofit_version" implementation "com.squareup.retrofit2:converter-gson:$retrofit_version" - def material_dialog_version = "3.1.1" + def material_dialog_version = "3.3.0" implementation "com.afollestad.material-dialogs:core:$material_dialog_version" implementation "com.afollestad.material-dialogs:input:$material_dialog_version" implementation "com.afollestad.material-dialogs:color:$material_dialog_version" - implementation "com.afollestad.material-dialogs:bottomsheets:$material_dialog_version" - implementation 'com.afollestad:material-cab:0.1.12' - implementation 'com.github.bumptech.glide:glide:3.8.0' - implementation 'com.github.bumptech.glide:okhttp3-integration:1.5.0' - implementation 'com.squareup.okhttp3:logging-interceptor:3.6.0' + implementation 'com.afollestad:material-cab:2.0.1' - implementation('com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.11.0@aar') { - transitive = true - } - /*UI Library*/ - implementation 'me.zhanghai.android.materialprogressbar:library:1.6.1' + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4" + def koin_version = '3.4.0' + implementation "io.insert-koin:koin-core:$koin_version" + implementation "io.insert-koin:koin-android:$koin_version" - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - def kotlin_coroutines_version = "1.3.3" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version" + def glide_version = '4.15.1' + implementation "com.github.bumptech.glide:glide:$glide_version" + ksp "com.github.bumptech.glide:ksp:$glide_version" - implementation 'org.eclipse.mylyn.github:org.eclipse.egit.github.core:3.4.0.201406110918-r' + implementation 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:1.0.0' - implementation 'com.github.ksoichiro:android-observablescrollview:1.6.0' - implementation 'com.github.kabouzeid:recyclerview-fastscroll:1.9-kmod' + implementation 'com.github.bosphere.android-fadingedgelayout:fadingedgelayout:1.0.0' - implementation 'com.github.AdrienPoupa:jaudiotagger:2.2.3' + implementation 'net.yslibrary.keyboardvisibilityevent:keyboardvisibilityevent:3.0.0-RC3' + implementation 'com.github.jetradarmobile:android-snowfall:1.2.1' - implementation 'com.anjlab.android.iab.v3:library:1.1.0' + implementation "dev.chrisbanes.insetter:insetter:0.6.1" + + implementation 'com.github.Adonai:jaudiotagger:2.3.15' implementation 'com.r0adkll:slidableactivity:2.1.0' - implementation 'com.heinrichreimersoftware:material-intro:1.6' - implementation 'me.zhanghai.android.fastscroll:library:1.1.0' - - def dagger_version = "2.23.1" - implementation "com.google.dagger:dagger:$dagger_version" - kapt "com.google.dagger:dagger-compiler:$dagger_version" + implementation 'com.heinrichreimersoftware:material-intro:2.0.0' + implementation 'com.github.dhaval2404:imagepicker:2.1' + implementation 'me.zhanghai.android.fastscroll:library:1.2.0' + implementation 'cat.ereza:customactivityoncrash:2.4.0' + implementation 'me.tankery.lib:circularSeekBar:1.4.2' } \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index b58c71e0b..c9f1d0067 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -16,9 +16,9 @@ # public *; #} -# Uncomment this to preserve the line number information for +# Preserve the line number information for # debugging stack traces. -#-keepattributes SourceFile,LineNumberTable +-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. @@ -26,45 +26,46 @@ -dontwarn java.lang.invoke.* -dontwarn **$$Lambda$* +-dontwarn javax.annotation.** # RetroFit -dontwarn retrofit.** -keep class retrofit.** { *; } --keepattributes Signature --keepattributes Exceptions --dontwarn javax.annotation.** # Glide -keep public class * implements com.bumptech.glide.module.GlideModule --keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** { - **[] $VALUES; - public *; +-keep class * extends com.bumptech.glide.module.AppGlideModule { + (...); +} +-keep public enum com.bumptech.glide.load.ImageHeaderParser$** { + **[] $VALUES; + public *; +} +-keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder { + *** rewind(); } --keep class !android.support.v7.internal.view.menu.**,** {*;} +# OkHttp +-keepattributes Signature +-keepattributes *Annotation* +-keep interface com.squareup.okhttp3.** { *; } +-dontwarn com.squareup.okhttp3.** --dontwarn --ignorewarnings +#-dontwarn +#-ignorewarnings --keep public class android.support.design.widget.BottomNavigationView { *; } --keep public class android.support.design.internal.BottomNavigationMenuView { *; } --keep public class android.support.design.internal.BottomNavigationPresenter { *; } --keep public class android.support.design.internal.BottomNavigationItemView { *; } +#Jaudiotagger +-dontwarn org.jaudiotagger.** +-dontwarn org.jcodec.** +-keep class org.jaudiotagger.** { *; } +-keep class org.jcodec.** { *; } -#-dontwarn android.support.v8.renderscript.* -#-keepclassmembers class android.support.v8.renderscript.RenderScript { -# native *** rsn*(...); -# native *** n*(...); -#} - -#-keep class org.jaudiotagger.** { *; } - -#For cast --keep class code.name.monkey.retromusic.cast.CastOptionsProvider { *; } --keep class android.support.** { *; } --keep class com.google.** { *; } --keep class java.nio.file.** { *; } - --obfuscationdictionary build/obfuscation-dictionary.txt --classobfuscationdictionary build/class-dictionary.txt --packageobfuscationdictionary build/package-dictionary.txt +-keepclassmembers enum * { *; } +-keepattributes *Annotation*, Signature, Exception +-keepnames class androidx.navigation.fragment.NavHostFragment +-keep class * extends androidx.fragment.app.Fragment{} +-keepnames class * extends android.os.Parcelable +-keepnames class * extends java.io.Serializable +-keep class code.name.monkey.retromusic.network.model.** { *; } +-keep class code.name.monkey.retromusic.model.** { *; } +-keep class com.google.android.material.bottomsheet.** { *; } \ No newline at end of file diff --git a/app/src/debug/res/font/bold.ttf b/app/src/debug/res/font/bold.ttf new file mode 100644 index 000000000..96619df92 Binary files /dev/null and b/app/src/debug/res/font/bold.ttf differ diff --git a/app/src/debug/res/font/google_sans_bold.ttf b/app/src/debug/res/font/google_sans_bold.ttf new file mode 100644 index 000000000..80497666e Binary files /dev/null and b/app/src/debug/res/font/google_sans_bold.ttf differ diff --git a/app/src/debug/res/font/google_sans_medium.ttf b/app/src/debug/res/font/google_sans_medium.ttf new file mode 100644 index 000000000..1543660da Binary files /dev/null and b/app/src/debug/res/font/google_sans_medium.ttf differ diff --git a/app/src/debug/res/font/google_sans_regular.ttf b/app/src/debug/res/font/google_sans_regular.ttf new file mode 100644 index 000000000..ab605f9e2 Binary files /dev/null and b/app/src/debug/res/font/google_sans_regular.ttf differ diff --git a/app/src/debug/res/font/medium.ttf b/app/src/debug/res/font/medium.ttf new file mode 100644 index 000000000..fd818d6f5 Binary files /dev/null and b/app/src/debug/res/font/medium.ttf differ diff --git a/app/src/debug/res/font/regular.ttf b/app/src/debug/res/font/regular.ttf new file mode 100644 index 000000000..e2c69c3fb Binary files /dev/null and b/app/src/debug/res/font/regular.ttf differ diff --git a/app/src/debug/res/font/sans.xml b/app/src/debug/res/font/sans.xml new file mode 100644 index 000000000..7bbc8513b --- /dev/null +++ b/app/src/debug/res/font/sans.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/debug/res/values/bools.xml b/app/src/debug/res/values/bools.xml new file mode 100644 index 000000000..7d3f0ee62 --- /dev/null +++ b/app/src/debug/res/values/bools.xml @@ -0,0 +1,5 @@ + + + true + false + \ No newline at end of file diff --git a/app/src/debug/res/values/donottranslate.xml b/app/src/debug/res/values/donottranslate.xml new file mode 100644 index 000000000..79e559838 --- /dev/null +++ b/app/src/debug/res/values/donottranslate.xml @@ -0,0 +1,4 @@ + + + Metro Debug + \ No newline at end of file diff --git a/app/src/debug/res/values/styles.xml b/app/src/debug/res/values/styles.xml new file mode 100644 index 000000000..f3761b219 --- /dev/null +++ b/app/src/debug/res/values/styles.xml @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1ff053167..14fbaaab7 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,40 +1,57 @@ + package="code.name.monkey.retromusic" + android:installLocation="auto"> - + + + + - - - - + + + + - - + + + android:usesCleartextTraffic="true" + tools:ignore="UnusedAttribute"> + android:exported="true" + android:launchMode="singleTop" + android:theme="@style/Theme.RetroMusic.SplashScreen"> @@ -45,7 +62,6 @@ - @@ -105,32 +121,54 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + - + - + @@ -177,7 +216,7 @@ @@ -190,7 +229,7 @@ @@ -202,7 +241,7 @@ @@ -214,7 +253,7 @@ @@ -226,7 +265,7 @@ @@ -236,13 +275,36 @@ android:name="android.appwidget.provider" android:resource="@xml/app_widget_card_info" /> + + + + + + + + + + + + + + + android:foregroundServiceType="mediaPlayback" + android:label="@string/app_name"> @@ -256,15 +318,33 @@ android:name="com.lge.support.SPLIT_WINDOW" android:value="true" /> + + android:name="com.google.android.gms.car.application" + android:resource="@xml/automotive_app_desc" /> + + - - + + + + + + + + + diff --git a/app/src/main/assets/contributors.json b/app/src/main/assets/contributors.json deleted file mode 100644 index 639b75535..000000000 --- a/app/src/main/assets/contributors.json +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "name": "Hemanth Savarala", - "summary": "Lead Developer & Designer", - "link": "https://github.com/h4h13", - "profile_image": "https://i.imgur.com/AoVs9oj.jpg" - }, - { - "name": "Lennart Glamann", - "summary": "Designer", - "link": "https://t.me/FlixbusLennart", - "profile_image": "https://i.imgur.com/Q5Nsx1R.jpg" - }, - { - "name": "GameSpeck", - "summary": "Telegram group maintainer", - "link": "https://t.me/GameSpeck", - "profile_image": "https://imgur.com/B15Kb9a.jpg" - }, - { - "name": "Milind Goel", - "summary": "Github & Telegram maintainer", - "link": "https://t.me/MilindGoel15", - "profile_image": "https://i.imgur.com/Bz4De21_d.jpg" - } -] \ No newline at end of file diff --git a/app/src/main/assets/images/daksh.png b/app/src/main/assets/images/daksh.png new file mode 100644 index 000000000..737f9066c Binary files /dev/null and b/app/src/main/assets/images/daksh.png differ diff --git a/app/src/main/assets/images/haythem.jpg b/app/src/main/assets/images/haythem.jpg new file mode 100644 index 000000000..c74527f1d Binary files /dev/null and b/app/src/main/assets/images/haythem.jpg differ diff --git a/app/src/main/assets/images/hemanth.jpg b/app/src/main/assets/images/hemanth.jpg new file mode 100644 index 000000000..b8f5e7805 Binary files /dev/null and b/app/src/main/assets/images/hemanth.jpg differ diff --git a/app/src/main/assets/images/lenny.jpg b/app/src/main/assets/images/lenny.jpg new file mode 100644 index 000000000..7f8025f08 Binary files /dev/null and b/app/src/main/assets/images/lenny.jpg differ diff --git a/app/src/main/assets/images/milind.png b/app/src/main/assets/images/milind.png new file mode 100644 index 000000000..bbf9b8278 Binary files /dev/null and b/app/src/main/assets/images/milind.png differ diff --git a/app/src/main/assets/images/pratham.jpg b/app/src/main/assets/images/pratham.jpg new file mode 100644 index 000000000..7f05ad9d5 Binary files /dev/null and b/app/src/main/assets/images/pratham.jpg differ diff --git a/app/src/main/assets/index.html b/app/src/main/assets/index.html deleted file mode 100644 index 037d52fad..000000000 --- a/app/src/main/assets/index.html +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - -

Phonograph by - Karim Abou Zeid

-

- VinylMusicPlayer by Adrien Poupa

-

RxJava by RxJava - authors

-

Material Dialogs and Cab - by Aidan Michael Follestad

-

- Android Sliding Up Panelby The Umano Team

-

AOSP Support Librariesby AOSP contributors

-

Glide by Sam Judd

-

Retrofit by Square team -

-

- Material Contextual Action Bar by Aidan Michael Follestad

-

OkHttp by Square team

-

- CircleImageView by Henning Dodenhof

-

- MaterialProgressBar by Zhang Hai

-

Android In-App Billing v3 Library by - Henning Dodenhof

-

Advanced RecyclerView by Haruki Hasegawa

-

Android-ObservableScrollView by Soichiro - Kashima

-

Font - used(CIRCULAR STD BOOK FONT) by NIELSON CAETANO

-

Icons by Austin Andrews

-

Material Design City Wallpaper -

- - - diff --git a/app/src/main/assets/license.html b/app/src/main/assets/license.html new file mode 100644 index 000000000..2fd8ba5ed --- /dev/null +++ b/app/src/main/assets/license.html @@ -0,0 +1,76 @@ + + + + + + + + + +

Phonograph by + Karim Abou Zeid

+

AOSP Support Libraries by AOSP contributors

+

Glide by Sam Judd

+

Retrofit by Square team +

+

OkHttp by Square team

+

Koin by Arnaud Giuliani

+

Material Dialogs and Cab + by Aidan Michael Follestad

+

+ Material Contextual Action Bar by Aidan Michael Follestad

+

Advanced RecyclerView by Haruki Hasegawa

+

Custom Activity on Crash by Eduard Ereza Martínez +

+

NanoHttpd by NanoHttpd Team

+

Circular Seekbar by Tankery

+

jAudioTagger by Kanedias

+

Android Fast Scroll by Zhang Hai

+

Image Picker by Dhaval Patel

+

Material Intro by Jan Heinrich Reimer

+

Slidr by Drew Heavner

+

FadingEdgeLayout by bosphere

+

KeyboardVisibilityEvent by Yasuhiro SHIMIZU

+

android-snowfall by Jetradar Mobile

+

Insetter by Chris Banes

+

Icons by Austin Andrews

+

Material Design City Wallpaper +

+ + diff --git a/app/src/main/assets/retro-changelog.html b/app/src/main/assets/retro-changelog.html index c3771c482..b6b1c411a 100644 --- a/app/src/main/assets/retro-changelog.html +++ b/app/src/main/assets/retro-changelog.html @@ -1 +1,466 @@ -

v3.5.010

  • Added grid size and layout change for songs list
  • Removed menu options (No use of having only settings)
  • Added settings option to toolbar
  • Updated internal library

v3.4.970

  • Added default cover with accent color
  • Added date modified option to sort songs
  • Added toggle bluetooth connection to play on device as soon as it connected
  • Major code refactor for library tabs
  • Folder option now in available in tabs
  • Improved drive mode page
  • Improved fit, full, card themes for status visibility
  • Fix tablet version of app
  • Fix Album and Artist details toolbar full width for better accessibility
  • Updated internal libraries

v3.4.900

  • Added playlist search
  • Added Drive mode
  • Added Album and Artist layout change option in library
  • Added Show more album and artist information in details
  • Added Pixel style scroller bar
  • Added current now playing share
  • Fix font issues and colors in some places
  • Improved Full now playing theme

If you see entire app white or dark or black select same theme in settings to fix

FAQ's

*If you face any UI related issues you clear app data and cache, if its not working try to uninstall and install again.

\ No newline at end of file + + + + + + + + +
+
March 30, 2023
+

v6.1.0

+

What's New

+
    +
  • App now targets Android 13, support for Granular media permissions, Photo picker, Per-app language preferences & Predictive back gesture
  • +
+

Fixed

+
    +
  • Fixed playlist reordering crash
  • +
  • Other minor bugs fixes and improvements
  • +
+
+
+
March 13, 2023
+

v6.0.4

+

What's New

+
    +
  • Minor redesign in Playlist details screen
  • +
  • Updated translations
  • +
+

Fixed

+
    +
  • Fixed file popup menu actions in Folders tab
  • +
  • Fixed playlist image loading
  • +
  • Fixed blurry album art in Android 13
  • +
  • Minor bug fixes and improvements
  • +
+
+
+
July 10, 2022
+

v6.0.3Beta

+

Fixed

+
    +
  • Migrated icons to Material symbols
  • +
+
+
+
June 21, 2022
+

v6.0.2Beta

+

Fixed

+
    +
  • Minor bug fixes and improvements
  • +
+
+
+
June 13, 2022
+

v6.0.1Beta

+

Fixed

+
    +
  • Fixed ChromeCast crash
  • +
  • Fixed Slider crashes
  • +
  • Fixed storage related crashes on Android 10
  • +
  • Fixed CrossFade not working Fade Audio is not working
  • +
+
+
+
June 7, 2022
+

v6.0.0Beta

+

What's New

+
    +
  • Better Cast
  • +
  • Mini player in settings screen
  • +
  • Changed Seekbar with Sliders
  • +
  • Added NavigationRailView for Landscape
  • +
  • Show remaining time in Sleep timer dialog
  • +
+

Fixed

+
    +
  • Fixed Top/Recent Artists/Albums not updating (Wrong sort order)
  • +
  • Fixed all Blacklist related crashes
  • +
  • Fix restart button not working in crash activity
  • +
+
+
+
May 25, 2022
+

v5.8.5

+

What's New

+
    +
  • Display song images along in the artist and album details pages
  • +
  • Removed the Internet permissions and all the associated features
  • +
+

Fixed

+
    +
  • Fixed crashing occurs during changing screen orientation
  • +
+
+
+
May 13, 2022
+

v5.8.4

+

What's New

+
    +
  • Added a toggle to enable/disable swipe down to dismiss mini player
  • +
+

Fixed

+
    +
  • Fixed Playback speed and pitch not working when CrossFade is enabled
  • +
  • Fixed crash when adding folders to blacklist
  • +
  • Fix bugs in MD3 theme
  • +
+
+
+
May 07, 2022
+

v5.8.3

+

What's New

+
    +
  • Added a new MD3 now playing theme
  • +
  • Swipe down to dismiss Mini player
  • +
  • Add support for Just Black with Material You
  • +
+

Fixed

+
    +
  • Fixed sharing of files from SD Card
  • +
  • Fix ChromeCast crash and bugs
  • +
  • Fix Audio Crossfade
  • +
  • Tried to fix incorrect song data in notification
  • +
+
+
+
April 8, 2022
+

v5.8.0

+

What's New

+
    +
  • Updated translations
  • +
+

Fixed

+
    +
  • Fixed Classic Notification crash
  • +
  • Fixed crash when clicking on Playlist in the Search Tab
  • +
  • Fixed settings change not reflecting immediately
  • +
  • Fixed shuffle
  • +
  • Fixed Song duration not visible in Card & Blur card themes
  • +
  • Fixed some Album skip styles
  • +
  • Minor bug fixes & UI improvements
  • +
+
+
+
March 13, 2022
+

v5.7.3

+

What's New

+
    +
  • Added adaptive color in Material now playing theme
  • +
  • Added an option to share crash report
  • +
  • Added options to clear, pause history
  • +
+

Fixed

+
    +
  • Adapt Wallpaper accent for better readability
  • +
  • Optimized search
  • +
  • Made sleep timer precise
  • +
+
+
+
February 13, 2022
+

v5.7.2Beta

+

What's New

+
    +
  • Animated splash screen on Android 12 devices
  • +
+

Fixed

+
    +
  • Fixed crash when removing song from Playing queue
  • +
  • Fixed lyrics editing crash
  • +
  • Fixed shuffle button not working
  • +
  • Fixed crash on song deletion
  • +
+
+
+
February 1, 2022
+

v5.7.1Beta

+

What's New

+
    +
  • Added option to disable changing song by swiping anywhere on the now playing screen
  • +
+

Fixed

+
    +
  • Fixed Playlist save on A11+
  • +
  • Fixed Just Black theme
  • +
  • Fixed some UI issues
  • +
+

Improved

+
    +
  • Improvements to search
  • +
+
+
+
January 25, 2022
+

v5.7.0Beta

+

What's New

+
    +
  • Added Android Auto
  • +
  • Added accent color extraction on Android 8.1+ devices
  • +
  • Added new Circle widget
  • +
  • Added Collapsing appbar to library tabs with an option to switch back to simple appbar +
  • +
  • Added Search tab
  • +
  • Added option to use circular play button
  • +
  • Added lyrics editing on A11+ devices again
  • +
  • Added Long Press to forward, rewind current song
  • +
  • Added ability to set Playback speed and pitch
  • +
  • Added option to show lyrics over Cover
  • +
  • Added option to keep screen on when showing lyrics
  • +
  • Added option to switch to Manrope font
  • +
+

Fixed

+
    +
  • Fixed Gapless Playback
  • +
  • Fixed Shuffle FAB going behind Mini Player
  • +
  • Fixed crashes on Pre-marshmallow devices
  • +
  • Blacklisted songs can't be played after opening from outside the app
  • +
  • Fixed various small bugs and some minor improvements
  • +
+
+
+
January 1, 2021
+

v5.6.1

+

Fixed

+
    +
  • Fixed artist covers not updating and showing album cover images.
  • +
  • Fixed FAB's not visible (Shuffle, Save, etc.)
  • +
  • Fixed a crash when a Song is deleted in Artist Details
  • +
  • Fixed Snowfall effect
  • +
  • Fixed empty notification when queue is cleared
  • +
+
+
+
December 25, 2021
+

v5.6.0Beta

+

What's New

+
    +
  • Added Artwork editing for songs
  • +
  • Circle theme has album art now
  • +
  • Upgraded tag editor library, we should support reading tags of more formats now e.g. + opus. +
  • +
  • Added Snowfall effect
  • +
  • Crossfade effect for background when Song is changed for Blur, Blur card themes
  • +
  • Album art is hidden when Show lyrics is enabled
  • +
  • Added fastscroll in Playlists tab
  • +
  • Added Chooser to choose what to restore
  • +
  • Hide BottomNavigation when only one tab is selected in Library Categories(This was + already there but when changing screens it was getting visible) +
  • +
+

Fixed

+
    +
  • Fixed Ringtone crash
  • +
  • Fixed blank album cover bug
  • +
  • Fixed bottom navigation visible in Playing Queue
  • +
  • Fixed lockscreen dragging glitch
  • +
  • Fixed incorrect colors when no cover art is available
  • +
  • Fixed favorite not updating when song is changed
  • +
  • Fixed playlist not getting created & playlist creation crash with same name
  • +
  • Fixed a bug in "Plain" Now playing theme where onClick event is consumed by the views + behind the bottom sheet +
  • +
+
+
+
December 6, 2021
+

v5.4.2Beta

+

Fixed

+
    +
  • Bug Fixes
  • +
+
+
+
December 1, 2021
+

v5.4.1Beta

+

What's New

+
    +
  • Added file selection from system file picker for restore
  • +
  • Added Grid size selection for Playlists
  • +
+

Improved

+
    +
  • Enable Material You by default on Android 12
  • +
  • Reworked Grid Style saving
  • +
  • Improved Playlist preview images
  • +
  • UI improvements
  • +
+

Improved

+
    +
  • Fixed File deletion on Android 10
  • +
  • Fixed Sleep Timer crash
  • +
  • Fixed Bottom Toolbar not clickable in now playing when Shuffle is clicked
  • +
  • Fixed Album Artist sort order
  • +
  • Fixed a crash when clicking the "Clear All" button in the Blacklist folder selection +
  • +
  • Fixed Continuous crashes on A12 when the song ends
  • +
  • Fixed New Music Mix multiple clicks crash
  • +
+
+
+
November 22, 2021
+

v5.4.0Beta

+

What's New

+
    +
  • Material You
  • +
  • Going Edge-to-Edge
  • +
  • Added Backup & restore
  • +
+

Improved

+
    +
  • Improved Animations
  • +
  • Improved Crossfade
  • +
+
+
+
September 06, 2021
+

v5.0.0

+

What's New

+
    +
  • Added ability to Remember last tab
  • +
  • Added Whitelisting songs
  • +
  • You can now browse SDCard from Folders Tab
  • +
+
+
+
August 22, 2021
+

v4.4.0Beta

+

What's New

+
    +
  • Added Crossfade
  • +
  • Multi-select in Album and Artist Details
  • +
  • Albums now show Album Artists instead of artist of first song
  • +
+

Fixed

+
    +
  • Fixed Playlist Preview Images
  • +
+
+
+
August 11, 2021
+

v4.2.30Beta

+

What's New

+
    +
  • Revamped Playlist Tab
  • +
  • Revamped Genres Tab
  • +
  • Added support for embedded Synced Lyrics
  • +
  • Added animated icons
  • +
+

Fixed

+
    +
  • Fixed Language Switching
  • +
  • Fixed some reported bugs
  • +
+
+
+
July 18, 2021
+

v4.2.020Beta

+

What's New

+
    +
  • Added ChromeCast Support
  • +
  • Added Lyrics Editor for Normal and Synced Lyrics
  • +
  • Added Ripple Animation for Color Theme
  • +
  • Added Drag to seek in Tiny Theme
  • +
  • Added Playlist Order
  • +
  • Added Search Filters
  • +
  • Added Audio Fade
  • +
  • Synced Lyrics in all Themes
  • +
  • Swipe anywhere to change song
  • +
+

Improved

+
    +
  • Fixed Navigate by Album Artist
  • +
  • Changed New Music Mix Actions
  • +
  • Improved Animations
  • +
  • And some minor bug fixes and improvements
  • +
+
+
+
October 12, 2020
+

v4.0.10

+

What's New

+
    +
  • Re-built from scratch using MVVM Architecture and JetPack Components
  • +
  • New Material Design icon
  • +
  • Implemented a custom database for playlists
  • +
  • Added new Material Design motions
  • +
  • Bug fixes & performance improvements
  • +
  • Revamped Home tab UI
  • +
  • Android 11 support
  • +
  • And more!
  • +
+
+
+
April 30, 2020
+

v3.5.110Beta

+

What's New

+
    +
  • Changed profile form image to icon
  • +
  • New what's new screen
  • +
  • Added In-App language changer, where you can select language
  • +
+

Improved

+
    +
  • Improved loading of Songs, Albums, Artists, Genres, Playlists
  • +
+
+ \ No newline at end of file diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png index 991844b5e..aa6e4ae9a 100644 Binary files a/app/src/main/ic_launcher-playstore.png and b/app/src/main/ic_launcher-playstore.png differ diff --git a/app/src/main/ic_launcher-web.png b/app/src/main/ic_launcher-web.png index ff0f8b9ff..7e7647db5 100644 Binary files a/app/src/main/ic_launcher-web.png and b/app/src/main/ic_launcher-web.png differ diff --git a/app/src/main/java/code/name/monkey/retromusic/App.kt b/app/src/main/java/code/name/monkey/retromusic/App.kt index afabc12b6..93dfe4d96 100644 --- a/app/src/main/java/code/name/monkey/retromusic/App.kt +++ b/app/src/main/java/code/name/monkey/retromusic/App.kt @@ -1,78 +1,67 @@ /* - * Copyright (c) 2019 Hemanth Savarala. + * Copyright (c) 2020 Hemanth Savarla. * * Licensed under the GNU General Public License v3 * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. + * This is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. + * */ - package code.name.monkey.retromusic -import android.widget.Toast -import androidx.multidex.MultiDexApplication +import android.app.Application +import androidx.preference.PreferenceManager +import cat.ereza.customactivityoncrash.config.CaocConfig import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.util.VersionUtils +import code.name.monkey.retromusic.activities.ErrorActivity +import code.name.monkey.retromusic.activities.MainActivity import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager -import code.name.monkey.retromusic.dagger.DaggerMusicComponent -import code.name.monkey.retromusic.dagger.MusicComponent -import code.name.monkey.retromusic.dagger.module.AppModule -import com.anjlab.android.iab.v3.BillingProcessor -import com.anjlab.android.iab.v3.TransactionDetails +import code.name.monkey.retromusic.helper.WallpaperAccentManager +import org.koin.android.ext.koin.androidContext +import org.koin.core.context.startKoin -class App : MultiDexApplication() { +class App : Application() { - lateinit var billingProcessor: BillingProcessor + private val wallpaperAccentManager = WallpaperAccentManager(this) override fun onCreate() { super.onCreate() instance = this - musicComponent = initDagger(this) + startKoin { + androidContext(this@App) + modules(appModules) + } // default theme if (!ThemeStore.isConfigured(this, 3)) { ThemeStore.editTheme(this) - .accentColorRes(R.color.md_deep_purple_A200) + .accentColorRes(code.name.monkey.appthemehelper.R.color.md_deep_purple_A200) .coloredNavigationBar(true) .commit() } + wallpaperAccentManager.init() if (VersionUtils.hasNougatMR()) DynamicShortcutManager(this).initDynamicShortcuts() - // automatically restores purchases - billingProcessor = BillingProcessor(this, BuildConfig.GOOGLE_PLAY_LICENSING_KEY, - object : BillingProcessor.IBillingHandler { - override fun onProductPurchased(productId: String, details: TransactionDetails?) {} + // setting Error activity + CaocConfig.Builder.create().errorActivity(ErrorActivity::class.java) + .restartActivity(MainActivity::class.java).apply() - override fun onPurchaseHistoryRestored() { - Toast.makeText( - this@App, - R.string.restored_previous_purchase_please_restart, - Toast.LENGTH_LONG - ) - .show() - } - - override fun onBillingError(errorCode: Int, error: Throwable?) {} - - override fun onBillingInitialized() {} - }) + // Set Default values for now playing preferences + // This will reduce startup time for now playing settings fragment as Preference listener of AbsSlidingMusicPanelActivity won't be called + PreferenceManager.setDefaultValues(this, R.xml.pref_now_playing_screen, false) } - private fun initDagger(app: App): MusicComponent = - DaggerMusicComponent.builder() - .appModule(AppModule(app)) - .build() - override fun onTerminate() { super.onTerminate() - billingProcessor.release() + wallpaperAccentManager.release() } companion object { @@ -81,15 +70,5 @@ class App : MultiDexApplication() { fun getContext(): App { return instance!! } - - fun isProVersion(): Boolean { - return BuildConfig.DEBUG || instance?.billingProcessor!!.isPurchased( - PRO_VERSION_PRODUCT_ID - ) - } - - lateinit var musicComponent: MusicComponent - - const val PRO_VERSION_PRODUCT_ID = "pro_version" } } diff --git a/app/src/main/java/code/name/monkey/retromusic/Constants.kt b/app/src/main/java/code/name/monkey/retromusic/Constants.kt index 0b3c6fa9d..31032f62b 100644 --- a/app/src/main/java/code/name/monkey/retromusic/Constants.kt +++ b/app/src/main/java/code/name/monkey/retromusic/Constants.kt @@ -1,53 +1,154 @@ /* - * Copyright (c) 2019 Hemanth Savarala. + * Copyright (c) 2020 Hemanth Savarla. * * Licensed under the GNU General Public License v3 * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. + * This is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. + * */ - package code.name.monkey.retromusic import android.provider.BaseColumns import android.provider.MediaStore object Constants { - - const val RATE_ON_GOOGLE_PLAY = - "https://play.google.com/store/apps/details?id=code.name.monkey.retromusic" - const val TRANSLATE = "http://monkeycodeapp.oneskyapp.com/collaboration/project?id=238534" - const val GITHUB_PROJECT = "https://github.com/h4h13/RetroMusicPlayer" - const val TELEGRAM_CHANGE_LOG = "https://t.me/retromusiclog" + const val TRANSLATE = "https://crowdin.com/project/retromusicplayer" + const val GITHUB_PROJECT = "https://github.com/MuntashirAkon/Metro" + const val TELEGRAM_CHANGE_LOG = "https://t.me/AppManagerChannel" const val USER_PROFILE = "profile.jpg" const val USER_BANNER = "banner.jpg" - const val APP_INSTAGRAM_LINK = "https://www.instagram.com/retromusicapp/" - const val APP_TELEGRAM_LINK = "https://t.me/retromusicapp/" - const val APP_TWITTER_LINK = "https://twitter.com/retromusicapp" - const val FAQ_LINK = "https://github.com/h4h13/RetroMusicPlayer/blob/master/FAQ.md" - const val PINTEREST = "https://in.pinterest.com/retromusicapp/" + const val FAQ_LINK = "https://github.com/MuntashirAkon/Metro/blob/master/FAQ.md" - const val BASE_SELECTION = + const val IS_MUSIC = MediaStore.Audio.AudioColumns.IS_MUSIC + "=1" + " AND " + MediaStore.Audio.AudioColumns.TITLE + " != ''" + const val DATA = "_data" + + @Suppress("Deprecation") val baseProjection = arrayOf( BaseColumns._ID, // 0 MediaStore.Audio.AudioColumns.TITLE, // 1 MediaStore.Audio.AudioColumns.TRACK, // 2 MediaStore.Audio.AudioColumns.YEAR, // 3 MediaStore.Audio.AudioColumns.DURATION, // 4 - MediaStore.Audio.AudioColumns.DATA, // 5 + DATA, // 5 MediaStore.Audio.AudioColumns.DATE_MODIFIED, // 6 MediaStore.Audio.AudioColumns.ALBUM_ID, // 7 MediaStore.Audio.AudioColumns.ALBUM, // 8 MediaStore.Audio.AudioColumns.ARTIST_ID, // 9 - MediaStore.Audio.AudioColumns.ARTIST,// 10 - MediaStore.Audio.AudioColumns.COMPOSER - )// 11 + MediaStore.Audio.AudioColumns.ARTIST, // 10 + MediaStore.Audio.AudioColumns.COMPOSER, // 11 + ALBUM_ARTIST // 12 + ) const val NUMBER_OF_TOP_TRACKS = 99 } + +const val EXTRA_PLAYLIST_TYPE = "type" +const val EXTRA_GENRE = "extra_genre" +const val EXTRA_PLAYLIST = "extra_playlist" +const val EXTRA_PLAYLIST_ID = "extra_playlist_id" +const val EXTRA_ALBUM_ID = "extra_album_id" +const val EXTRA_ARTIST_ID = "extra_artist_id" +const val EXTRA_SONG = "extra_songs" +const val EXTRA_PLAYLISTS = "extra_playlists" +const val LIBRARY_CATEGORIES = "library_categories" +const val EXTRA_SONG_INFO = "extra_song_info" +const val DESATURATED_COLOR = "desaturated_color" +const val BLACK_THEME = "black_theme" +const val KEEP_SCREEN_ON = "keep_screen_on" +const val TOGGLE_HOME_BANNER = "toggle_home_banner" +const val NOW_PLAYING_SCREEN_ID = "now_playing_screen_id" +const val CAROUSEL_EFFECT = "carousel_effect" +const val COLORED_NOTIFICATION = "colored_notification" +const val CLASSIC_NOTIFICATION = "classic_notification" +const val GAP_LESS_PLAYBACK = "gapless_playback" +const val ALBUM_ART_ON_LOCK_SCREEN = "album_art_on_lock_screen" +const val BLURRED_ALBUM_ART = "blurred_album_art" +const val NEW_BLUR_AMOUNT = "new_blur_amount" +const val TOGGLE_HEADSET = "toggle_headset" +const val GENERAL_THEME = "general_theme" +const val ACCENT_COLOR = "accent_color" +const val SHOULD_COLOR_APP_SHORTCUTS = "should_color_app_shortcuts" +const val CIRCULAR_ALBUM_ART = "circular_album_art" +const val USER_NAME = "user_name" +const val TOGGLE_FULL_SCREEN = "toggle_full_screen" +const val TOGGLE_VOLUME = "toggle_volume" +const val ADAPTIVE_COLOR_APP = "adaptive_color_app" +const val HOME_ARTIST_GRID_STYLE = "home_artist_grid_style" +const val HOME_ALBUM_GRID_STYLE = "home_album_grid_style" +const val TOGGLE_ADD_CONTROLS = "toggle_add_controls" +const val ALBUM_COVER_STYLE = "album_cover_style_id" +const val ALBUM_COVER_TRANSFORM = "album_cover_transform" +const val TAB_TEXT_MODE = "tab_text_mode" +const val LANGUAGE_NAME = "language_name" +const val LOCALE_AUTO_STORE_ENABLED = "locale_auto_store_enabled" +const val SLEEP_TIMER_FINISH_SONG = "sleep_timer_finish_song" +const val ALBUM_GRID_STYLE = "album_grid_style_home" +const val ARTIST_GRID_STYLE = "artist_grid_style_home" +const val SAF_SDCARD_URI = "saf_sdcard_uri" +const val SONG_SORT_ORDER = "song_sort_order" +const val SONG_GRID_SIZE = "song_grid_size" +const val GENRE_SORT_ORDER = "genre_sort_order" +const val BLUETOOTH_PLAYBACK = "bluetooth_playback" +const val INITIALIZED_BLACKLIST = "initialized_blacklist" +const val ARTIST_SORT_ORDER = "artist_sort_order" +const val ARTIST_ALBUM_SORT_ORDER = "artist_album_sort_order" +const val ALBUM_SORT_ORDER = "album_sort_order" +const val PLAYLIST_SORT_ORDER = "playlist_sort_order" +const val ALBUM_SONG_SORT_ORDER = "album_song_sort_order" +const val ARTIST_SONG_SORT_ORDER = "artist_song_sort_order" +const val ALBUM_GRID_SIZE = "album_grid_size" +const val ALBUM_GRID_SIZE_LAND = "album_grid_size_land" +const val SONG_GRID_SIZE_LAND = "song_grid_size_land" +const val ARTIST_GRID_SIZE = "artist_grid_size" +const val ARTIST_GRID_SIZE_LAND = "artist_grid_size_land" +const val PLAYLIST_GRID_SIZE = "playlist_grid_size" +const val PLAYLIST_GRID_SIZE_LAND = "playlist_grid_size_land" +const val COLORED_APP_SHORTCUTS = "colored_app_shortcuts" +const val LAST_ADDED_CUTOFF = "last_added_interval" +const val LAST_SLEEP_TIMER_VALUE = "last_sleep_timer_value" +const val NEXT_SLEEP_TIMER_ELAPSED_REALTIME = "next_sleep_timer_elapsed_real_time" +const val IGNORE_MEDIA_STORE_ARTWORK = "ignore_media_store_artwork" +const val LAST_CHANGELOG_VERSION = "last_changelog_version" +const val START_DIRECTORY = "start_directory" +const val RECENTLY_PLAYED_CUTOFF = "recently_played_interval" +const val LOCK_SCREEN = "lock_screen" +const val ALBUM_ARTISTS_ONLY = "album_artists_only" +const val ALBUM_ARTIST = "album_artist" +const val ALBUM_DETAIL_SONG_SORT_ORDER = "album_detail_song_sort_order" +const val ARTIST_DETAIL_SONG_SORT_ORDER = "artist_detail_song_sort_order" +const val LYRICS_OPTIONS = "lyrics_tab_position" +const val CHOOSE_EQUALIZER = "choose_equalizer" +const val EQUALIZER = "equalizer" +const val SONG_GRID_STYLE = "song_grid_style" +const val PAUSE_ON_ZERO_VOLUME = "pause_on_zero_volume" +const val FILTER_SONG = "filter_song" +const val EXPAND_NOW_PLAYING_PANEL = "expand_now_playing_panel" +const val EXTRA_ARTIST_NAME = "extra_artist_name" +const val TOGGLE_SUGGESTIONS = "toggle_suggestions" +const val AUDIO_FADE_DURATION = "audio_fade_duration" +const val CROSS_FADE_DURATION = "cross_fade_duration" +const val SHOW_LYRICS = "show_lyrics" +const val REMEMBER_LAST_TAB = "remember_last_tab" +const val LAST_USED_TAB = "last_used_tab" +const val WHITELIST_MUSIC = "whitelist_music" +const val MATERIAL_YOU = "material_you" +const val SNOWFALL = "snowfall" +const val LYRICS_TYPE = "lyrics_type" +const val PLAYBACK_SPEED = "playback_speed" +const val PLAYBACK_PITCH = "playback_pitch" +const val CUSTOM_FONT = "custom_font" +const val APPBAR_MODE = "appbar_mode" +const val WALLPAPER_ACCENT = "wallpaper_accent" +const val SCREEN_ON_LYRICS = "screen_on_lyrics" +const val CIRCLE_PLAY_BUTTON = "circle_play_button" +const val SWIPE_ANYWHERE_NOW_PLAYING = "swipe_anywhere_now_playing" +const val PAUSE_HISTORY = "pause_history" +const val MANAGE_AUDIO_FOCUS = "manage_audio_focus" +const val SWIPE_DOWN_DISMISS = "swipe_to_dismiss" \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/HomeSection.kt b/app/src/main/java/code/name/monkey/retromusic/HomeSection.kt new file mode 100644 index 000000000..4f1273a03 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/HomeSection.kt @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020 Hemanth Savarla. + * + * Licensed under the GNU General Public License v3 + * + * This is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + */ +package code.name.monkey.retromusic + +import androidx.annotation.IntDef + +@IntDef( + RECENT_ALBUMS, + TOP_ALBUMS, + RECENT_ARTISTS, + TOP_ARTISTS, + SUGGESTIONS, + FAVOURITES, + GENRES, + PLAYLISTS +) +@Retention(AnnotationRetention.SOURCE) +annotation class HomeSection + +const val RECENT_ALBUMS = 3 +const val TOP_ALBUMS = 1 +const val RECENT_ARTISTS = 2 +const val TOP_ARTISTS = 0 +const val SUGGESTIONS = 5 +const val FAVOURITES = 4 +const val GENRES = 6 +const val PLAYLISTS = 7 +const val HISTORY_PLAYLIST = 8 +const val LAST_ADDED_PLAYLIST = 9 +const val TOP_PLAYED_PLAYLIST = 10 diff --git a/app/src/main/java/code/name/monkey/retromusic/LanguageContextWrapper.java b/app/src/main/java/code/name/monkey/retromusic/LanguageContextWrapper.java deleted file mode 100644 index 72ae6aba3..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/LanguageContextWrapper.java +++ /dev/null @@ -1,42 +0,0 @@ -package code.name.monkey.retromusic; - -import android.content.Context; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.os.LocaleList; - -import java.util.Locale; - -import code.name.monkey.appthemehelper.util.VersionUtils; - -public class LanguageContextWrapper extends android.content.ContextWrapper { - - public LanguageContextWrapper(Context base) { - super(base); - } - - public static LanguageContextWrapper wrap(Context context, Locale newLocale) { - Resources res = context.getResources(); - Configuration configuration = res.getConfiguration(); - - if (VersionUtils.INSTANCE.hasNougatMR()) { - configuration.setLocale(newLocale); - - LocaleList localeList = new LocaleList(newLocale); - LocaleList.setDefault(localeList); - configuration.setLocales(localeList); - - context = context.createConfigurationContext(configuration); - - } else if (VersionUtils.INSTANCE.hasLollipop()) { - configuration.setLocale(newLocale); - context = context.createConfigurationContext(configuration); - - } else { - configuration.locale = newLocale; - res.updateConfiguration(configuration, res.getDisplayMetrics()); - } - - return new LanguageContextWrapper(context); - } -} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt new file mode 100644 index 000000000..d88f8a760 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt @@ -0,0 +1,156 @@ +package code.name.monkey.retromusic + +import androidx.room.Room +import code.name.monkey.retromusic.auto.AutoMusicProvider +import code.name.monkey.retromusic.db.MIGRATION_23_24 +import code.name.monkey.retromusic.db.RetroDatabase +import code.name.monkey.retromusic.fragments.LibraryViewModel +import code.name.monkey.retromusic.fragments.albums.AlbumDetailsViewModel +import code.name.monkey.retromusic.fragments.artists.ArtistDetailsViewModel +import code.name.monkey.retromusic.fragments.genres.GenreDetailsViewModel +import code.name.monkey.retromusic.fragments.playlists.PlaylistDetailsViewModel +import code.name.monkey.retromusic.model.Genre +import code.name.monkey.retromusic.repository.* +import org.koin.android.ext.koin.androidContext +import org.koin.androidx.viewmodel.dsl.viewModel +import org.koin.dsl.bind +import org.koin.dsl.module + +private val roomModule = module { + + single { + Room.databaseBuilder(androidContext(), RetroDatabase::class.java, "playlist.db") + .addMigrations(MIGRATION_23_24) + .build() + } + + factory { + get().playlistDao() + } + + factory { + get().playCountDao() + } + + factory { + get().historyDao() + } + + single { + RealRoomRepository(get(), get(), get()) + } bind RoomRepository::class +} +private val autoModule = module { + single { + AutoMusicProvider( + androidContext(), + get(), + get(), + get(), + get(), + get(), + get() + ) + } +} +private val mainModule = module { + single { + androidContext().contentResolver + } +} +private val dataModule = module { + single { + RealRepository( + get(), + get(), + get(), + get(), + get(), + get(), + get(), + get(), + get(), + get(), + ) + } bind Repository::class + + single { + RealSongRepository(get()) + } bind SongRepository::class + + single { + RealGenreRepository(get(), get()) + } bind GenreRepository::class + + single { + RealAlbumRepository(get()) + } bind AlbumRepository::class + + single { + RealArtistRepository(get(), get()) + } bind ArtistRepository::class + + single { + RealPlaylistRepository(get()) + } bind PlaylistRepository::class + + single { + RealTopPlayedRepository(get(), get(), get(), get()) + } bind TopPlayedRepository::class + + single { + RealLastAddedRepository( + get(), + get(), + get() + ) + } bind LastAddedRepository::class + + single { + RealSearchRepository( + get(), + get(), + get(), + get(), + get() + ) + } +} + +private val viewModules = module { + + viewModel { + LibraryViewModel(get()) + } + + viewModel { (albumId: Long) -> + AlbumDetailsViewModel( + get(), + albumId + ) + } + + viewModel { (artistId: Long?, artistName: String?) -> + ArtistDetailsViewModel( + get(), + artistId, + artistName + ) + } + + viewModel { (playlistId: Long) -> + PlaylistDetailsViewModel( + get(), + playlistId + ) + } + + viewModel { (genre: Genre) -> + GenreDetailsViewModel( + get(), + genre + ) + } +} + +val appModules = listOf(mainModule, dataModule, autoModule, viewModules, roomModule) \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/Result.kt b/app/src/main/java/code/name/monkey/retromusic/Result.kt deleted file mode 100644 index 64b638a6e..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/Result.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - -package code.name.monkey.retromusic - -/** - * Created by hemanths on 2019-10-23. - */ - -sealed class Result { - - class Success(val data: T) : Result() - - class Error(val exception: Throwable) : Result() -} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/AboutActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/AboutActivity.kt deleted file mode 100644 index 704e92c6f..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/activities/AboutActivity.kt +++ /dev/null @@ -1,171 +0,0 @@ -package code.name.monkey.retromusic.activities - -import android.content.Intent -import android.content.pm.PackageManager -import android.net.Uri -import android.os.Bundle -import android.view.MenuItem -import android.view.View -import androidx.core.app.ShareCompat -import androidx.recyclerview.widget.DefaultItemAnimator -import androidx.recyclerview.widget.LinearLayoutManager -import code.name.monkey.appthemehelper.util.ATHUtil -import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper -import code.name.monkey.retromusic.App -import code.name.monkey.retromusic.Constants.APP_INSTAGRAM_LINK -import code.name.monkey.retromusic.Constants.APP_TELEGRAM_LINK -import code.name.monkey.retromusic.Constants.APP_TWITTER_LINK -import code.name.monkey.retromusic.Constants.FAQ_LINK -import code.name.monkey.retromusic.Constants.GITHUB_PROJECT -import code.name.monkey.retromusic.Constants.PINTEREST -import code.name.monkey.retromusic.Constants.RATE_ON_GOOGLE_PLAY -import code.name.monkey.retromusic.Constants.TELEGRAM_CHANGE_LOG -import code.name.monkey.retromusic.Constants.TRANSLATE -import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.activities.base.AbsBaseActivity -import code.name.monkey.retromusic.adapter.ContributorAdapter -import code.name.monkey.retromusic.model.Contributor -import code.name.monkey.retromusic.util.NavigationUtil -import code.name.monkey.retromusic.util.PreferenceUtil -import com.afollestad.materialdialogs.LayoutMode -import com.afollestad.materialdialogs.MaterialDialog -import com.afollestad.materialdialogs.bottomsheets.BottomSheet -import com.afollestad.materialdialogs.list.listItems -import com.google.gson.Gson -import com.google.gson.reflect.TypeToken -import kotlinx.android.synthetic.main.activity_about.* -import kotlinx.android.synthetic.main.card_credit.* -import kotlinx.android.synthetic.main.card_other.* -import kotlinx.android.synthetic.main.card_retro_info.* -import kotlinx.android.synthetic.main.card_social.* -import java.io.IOException -import java.nio.charset.StandardCharsets - -class AboutActivity : AbsBaseActivity(), View.OnClickListener { - - private val contributorsJson: String? - get() { - val json: String - try { - val inputStream = assets.open("contributors.json") - val size = inputStream.available() - val buffer = ByteArray(size) - inputStream.read(buffer) - inputStream.close() - json = String(buffer, StandardCharsets.UTF_8) - } catch (ex: IOException) { - ex.printStackTrace() - return null - } - return json - } - - - override fun onCreate(savedInstanceState: Bundle?) { - setDrawUnderStatusBar() - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_about) - setStatusbarColorAuto() - setNavigationbarColorAuto() - setLightNavigationBar(true) - - val toolbarColor = ATHUtil.resolveColor(this, R.attr.colorSurface) - toolbar.setBackgroundColor(toolbarColor) - ToolbarContentTintHelper.colorBackButton(toolbar) - setSupportActionBar(toolbar) - version.setSummary(getAppVersion()) - setUpView() - loadContributors() - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - if (item.itemId == android.R.id.home) { - onBackPressed() - return true - } - return super.onOptionsItemSelected(item) - } - - private fun openUrl(url: String) { - val i = Intent(Intent.ACTION_VIEW) - i.data = Uri.parse(url) - i.flags = Intent.FLAG_ACTIVITY_NEW_TASK - startActivity(i) - } - - private fun setUpView() { - appGithub.setOnClickListener(this) - faqLink.setOnClickListener(this) - telegramLink.setOnClickListener(this) - appRate.setOnClickListener(this) - appTranslation.setOnClickListener(this) - appShare.setOnClickListener(this) - donateLink.setOnClickListener(this) - instagramLink.setOnClickListener(this) - twitterLink.setOnClickListener(this) - changelog.setOnClickListener(this) - openSource.setOnClickListener(this) - pinterestLink.setOnClickListener(this) - bugReportLink.setOnClickListener(this) - } - - override fun onClick(view: View) { - when (view.id) { - R.id.pinterestLink -> openUrl(PINTEREST) - R.id.faqLink -> openUrl(FAQ_LINK) - R.id.telegramLink -> openUrl(APP_TELEGRAM_LINK) - R.id.appGithub -> openUrl(GITHUB_PROJECT) - R.id.appTranslation -> openUrl(TRANSLATE) - R.id.appRate -> openUrl(RATE_ON_GOOGLE_PLAY) - R.id.appShare -> shareApp() - R.id.donateLink -> NavigationUtil.goToSupportDevelopment(this) - R.id.instagramLink -> openUrl(APP_INSTAGRAM_LINK) - R.id.twitterLink -> openUrl(APP_TWITTER_LINK) - R.id.changelog -> showChangeLogOptions() - R.id.openSource -> NavigationUtil.goToOpenSource(this) - R.id.bugReportLink -> NavigationUtil.bugReport(this) - } - } - - private fun showChangeLogOptions() { - MaterialDialog(this, BottomSheet(LayoutMode.WRAP_CONTENT)).show { - cornerRadius(PreferenceUtil.getInstance(this@AboutActivity).dialogCorner) - listItems(items = listOf("Telegram Channel", "App")) { _, position, _ -> - if (position == 0) { - openUrl(TELEGRAM_CHANGE_LOG) - } else { - NavigationUtil.gotoWhatNews(this@AboutActivity) - } - } - } - } - - private fun getAppVersion(): String { - return try { - val isPro = if (App.isProVersion()) "Pro" else "Free" - val packageInfo = packageManager.getPackageInfo(packageName, 0) - "${packageInfo.versionName} $isPro" - } catch (e: PackageManager.NameNotFoundException) { - e.printStackTrace() - "0.0.0" - } - } - - private fun shareApp() { - ShareCompat.IntentBuilder.from(this).setType("text/plain") - .setChooserTitle(R.string.share_app) - .setText(String.format(getString(R.string.app_share), packageName)).startChooser() - } - - private fun loadContributors() { - val type = object : TypeToken>() { - - }.type - val contributors = Gson().fromJson>(contributorsJson, type) - - val contributorAdapter = ContributorAdapter(contributors) - recyclerView.layoutManager = LinearLayoutManager(this) - recyclerView.itemAnimator = DefaultItemAnimator() - recyclerView.adapter = contributorAdapter - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/AlbumDetailsActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/AlbumDetailsActivity.kt deleted file mode 100644 index 7be3cbeb0..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/activities/AlbumDetailsActivity.kt +++ /dev/null @@ -1,396 +0,0 @@ -package code.name.monkey.retromusic.activities - -import android.app.ActivityOptions -import android.content.Intent -import android.os.Bundle -import android.transition.Slide -import android.view.Menu -import android.view.MenuItem -import android.view.SubMenu -import android.view.View -import android.widget.ImageView -import androidx.core.app.ActivityCompat -import androidx.recyclerview.widget.DefaultItemAnimator -import androidx.recyclerview.widget.GridLayoutManager -import androidx.recyclerview.widget.LinearLayoutManager -import code.name.monkey.appthemehelper.util.ATHUtil -import code.name.monkey.appthemehelper.util.MaterialUtil -import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper -import code.name.monkey.retromusic.App -import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity -import code.name.monkey.retromusic.activities.tageditor.AbsTagEditorActivity -import code.name.monkey.retromusic.activities.tageditor.AlbumTagEditorActivity -import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter -import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter -import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog -import code.name.monkey.retromusic.dialogs.DeleteSongsDialog -import code.name.monkey.retromusic.extensions.ripAlpha -import code.name.monkey.retromusic.extensions.show -import code.name.monkey.retromusic.glide.AlbumGlideRequest -import code.name.monkey.retromusic.glide.ArtistGlideRequest -import code.name.monkey.retromusic.glide.RetroMusicColoredTarget -import code.name.monkey.retromusic.helper.MusicPlayerRemote -import code.name.monkey.retromusic.helper.SortOrder.AlbumSongSortOrder -import code.name.monkey.retromusic.interfaces.CabHolder -import code.name.monkey.retromusic.model.Album -import code.name.monkey.retromusic.model.Artist -import code.name.monkey.retromusic.mvp.presenter.AlbumDetailsPresenter -import code.name.monkey.retromusic.mvp.presenter.AlbumDetailsView -import code.name.monkey.retromusic.rest.model.LastFmAlbum -import code.name.monkey.retromusic.util.* -import com.afollestad.materialcab.MaterialCab -import com.bumptech.glide.Glide -import kotlinx.android.synthetic.main.activity_album.* -import kotlinx.android.synthetic.main.activity_album_content.* -import java.util.* -import javax.inject.Inject -import android.util.Pair as UtilPair - -class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsView, CabHolder { - override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab { - cab?.let { - if (it.isActive) it.finish() - } - cab = MaterialCab(this, R.id.cab_stub) - .setMenu(menuRes) - .setCloseDrawableRes(R.drawable.ic_close_white_24dp) - .setBackgroundColor( - RetroColorUtil.shiftBackgroundColorForLightText( - ATHUtil.resolveColor( - this, - R.attr.colorSurface - ) - ) - ) - .start(callback) - return cab as MaterialCab - } - - private lateinit var simpleSongAdapter: SimpleSongAdapter - private lateinit var album: Album - private lateinit var artistImage: ImageView - private var cab: MaterialCab? = null - private val savedSortOrder: String - get() = PreferenceUtil.getInstance(this).albumDetailSongSortOrder - - override fun createContentView(): View { - return wrapSlidingMusicPanel(R.layout.activity_album) - } - - @Inject - lateinit var albumDetailsPresenter: AlbumDetailsPresenter - - private fun windowEnterTransition() { - val slide = Slide() - slide.excludeTarget(R.id.appBarLayout, true) - slide.excludeTarget(R.id.status_bar, true) - slide.excludeTarget(android.R.id.statusBarBackground, true) - slide.excludeTarget(android.R.id.navigationBarBackground, true) - - window.enterTransition = slide - } - - override fun onCreate(savedInstanceState: Bundle?) { - setDrawUnderStatusBar() - super.onCreate(savedInstanceState) - toggleBottomNavigationView(true) - setStatusbarColorAuto() - setNavigationbarColorAuto() - setTaskDescriptionColorAuto() - setLightNavigationBar(true) - window.sharedElementsUseOverlay = true - - App.musicComponent.inject(this) - albumDetailsPresenter.attachView(this) - - if (intent.extras!!.containsKey(EXTRA_ALBUM_ID)) { - intent.extras?.getInt(EXTRA_ALBUM_ID)?.let { - albumDetailsPresenter.loadAlbum(it) - albumCoverContainer?.transitionName = - "${getString(R.string.transition_album_art)}_$it" - } - } else { - finish() - } - - windowEnterTransition() - ActivityCompat.postponeEnterTransition(this) - - - artistImage = findViewById(R.id.artistImage) - - setupRecyclerView() - - artistImage.setOnClickListener { - val artistPairs = ActivityOptions.makeSceneTransitionAnimation( - this, - UtilPair.create( - artistImage, - "${getString(R.string.transition_artist_image)}_${album.artistId}" - ) - ) - NavigationUtil.goToArtistOptions(this, album.artistId, artistPairs) - } - playAction.apply { - setOnClickListener { MusicPlayerRemote.openQueue(album.songs!!, 0, true) } - } - shuffleAction.apply { - setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(album.songs!!, true) } - } - - aboutAlbumText.setOnClickListener { - if (aboutAlbumText.maxLines == 4) { - aboutAlbumText.maxLines = Integer.MAX_VALUE - } else { - aboutAlbumText.maxLines = 4 - } - } - } - - private fun setupRecyclerView() { - simpleSongAdapter = SimpleSongAdapter(this, ArrayList(), R.layout.item_song, this) - recyclerView.apply { - layoutManager = LinearLayoutManager(this@AlbumDetailsActivity) - itemAnimator = DefaultItemAnimator() - isNestedScrollingEnabled = false - adapter = simpleSongAdapter - } - } - - override fun onDestroy() { - super.onDestroy() - albumDetailsPresenter.detachView() - } - - override fun complete() { - ActivityCompat.startPostponedEnterTransition(this) - } - - override fun album(album: Album) { - complete() - if (album.songs!!.isEmpty()) { - finish() - return - } - this.album = album - - albumTitle.text = album.title - if (MusicUtil.getYearString(album.year) == "-") { - albumText.text = String.format( - "%s • %s", - album.artistName, - MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(album.songs)) - ) - } else { - albumText.text = String.format( - "%s • %s • %s", - album.artistName, - MusicUtil.getYearString(album.year), - MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(album.songs)) - ) - } - loadAlbumCover() - simpleSongAdapter.swapDataSet(album.songs) - albumDetailsPresenter.loadMore(album.artistId) - albumDetailsPresenter.aboutAlbum(album.artistName!!, album.title!!) - } - - override fun moreAlbums(albums: List) { - moreTitle.show() - moreRecyclerView.show() - moreTitle.text = String.format(getString(R.string.label_more_from), album.artistName) - - val albumAdapter = HorizontalAlbumAdapter(this, albums, null) - moreRecyclerView.layoutManager = GridLayoutManager( - this, - 1, - GridLayoutManager.HORIZONTAL, - false - ) - moreRecyclerView.adapter = albumAdapter - } - - override fun aboutAlbum(lastFmAlbum: LastFmAlbum) { - if (lastFmAlbum.album != null) { - if (lastFmAlbum.album.wiki != null) { - aboutAlbumText.show() - aboutAlbumTitle.show() - aboutAlbumTitle.text = String.format(getString(R.string.about_album_label), lastFmAlbum.album.name) - aboutAlbumText.text = lastFmAlbum.album.wiki.content - } - if (lastFmAlbum.album.listeners.isNotEmpty()) { - listeners.show() - listenersLabel.show() - scrobbles.show() - scrobblesLabel.show() - - listeners.text = RetroUtil.formatValue(lastFmAlbum.album.listeners.toFloat()) - scrobbles.text = RetroUtil.formatValue(lastFmAlbum.album.playcount.toFloat()) - } - } - } - - override fun loadArtistImage(artist: Artist) { - ArtistGlideRequest.Builder.from(Glide.with(this), artist) - .generatePalette(this) - .build() - .dontAnimate() - .dontTransform() - .into(object : RetroMusicColoredTarget(artistImage) { - override fun onColorReady(color: Int) { - } - }) - } - - private fun loadAlbumCover() { - AlbumGlideRequest.Builder.from(Glide.with(this), album.safeGetFirstSong()) - .checkIgnoreMediaStore(this) - .ignoreMediaStore(PreferenceUtil.getInstance(this).ignoreMediaStoreArtwork()) - .generatePalette(this) - .build() - .dontAnimate() - .dontTransform() - .into(object : RetroMusicColoredTarget(image) { - override fun onColorReady(color: Int) { - setColors(color) - } - }) - } - - private fun setColors(color: Int) { - val textColor = if (PreferenceUtil.getInstance(this).adaptiveColor) - color.ripAlpha() - else - ATHUtil.resolveColor(this, android.R.attr.textColorPrimary) - - songTitle.setTextColor(textColor) - moreTitle.setTextColor(textColor) - aboutAlbumTitle.setTextColor(textColor) - - val buttonColor = if (PreferenceUtil.getInstance(this).adaptiveColor) - color.ripAlpha() - else - ATHUtil.resolveColor(this, R.attr.colorSurface) - - MaterialUtil.setTint(button = shuffleAction, color = buttonColor) - MaterialUtil.setTint(button = playAction, color = buttonColor) - - val toolbarColor = ATHUtil.resolveColor(this, R.attr.colorSurface) - toolbar.setBackgroundColor(toolbarColor) - setSupportActionBar(toolbar) - supportActionBar?.title = null - } - - override fun onCreateOptionsMenu(menu: Menu): Boolean { - menuInflater.inflate(R.menu.menu_album_detail, menu) - val sortOrder = menu.findItem(R.id.action_sort_order) - setUpSortOrderMenu(sortOrder.subMenu) - ToolbarContentTintHelper.handleOnCreateOptionsMenu( - this, - toolbar, - menu, - getToolbarBackgroundColor(toolbar) - ) - return super.onCreateOptionsMenu(menu) - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - return handleSortOrderMenuItem(item) - } - - private fun handleSortOrderMenuItem(item: MenuItem): Boolean { - var sortOrder: String? = null - val songs = simpleSongAdapter.dataSet - when (item.itemId) { - R.id.action_play_next -> { - MusicPlayerRemote.playNext(songs) - return true - } - R.id.action_add_to_current_playing -> { - MusicPlayerRemote.enqueue(songs) - return true - } - R.id.action_add_to_playlist -> { - AddToPlaylistDialog.create(songs).show(supportFragmentManager, "ADD_PLAYLIST") - return true - } - R.id.action_delete_from_device -> { - DeleteSongsDialog.create(songs).show(supportFragmentManager, "DELETE_SONGS") - return true - } - android.R.id.home -> { - super.onBackPressed() - return true - } - R.id.action_tag_editor -> { - val intent = Intent(this, AlbumTagEditorActivity::class.java) - intent.putExtra(AbsTagEditorActivity.EXTRA_ID, album.id) - val options = ActivityOptions.makeSceneTransitionAnimation( - this, - albumCoverContainer, - "${getString(R.string.transition_album_art)}_${album.id}" - ) - startActivityForResult(intent, TAG_EDITOR_REQUEST, options.toBundle()) - return true - } - /*Sort*/ - R.id.action_sort_order_title -> sortOrder = AlbumSongSortOrder.SONG_A_Z - R.id.action_sort_order_title_desc -> sortOrder = AlbumSongSortOrder.SONG_Z_A - R.id.action_sort_order_track_list -> sortOrder = AlbumSongSortOrder.SONG_TRACK_LIST - R.id.action_sort_order_artist_song_duration -> sortOrder = - AlbumSongSortOrder.SONG_DURATION - } - if (sortOrder != null) { - item.isChecked = true - setSaveSortOrder(sortOrder) - } - return true - } - - private fun setUpSortOrderMenu(sortOrder: SubMenu) { - when (savedSortOrder) { - AlbumSongSortOrder.SONG_A_Z -> sortOrder.findItem(R.id.action_sort_order_title) - .isChecked = true - AlbumSongSortOrder.SONG_Z_A -> sortOrder.findItem(R.id.action_sort_order_title_desc) - .isChecked = true - AlbumSongSortOrder.SONG_TRACK_LIST -> sortOrder.findItem(R.id.action_sort_order_track_list) - .isChecked = - true - AlbumSongSortOrder.SONG_DURATION -> sortOrder.findItem(R.id.action_sort_order_artist_song_duration) - .isChecked = true - } - } - - private fun setSaveSortOrder(sortOrder: String?) { - PreferenceUtil.getInstance(this).albumDetailSongSortOrder = sortOrder - reload() - } - - override fun onMediaStoreChanged() { - super.onMediaStoreChanged() - reload() - } - - private fun reload() { - if (intent.extras!!.containsKey(EXTRA_ALBUM_ID)) { - intent.extras?.getInt(EXTRA_ALBUM_ID)?.let { albumDetailsPresenter.loadAlbum(it) } - } else { - finish() - } - } - - override fun onBackPressed() { - if (cab != null && cab!!.isActive) { - cab?.finish() - } else { - super.onBackPressed() - } - } - - companion object { - - const val EXTRA_ALBUM_ID = "extra_album_id" - private const val TAG_EDITOR_REQUEST = 2001 - } -} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/ArtistDetailActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/ArtistDetailActivity.kt deleted file mode 100755 index e0fdbe4a0..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/activities/ArtistDetailActivity.kt +++ /dev/null @@ -1,347 +0,0 @@ -package code.name.monkey.retromusic.activities - -import android.app.Activity -import android.content.Intent -import android.os.Build -import android.os.Bundle -import android.text.Html -import android.text.Spanned -import android.transition.Slide -import android.view.Menu -import android.view.MenuItem -import android.view.View -import android.widget.Toast -import androidx.core.app.ActivityCompat -import androidx.core.text.HtmlCompat -import androidx.recyclerview.widget.DefaultItemAnimator -import androidx.recyclerview.widget.GridLayoutManager -import androidx.recyclerview.widget.LinearLayoutManager -import code.name.monkey.appthemehelper.util.ATHUtil -import code.name.monkey.appthemehelper.util.MaterialUtil -import code.name.monkey.retromusic.App -import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity -import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter -import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter -import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog -import code.name.monkey.retromusic.extensions.ripAlpha -import code.name.monkey.retromusic.extensions.show -import code.name.monkey.retromusic.glide.ArtistGlideRequest -import code.name.monkey.retromusic.glide.RetroMusicColoredTarget -import code.name.monkey.retromusic.helper.MusicPlayerRemote -import code.name.monkey.retromusic.interfaces.CabHolder -import code.name.monkey.retromusic.model.Artist -import code.name.monkey.retromusic.mvp.presenter.ArtistDetailsPresenter -import code.name.monkey.retromusic.mvp.presenter.ArtistDetailsView -import code.name.monkey.retromusic.rest.model.LastFmArtist -import code.name.monkey.retromusic.util.* -import com.afollestad.materialcab.MaterialCab -import com.bumptech.glide.Glide -import kotlinx.android.synthetic.main.activity_artist_content.* -import kotlinx.android.synthetic.main.activity_artist_details.* -import java.util.* -import javax.inject.Inject -import kotlin.collections.ArrayList - -class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailsView, CabHolder { - override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab { - cab?.let { - if (it.isActive) it.finish() - } - cab = MaterialCab(this, R.id.cab_stub) - .setMenu(menuRes) - .setCloseDrawableRes(R.drawable.ic_close_white_24dp) - .setBackgroundColor( - RetroColorUtil.shiftBackgroundColorForLightText( - ATHUtil.resolveColor( - this, - R.attr.colorSurface - ) - ) - ) - .start(callback) - return cab as MaterialCab - } - - private var cab: MaterialCab? = null - private var biography: Spanned? = null - private lateinit var artist: Artist - private lateinit var songAdapter: SimpleSongAdapter - private lateinit var albumAdapter: HorizontalAlbumAdapter - private var forceDownload: Boolean = false - - override fun createContentView(): View { - return wrapSlidingMusicPanel(R.layout.activity_artist_details) - } - - @Inject - lateinit var artistDetailsPresenter: ArtistDetailsPresenter - - private fun windowEnterTransition() { - val slide = Slide() - slide.excludeTarget(R.id.appBarLayout, true) - slide.excludeTarget(R.id.status_bar, true) - slide.excludeTarget(android.R.id.statusBarBackground, true) - slide.excludeTarget(android.R.id.navigationBarBackground, true) - window.enterTransition = slide - } - - override fun onCreate(savedInstanceState: Bundle?) { - setDrawUnderStatusBar() - super.onCreate(savedInstanceState) - toggleBottomNavigationView(true) - setStatusbarColorAuto() - setNavigationbarColorAuto() - setTaskDescriptionColorAuto() - setLightNavigationBar(true) - window.sharedElementsUseOverlay = true - - App.musicComponent.inject(this) - artistDetailsPresenter.attachView(this) - - if (intent.extras!!.containsKey(EXTRA_ARTIST_ID)) { - intent.extras?.getInt(EXTRA_ARTIST_ID)?.let { - artistDetailsPresenter.loadArtist(it) - val name = "${getString(R.string.transition_artist_image)}_$it" - artistCoverContainer?.transitionName = name - } - } else { - finish() - } - - windowEnterTransition() - ActivityCompat.postponeEnterTransition(this) - - setupRecyclerView() - - playAction.apply { - setOnClickListener { MusicPlayerRemote.openQueue(artist.songs, 0, true) } - } - shuffleAction.apply { - setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(artist.songs, true) } - } - - biographyText.setOnClickListener { - if (biographyText.maxLines == 4) { - biographyText.maxLines = Integer.MAX_VALUE - } else { - biographyText.maxLines = 4 - } - } - } - - override fun onDestroy() { - super.onDestroy() - artistDetailsPresenter.detachView() - } - - private fun setupRecyclerView() { - albumAdapter = HorizontalAlbumAdapter(this, ArrayList(), null) - albumRecyclerView.apply { - itemAnimator = DefaultItemAnimator() - layoutManager = GridLayoutManager(this.context, 1, GridLayoutManager.HORIZONTAL, false) - adapter = albumAdapter - } - songAdapter = SimpleSongAdapter(this, ArrayList(), R.layout.item_song, this) - recyclerView.apply { - itemAnimator = DefaultItemAnimator() - layoutManager = LinearLayoutManager(this.context) - adapter = songAdapter - } - } - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - when (requestCode) { - REQUEST_CODE_SELECT_IMAGE -> if (resultCode == Activity.RESULT_OK) { - data?.data?.let { - CustomArtistImageUtil.getInstance(this).setCustomArtistImage(artist, it) - } - } - else -> if (resultCode == Activity.RESULT_OK) { - reload() - } - } - } - - override fun showEmptyView() { - } - - override fun complete() { - ActivityCompat.startPostponedEnterTransition(this) - } - - override fun artist(artist: Artist) { - complete() - if (artist.songCount <= 0) { - finish() - } - this.artist = artist - loadArtistImage() - - if (RetroUtil.isAllowedToDownloadMetadata(this)) { - loadBiography(artist.name) - } - artistTitle.text = artist.name - text.text = String.format( - "%s • %s", - MusicUtil.getArtistInfoString(this, artist), - MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(artist.songs)) - ) - - songAdapter.swapDataSet(artist.songs) - albumAdapter.swapDataSet(artist.albums!!) - } - - private fun loadBiography( - name: String, - lang: String? = Locale.getDefault().language - ) { - biography = null - this.lang = lang - artistDetailsPresenter.loadBiography(name, lang, null) - } - - override fun artistInfo(lastFmArtist: LastFmArtist?) { - if (lastFmArtist != null && lastFmArtist.artist != null) { - val bioContent = lastFmArtist.artist.bio.content - if (bioContent != null && bioContent.trim { it <= ' ' }.isNotEmpty()) { - biographyText.visibility = View.VISIBLE - biographyTitle.visibility = View.VISIBLE - biography = HtmlCompat.fromHtml(bioContent,HtmlCompat.FROM_HTML_MODE_LEGACY) - biographyText.text = biography - if (lastFmArtist.artist.stats.listeners.isNotEmpty()) { - listeners.show() - listenersLabel.show() - scrobbles.show() - scrobblesLabel.show() - - listeners.text = - RetroUtil.formatValue(lastFmArtist.artist.stats.listeners.toFloat()) - scrobbles.text = - RetroUtil.formatValue(lastFmArtist.artist.stats.playcount.toFloat()) - } - } - } - - // If the "lang" parameter is set and no biography is given, retry with default language - if (biography == null && lang != null) { - loadBiography(artist.name, null) - } - } - - private var lang: String? = null - - private fun loadArtistImage() { - ArtistGlideRequest.Builder.from(Glide.with(this), artist).generatePalette(this).build() - .dontAnimate().into(object : RetroMusicColoredTarget(image) { - override fun onColorReady(color: Int) { - setColors(color) - } - }) - } - - private fun setColors(color: Int) { - val textColor = if (PreferenceUtil.getInstance(this).adaptiveColor) - color.ripAlpha() - else - ATHUtil.resolveColor(this, android.R.attr.textColorPrimary) - - albumTitle.setTextColor(textColor) - songTitle.setTextColor(textColor) - biographyTitle.setTextColor(textColor) - - val buttonColor = if (PreferenceUtil.getInstance(this).adaptiveColor) - color.ripAlpha() - else - ATHUtil.resolveColor(this, R.attr.colorSurface) - - MaterialUtil.setTint(button = shuffleAction, color = buttonColor) - MaterialUtil.setTint(button = playAction, color = buttonColor) - - val toolbarColor = ATHUtil.resolveColor(this, R.attr.colorSurface) - toolbar.setBackgroundColor(toolbarColor) - setSupportActionBar(toolbar) - supportActionBar?.title = null - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - return handleSortOrderMenuItem(item) - } - - private fun handleSortOrderMenuItem(item: MenuItem): Boolean { - val songs = artist.songs - when (item.itemId) { - android.R.id.home -> { - super.onBackPressed() - return true - } - R.id.action_play_next -> { - MusicPlayerRemote.playNext(songs) - return true - } - R.id.action_add_to_current_playing -> { - MusicPlayerRemote.enqueue(songs) - return true - } - R.id.action_add_to_playlist -> { - AddToPlaylistDialog.create(songs).show(supportFragmentManager, "ADD_PLAYLIST") - return true - } - R.id.action_set_artist_image -> { - val intent = Intent(Intent.ACTION_GET_CONTENT) - intent.type = "image/*" - startActivityForResult( - Intent.createChooser(intent, getString(R.string.pick_from_local_storage)), - REQUEST_CODE_SELECT_IMAGE - ) - return true - } - R.id.action_reset_artist_image -> { - Toast.makeText( - this@ArtistDetailActivity, - resources.getString(R.string.updating), - Toast.LENGTH_SHORT - ) - .show() - CustomArtistImageUtil.getInstance(this@ArtistDetailActivity) - .resetCustomArtistImage(artist) - forceDownload = true - return true - } - } - return true - } - - override fun onCreateOptionsMenu(menu: Menu): Boolean { - menuInflater.inflate(R.menu.menu_artist_detail, menu) - return super.onCreateOptionsMenu(menu) - } - - override fun onMediaStoreChanged() { - super.onMediaStoreChanged() - reload() - } - - private fun reload() { - if (intent.extras!!.containsKey(EXTRA_ARTIST_ID)) { - intent.extras?.getInt(EXTRA_ARTIST_ID)?.let { artistDetailsPresenter.loadArtist(it) } - } else { - finish() - } - } - - override fun onBackPressed() { - if (cab != null && cab!!.isActive) { - cab?.finish() - } else { - super.onBackPressed() - } - } - - companion object { - - const val EXTRA_ARTIST_ID = "extra_artist_id" - const val REQUEST_CODE_SELECT_IMAGE = 9003 - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/DriveModeActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/DriveModeActivity.kt index 633bf0fd9..af3890d22 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/DriveModeActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/DriveModeActivity.kt @@ -1,45 +1,48 @@ /* - * Copyright (c) 2020 Hemanth Savarala. + * Copyright (c) 2020 Hemanth Savarla. * * Licensed under the GNU General Public License v3 * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. + * This is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. + * */ - package code.name.monkey.retromusic.activities -import android.animation.ObjectAnimator +import android.content.Intent import android.graphics.Color import android.graphics.PorterDuff import android.os.Bundle -import android.view.animation.LinearInterpolator -import android.widget.SeekBar -import code.name.monkey.appthemehelper.ThemeStore +import androidx.lifecycle.lifecycleScope import code.name.monkey.retromusic.R import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity -import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment +import code.name.monkey.retromusic.databinding.ActivityDriveModeBinding +import code.name.monkey.retromusic.db.toSongEntity +import code.name.monkey.retromusic.extensions.accentColor +import code.name.monkey.retromusic.extensions.drawAboveSystemBars import code.name.monkey.retromusic.glide.BlurTransformation -import code.name.monkey.retromusic.glide.RetroMusicColoredTarget -import code.name.monkey.retromusic.glide.SongGlideRequest +import code.name.monkey.retromusic.glide.RetroGlideExtension +import code.name.monkey.retromusic.glide.RetroGlideExtension.songCoverOptions import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper.Callback import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler -import code.name.monkey.retromusic.misc.SimpleOnSeekbarChangeListener +import code.name.monkey.retromusic.model.Song +import code.name.monkey.retromusic.repository.RealRepository import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.util.MusicUtil import com.bumptech.glide.Glide -import kotlinx.android.synthetic.main.activity_drive_mode.* -import kotlinx.coroutines.CoroutineScope +import com.google.android.material.slider.Slider import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import org.koin.android.ext.android.inject + /** * Created by hemanths on 2020-02-02. @@ -47,21 +50,24 @@ import kotlinx.coroutines.withContext class DriveModeActivity : AbsMusicServiceActivity(), Callback { + private lateinit var binding: ActivityDriveModeBinding private var lastPlaybackControlsColor: Int = Color.GRAY private var lastDisabledPlaybackControlsColor: Int = Color.GRAY private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper + private val repository: RealRepository by inject() override fun onCreate(savedInstanceState: Bundle?) { - setDrawUnderStatusBar() super.onCreate(savedInstanceState) - setContentView(R.layout.activity_drive_mode) + binding = ActivityDriveModeBinding.inflate(layoutInflater) + setContentView(binding.root) setUpMusicControllers() progressViewUpdateHelper = MusicProgressViewUpdateHelper(this) - lastPlaybackControlsColor = ThemeStore.accentColor(this) - close.setOnClickListener { - onBackPressed() + lastPlaybackControlsColor = accentColor() + binding.close.setOnClickListener { + onBackPressedDispatcher.onBackPressed() } + binding.repeatButton.drawAboveSystemBars() } private fun setUpMusicControllers() { @@ -74,36 +80,45 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback { } private fun setupFavouriteToggle() { - songFavourite.setOnClickListener { - MusicUtil.toggleFavorite( - this@DriveModeActivity, - MusicPlayerRemote.currentSong - ) + binding.songFavourite.setOnClickListener { + toggleFavorite(MusicPlayerRemote.currentSong) } } - private fun toggleFavourite() { - CoroutineScope(Dispatchers.IO).launch { - val isFavourite = - MusicUtil.isFavorite(this@DriveModeActivity, MusicPlayerRemote.currentSong) + private fun toggleFavorite(song: Song) { + lifecycleScope.launch(Dispatchers.IO) { + val playlist = repository.favoritePlaylist() + val songEntity = song.toSongEntity(playlist.playListId) + val isFavorite = repository.isSongFavorite(song.id) + if (isFavorite) { + repository.removeSongFromPlaylist(songEntity) + } else { + repository.insertSongs(listOf(song.toSongEntity(playlist.playListId))) + } + sendBroadcast(Intent(MusicService.FAVORITE_STATE_CHANGED)) + } + } + + private fun updateFavorite() { + lifecycleScope.launch(Dispatchers.IO) { + val isFavorite: Boolean = + repository.isSongFavorite(MusicPlayerRemote.currentSong.id) withContext(Dispatchers.Main) { - songFavourite.setImageResource(if (isFavourite) R.drawable.ic_favorite_white_24dp else R.drawable.ic_favorite_border_white_24dp) + binding.songFavourite.setImageResource(if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border) } } } private fun setUpProgressSlider() { - progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() { - override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { - if (fromUser) { - MusicPlayerRemote.seekTo(progress) - onUpdateProgressViews( - MusicPlayerRemote.songProgressMillis, - MusicPlayerRemote.songDurationMillis - ) - } + binding.progressSlider.addOnChangeListener { _: Slider, progress: Float, fromUser: Boolean -> + if (fromUser) { + MusicPlayerRemote.seekTo(progress.toInt()) + onUpdateProgressViews( + MusicPlayerRemote.songProgressMillis, + MusicPlayerRemote.songDurationMillis + ) } - }) + } } override fun onPause() { @@ -117,21 +132,20 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback { } private fun setUpPrevNext() { - - nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() } - previousButton.setOnClickListener { MusicPlayerRemote.back() } + binding.nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() } + binding.previousButton.setOnClickListener { MusicPlayerRemote.back() } } private fun setUpShuffleButton() { - shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() } + binding.shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() } } private fun setUpRepeatButton() { - repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() } + binding.repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() } } private fun setUpPlayPauseFab() { - playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler()) + binding.playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler()) } override fun onRepeatModeChanged() { @@ -155,24 +169,25 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback { updateSong() updateRepeatState() updateShuffleState() - toggleFavourite() + updateFavorite() } private fun updatePlayPauseDrawableState() { if (MusicPlayerRemote.isPlaying) { - playPauseButton.setImageResource(R.drawable.ic_pause_white_24dp) + binding.playPauseButton.setImageResource(R.drawable.ic_pause) } else { - playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_24dp) + binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow) } } fun updateShuffleState() { when (MusicPlayerRemote.shuffleMode) { - MusicService.SHUFFLE_MODE_SHUFFLE -> shuffleButton.setColorFilter( + MusicService.SHUFFLE_MODE_SHUFFLE -> binding.shuffleButton.setColorFilter( lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN ) - else -> shuffleButton.setColorFilter( + + else -> binding.shuffleButton.setColorFilter( lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN ) @@ -182,19 +197,27 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback { private fun updateRepeatState() { when (MusicPlayerRemote.repeatMode) { MusicService.REPEAT_MODE_NONE -> { - repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp) - repeatButton.setColorFilter( + binding.repeatButton.setImageResource(R.drawable.ic_repeat) + binding.repeatButton.setColorFilter( lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN ) } + MusicService.REPEAT_MODE_ALL -> { - repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp) - repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN) + binding.repeatButton.setImageResource(R.drawable.ic_repeat) + binding.repeatButton.setColorFilter( + lastPlaybackControlsColor, + PorterDuff.Mode.SRC_IN + ) } + MusicService.REPEAT_MODE_THIS -> { - repeatButton.setImageResource(R.drawable.ic_repeat_one_white_24dp) - repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN) + binding.repeatButton.setImageResource(R.drawable.ic_repeat_one) + binding.repeatButton.setColorFilter( + lastPlaybackControlsColor, + PorterDuff.Mode.SRC_IN + ) } } } @@ -202,35 +225,34 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback { override fun onPlayingMetaChanged() { super.onPlayingMetaChanged() updateSong() - toggleFavourite() + updateFavorite() + } + + override fun onFavoriteStateChanged() { + super.onFavoriteStateChanged() + updateFavorite() } private fun updateSong() { val song = MusicPlayerRemote.currentSong - songTitle.text = song.title - songText.text = song.artistName + binding.songTitle.text = song.title + binding.songText.text = song.artistName - SongGlideRequest.Builder.from(Glide.with(this), song) - .checkIgnoreMediaStore(this) - .generatePalette(this) - .build() + Glide.with(this) + .load(RetroGlideExtension.getSongModel(song)) + .songCoverOptions(song) .transform(BlurTransformation.Builder(this).build()) - .into(object : RetroMusicColoredTarget(image) { - override fun onColorReady(color: Int) { - } - }) + .into(binding.image) } override fun onUpdateProgressViews(progress: Int, total: Int) { - progressSlider.max = total + binding.progressSlider.run { + valueTo = total.toFloat() + value = progress.toFloat().coerceIn(valueFrom, valueTo) + } - val animator = ObjectAnimator.ofInt(progressSlider, "progress", progress) - animator.duration = AbsPlayerControlsFragment.SLIDER_ANIMATION_TIME - animator.interpolator = LinearInterpolator() - animator.start() - - songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong()) - songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong()) + binding.songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong()) + binding.songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong()) } -} \ No newline at end of file +} diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/ErrorActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/ErrorActivity.kt new file mode 100644 index 000000000..6823b80f8 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/activities/ErrorActivity.kt @@ -0,0 +1,80 @@ +package code.name.monkey.retromusic.activities + +import android.os.Bundle +import android.widget.Button +import android.widget.ImageView +import androidx.appcompat.app.AppCompatActivity +import cat.ereza.customactivityoncrash.CustomActivityOnCrash +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.util.FileUtils.createFile +import code.name.monkey.retromusic.util.Share.shareFile +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import java.text.DateFormat +import java.text.SimpleDateFormat +import java.util.* + +class ErrorActivity : AppCompatActivity() { + private val dayFormat: DateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) + private val reportPrefix = "bug_report-" + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(cat.ereza.customactivityoncrash.R.layout.customactivityoncrash_default_error_activity) + + val restartButton = + findViewById