Initial commit
2
.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
14
.gitignore
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/caches
|
||||
/.idea/libraries
|
||||
/.idea/modules.xml
|
||||
/.idea/workspace.xml
|
||||
/.idea/navEditor.xml
|
||||
/.idea/assetWizardSettings.xml
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
.cxx
|
1
.idea/.name
generated
Normal file
@ -0,0 +1 @@
|
||||
JLyrics
|
164
.idea/codeStyles/Project.xml
generated
Normal file
@ -0,0 +1,164 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<DBN-PSQL>
|
||||
<case-options enabled="true">
|
||||
<option name="KEYWORD_CASE" value="lower" />
|
||||
<option name="FUNCTION_CASE" value="lower" />
|
||||
<option name="PARAMETER_CASE" value="lower" />
|
||||
<option name="DATATYPE_CASE" value="lower" />
|
||||
<option name="OBJECT_CASE" value="preserve" />
|
||||
</case-options>
|
||||
<formatting-settings enabled="false" />
|
||||
</DBN-PSQL>
|
||||
<DBN-SQL>
|
||||
<case-options enabled="true">
|
||||
<option name="KEYWORD_CASE" value="lower" />
|
||||
<option name="FUNCTION_CASE" value="lower" />
|
||||
<option name="PARAMETER_CASE" value="lower" />
|
||||
<option name="DATATYPE_CASE" value="lower" />
|
||||
<option name="OBJECT_CASE" value="preserve" />
|
||||
</case-options>
|
||||
<formatting-settings enabled="false">
|
||||
<option name="STATEMENT_SPACING" value="one_line" />
|
||||
<option name="CLAUSE_CHOP_DOWN" value="chop_down_if_statement_long" />
|
||||
<option name="ITERATION_ELEMENTS_WRAPPING" value="chop_down_if_not_single" />
|
||||
</formatting-settings>
|
||||
</DBN-SQL>
|
||||
<DBN-PSQL>
|
||||
<case-options enabled="true">
|
||||
<option name="KEYWORD_CASE" value="lower" />
|
||||
<option name="FUNCTION_CASE" value="lower" />
|
||||
<option name="PARAMETER_CASE" value="lower" />
|
||||
<option name="DATATYPE_CASE" value="lower" />
|
||||
<option name="OBJECT_CASE" value="preserve" />
|
||||
</case-options>
|
||||
<formatting-settings enabled="false" />
|
||||
</DBN-PSQL>
|
||||
<DBN-SQL>
|
||||
<case-options enabled="true">
|
||||
<option name="KEYWORD_CASE" value="lower" />
|
||||
<option name="FUNCTION_CASE" value="lower" />
|
||||
<option name="PARAMETER_CASE" value="lower" />
|
||||
<option name="DATATYPE_CASE" value="lower" />
|
||||
<option name="OBJECT_CASE" value="preserve" />
|
||||
</case-options>
|
||||
<formatting-settings enabled="false">
|
||||
<option name="STATEMENT_SPACING" value="one_line" />
|
||||
<option name="CLAUSE_CHOP_DOWN" value="chop_down_if_statement_long" />
|
||||
<option name="ITERATION_ELEMENTS_WRAPPING" value="chop_down_if_not_single" />
|
||||
</formatting-settings>
|
||||
</DBN-SQL>
|
||||
<codeStyleSettings language="XML">
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
<arrangement>
|
||||
<rules>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:android</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:id</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>style</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
</rules>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
454
.idea/dbnavigator.xml
generated
Normal file
@ -0,0 +1,454 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DBNavigator.Project.DataEditorManager">
|
||||
<record-view-column-sorting-type value="BY_INDEX" />
|
||||
<value-preview-text-wrapping value="true" />
|
||||
<value-preview-pinned value="false" />
|
||||
</component>
|
||||
<component name="DBNavigator.Project.DataExportManager">
|
||||
<export-instructions>
|
||||
<create-header value="true" />
|
||||
<quote-values-containing-separator value="true" />
|
||||
<quote-all-values value="false" />
|
||||
<value-separator value="" />
|
||||
<file-name value="" />
|
||||
<file-location value="" />
|
||||
<scope value="GLOBAL" />
|
||||
<destination value="FILE" />
|
||||
<format value="EXCEL" />
|
||||
<charset value="windows-31j" />
|
||||
</export-instructions>
|
||||
</component>
|
||||
<component name="DBNavigator.Project.DatabaseBrowserManager">
|
||||
<autoscroll-to-editor value="false" />
|
||||
<autoscroll-from-editor value="true" />
|
||||
<show-object-properties value="true" />
|
||||
<loaded-nodes />
|
||||
</component>
|
||||
<component name="DBNavigator.Project.DatabaseFileManager">
|
||||
<open-files />
|
||||
</component>
|
||||
<component name="DBNavigator.Project.EditorStateManager">
|
||||
<last-used-providers />
|
||||
</component>
|
||||
<component name="DBNavigator.Project.MethodExecutionManager">
|
||||
<method-browser />
|
||||
<execution-history>
|
||||
<group-entries value="true" />
|
||||
<execution-inputs />
|
||||
</execution-history>
|
||||
<argument-values-cache />
|
||||
</component>
|
||||
<component name="DBNavigator.Project.ObjectDependencyManager">
|
||||
<last-used-dependency-type value="INCOMING" />
|
||||
</component>
|
||||
<component name="DBNavigator.Project.ObjectQuickFilterManager">
|
||||
<last-used-operator value="EQUAL" />
|
||||
<filters />
|
||||
</component>
|
||||
<component name="DBNavigator.Project.ScriptExecutionManager" clear-outputs="true">
|
||||
<recently-used-interfaces />
|
||||
</component>
|
||||
<component name="DBNavigator.Project.Settings">
|
||||
<connections />
|
||||
<browser-settings>
|
||||
<general>
|
||||
<display-mode value="TABBED" />
|
||||
<navigation-history-size value="100" />
|
||||
<show-object-details value="false" />
|
||||
</general>
|
||||
<filters>
|
||||
<object-type-filter>
|
||||
<object-type name="SCHEMA" enabled="true" />
|
||||
<object-type name="USER" enabled="true" />
|
||||
<object-type name="ROLE" enabled="true" />
|
||||
<object-type name="PRIVILEGE" enabled="true" />
|
||||
<object-type name="CHARSET" enabled="true" />
|
||||
<object-type name="TABLE" enabled="true" />
|
||||
<object-type name="VIEW" enabled="true" />
|
||||
<object-type name="MATERIALIZED_VIEW" enabled="true" />
|
||||
<object-type name="NESTED_TABLE" enabled="true" />
|
||||
<object-type name="COLUMN" enabled="true" />
|
||||
<object-type name="INDEX" enabled="true" />
|
||||
<object-type name="CONSTRAINT" enabled="true" />
|
||||
<object-type name="DATASET_TRIGGER" enabled="true" />
|
||||
<object-type name="DATABASE_TRIGGER" enabled="true" />
|
||||
<object-type name="SYNONYM" enabled="true" />
|
||||
<object-type name="SEQUENCE" enabled="true" />
|
||||
<object-type name="PROCEDURE" enabled="true" />
|
||||
<object-type name="FUNCTION" enabled="true" />
|
||||
<object-type name="PACKAGE" enabled="true" />
|
||||
<object-type name="TYPE" enabled="true" />
|
||||
<object-type name="TYPE_ATTRIBUTE" enabled="true" />
|
||||
<object-type name="ARGUMENT" enabled="true" />
|
||||
<object-type name="DIMENSION" enabled="true" />
|
||||
<object-type name="CLUSTER" enabled="true" />
|
||||
<object-type name="DBLINK" enabled="true" />
|
||||
</object-type-filter>
|
||||
</filters>
|
||||
<sorting>
|
||||
<object-type name="COLUMN" sorting-type="NAME" />
|
||||
<object-type name="FUNCTION" sorting-type="NAME" />
|
||||
<object-type name="PROCEDURE" sorting-type="NAME" />
|
||||
<object-type name="ARGUMENT" sorting-type="POSITION" />
|
||||
</sorting>
|
||||
<default-editors>
|
||||
<object-type name="VIEW" editor-type="SELECTION" />
|
||||
<object-type name="PACKAGE" editor-type="SELECTION" />
|
||||
<object-type name="TYPE" editor-type="SELECTION" />
|
||||
</default-editors>
|
||||
</browser-settings>
|
||||
<navigation-settings>
|
||||
<lookup-filters>
|
||||
<lookup-objects>
|
||||
<object-type name="SCHEMA" enabled="true" />
|
||||
<object-type name="USER" enabled="false" />
|
||||
<object-type name="ROLE" enabled="false" />
|
||||
<object-type name="PRIVILEGE" enabled="false" />
|
||||
<object-type name="CHARSET" enabled="false" />
|
||||
<object-type name="TABLE" enabled="true" />
|
||||
<object-type name="VIEW" enabled="true" />
|
||||
<object-type name="MATERIALIZED VIEW" enabled="true" />
|
||||
<object-type name="NESTED TABLE" enabled="false" />
|
||||
<object-type name="COLUMN" enabled="false" />
|
||||
<object-type name="INDEX" enabled="true" />
|
||||
<object-type name="CONSTRAINT" enabled="true" />
|
||||
<object-type name="DATASET TRIGGER" enabled="true" />
|
||||
<object-type name="DATABASE TRIGGER" enabled="true" />
|
||||
<object-type name="SYNONYM" enabled="false" />
|
||||
<object-type name="SEQUENCE" enabled="true" />
|
||||
<object-type name="PROCEDURE" enabled="true" />
|
||||
<object-type name="FUNCTION" enabled="true" />
|
||||
<object-type name="PACKAGE" enabled="true" />
|
||||
<object-type name="TYPE" enabled="true" />
|
||||
<object-type name="TYPE ATTRIBUTE" enabled="false" />
|
||||
<object-type name="ARGUMENT" enabled="false" />
|
||||
<object-type name="DIMENSION" enabled="false" />
|
||||
<object-type name="CLUSTER" enabled="false" />
|
||||
<object-type name="DBLINK" enabled="true" />
|
||||
</lookup-objects>
|
||||
<force-database-load value="false" />
|
||||
<prompt-connection-selection value="true" />
|
||||
<prompt-schema-selection value="true" />
|
||||
</lookup-filters>
|
||||
</navigation-settings>
|
||||
<dataset-grid-settings>
|
||||
<general>
|
||||
<enable-zooming value="true" />
|
||||
<enable-column-tooltip value="true" />
|
||||
</general>
|
||||
<sorting>
|
||||
<nulls-first value="true" />
|
||||
<max-sorting-columns value="4" />
|
||||
</sorting>
|
||||
<tracking-columns>
|
||||
<columnNames value="" />
|
||||
<visible value="true" />
|
||||
<editable value="false" />
|
||||
</tracking-columns>
|
||||
</dataset-grid-settings>
|
||||
<dataset-editor-settings>
|
||||
<text-editor-popup>
|
||||
<active value="false" />
|
||||
<active-if-empty value="false" />
|
||||
<data-length-threshold value="100" />
|
||||
<popup-delay value="1000" />
|
||||
</text-editor-popup>
|
||||
<values-actions-popup>
|
||||
<show-popup-button value="true" />
|
||||
<element-count-threshold value="1000" />
|
||||
<data-length-threshold value="250" />
|
||||
</values-actions-popup>
|
||||
<general>
|
||||
<fetch-block-size value="100" />
|
||||
<fetch-timeout value="30" />
|
||||
<trim-whitespaces value="true" />
|
||||
<convert-empty-strings-to-null value="true" />
|
||||
<select-content-on-cell-edit value="true" />
|
||||
<large-value-preview-active value="true" />
|
||||
</general>
|
||||
<filters>
|
||||
<prompt-filter-dialog value="true" />
|
||||
<default-filter-type value="BASIC" />
|
||||
</filters>
|
||||
<qualified-text-editor text-length-threshold="300">
|
||||
<content-types>
|
||||
<content-type name="Text" enabled="true" />
|
||||
<content-type name="Properties" enabled="true" />
|
||||
<content-type name="XML" enabled="true" />
|
||||
<content-type name="DTD" enabled="true" />
|
||||
<content-type name="HTML" enabled="true" />
|
||||
<content-type name="XHTML" enabled="true" />
|
||||
<content-type name="Java" enabled="true" />
|
||||
<content-type name="Groovy" enabled="true" />
|
||||
<content-type name="AIDL" enabled="true" />
|
||||
<content-type name="YAML" enabled="true" />
|
||||
<content-type name="Manifest" enabled="true" />
|
||||
</content-types>
|
||||
</qualified-text-editor>
|
||||
<record-navigation>
|
||||
<navigation-target value="VIEWER" />
|
||||
</record-navigation>
|
||||
</dataset-editor-settings>
|
||||
<code-editor-settings>
|
||||
<general>
|
||||
<show-object-navigation-gutter value="false" />
|
||||
<show-spec-declaration-navigation-gutter value="true" />
|
||||
<enable-spellchecking value="true" />
|
||||
<enable-reference-spellchecking value="false" />
|
||||
</general>
|
||||
<confirmations>
|
||||
<save-changes value="false" />
|
||||
<revert-changes value="true" />
|
||||
</confirmations>
|
||||
</code-editor-settings>
|
||||
<code-completion-settings>
|
||||
<filters>
|
||||
<basic-filter>
|
||||
<filter-element type="RESERVED_WORD" id="keyword" selected="true" />
|
||||
<filter-element type="RESERVED_WORD" id="function" selected="true" />
|
||||
<filter-element type="RESERVED_WORD" id="parameter" selected="true" />
|
||||
<filter-element type="RESERVED_WORD" id="datatype" selected="true" />
|
||||
<filter-element type="RESERVED_WORD" id="exception" selected="true" />
|
||||
<filter-element type="OBJECT" id="schema" selected="true" />
|
||||
<filter-element type="OBJECT" id="role" selected="true" />
|
||||
<filter-element type="OBJECT" id="user" selected="true" />
|
||||
<filter-element type="OBJECT" id="privilege" selected="true" />
|
||||
<user-schema>
|
||||
<filter-element type="OBJECT" id="table" selected="true" />
|
||||
<filter-element type="OBJECT" id="view" selected="true" />
|
||||
<filter-element type="OBJECT" id="materialized view" selected="true" />
|
||||
<filter-element type="OBJECT" id="index" selected="true" />
|
||||
<filter-element type="OBJECT" id="constraint" selected="true" />
|
||||
<filter-element type="OBJECT" id="trigger" selected="true" />
|
||||
<filter-element type="OBJECT" id="synonym" selected="false" />
|
||||
<filter-element type="OBJECT" id="sequence" selected="true" />
|
||||
<filter-element type="OBJECT" id="procedure" selected="true" />
|
||||
<filter-element type="OBJECT" id="function" selected="true" />
|
||||
<filter-element type="OBJECT" id="package" selected="true" />
|
||||
<filter-element type="OBJECT" id="type" selected="true" />
|
||||
<filter-element type="OBJECT" id="dimension" selected="true" />
|
||||
<filter-element type="OBJECT" id="cluster" selected="true" />
|
||||
<filter-element type="OBJECT" id="dblink" selected="true" />
|
||||
</user-schema>
|
||||
<public-schema>
|
||||
<filter-element type="OBJECT" id="table" selected="false" />
|
||||
<filter-element type="OBJECT" id="view" selected="false" />
|
||||
<filter-element type="OBJECT" id="materialized view" selected="false" />
|
||||
<filter-element type="OBJECT" id="index" selected="false" />
|
||||
<filter-element type="OBJECT" id="constraint" selected="false" />
|
||||
<filter-element type="OBJECT" id="trigger" selected="false" />
|
||||
<filter-element type="OBJECT" id="synonym" selected="false" />
|
||||
<filter-element type="OBJECT" id="sequence" selected="false" />
|
||||
<filter-element type="OBJECT" id="procedure" selected="false" />
|
||||
<filter-element type="OBJECT" id="function" selected="false" />
|
||||
<filter-element type="OBJECT" id="package" selected="false" />
|
||||
<filter-element type="OBJECT" id="type" selected="false" />
|
||||
<filter-element type="OBJECT" id="dimension" selected="false" />
|
||||
<filter-element type="OBJECT" id="cluster" selected="false" />
|
||||
<filter-element type="OBJECT" id="dblink" selected="false" />
|
||||
</public-schema>
|
||||
<any-schema>
|
||||
<filter-element type="OBJECT" id="table" selected="true" />
|
||||
<filter-element type="OBJECT" id="view" selected="true" />
|
||||
<filter-element type="OBJECT" id="materialized view" selected="true" />
|
||||
<filter-element type="OBJECT" id="index" selected="true" />
|
||||
<filter-element type="OBJECT" id="constraint" selected="true" />
|
||||
<filter-element type="OBJECT" id="trigger" selected="true" />
|
||||
<filter-element type="OBJECT" id="synonym" selected="true" />
|
||||
<filter-element type="OBJECT" id="sequence" selected="true" />
|
||||
<filter-element type="OBJECT" id="procedure" selected="true" />
|
||||
<filter-element type="OBJECT" id="function" selected="true" />
|
||||
<filter-element type="OBJECT" id="package" selected="true" />
|
||||
<filter-element type="OBJECT" id="type" selected="true" />
|
||||
<filter-element type="OBJECT" id="dimension" selected="true" />
|
||||
<filter-element type="OBJECT" id="cluster" selected="true" />
|
||||
<filter-element type="OBJECT" id="dblink" selected="true" />
|
||||
</any-schema>
|
||||
</basic-filter>
|
||||
<extended-filter>
|
||||
<filter-element type="RESERVED_WORD" id="keyword" selected="true" />
|
||||
<filter-element type="RESERVED_WORD" id="function" selected="true" />
|
||||
<filter-element type="RESERVED_WORD" id="parameter" selected="true" />
|
||||
<filter-element type="RESERVED_WORD" id="datatype" selected="true" />
|
||||
<filter-element type="RESERVED_WORD" id="exception" selected="true" />
|
||||
<filter-element type="OBJECT" id="schema" selected="true" />
|
||||
<filter-element type="OBJECT" id="user" selected="true" />
|
||||
<filter-element type="OBJECT" id="role" selected="true" />
|
||||
<filter-element type="OBJECT" id="privilege" selected="true" />
|
||||
<user-schema>
|
||||
<filter-element type="OBJECT" id="table" selected="true" />
|
||||
<filter-element type="OBJECT" id="view" selected="true" />
|
||||
<filter-element type="OBJECT" id="materialized view" selected="true" />
|
||||
<filter-element type="OBJECT" id="index" selected="true" />
|
||||
<filter-element type="OBJECT" id="constraint" selected="true" />
|
||||
<filter-element type="OBJECT" id="trigger" selected="true" />
|
||||
<filter-element type="OBJECT" id="synonym" selected="true" />
|
||||
<filter-element type="OBJECT" id="sequence" selected="true" />
|
||||
<filter-element type="OBJECT" id="procedure" selected="true" />
|
||||
<filter-element type="OBJECT" id="function" selected="true" />
|
||||
<filter-element type="OBJECT" id="package" selected="true" />
|
||||
<filter-element type="OBJECT" id="type" selected="true" />
|
||||
<filter-element type="OBJECT" id="dimension" selected="true" />
|
||||
<filter-element type="OBJECT" id="cluster" selected="true" />
|
||||
<filter-element type="OBJECT" id="dblink" selected="true" />
|
||||
</user-schema>
|
||||
<public-schema>
|
||||
<filter-element type="OBJECT" id="table" selected="true" />
|
||||
<filter-element type="OBJECT" id="view" selected="true" />
|
||||
<filter-element type="OBJECT" id="materialized view" selected="true" />
|
||||
<filter-element type="OBJECT" id="index" selected="true" />
|
||||
<filter-element type="OBJECT" id="constraint" selected="true" />
|
||||
<filter-element type="OBJECT" id="trigger" selected="true" />
|
||||
<filter-element type="OBJECT" id="synonym" selected="true" />
|
||||
<filter-element type="OBJECT" id="sequence" selected="true" />
|
||||
<filter-element type="OBJECT" id="procedure" selected="true" />
|
||||
<filter-element type="OBJECT" id="function" selected="true" />
|
||||
<filter-element type="OBJECT" id="package" selected="true" />
|
||||
<filter-element type="OBJECT" id="type" selected="true" />
|
||||
<filter-element type="OBJECT" id="dimension" selected="true" />
|
||||
<filter-element type="OBJECT" id="cluster" selected="true" />
|
||||
<filter-element type="OBJECT" id="dblink" selected="true" />
|
||||
</public-schema>
|
||||
<any-schema>
|
||||
<filter-element type="OBJECT" id="table" selected="true" />
|
||||
<filter-element type="OBJECT" id="view" selected="true" />
|
||||
<filter-element type="OBJECT" id="materialized view" selected="true" />
|
||||
<filter-element type="OBJECT" id="index" selected="true" />
|
||||
<filter-element type="OBJECT" id="constraint" selected="true" />
|
||||
<filter-element type="OBJECT" id="trigger" selected="true" />
|
||||
<filter-element type="OBJECT" id="synonym" selected="true" />
|
||||
<filter-element type="OBJECT" id="sequence" selected="true" />
|
||||
<filter-element type="OBJECT" id="procedure" selected="true" />
|
||||
<filter-element type="OBJECT" id="function" selected="true" />
|
||||
<filter-element type="OBJECT" id="package" selected="true" />
|
||||
<filter-element type="OBJECT" id="type" selected="true" />
|
||||
<filter-element type="OBJECT" id="dimension" selected="true" />
|
||||
<filter-element type="OBJECT" id="cluster" selected="true" />
|
||||
<filter-element type="OBJECT" id="dblink" selected="true" />
|
||||
</any-schema>
|
||||
</extended-filter>
|
||||
</filters>
|
||||
<sorting enabled="true">
|
||||
<sorting-element type="RESERVED_WORD" id="keyword" />
|
||||
<sorting-element type="RESERVED_WORD" id="datatype" />
|
||||
<sorting-element type="OBJECT" id="column" />
|
||||
<sorting-element type="OBJECT" id="table" />
|
||||
<sorting-element type="OBJECT" id="view" />
|
||||
<sorting-element type="OBJECT" id="materialized view" />
|
||||
<sorting-element type="OBJECT" id="index" />
|
||||
<sorting-element type="OBJECT" id="constraint" />
|
||||
<sorting-element type="OBJECT" id="trigger" />
|
||||
<sorting-element type="OBJECT" id="synonym" />
|
||||
<sorting-element type="OBJECT" id="sequence" />
|
||||
<sorting-element type="OBJECT" id="procedure" />
|
||||
<sorting-element type="OBJECT" id="function" />
|
||||
<sorting-element type="OBJECT" id="package" />
|
||||
<sorting-element type="OBJECT" id="type" />
|
||||
<sorting-element type="OBJECT" id="dimension" />
|
||||
<sorting-element type="OBJECT" id="cluster" />
|
||||
<sorting-element type="OBJECT" id="dblink" />
|
||||
<sorting-element type="OBJECT" id="schema" />
|
||||
<sorting-element type="OBJECT" id="role" />
|
||||
<sorting-element type="OBJECT" id="user" />
|
||||
<sorting-element type="RESERVED_WORD" id="function" />
|
||||
<sorting-element type="RESERVED_WORD" id="parameter" />
|
||||
</sorting>
|
||||
<format>
|
||||
<enforce-code-style-case value="true" />
|
||||
</format>
|
||||
</code-completion-settings>
|
||||
<execution-engine-settings>
|
||||
<statement-execution>
|
||||
<fetch-block-size value="100" />
|
||||
<execution-timeout value="20" />
|
||||
<debug-execution-timeout value="600" />
|
||||
<focus-result value="false" />
|
||||
<prompt-execution value="false" />
|
||||
</statement-execution>
|
||||
<script-execution>
|
||||
<command-line-interfaces />
|
||||
<execution-timeout value="300" />
|
||||
</script-execution>
|
||||
<method-execution>
|
||||
<execution-timeout value="30" />
|
||||
<debug-execution-timeout value="600" />
|
||||
<parameter-history-size value="10" />
|
||||
</method-execution>
|
||||
</execution-engine-settings>
|
||||
<operation-settings>
|
||||
<transactions>
|
||||
<uncommitted-changes>
|
||||
<on-project-close value="ASK" />
|
||||
<on-disconnect value="ASK" />
|
||||
<on-autocommit-toggle value="ASK" />
|
||||
</uncommitted-changes>
|
||||
<multiple-uncommitted-changes>
|
||||
<on-commit value="ASK" />
|
||||
<on-rollback value="ASK" />
|
||||
</multiple-uncommitted-changes>
|
||||
</transactions>
|
||||
<session-browser>
|
||||
<disconnect-session value="ASK" />
|
||||
<kill-session value="ASK" />
|
||||
<reload-on-filter-change value="false" />
|
||||
</session-browser>
|
||||
<compiler>
|
||||
<compile-type value="KEEP" />
|
||||
<compile-dependencies value="ASK" />
|
||||
<always-show-controls value="false" />
|
||||
</compiler>
|
||||
<debugger>
|
||||
<debugger-type value="ASK" />
|
||||
<use-generic-runners value="true" />
|
||||
</debugger>
|
||||
</operation-settings>
|
||||
<ddl-file-settings>
|
||||
<extensions>
|
||||
<mapping file-type-id="VIEW" extensions="vw" />
|
||||
<mapping file-type-id="TRIGGER" extensions="trg" />
|
||||
<mapping file-type-id="PROCEDURE" extensions="prc" />
|
||||
<mapping file-type-id="FUNCTION" extensions="fnc" />
|
||||
<mapping file-type-id="PACKAGE" extensions="pkg" />
|
||||
<mapping file-type-id="PACKAGE_SPEC" extensions="pks" />
|
||||
<mapping file-type-id="PACKAGE_BODY" extensions="pkb" />
|
||||
<mapping file-type-id="TYPE" extensions="tpe" />
|
||||
<mapping file-type-id="TYPE_SPEC" extensions="tps" />
|
||||
<mapping file-type-id="TYPE_BODY" extensions="tpb" />
|
||||
</extensions>
|
||||
<general>
|
||||
<lookup-ddl-files value="true" />
|
||||
<create-ddl-files value="false" />
|
||||
<synchronize-ddl-files value="true" />
|
||||
<use-qualified-names value="false" />
|
||||
<make-scripts-rerunnable value="true" />
|
||||
</general>
|
||||
</ddl-file-settings>
|
||||
<general-settings>
|
||||
<regional-settings>
|
||||
<date-format value="MEDIUM" />
|
||||
<number-format value="UNGROUPED" />
|
||||
<locale value="SYSTEM_DEFAULT" />
|
||||
<use-custom-formats value="false" />
|
||||
</regional-settings>
|
||||
<environment>
|
||||
<environment-types>
|
||||
<environment-type id="development" name="Development" description="Development environment" color="-2430209/-12296320" readonly-code="false" readonly-data="false" />
|
||||
<environment-type id="integration" name="Integration" description="Integration environment" color="-2621494/-12163514" readonly-code="true" readonly-data="false" />
|
||||
<environment-type id="production" name="Production" description="Productive environment" color="-11574/-10271420" readonly-code="true" readonly-data="true" />
|
||||
<environment-type id="other" name="Other" description="" color="-1576/-10724543" readonly-code="false" readonly-data="false" />
|
||||
</environment-types>
|
||||
<visibility-settings>
|
||||
<connection-tabs value="true" />
|
||||
<dialog-headers value="true" />
|
||||
<object-editor-tabs value="true" />
|
||||
<script-editor-tabs value="false" />
|
||||
<execution-result-tabs value="true" />
|
||||
</visibility-settings>
|
||||
</environment>
|
||||
</general-settings>
|
||||
</component>
|
||||
<component name="DBNavigator.Project.StatementExecutionManager">
|
||||
<execution-variables />
|
||||
</component>
|
||||
</project>
|
16
.idea/gradle.xml
generated
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<compositeConfiguration>
|
||||
<compositeBuild compositeDefinitionSource="SCRIPT" />
|
||||
</compositeConfiguration>
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
<option name="testRunner" value="PLATFORM" />
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
9
.idea/misc.xml
generated
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="JDK" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="Android" />
|
||||
</component>
|
||||
</project>
|
12
.idea/runConfigurations.xml
generated
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RunConfigurationProducerService">
|
||||
<option name="ignoredProducers">
|
||||
<set>
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
|
||||
</set>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
BIN
JLyrics.zip
Normal file
201
LICENSE
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
2
README.md
Normal file
@ -0,0 +1,2 @@
|
||||
# jlyrics-android
|
||||
An unoffical android client of j-lyrics.net
|
1
app/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/build
|
85
app/build.gradle
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2019 bernd32
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
android {
|
||||
// Kuromoji
|
||||
packagingOptions {
|
||||
exclude 'META-INF/CONTRIBUTORS.md'
|
||||
exclude 'META-INF/LICENSE.md'
|
||||
exclude 'META-INF/MANIFEST.MF'
|
||||
exclude 'META-INF/NOTICE.md'
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion "29.0.2"
|
||||
defaultConfig {
|
||||
applicationId "com.bernd32.jlyrics"
|
||||
minSdkVersion 23
|
||||
targetSdkVersion 29
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test:runner:1.2.0'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
//Jsoup
|
||||
implementation 'org.jsoup:jsoup:1.12.1'
|
||||
// RecyclerView
|
||||
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||
// Glide
|
||||
implementation 'com.github.bumptech.glide:glide:4.10.0'
|
||||
annotationProcessor 'com.github.bumptech.glide:glide:4.10.0'
|
||||
// Material
|
||||
implementation 'com.google.android.material:material:1.2.0-alpha02'
|
||||
|
||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'
|
||||
|
||||
implementation 'androidx.paging:paging-runtime:2.1.0'
|
||||
// Room components
|
||||
implementation "androidx.room:room-runtime:$rootProject.roomVersion"
|
||||
annotationProcessor "androidx.room:room-compiler:$rootProject.roomVersion"
|
||||
androidTestImplementation "androidx.room:room-testing:$rootProject.roomVersion"
|
||||
// Lifecycle components
|
||||
implementation "androidx.lifecycle:lifecycle-extensions:$rootProject.archLifecycleVersion"
|
||||
annotationProcessor "androidx.lifecycle:lifecycle-compiler:$rootProject.archLifecycleVersion"
|
||||
// Junit
|
||||
implementation 'androidx.test.ext:junit:1.1.2-alpha02'
|
||||
// debugImplementation because LeakCanary should only run in debug builds.
|
||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.0'
|
||||
// Romaji-henkan
|
||||
implementation 'io.github.bernd32:romaji-henkan:0.0.1'
|
||||
}
|
21
app/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
62
app/roadmap/todo.txt
Normal file
@ -0,0 +1,62 @@
|
||||
1. Implement detailed search
|
||||
✓1.1 Prepare UI
|
||||
✓1.1.1 In MainActivity add spinner (song name, artist, words from lyrics)
|
||||
✓1.1.2 Add "Detailed search button"
|
||||
✓1.1.3 Show hidden UI elements: song name, artist and lyrics EditText and spinner (full, partial )
|
||||
✓1.2 If user entered only artist, show artist search result
|
||||
✓1.2.1 Modify SearchActivity.documentHandle()
|
||||
✓1.3 Implement artist page
|
||||
|
||||
2. UI changes
|
||||
✓2.1 Add Magnifying-glass icon on the search button
|
||||
✓2.2 Add FAB button which scrolls the page all the way up, and which appears after user scrolled 2nd page
|
||||
✓2.3 Change app's color theme
|
||||
2.4 Add an additional search button (at the bottom of detailed search form)
|
||||
|
||||
✓3. Handle a no results situation
|
||||
|
||||
4. Add options menu
|
||||
✓5.1 Enable dark theme
|
||||
✓5.2 Quit app
|
||||
✓5.3 Contact developer
|
||||
✓5.4 Add/Remove to favorites
|
||||
✓5.5 Copy lyrics
|
||||
✓5.6 Change font size (dialog)
|
||||
✓5.7 Open favorites
|
||||
✓5.7.1 Create favorites activity
|
||||
|
||||
5. Fix lyrics page
|
||||
✓4.1 Add toolbar
|
||||
✓4.2 Make page scrollable
|
||||
✓4.3 Scale font size of textview with pinch zoom (https://stackoverflow.com/questions/40203241/android-custom-shape-for-zoom-buttons)
|
||||
✓4.4 Add option in toolbar to translate lyrics to romaji
|
||||
✓4.5 Show ProgressBar when loading lyrics
|
||||
✓4.6 Hide toolbar when scrolled
|
||||
✓4.7 Finish making share button
|
||||
|
||||
✓6. Create "Add lyrics to favorites" feature (https://codelabs.developers.google.com/codelabs/android-room-with-a-view/)
|
||||
✓6.1 Delete lyric by swiping
|
||||
✓6.2 Delete lyric by long tap
|
||||
✓6.3 In LyricsView, detect that if current lyrics is in the database
|
||||
|
||||
7. Catch all possible exceptions
|
||||
|
||||
8. Miscellaneous
|
||||
✓8.1 Fix the progress bar bug: from artist-list to song
|
||||
✓8.2 Add auto-increment ID field into the sql table
|
||||
✓8.3 Add app icon
|
||||
✓8.4 Change default picture in CardView
|
||||
✓8.5 Optimize the code
|
||||
✓8.5.1 Get rid of ButterKnife dependence
|
||||
✓8.6 Create random user-agent generator
|
||||
✓8.7 Adapt app's color theme in WebView
|
||||
|
||||
9. Convert lyrics to romaji
|
||||
✓9.1 Install kuromoji dependence
|
||||
✓9.2 Adapt jakaroma library
|
||||
✓9.3 Execute romanize() in AsyncTask
|
||||
✓9.4 Switch to original
|
||||
✓9.5 Hide layout and show progressBar and cancel fab
|
||||
|
||||
✓ - completed
|
||||
|
49
app/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2019 bernd32
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.bernd32.jlyrics">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application
|
||||
android:allowBackup="false"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
<activity android:name=".ui.FuriganaActivity" />
|
||||
<activity android:name=".ui.ArtistSongsActivity" />
|
||||
<activity
|
||||
android:name=".ui.FavoritesActivity"
|
||||
android:parentActivityName=".ui.LauncherActivity" />
|
||||
<activity android:name=".ui.ShowLyricsActivity" />
|
||||
<activity
|
||||
android:name=".ui.SearchActivity"
|
||||
android:parentActivityName=".ui.LauncherActivity" />
|
||||
<activity android:name=".ui.LauncherActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
BIN
app/src/main/ic_launcher-web.png
Normal file
After Width: | Height: | Size: 15 KiB |
43
app/src/main/java/com/bernd32/jlyrics/BaseViewHolder.java
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2019 bernd32
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bernd32.jlyrics;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
public abstract class BaseViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private int mCurrentPosition;
|
||||
|
||||
protected BaseViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
}
|
||||
|
||||
protected abstract void clear();
|
||||
|
||||
public void onBind(int position) {
|
||||
mCurrentPosition = position;
|
||||
clear();
|
||||
}
|
||||
|
||||
public int getCurrentPosition() {
|
||||
return mCurrentPosition;
|
||||
}
|
||||
|
||||
}
|
||||
|
75
app/src/main/java/com/bernd32/jlyrics/Lyric.java
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2019 bernd32
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bernd32.jlyrics;
|
||||
|
||||
public class Lyric {
|
||||
|
||||
private String cardTitle;
|
||||
private String cardDescription;
|
||||
private String imgUrl;
|
||||
private String songUrl;
|
||||
private String artistUrl;
|
||||
private String url;
|
||||
|
||||
public String getArtistUrl() {
|
||||
return artistUrl;
|
||||
}
|
||||
|
||||
public void setArtistUrl(String artistUrl) {
|
||||
this.artistUrl = artistUrl;
|
||||
}
|
||||
|
||||
public String getCardTitle() {
|
||||
return cardTitle;
|
||||
}
|
||||
|
||||
public void setCardTitle(String cardTitle) {
|
||||
this.cardTitle = cardTitle;
|
||||
}
|
||||
|
||||
public String getCardDescription() {
|
||||
return cardDescription;
|
||||
}
|
||||
|
||||
public void setCardDescription(String cardDescription) {
|
||||
this.cardDescription = cardDescription;
|
||||
}
|
||||
|
||||
public String getImgUrl() {
|
||||
return imgUrl;
|
||||
}
|
||||
|
||||
public void setImgUrl(String imgUrl) {
|
||||
this.imgUrl = imgUrl;
|
||||
}
|
||||
|
||||
public String getSongUrl() {
|
||||
return songUrl;
|
||||
}
|
||||
|
||||
public void setSongUrl(String songUrl) {
|
||||
this.songUrl = songUrl;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2019 bernd32
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bernd32.jlyrics;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
public abstract class PaginationListener extends RecyclerView.OnScrollListener {
|
||||
|
||||
public static final int PAGE_START = 1;
|
||||
@NonNull
|
||||
private LinearLayoutManager layoutManager;
|
||||
private static final int PAGE_SIZE = 20;
|
||||
|
||||
public PaginationListener(@NonNull LinearLayoutManager layoutManager) {
|
||||
this.layoutManager = layoutManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
|
||||
super.onScrolled(recyclerView, dx, dy);
|
||||
|
||||
int visibleItemCount = layoutManager.getChildCount();
|
||||
int totalItemCount = layoutManager.getItemCount();
|
||||
int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition();
|
||||
|
||||
if (!isLoading() && !isLastPage()) {
|
||||
if ((visibleItemCount + firstVisibleItemPosition) >= totalItemCount
|
||||
&& firstVisibleItemPosition >= 0
|
||||
&& totalItemCount >= PAGE_SIZE) {
|
||||
loadMoreItems();
|
||||
}
|
||||
}
|
||||
|
||||
if (dy > 0 && firstVisibleItemPosition > 5) {
|
||||
showFAB();
|
||||
}
|
||||
|
||||
if(dy < 0 && firstVisibleItemPosition < 5)
|
||||
hideFAB();
|
||||
}
|
||||
|
||||
protected abstract void showFAB();
|
||||
|
||||
protected abstract void hideFAB();
|
||||
|
||||
protected abstract void loadMoreItems();
|
||||
|
||||
protected abstract boolean isLastPage();
|
||||
|
||||
protected abstract boolean isLoading();
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2019 bernd32
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bernd32.jlyrics.adapters;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bernd32.jlyrics.BaseViewHolder;
|
||||
import com.bernd32.jlyrics.R;
|
||||
import com.bernd32.jlyrics.database.FavLyrics;
|
||||
import com.bernd32.jlyrics.ui.SearchActivity;
|
||||
import com.bernd32.jlyrics.ui.ShowLyricsActivity;
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.google.android.material.card.MaterialCardView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class FavLyricsAdapter extends RecyclerView.Adapter<BaseViewHolder> {
|
||||
private static final String TAG = "PostRecyclerAdapter";
|
||||
private List<FavLyrics> mPostItems;
|
||||
private Context mContext;
|
||||
|
||||
public FavLyricsAdapter(Context context, List<FavLyrics> postItems) {
|
||||
Log.d(TAG, "PostRecyclerAdapter: constructor activated");
|
||||
this.mPostItems = postItems;
|
||||
this.mContext = context;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
return new ViewHolder(
|
||||
LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_listitem, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull BaseViewHolder holder, int position) {
|
||||
holder.onBind(position);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mPostItems == null ? 0 : mPostItems.size();
|
||||
}
|
||||
|
||||
public void addItems(List<FavLyrics> postItems) {
|
||||
mPostItems.addAll(postItems);
|
||||
mPostItems = postItems;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
mPostItems.clear();
|
||||
notifyDataSetChanged();
|
||||
Glide.get(mContext).clearMemory();
|
||||
}
|
||||
|
||||
public FavLyrics getItem(int position) {
|
||||
return mPostItems.get(position);
|
||||
}
|
||||
|
||||
public class ViewHolder extends BaseViewHolder {
|
||||
TextView cardTitle;
|
||||
TextView cardDescription;
|
||||
ImageView image;
|
||||
MaterialCardView parentLayout;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
cardTitle = itemView.findViewById(R.id.card_title);
|
||||
cardDescription = itemView.findViewById(R.id.card_description);
|
||||
image = itemView.findViewById(R.id.image);
|
||||
parentLayout = itemView.findViewById(R.id.parent_layout);
|
||||
}
|
||||
|
||||
protected void clear() {
|
||||
|
||||
}
|
||||
|
||||
public void onBind(int position) {
|
||||
super.onBind(position);
|
||||
FavLyrics item = mPostItems.get(position);
|
||||
cardTitle.setText(item.getTitle());
|
||||
cardDescription.setText(item.getDescription());
|
||||
// If no picture found, set default picture
|
||||
if (item.getImgUrl().equals(SearchActivity.NO_IMG)) {
|
||||
image.setVisibility(View.GONE);
|
||||
} else {
|
||||
image.setVisibility(View.VISIBLE);
|
||||
Glide.with(mContext)
|
||||
.asBitmap()
|
||||
.load(item.getImgUrl())
|
||||
.into(image);
|
||||
}
|
||||
// click listener
|
||||
parentLayout.setOnClickListener(view -> {
|
||||
Intent intent = new Intent(mContext, ShowLyricsActivity.class);
|
||||
intent.putExtra("song_url", item.getUrl());
|
||||
intent.putExtra("title", item.getTitle());
|
||||
intent.putExtra("description", item.getDescription());
|
||||
intent.putExtra("img_url", item.getImgUrl());
|
||||
mContext.startActivity(intent);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright 2019 bernd32
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bernd32.jlyrics.adapters;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bernd32.jlyrics.BaseViewHolder;
|
||||
import com.bernd32.jlyrics.Lyric;
|
||||
import com.bernd32.jlyrics.R;
|
||||
import com.bernd32.jlyrics.ui.ArtistSongsActivity;
|
||||
import com.bernd32.jlyrics.ui.SearchActivity;
|
||||
import com.bernd32.jlyrics.ui.ShowLyricsActivity;
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.google.android.material.card.MaterialCardView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PostRecyclerAdapter extends RecyclerView.Adapter<BaseViewHolder> {
|
||||
private static final String TAG = "PostRecyclerAdapter";
|
||||
private static final int VIEW_TYPE_LOADING = 0;
|
||||
private static final int VIEW_TYPE_NORMAL = 1;
|
||||
public static final int SONG_PAGE = 0;
|
||||
public static final int ARTIST_LYRICS_PAGE = 1;
|
||||
public static final int ARTISTS_PAGE = 2;
|
||||
public static final int LYRICS_PAGE = 3;
|
||||
private boolean isLoaderVisible = false;
|
||||
private List<Lyric> mPostItems;
|
||||
private Context mContext;
|
||||
private int pageType;
|
||||
|
||||
public PostRecyclerAdapter(Context context, List<Lyric> postItems) {
|
||||
Log.d(TAG, "PostRecyclerAdapter: constructor activated");
|
||||
this.mPostItems = postItems;
|
||||
this.mContext = context;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public BaseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
|
||||
switch (viewType) {
|
||||
case VIEW_TYPE_NORMAL:
|
||||
return new ViewHolder(
|
||||
LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_listitem, parent, false));
|
||||
case VIEW_TYPE_LOADING:
|
||||
return new ProgressHolder(
|
||||
LayoutInflater.from(parent.getContext()).inflate(R.layout.item_loading, parent, false));
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull BaseViewHolder holder, int position) {
|
||||
holder.onBind(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
if (isLoaderVisible) {
|
||||
return position == mPostItems.size() - 1 ? VIEW_TYPE_LOADING : VIEW_TYPE_NORMAL;
|
||||
} else {
|
||||
return VIEW_TYPE_NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mPostItems == null ? 0 : mPostItems.size();
|
||||
}
|
||||
|
||||
public void addItems(List<Lyric> postItems) {
|
||||
mPostItems.addAll(postItems);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void addLoading() {
|
||||
isLoaderVisible = true;
|
||||
mPostItems.add(new Lyric());
|
||||
notifyItemInserted(mPostItems.size() - 1);
|
||||
}
|
||||
|
||||
public void removeLoading() {
|
||||
isLoaderVisible = false;
|
||||
int position = mPostItems.size() - 1;
|
||||
Lyric item = getItem(position);
|
||||
if (item != null) {
|
||||
mPostItems.remove(position);
|
||||
notifyItemRemoved(position);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
Log.d(TAG, "clear: started");
|
||||
// use it when performing new search
|
||||
mPostItems.clear();
|
||||
notifyDataSetChanged();
|
||||
Glide.get(mContext).clearMemory();
|
||||
}
|
||||
|
||||
private Lyric getItem(int position) {
|
||||
return mPostItems.get(position);
|
||||
}
|
||||
|
||||
public void setPageType(int pageType) {
|
||||
this.pageType = pageType;
|
||||
}
|
||||
|
||||
public class ViewHolder extends BaseViewHolder {
|
||||
TextView cardTitle;
|
||||
TextView cardDescription;
|
||||
ImageView image;
|
||||
MaterialCardView parentLayout;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
cardTitle = itemView.findViewById(R.id.card_title);
|
||||
cardDescription = itemView.findViewById(R.id.card_description);
|
||||
image = itemView.findViewById(R.id.image);
|
||||
parentLayout = itemView.findViewById(R.id.parent_layout);
|
||||
}
|
||||
|
||||
protected void clear() {
|
||||
|
||||
}
|
||||
|
||||
public void onBind(int position) {
|
||||
super.onBind(position);
|
||||
Lyric item = mPostItems.get(position);
|
||||
cardTitle.setText(item.getCardTitle());
|
||||
cardDescription.setText(item.getCardDescription());
|
||||
Log.d(TAG, "onBind: item#"+position+" img url="+ item.getImgUrl());
|
||||
// If no picture found, set default picture
|
||||
if (item.getImgUrl().equals(SearchActivity.NO_IMG)) {
|
||||
image.setVisibility(View.GONE);
|
||||
} else {
|
||||
image.setVisibility(View.VISIBLE);
|
||||
Glide.with(mContext)
|
||||
.asBitmap()
|
||||
.load(item.getImgUrl())
|
||||
.into(image);
|
||||
}
|
||||
// click listener
|
||||
parentLayout.setOnClickListener(view -> {
|
||||
Log.d(TAG, "onBind: " + pageType);
|
||||
if (pageType == SONG_PAGE || pageType == ARTIST_LYRICS_PAGE) {
|
||||
Intent intent = new Intent(mContext, ShowLyricsActivity.class);
|
||||
intent.putExtra("song_url", item.getSongUrl());
|
||||
intent.putExtra("title", item.getCardTitle());
|
||||
intent.putExtra("description", item.getCardDescription());
|
||||
intent.putExtra("img_url", item.getImgUrl());
|
||||
mContext.startActivity(intent);
|
||||
} else {
|
||||
Intent intent = new Intent(mContext, ArtistSongsActivity.class);
|
||||
intent.putExtra("url", item.getArtistUrl());
|
||||
intent.putExtra("title", item.getCardTitle());
|
||||
intent.putExtra("description", item.getCardDescription());
|
||||
intent.putExtra("img_url", item.getImgUrl());
|
||||
mContext.startActivity(intent);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected class ProgressHolder extends BaseViewHolder {
|
||||
ProgressHolder(View itemView) {
|
||||
super(itemView);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clear() {
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2019 bernd32
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bernd32.jlyrics.async;
|
||||
|
||||
public interface AsyncTaskListener<T> {
|
||||
void onPreTask();
|
||||
void onPostTask(T object);
|
||||
void onFailure(Exception e, int statusCode);
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2019 bernd32
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bernd32.jlyrics.async;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import com.bernd32.jlyrics.utils.HelperClass;
|
||||
|
||||
import org.jsoup.HttpStatusException;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
|
||||
public class GetDataAsyncTask extends AsyncTask<String, Void, Document> { // <[Input_Parameter Type], [Progress_Report Type], [Result Type]>
|
||||
private static final String TAG = "GetDataAsyncTask";
|
||||
private Exception exception;
|
||||
private int httpStatusCode;
|
||||
private AsyncTaskListener<Document> asyncTaskListener;
|
||||
|
||||
public GetDataAsyncTask(AsyncTaskListener<Document> asyncTaskListener) {
|
||||
this.asyncTaskListener = asyncTaskListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCancelled() {
|
||||
super.onCancelled();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
asyncTaskListener.onPreTask();
|
||||
super.onPreExecute();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Document doInBackground(String... params) {
|
||||
String url = params[0];
|
||||
Log.d(TAG, "doInBackground: loading url: " + url);
|
||||
Document doc;
|
||||
String userAgent = HelperClass.getUserAgent();
|
||||
try {
|
||||
doc = Jsoup
|
||||
.connect(url)
|
||||
.userAgent(userAgent)
|
||||
.referrer("https://www.google.co.jp/")
|
||||
.get();
|
||||
} catch (Exception e) {
|
||||
if (e instanceof HttpStatusException) {
|
||||
httpStatusCode = ((HttpStatusException) e).getStatusCode();
|
||||
}
|
||||
exception = e;
|
||||
Log.d(TAG, "doInBackground: " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
return doc.outputSettings(new Document.OutputSettings().prettyPrint(false));
|
||||
}
|
||||
|
||||
protected void onPostExecute(Document s) {
|
||||
super.onPostExecute(s);
|
||||
if (asyncTaskListener != null) {
|
||||
if (exception == null) {
|
||||
asyncTaskListener.onPostTask(s);
|
||||
} else {
|
||||
asyncTaskListener.onFailure(exception, httpStatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2019 bernd32
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bernd32.jlyrics.async;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import com.bernd32.jlyrics.utils.HelperClass;
|
||||
|
||||
import org.jsoup.Connection;
|
||||
import org.jsoup.HttpStatusException;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
|
||||
/**
|
||||
* Used for showing furigana
|
||||
*/
|
||||
|
||||
public class PostDataAsyncTask extends AsyncTask<String, Void, Document> { // <[Input_Parameter Type], [Progress_Report Type], [Result Type]>
|
||||
private static final String TAG = "PostDataAsyncTask";
|
||||
private Exception exception;
|
||||
private int httpStatusCode;
|
||||
private AsyncTaskListener<String> listener;
|
||||
|
||||
public PostDataAsyncTask(AsyncTaskListener<String> listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCancelled() {
|
||||
super.onCancelled();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
super.onPreExecute();
|
||||
listener.onPreTask();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Document doInBackground(String... params) {
|
||||
// params[0] is a lyric text
|
||||
String url;
|
||||
url = "https://www.jcinfo.net/ja/tools/kana";
|
||||
Log.d(TAG, "doInBackground: params="+params[0]);
|
||||
Document doc;
|
||||
String userAgent = HelperClass.getUserAgent();
|
||||
try {
|
||||
|
||||
Connection.Response response = Jsoup
|
||||
.connect(url)
|
||||
.method(Connection.Method.POST)
|
||||
.userAgent(userAgent)
|
||||
.referrer("https://www.google.co.jp/")
|
||||
.data("txt", params[0])
|
||||
.execute();
|
||||
doc = response.parse();
|
||||
} catch (Exception e) {
|
||||
if (e instanceof HttpStatusException) {
|
||||
httpStatusCode = ((HttpStatusException) e).getStatusCode();
|
||||
}
|
||||
exception = e;
|
||||
Log.d(TAG, "doInBackground: " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
return doc;
|
||||
}
|
||||
|
||||
protected void onPostExecute(Document s) {
|
||||
String htmlString = s.select("#main-content > div.dsp2.radius_5").html();
|
||||
Log.d(TAG, "onPostExecute: \n\n" + htmlString);
|
||||
super.onPostExecute(s);
|
||||
if (listener != null) {
|
||||
if (exception == null) {
|
||||
listener.onPostTask(htmlString);
|
||||
} else {
|
||||
listener.onFailure(exception, httpStatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2019 bernd32
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bernd32.jlyrics.async;
|
||||
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import com.bernd32.romajihenkan.RomajiHenkan;
|
||||
|
||||
/**
|
||||
* Converting a Japanese text to romaji.
|
||||
* Since this operation is time-consuming, it should be performed in a non-UI thread
|
||||
*/
|
||||
|
||||
public class RomanizeAsyncTask extends AsyncTask<String, Void, String> {
|
||||
|
||||
private AsyncTaskListener<String> listener;
|
||||
|
||||
public RomanizeAsyncTask(AsyncTaskListener<String> listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
super.onPreExecute();
|
||||
listener.onPreTask();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String string) {
|
||||
if (listener != null) {
|
||||
listener.onPostTask(string);
|
||||
}
|
||||
super.onPostExecute(string);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCancelled() {
|
||||
super.onCancelled();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doInBackground(String... strings) {
|
||||
RomajiHenkan henkan = new RomajiHenkan();
|
||||
return henkan.convert(strings[0]);
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2019 bernd32
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bernd32.jlyrics.database;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.room.ColumnInfo;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
@Entity(tableName = "lyrics")
|
||||
public class FavLyrics {
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
private Integer id;
|
||||
|
||||
@NonNull
|
||||
@ColumnInfo(name = "title")
|
||||
private String mTitle;
|
||||
|
||||
@NonNull
|
||||
@ColumnInfo(name = "description")
|
||||
private String mDescription;
|
||||
|
||||
@NonNull
|
||||
@ColumnInfo(name = "url")
|
||||
private String mUrl;
|
||||
|
||||
@NonNull
|
||||
@ColumnInfo(name = "img_url")
|
||||
private String mImgUrl;
|
||||
|
||||
@ColumnInfo(name = "time_stamp")
|
||||
private long mTimeStamp;
|
||||
|
||||
public FavLyrics(@NonNull String title, @NonNull String description,
|
||||
@NonNull String url, @NonNull String imgUrl, long timeStamp) {
|
||||
this.mTitle = title;
|
||||
this.mDescription = description;
|
||||
this.mUrl = url;
|
||||
this.mImgUrl = imgUrl;
|
||||
this.mTimeStamp = timeStamp;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getTitle() {
|
||||
return this.mTitle;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getDescription() {
|
||||
return this.mDescription;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getUrl() {
|
||||
return this.mUrl;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getImgUrl() {
|
||||
return this.mImgUrl;
|
||||
}
|
||||
|
||||
public long getTimeStamp() {return this.mTimeStamp; }
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2019 bernd32
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bernd32.jlyrics.database;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Delete;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.OnConflictStrategy;
|
||||
import androidx.room.Query;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Dao
|
||||
public interface LyricsDao {
|
||||
|
||||
// Notifies its active observers when the data has changed.
|
||||
|
||||
@Query("SELECT * from lyrics ORDER BY id DESC")
|
||||
LiveData<List<FavLyrics>> getFavLyricsById();
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
void insert(FavLyrics lyrics);
|
||||
|
||||
@Query("DELETE FROM lyrics")
|
||||
void deleteAll();
|
||||
|
||||
@Delete
|
||||
void deleteLyrics(FavLyrics lyrics);
|
||||
|
||||
@Query("SELECT count(*) FROM lyrics WHERE url = :url")
|
||||
int isLyricsExists(String url);
|
||||
|
||||
@Query("DELETE FROM lyrics WHERE url = :url")
|
||||
void deleteLyricsByUrl(String url);
|
||||
}
|
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright 2019 bernd32
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bernd32.jlyrics.database;
|
||||
|
||||
import android.app.Application;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
class LyricsRepository {
|
||||
|
||||
private LyricsDao mLyricsDao;
|
||||
private LiveData<List<FavLyrics>> mAllFavLyrics;
|
||||
|
||||
public LyricsRepository(Application application) {
|
||||
LyricsRoomDatabase db = LyricsRoomDatabase.getDatabase(application);
|
||||
mLyricsDao = db.lyricsDao();
|
||||
mAllFavLyrics = mLyricsDao.getFavLyricsById();
|
||||
}
|
||||
|
||||
// Room executes all queries on a separate thread.
|
||||
// Observed LiveData will notify the observer when the data has changed.
|
||||
public LiveData<List<FavLyrics>> getAllLyrics() {
|
||||
return mAllFavLyrics;
|
||||
}
|
||||
|
||||
// Must call this on a non-UI thread
|
||||
public void insert(FavLyrics lyrics) {
|
||||
LyricsRoomDatabase.databaseWriteExecutor.execute(() -> {
|
||||
mLyricsDao.insert(lyrics);
|
||||
});
|
||||
}
|
||||
|
||||
public void deleteAll() {
|
||||
new DeleteAllLyricsAsyncTask(mLyricsDao).execute();
|
||||
}
|
||||
|
||||
// Need to run off main thread
|
||||
public void deleteLyrics(FavLyrics lyrics) {
|
||||
new DeleteLyricsAsyncTask(mLyricsDao).execute(lyrics);
|
||||
}
|
||||
|
||||
public boolean isLyricsExists(String url) throws ExecutionException, InterruptedException {
|
||||
new SearchLyricsAsyncTask(mLyricsDao).execute(url);
|
||||
SearchLyricsAsyncTask searchLyricsAsyncTask = new SearchLyricsAsyncTask(mLyricsDao);
|
||||
return searchLyricsAsyncTask.execute(url).get();
|
||||
}
|
||||
|
||||
|
||||
public void deleteLyricsByUrl(String url) {
|
||||
new DeleteLyricsByURLAsyncTask(mLyricsDao).execute(url);
|
||||
}
|
||||
|
||||
|
||||
// Delete all favorites from the database (does not delete the table)
|
||||
private static class DeleteAllLyricsAsyncTask extends AsyncTask<Void, Void, Void> {
|
||||
private LyricsDao mAsyncTaskDao;
|
||||
|
||||
DeleteAllLyricsAsyncTask(LyricsDao dao) {
|
||||
mAsyncTaskDao = dao;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
mAsyncTaskDao.deleteAll();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete a single favorite from the database.
|
||||
|
||||
private static class DeleteLyricsAsyncTask extends AsyncTask<FavLyrics, Void, Void> {
|
||||
private LyricsDao mAsyncTaskDao;
|
||||
|
||||
DeleteLyricsAsyncTask(LyricsDao dao) {
|
||||
mAsyncTaskDao = dao;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(final FavLyrics... params) {
|
||||
mAsyncTaskDao.deleteLyrics(params[0]);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class SearchLyricsAsyncTask extends AsyncTask<String, Void, Boolean> {
|
||||
private LyricsDao mAsyncTaskDao;
|
||||
|
||||
SearchLyricsAsyncTask(LyricsDao dao) {
|
||||
mAsyncTaskDao = dao;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(final String... params) {
|
||||
int count = mAsyncTaskDao.isLyricsExists(params[0]);
|
||||
return count != 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static class DeleteLyricsByURLAsyncTask extends AsyncTask<String, Void, Void> {
|
||||
private LyricsDao mAsyncTaskDao;
|
||||
|
||||
DeleteLyricsByURLAsyncTask(LyricsDao dao) {
|
||||
mAsyncTaskDao = dao;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(final String... params) {
|
||||
mAsyncTaskDao.deleteLyricsByUrl(params[0]);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2019 bernd32
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bernd32.jlyrics.database;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.room.Database;
|
||||
import androidx.room.Room;
|
||||
import androidx.room.RoomDatabase;
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
@Database(entities = {FavLyrics.class}, version = 3, exportSchema = false)
|
||||
public abstract class LyricsRoomDatabase extends RoomDatabase {
|
||||
|
||||
abstract LyricsDao lyricsDao();
|
||||
|
||||
// marking the instance as volatile to ensure atomic access to the variable
|
||||
private static volatile LyricsRoomDatabase INSTANCE;
|
||||
private static final int NUMBER_OF_THREADS = 4;
|
||||
static final ExecutorService databaseWriteExecutor =
|
||||
Executors.newFixedThreadPool(NUMBER_OF_THREADS);
|
||||
|
||||
static LyricsRoomDatabase getDatabase(final Context context) {
|
||||
if (INSTANCE == null) {
|
||||
synchronized (LyricsRoomDatabase.class) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
|
||||
LyricsRoomDatabase.class, "lyrics_database")
|
||||
.fallbackToDestructiveMigration()
|
||||
.addCallback(sRoomDatabaseCallback)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the onOpen method to populate the database.
|
||||
* For this sample, we clear the database every time it is created or opened.
|
||||
*
|
||||
* If you want to populate the database only when the database is created for the 1st time,
|
||||
* override RoomDatabase.Callback()#onCreate
|
||||
*/
|
||||
private static RoomDatabase.Callback sRoomDatabaseCallback = new RoomDatabase.Callback() {
|
||||
@Override
|
||||
public void onOpen(@NonNull SupportSQLiteDatabase db) {
|
||||
super.onOpen(db);
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2019 bernd32
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bernd32.jlyrics.database;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/**
|
||||
* View Model to keep a reference to the lyrics repository and
|
||||
* an up-to-date list of all words.
|
||||
*/
|
||||
|
||||
public class LyricsViewModel extends AndroidViewModel {
|
||||
|
||||
private LyricsRepository mRepository;
|
||||
// Using LiveData and caching what getFavLyricsById returns has several benefits:
|
||||
// - We can put an observer on the data (instead of polling for changes) and only update the
|
||||
// the UI when the data actually changes.
|
||||
// - Repository is completely separated from the UI through the ViewModel.
|
||||
private LiveData<List<FavLyrics>> mAllLyrics;
|
||||
|
||||
public LyricsViewModel(Application application) {
|
||||
super(application);
|
||||
mRepository = new LyricsRepository(application);
|
||||
mAllLyrics = mRepository.getAllLyrics();
|
||||
}
|
||||
|
||||
public LiveData<List<FavLyrics>> getAllLyrics() {
|
||||
return mAllLyrics;
|
||||
}
|
||||
|
||||
public void insert(FavLyrics lyrics) {
|
||||
mRepository.insert(lyrics);
|
||||
}
|
||||
|
||||
public void deleteAll() {
|
||||
mRepository.deleteAll();
|
||||
}
|
||||
|
||||
public void deleteLyrics(FavLyrics lyrics) {
|
||||
mRepository.deleteLyrics(lyrics);
|
||||
}
|
||||
|
||||
public boolean isLyricsExists(String url) throws ExecutionException, InterruptedException {
|
||||
return mRepository.isLyricsExists(url);
|
||||
}
|
||||
|
||||
public void deleteLyricsByUrl(String url) {
|
||||
mRepository.deleteLyricsByUrl(url);
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.bernd32.jlyrics.search;
|
||||
|
||||
import com.bernd32.jlyrics.Lyric;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public interface CallbackInterface {
|
||||
|
||||
void showAlertDialog();
|
||||
void setActivityTitle(int numberOfSongs);
|
||||
void setPageType(int pageType);
|
||||
void getSearchResults(ArrayList<Lyric> items);
|
||||
void taskStarted();
|
||||
void taskFinished();
|
||||
void taskFailed(Exception e, int statusCode);
|
||||
|
||||
}
|
@ -0,0 +1,230 @@
|
||||
package com.bernd32.jlyrics.search;
|
||||
|
||||
import android.app.Application;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import com.bernd32.jlyrics.Lyric;
|
||||
import com.bernd32.jlyrics.adapters.PostRecyclerAdapter;
|
||||
import com.bernd32.jlyrics.async.AsyncTaskListener;
|
||||
import com.bernd32.jlyrics.async.GetDataAsyncTask;
|
||||
|
||||
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static com.bernd32.jlyrics.adapters.PostRecyclerAdapter.ARTISTS_PAGE;
|
||||
import static com.bernd32.jlyrics.adapters.PostRecyclerAdapter.SONG_PAGE;
|
||||
import static com.bernd32.jlyrics.ui.SearchActivity.NO_IMG;
|
||||
|
||||
class SearchLyricsRepository {
|
||||
|
||||
private static final String TAG = "SearchLyricsRepository";
|
||||
private CallbackInterface listener;
|
||||
private int pageType;
|
||||
private int maxPage;
|
||||
|
||||
SearchLyricsRepository(Application application) {
|
||||
}
|
||||
|
||||
void newSearchRequest(String url) {
|
||||
getDocumentAsyncTask(url);
|
||||
}
|
||||
|
||||
private ArrayList<Lyric> artistSearch(Document doc) {
|
||||
// Handles artist search result
|
||||
final ArrayList<Lyric> items = new ArrayList<>();
|
||||
Elements imgElements = doc.select("#mnb > div.bdy");
|
||||
Elements artists = doc.select("#mnb > div > p.mid > a");
|
||||
Elements urls = doc.select("#mnb > div > p.mid > a");
|
||||
Elements lyricsNumber = doc.select("#mnb > div > p.sml:contains(収録数:)");
|
||||
int maxPages = 1;
|
||||
// Show alert dialog if nothing found
|
||||
if (artists.size() == 0) {
|
||||
listener.showAlertDialog();
|
||||
} else {
|
||||
for (int i = 0; i < artists.size(); i++) {
|
||||
Lyric postItem = new Lyric();
|
||||
String getArtist = artists.get(i).text();
|
||||
String getNumberOfSongs = lyricsNumber.get(i).text()
|
||||
.replace("収録数:", "Lyrics: ")
|
||||
.replace("曲", "");
|
||||
String imgSrc = imgElements.get(i).select("a > img").attr("src");
|
||||
if (!imgSrc.isEmpty()) {
|
||||
postItem.setImgUrl(imgSrc);
|
||||
} else {
|
||||
postItem.setImgUrl(NO_IMG);
|
||||
}
|
||||
String artistUrl = urls.get(i).attr("href");
|
||||
postItem.setCardTitle(getArtist);
|
||||
postItem.setCardDescription(getNumberOfSongs);
|
||||
postItem.setArtistUrl(artistUrl);
|
||||
items.add(postItem);
|
||||
}
|
||||
listener.setActivityTitle(artists.size());
|
||||
setMaxPage(maxPage);
|
||||
}
|
||||
listener.getSearchResults(items);
|
||||
return items;
|
||||
}
|
||||
|
||||
private ArrayList<Lyric> songSearch(Document doc) {
|
||||
Log.d(TAG, "songSearch: started");
|
||||
final ArrayList<Lyric> items = new ArrayList<>();
|
||||
maxPage = 1;
|
||||
Elements imgElements = doc.select("#mnb > div.bdy");
|
||||
Elements urls = doc.select("#mnb > div > p.mid > a");
|
||||
Elements songNames = doc.select("#mnb > div.bdy > p.mid");
|
||||
Elements artists = doc.select("#mnb > div.bdy > p.sml:contains(歌:)");
|
||||
Element pageUrlElement = doc.select("#pager > a").first();
|
||||
// Show alert dialog if nothing found
|
||||
if (artists.size() == 0) {
|
||||
listener.showAlertDialog();
|
||||
} else {
|
||||
for (int i = 0; i < artists.size(); i++) {
|
||||
Lyric lyric = new Lyric();
|
||||
String imgSrc = imgElements.get(i).select("a > img").attr("src");
|
||||
if (!imgSrc.isEmpty()) {
|
||||
lyric.setImgUrl(imgSrc);
|
||||
} else {
|
||||
lyric.setImgUrl(NO_IMG);
|
||||
}
|
||||
String url = urls.get(i).attr("href");
|
||||
lyric.setSongUrl(url);
|
||||
lyric.setCardTitle(songNames.get(i).text());
|
||||
lyric.setCardDescription(artists.get(i).text().replace("歌:", ""));
|
||||
items.add(lyric);
|
||||
maxPage = numberOfPages(getNumberOfSongsFound(pageUrlElement));
|
||||
setMaxPage(maxPage);
|
||||
}
|
||||
listener.setActivityTitle(getNumberOfSongsFound(pageUrlElement));
|
||||
}
|
||||
listener.getSearchResults(items);
|
||||
return items;
|
||||
}
|
||||
|
||||
private int getPageType(Document doc) {
|
||||
String description = doc.select("meta[name=description]").first().attr("content");
|
||||
Elements lyricsNumber = doc.select("#mnb > div > p.sml:contains(収録数:)");
|
||||
// keywords for detecting a page type
|
||||
final String search_result_keyword = "検索結果ページ";
|
||||
final String lyrics_page_keyword = "歌詞ページ";
|
||||
final String artist_list_keyword = "歌詞一覧ページ";
|
||||
final String artist_search_result_keyword = "歌手名に";
|
||||
if (description.contains(search_result_keyword) && lyricsNumber.isEmpty()) {
|
||||
// Song search result (has pages)
|
||||
Log.d(TAG, "getPageType: Search result page detected");
|
||||
pageType = PostRecyclerAdapter.SONG_PAGE;
|
||||
//adapter.setPageType(pageType);
|
||||
listener.setPageType(pageType);
|
||||
return pageType;
|
||||
|
||||
} else if (description.contains(lyrics_page_keyword)) {
|
||||
Log.d(TAG, "getPageType: Lyrics page detected");
|
||||
pageType = PostRecyclerAdapter.LYRICS_PAGE;
|
||||
//adapter.setPageType(pageType);
|
||||
return pageType;
|
||||
} else if (description.contains(artist_list_keyword)) {
|
||||
Log.d(TAG, "getPageType: Artist list page detected");
|
||||
pageType = PostRecyclerAdapter.ARTIST_LYRICS_PAGE;
|
||||
listener.setPageType(pageType);
|
||||
return pageType;
|
||||
} else if(description.contains(artist_search_result_keyword) && !lyricsNumber.isEmpty()) {
|
||||
Log.d(TAG, "getPageType: Artist search result page detected");
|
||||
pageType = PostRecyclerAdapter.ARTISTS_PAGE;
|
||||
listener.setPageType(pageType);
|
||||
return pageType;
|
||||
} else {
|
||||
Log.d(TAG, "getPageType: cannot detect page type");
|
||||
return PostRecyclerAdapter.SONG_PAGE;
|
||||
}
|
||||
}
|
||||
|
||||
private void getDocumentAsyncTask(String url) {
|
||||
Log.d(TAG, "startAsyncTask: " + url);
|
||||
GetDataAsyncTask task = new GetDataAsyncTask(new AsyncTaskListener<Document>() {
|
||||
@Override
|
||||
public void onPreTask() {
|
||||
listener.taskStarted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostTask(Document doc) {
|
||||
pageType = getPageType(doc);
|
||||
// Get lyrics from a song search type
|
||||
if (pageType == SONG_PAGE) {
|
||||
songSearch(doc);
|
||||
} else if (pageType == ARTISTS_PAGE) {
|
||||
artistSearch(doc);
|
||||
} else {
|
||||
artistSongList(doc);
|
||||
}
|
||||
listener.taskFinished();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e, int statusCode) {
|
||||
listener.taskFailed(e, statusCode);
|
||||
}
|
||||
});
|
||||
task.execute(url);
|
||||
}
|
||||
|
||||
private ArrayList<Lyric> artistSongList(Document doc) {
|
||||
// Handles artist's list of lyrics
|
||||
final ArrayList<Lyric> items = new ArrayList<>();
|
||||
Elements imgElements = doc.select("#mnb > div.cnt > div[id^=ly]");
|
||||
Elements titles = doc.select("#mnb > div.cnt > div[id^=ly] > p.ttl > a");
|
||||
String description = doc.selectFirst("#mnb > div.cnt > div.cap > h2").text();
|
||||
for (int i = 0; i < titles.size(); i++) {
|
||||
Lyric postItem = new Lyric();
|
||||
String imgSrc = imgElements.get(i).select("a > img.i5r").attr("src");
|
||||
if (!imgSrc.isEmpty()) {
|
||||
Log.d(TAG, i + " = " + imgSrc);
|
||||
postItem.setImgUrl(imgSrc);
|
||||
} else {
|
||||
Log.d(TAG, "artistDocumentHandle: no image found");
|
||||
postItem.setImgUrl(NO_IMG);
|
||||
}
|
||||
String title = titles.get(i).text();
|
||||
String url = titles.get(i).attr("href");
|
||||
postItem.setCardTitle(title);
|
||||
postItem.setCardDescription(description.replace("の歌詞リスト", "")); // leave blank for now
|
||||
postItem.setSongUrl("http://j-lyric.net" + url);
|
||||
Log.d(TAG, "documentHandler: url = http://j-lyric.net" + url);
|
||||
items.add(postItem);
|
||||
}
|
||||
listener.setActivityTitle(titles.size());
|
||||
listener.getSearchResults(items);
|
||||
return items;
|
||||
}
|
||||
|
||||
private int getNumberOfSongsFound(Element pageUrlElement) {
|
||||
String url = pageUrlElement.attr("href");
|
||||
Uri uri = Uri.parse(url);
|
||||
String c = uri.getQueryParameter("c");
|
||||
assert c != null;
|
||||
return Integer.valueOf(c);
|
||||
}
|
||||
|
||||
private int numberOfPages(int songs) {
|
||||
double p = Math.ceil((double) songs/20);
|
||||
return (int) p;
|
||||
}
|
||||
|
||||
public void addListener(CallbackInterface listener) {
|
||||
this.listener = listener;
|
||||
|
||||
}
|
||||
|
||||
public void setMaxPage(int maxPage) {
|
||||
this.maxPage = maxPage;
|
||||
}
|
||||
|
||||
public int getMaxPage() {
|
||||
return maxPage;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.bernd32.jlyrics.search;
|
||||
|
||||
import android.app.Application;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
|
||||
public class SearchLyricsViewModel extends AndroidViewModel {
|
||||
|
||||
private SearchLyricsRepository mRepository;
|
||||
private static final String TAG = "SearchLyricsViewModel";
|
||||
|
||||
public SearchLyricsViewModel(Application application) {
|
||||
super(application);
|
||||
mRepository = new SearchLyricsRepository(application);
|
||||
}
|
||||
|
||||
public void newSearchRequest(String url) {
|
||||
Log.d(TAG, "newSearchRequest: " + url);
|
||||
mRepository.newSearchRequest(url);
|
||||
}
|
||||
|
||||
public void addListener(CallbackInterface callback) {
|
||||
mRepository.addListener(callback);
|
||||
}
|
||||
|
||||
public int getMaxPage() {
|
||||
Log.d(TAG, "getMaxPage: " + mRepository.getMaxPage());
|
||||
return mRepository.getMaxPage();
|
||||
}
|
||||
}
|
@ -0,0 +1,174 @@
|
||||
package com.bernd32.jlyrics.ui;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bernd32.jlyrics.Lyric;
|
||||
import com.bernd32.jlyrics.PaginationListener;
|
||||
import com.bernd32.jlyrics.R;
|
||||
import com.bernd32.jlyrics.adapters.PostRecyclerAdapter;
|
||||
import com.bernd32.jlyrics.async.GetDataAsyncTask;
|
||||
import com.bernd32.jlyrics.search.CallbackInterface;
|
||||
import com.bernd32.jlyrics.search.SearchLyricsViewModel;
|
||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ArtistSongsActivity extends AppCompatActivity {
|
||||
|
||||
private static final String TAG = "SearchActivity";
|
||||
private static final String NO_IMG = "no_img";
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public RecyclerView mRecyclerView;
|
||||
private ProgressBar progressBar;
|
||||
private PostRecyclerAdapter adapter;
|
||||
private String url;
|
||||
private FloatingActionButton floatingActionButton;
|
||||
private ExtendedFloatingActionButton cancelFAB;
|
||||
private GetDataAsyncTask task;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
Log.d(TAG, "onCreate: started");
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_search);
|
||||
cancelFAB = findViewById(R.id.load_cancel);
|
||||
progressBar = findViewById(R.id.progress_bar);
|
||||
mRecyclerView = findViewById(R.id.recyclerv_view);
|
||||
floatingActionButton = findViewById(R.id.floating_action_button);
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
assert actionBar != null;
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
Bundle extras = getIntent().getExtras();
|
||||
if (extras != null) {
|
||||
loadIntents();
|
||||
}
|
||||
mRecyclerView.setHasFixedSize(true);
|
||||
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
|
||||
mRecyclerView.setLayoutManager(layoutManager);
|
||||
adapter = new PostRecyclerAdapter(this, new ArrayList<>());
|
||||
mRecyclerView.setAdapter(adapter);
|
||||
|
||||
SearchLyricsViewModel viewModel = new ViewModelProvider(this).get(SearchLyricsViewModel.class);
|
||||
// show progressbar only in initial loading
|
||||
CallbackInterface listener = new CallbackInterface() {
|
||||
|
||||
@Override
|
||||
public void showAlertDialog() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActivityTitle(int numberOfSongs) {
|
||||
ArtistSongsActivity.this.setTitle(getString(R.string.title_found) +
|
||||
" " + numberOfSongs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPageType(int pageType) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getSearchResults(ArrayList<Lyric> items) {
|
||||
adapter.addItems(items);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void taskStarted() {
|
||||
Log.d(TAG, "onPreTask: started");
|
||||
// show progressbar only in initial loading
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
cancelFAB.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void taskFinished() {
|
||||
Log.d(TAG, "onPostTask: started");
|
||||
progressBar.setVisibility(View.GONE);
|
||||
cancelFAB.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void taskFailed(Exception e, int statusCode) {
|
||||
Toast.makeText(ArtistSongsActivity.this,
|
||||
getString(R.string.connection_failed),
|
||||
Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
Log.d(TAG, "onFailure: " + e.toString());
|
||||
}
|
||||
};
|
||||
|
||||
viewModel.addListener(listener);
|
||||
viewModel.newSearchRequest(url);
|
||||
|
||||
floatingActionButton.setOnClickListener(view -> {
|
||||
mRecyclerView.smoothScrollToPosition(0);
|
||||
});
|
||||
mRecyclerView.addOnScrollListener(new PaginationListener(layoutManager) {
|
||||
@Override
|
||||
protected void loadMoreItems() {
|
||||
floatingActionButton.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLastPage() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLoading() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void showFAB() {
|
||||
if(floatingActionButton.getVisibility() != View.VISIBLE) {
|
||||
floatingActionButton.show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void hideFAB() {
|
||||
if(floatingActionButton.getVisibility() == View.VISIBLE) {
|
||||
floatingActionButton.hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSupportNavigateUp(){
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onLoadCancel(View view) {
|
||||
if (task != null)
|
||||
task.cancel(true);
|
||||
finish();
|
||||
}
|
||||
|
||||
private void loadIntents() {
|
||||
Intent intent = getIntent();
|
||||
String title = intent.getStringExtra("title");
|
||||
String description = intent.getStringExtra("description");
|
||||
url = intent.getStringExtra("url");
|
||||
String imgUrl = intent.getStringExtra("img_url");
|
||||
}
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright 2019 bernd32
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bernd32.jlyrics.ui;
|
||||
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
|
||||
import com.bernd32.jlyrics.R;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
class ChangeFontDialogFragment extends DialogFragment {
|
||||
private static final String TAG = "ChangeFontDialogFragmen";
|
||||
private OnDialogButtonClick listener;
|
||||
|
||||
public void setOnDialogButtonClick(OnDialogButtonClick buttonClick) {
|
||||
this.listener = buttonClick;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(@NonNull Context context) {
|
||||
super.onAttach(context);
|
||||
// Instantiate the NoticeDialogListener so we can send events to the host
|
||||
listener = (OnDialogButtonClick) context;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
Log.d(TAG, "onCreate: started");
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
Log.d(TAG, "onCreateView: started");
|
||||
return inflater.inflate(R.layout.dialog_change_fontsize, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
Log.d(TAG, "onViewCreated: started");
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
Log.d(TAG, "onCreateDialog: started");
|
||||
// Use the Builder class for convenient dialog construction
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(Objects.requireNonNull(getActivity()));
|
||||
// Get the layout inflater
|
||||
LayoutInflater inflater = requireActivity().getLayoutInflater();
|
||||
// Inflate and set the layout for the dialog
|
||||
// Pass null as the parent view because its going in the dialog layout
|
||||
@SuppressLint("InflateParams") View content = inflater.inflate(R.layout.dialog_change_fontsize, null);
|
||||
builder.setView(content);
|
||||
final TextView fontSizeTV = content.findViewById(R.id.font_size_textview);
|
||||
final SeekBar seekBar = content.findViewById(R.id.seek_bar);
|
||||
TextView lyricsTV = ((ShowLyricsActivity) getActivity()).lyricsTV;
|
||||
// Convert received font size from px to sp metrics
|
||||
float px = lyricsTV.getTextSize();
|
||||
float sp = px / getResources().getDisplayMetrics().scaledDensity;
|
||||
seekBar.setProgress((int) sp);
|
||||
fontSizeTV.setText(String.valueOf((int) sp));
|
||||
builder.setMessage(R.string.change_font)
|
||||
.setPositiveButton(R.string.ok, (dialog, id) -> {
|
||||
listener.onOkClicked(ChangeFontDialogFragment.this);
|
||||
// Send data (seekBar.getProgress()) through the interface
|
||||
// (OnDialogButtonClick.changeFontSize()) back to the activity (ShowLyricsActivty)
|
||||
listener.changeFontSize(seekBar.getProgress());
|
||||
})
|
||||
.setNegativeButton(R.string.cancel, (dialog, id) -> {
|
||||
// Send the negative button event back to the host activity
|
||||
listener.onCancelClicked(ChangeFontDialogFragment.this);
|
||||
});
|
||||
|
||||
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
fontSizeTV.setText(" " + progress);
|
||||
}
|
||||
});
|
||||
// Create the AlertDialog object and return it
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
public interface OnDialogButtonClick {
|
||||
void onOkClicked(DialogFragment dialog);
|
||||
void onCancelClicked(DialogFragment dialog);
|
||||
void changeFontSize(int i);
|
||||
}
|
||||
}
|
123
app/src/main/java/com/bernd32/jlyrics/ui/FavoritesActivity.java
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright 2019 bernd32
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bernd32.jlyrics.ui;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bernd32.jlyrics.R;
|
||||
import com.bernd32.jlyrics.adapters.FavLyricsAdapter;
|
||||
import com.bernd32.jlyrics.database.FavLyrics;
|
||||
import com.bernd32.jlyrics.database.LyricsViewModel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FavoritesActivity extends AppCompatActivity {
|
||||
private static final String TAG = "FavoritesActivity";
|
||||
private LyricsViewModel lyricsViewModel;
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public RecyclerView recyclerView; // must not be private or static
|
||||
private FavLyricsAdapter adapter;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
Log.d(TAG, "onCreate: has been called");
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_favorites);
|
||||
recyclerView = findViewById(R.id.recycler_view_favs);
|
||||
TextView emptyMsg = findViewById(R.id.empty_message);
|
||||
// Find the toolbar view inside the activity layout
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
assert actionBar != null;
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
recyclerView.setHasFixedSize(true);
|
||||
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
|
||||
recyclerView.setLayoutManager(layoutManager);
|
||||
adapter = new FavLyricsAdapter(this, new ArrayList<>());
|
||||
recyclerView.setAdapter(adapter);
|
||||
lyricsViewModel = new ViewModelProvider(this).get(LyricsViewModel.class);
|
||||
// Get all the lyrics from the database
|
||||
// and associate them with the adapter
|
||||
lyricsViewModel.getAllLyrics().observe(this, (List<FavLyrics> lyrics) -> {
|
||||
// Update the cached copy of the lyrics in the adapter.
|
||||
adapter.addItems(lyrics);
|
||||
// Show a message if the list is empty
|
||||
emptyMsg.setVisibility(adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
|
||||
});
|
||||
deleteFavoriteBySwipe();
|
||||
FavoritesActivity.this.setTitle(getString(R.string.favs));
|
||||
}
|
||||
|
||||
private void deleteFavoriteBySwipe() {
|
||||
ItemTouchHelper helper = new ItemTouchHelper(
|
||||
new ItemTouchHelper.SimpleCallback(0,
|
||||
ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
|
||||
@Override
|
||||
public boolean onMove(@NonNull RecyclerView recyclerView,
|
||||
@NonNull RecyclerView.ViewHolder viewHolder,
|
||||
@NonNull RecyclerView.ViewHolder target) {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
// Delete an item from the database.
|
||||
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
|
||||
int position = viewHolder.getAdapterPosition();
|
||||
FavLyrics myLyrics = adapter.getItem(position);
|
||||
Toast.makeText(FavoritesActivity.this,
|
||||
getString(R.string.delete_lyrics_preamble), Toast.LENGTH_LONG).show();
|
||||
lyricsViewModel.deleteLyrics(myLyrics);
|
||||
}
|
||||
});
|
||||
// Attach the item touch helper to the recycler view
|
||||
helper.attachToRecyclerView(recyclerView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu_favorites, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == R.id.delete_all) {
|
||||
lyricsViewModel.deleteAll();
|
||||
adapter.clear();
|
||||
Toast.makeText(this, "Cleared", Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
171
app/src/main/java/com/bernd32/jlyrics/ui/FuriganaActivity.java
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright 2019 bernd32
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bernd32.jlyrics.ui;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.webkit.WebSettings;
|
||||
import android.webkit.WebView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
import com.bernd32.jlyrics.R;
|
||||
import com.bernd32.jlyrics.async.AsyncTaskListener;
|
||||
import com.bernd32.jlyrics.async.PostDataAsyncTask;
|
||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;
|
||||
|
||||
public class FuriganaActivity extends AppCompatActivity {
|
||||
|
||||
private static final String TAG = "FuriganaActivity";
|
||||
private ProgressBar progressBar;
|
||||
private ExtendedFloatingActionButton cancelFAB;
|
||||
private PostDataAsyncTask task;
|
||||
private String savedHtmlString = "";
|
||||
private boolean darkTheme;
|
||||
private float fontSize;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_furigana);
|
||||
progressBar = findViewById(R.id.progress_bar);
|
||||
cancelFAB = findViewById(R.id.load_cancel);
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
assert actionBar != null;
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
Intent intent = getIntent();
|
||||
String lyrics = intent.getStringExtra("lyrics_text");
|
||||
darkTheme = intent.getBooleanExtra("theme", false);
|
||||
fontSize = intent.getFloatExtra("font_size", 20);
|
||||
// Load lyrics from savedInstanceState, so we don't have to call startAsyncTask
|
||||
// if activity is stopped or destroyed
|
||||
if (savedInstanceState == null) {
|
||||
startAsyncTask(lyrics);
|
||||
} else {
|
||||
savedHtmlString = savedInstanceState.getString("saved_lyrics");
|
||||
startWebView(savedHtmlString);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
Log.d(TAG, "onSaveInstanceState: ");
|
||||
if (!savedHtmlString.isEmpty()) {
|
||||
outState.putString("saved_lyrics", savedHtmlString);
|
||||
}
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
private void startAsyncTask(String textToConvert) {
|
||||
Log.d(TAG, "startAsyncTask: started");
|
||||
task = new PostDataAsyncTask(new AsyncTaskListener<String>() {
|
||||
|
||||
@Override
|
||||
public void onPreTask() {
|
||||
Log.d(TAG, "onPreTask: started");
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
cancelFAB.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostTask(String htmlString) {
|
||||
Log.d(TAG, "onPostTask: started");
|
||||
// Save a string from AsyncTask to the local variable
|
||||
savedHtmlString = htmlString;
|
||||
progressBar.setVisibility(View.GONE);
|
||||
cancelFAB.setVisibility(View.GONE);
|
||||
startWebView(htmlString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e, int statusCode) {
|
||||
Toast.makeText(FuriganaActivity.this,
|
||||
getString(R.string.connection_failed),
|
||||
Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
// TODO: 24.11.2019 log Exception e and int statusCode
|
||||
Log.d(TAG, "onFailure: " + e.toString());
|
||||
}
|
||||
});
|
||||
task.execute(textToConvert);
|
||||
}
|
||||
|
||||
public void onLoadCancel(View view) {
|
||||
if (task != null)
|
||||
task.cancel(true);
|
||||
finish();
|
||||
}
|
||||
|
||||
private void startWebView(String htmlString) {
|
||||
WebView webView = findViewById(R.id.webview);
|
||||
WebSettings webSettings = webView.getSettings();
|
||||
webSettings.setTextZoom(120);
|
||||
webSettings.setSupportZoom(true);
|
||||
webSettings.setBuiltInZoomControls(true);
|
||||
webSettings.setDisplayZoomControls(false);
|
||||
String html = setUpHtmlString(htmlString, (int)fontSize, darkTheme);
|
||||
webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING);
|
||||
webView.loadData(html,"text/html", "UTF-8");
|
||||
}
|
||||
|
||||
private String setUpHtmlString(String htmlString, int fontSize, boolean darkTheme) {
|
||||
String bgColor = darkTheme ? "black":"white";
|
||||
String fontColor = darkTheme ? "white":"black";
|
||||
String html = String.format("<html><head><style>"
|
||||
+ "span {color:%s}"
|
||||
+ "</style></head><body style=\"background-color:%s\">"
|
||||
+ "%s"
|
||||
+ "</body></html>",fontColor, bgColor, htmlString);
|
||||
Log.d(TAG, "setUpHtmlString: "+html);
|
||||
return html;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
return super.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
Log.d(TAG, "onCreateOptionsMenu: started");
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSupportNavigateUp(){
|
||||
if (task != null)
|
||||
task.cancel(true);
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
214
app/src/main/java/com/bernd32/jlyrics/ui/LauncherActivity.java
Normal file
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright 2019 bernd32
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bernd32.jlyrics.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Spinner;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.constraintlayout.widget.Group;
|
||||
|
||||
import com.bernd32.jlyrics.R;
|
||||
import com.bernd32.jlyrics.utils.PreferencesManager;
|
||||
|
||||
public class LauncherActivity extends AppCompatActivity {
|
||||
|
||||
private static final String TAG = "LauncherActivity";
|
||||
public static final String SEARCH_QUERY_SONG = "com.bernd32.jlyrics.SEARCH_QUERY_SONG";
|
||||
public static final String SPINNER_LIST = "com.bernd32.jlyrics.SPINNER_LIST";
|
||||
public static final String ARTIST_INPUT = "com.bernd32.jlyrics.ARTIST_INPUT";
|
||||
public static final String SONG_INPUT = "com.bernd32.jlyrics.SONG_INPUT";
|
||||
public static final String LYRICS_INPUT = "com.bernd32.jlyrics.LYRICS_INPUT";
|
||||
public static final String ARTIST_SPINNER = "com.bernd32.jlyrics.ARTIST_SPINNER";
|
||||
public static final String SONG_SPINNER = "com.bernd32.jlyrics.SONG_SPINNER";
|
||||
public static final String LYRICS_SPINNER = "com.bernd32.jlyrics.LYRICS_SPINNER";
|
||||
public static final String IGNORE_MAIN_SEARCH_INPUT = "com.bernd32.jlyrics.IGNORE_MAIN_SEARCH_INPUT";
|
||||
|
||||
private EditText mainSearchInput;
|
||||
private EditText songInput;
|
||||
private EditText artistInput;
|
||||
private EditText lyricsInput;
|
||||
private Spinner songSpinner;
|
||||
private Spinner artistSpinner;
|
||||
private Spinner lyricsSpinner;
|
||||
private Spinner spinner;
|
||||
private Button detailedSearchButton;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
mainSearchInput = findViewById(R.id.search_input);
|
||||
spinner = findViewById(R.id.spinner);
|
||||
songSpinner = findViewById(R.id.song_spinner);
|
||||
artistSpinner = findViewById(R.id.artist_spinner);
|
||||
lyricsSpinner = findViewById(R.id.lyrics_spinner);
|
||||
songInput = findViewById(R.id.song_input);
|
||||
artistInput = findViewById(R.id.artist_input);
|
||||
lyricsInput = findViewById(R.id.lyrics_input);
|
||||
detailedSearchButton = findViewById(R.id.detailed_search_button);
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
// Create an ArrayAdapter using the string array and a default spinner layout
|
||||
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
|
||||
R.array.spinner_items, android.R.layout.simple_spinner_item);
|
||||
ArrayAdapter<CharSequence> adapter_d = ArrayAdapter.createFromResource(this,
|
||||
R.array.spinner_search_options, android.R.layout.simple_spinner_item);
|
||||
ArrayAdapter<CharSequence> adapter_l = ArrayAdapter.createFromResource(this,
|
||||
R.array.lyrics_spinner_options, android.R.layout.simple_spinner_item);
|
||||
// Specify the layout to use when the list of choices appears
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
adapter_d.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
adapter_l.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
// Apply the adapter to the spinner
|
||||
spinner.setAdapter(adapter);
|
||||
songSpinner.setAdapter(adapter_d);
|
||||
artistSpinner.setAdapter(adapter_d);
|
||||
lyricsSpinner.setAdapter(adapter_l);
|
||||
// Set default values to the spinners
|
||||
songSpinner.setSelection(2);
|
||||
artistSpinner.setSelection(2);
|
||||
lyricsSpinner.setSelection(1);
|
||||
// Load theme settings from PrefManager
|
||||
AppCompatDelegate.setDefaultNightMode(
|
||||
AppCompatDelegate.MODE_NIGHT_NO);
|
||||
PreferencesManager.initializeInstance(this);
|
||||
PreferencesManager pm = PreferencesManager.getInstance();
|
||||
if (pm.getDarkThemeSelected()) {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
|
||||
} else {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
getMenuInflater().inflate(R.menu.menu_main, menu);
|
||||
// Get saved data and set value to the checkable menu item
|
||||
MenuItem darkThemeItem = menu.findItem(R.id.dark_theme);
|
||||
PreferencesManager.initializeInstance(this);
|
||||
PreferencesManager pm = PreferencesManager.getInstance();
|
||||
darkThemeItem.setChecked(pm.getDarkThemeSelected());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.toolbar_show_favs:
|
||||
Intent intent = new Intent(this, FavoritesActivity.class);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
case R.id.quit:
|
||||
this.finishAffinity();
|
||||
return true;
|
||||
case R.id.contact:
|
||||
sendMail(getString(R.string.email_address), getString(R.string.email_subject_question));
|
||||
case R.id.dark_theme:
|
||||
item.setChecked(!item.isChecked());
|
||||
// Save to value
|
||||
PreferencesManager.initializeInstance(this);
|
||||
PreferencesManager pm = PreferencesManager.getInstance();
|
||||
pm.setDarkThemeSelected(item.isChecked());
|
||||
if (item.isChecked()) {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
|
||||
} else {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendMail(String email, String subject) {
|
||||
String[] email_address = new String[] {email};
|
||||
Intent mailto = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto", email, null));
|
||||
mailto.putExtra(Intent.EXTRA_EMAIL, email_address);
|
||||
mailto.putExtra(Intent.EXTRA_SUBJECT, subject);
|
||||
startActivity(Intent.createChooser(mailto, "Send E-mail"));
|
||||
}
|
||||
|
||||
public void onLoadLyrics(View view) {
|
||||
Intent intent = new Intent(this, SearchActivity.class);
|
||||
boolean ignoreMainSearchInput = true;
|
||||
String mainSearchText = mainSearchInput.getText().toString().trim();
|
||||
int spinnerPos = spinner.getSelectedItemPosition();
|
||||
String artistText = artistInput.getText().toString().trim();
|
||||
String songText = songInput.getText().toString().trim();
|
||||
String lyricsText = lyricsInput.getText().toString().trim();
|
||||
int artistSpinnerPos = artistSpinner.getSelectedItemPosition();
|
||||
int songSpinnerPos = songSpinner.getSelectedItemPosition();
|
||||
int lyricsSpinnerPos = lyricsSpinner.getSelectedItemPosition();
|
||||
if (artistText.isEmpty() && songText.isEmpty() && lyricsText.isEmpty()) {
|
||||
ignoreMainSearchInput = false;
|
||||
}
|
||||
if (!mainSearchText.isEmpty() && !ignoreMainSearchInput) {
|
||||
Log.d(TAG, "onLoadLyrics: user didn't use detailed search");
|
||||
intent.putExtra(SEARCH_QUERY_SONG, mainSearchText);
|
||||
intent.putExtra(SPINNER_LIST, spinnerPos);
|
||||
}
|
||||
if (ignoreMainSearchInput){
|
||||
Log.d(TAG, "onLoadLyrics: user used detailed search");
|
||||
intent.putExtra(ARTIST_INPUT, artistText);
|
||||
intent.putExtra(SONG_INPUT, songText);
|
||||
intent.putExtra(LYRICS_INPUT, lyricsText);
|
||||
intent.putExtra(ARTIST_SPINNER, artistSpinnerPos);
|
||||
intent.putExtra(SONG_SPINNER, songSpinnerPos);
|
||||
intent.putExtra(LYRICS_SPINNER, lyricsSpinnerPos);
|
||||
}
|
||||
if (intent.resolveActivity(getPackageManager()) != null &&
|
||||
(!mainSearchText.isEmpty() || ignoreMainSearchInput)) {
|
||||
intent.putExtra(IGNORE_MAIN_SEARCH_INPUT, ignoreMainSearchInput);
|
||||
startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
||||
public void onDetailedSearch(View view) {
|
||||
Group group = findViewById(R.id.group);
|
||||
if (group.getVisibility() == View.GONE) {
|
||||
// Hide keyboard
|
||||
view = this.getCurrentFocus();
|
||||
if (view != null) {
|
||||
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
assert imm != null;
|
||||
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
||||
}
|
||||
group.setVisibility(View.VISIBLE);
|
||||
detailedSearchButton.setText(getString(R.string.detailed_search_hide));
|
||||
}
|
||||
else {
|
||||
group.setVisibility(View.GONE);
|
||||
detailedSearchButton.setText(getString(R.string.detailed_search_show));
|
||||
}
|
||||
}
|
||||
}
|
322
app/src/main/java/com/bernd32/jlyrics/ui/SearchActivity.java
Normal file
@ -0,0 +1,322 @@
|
||||
/*
|
||||
* Copyright 2019 bernd32
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bernd32.jlyrics.ui;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bernd32.jlyrics.PaginationListener;
|
||||
import com.bernd32.jlyrics.Lyric;
|
||||
import com.bernd32.jlyrics.R;
|
||||
import com.bernd32.jlyrics.adapters.PostRecyclerAdapter;
|
||||
import com.bernd32.jlyrics.async.GetDataAsyncTask;
|
||||
import com.bernd32.jlyrics.search.CallbackInterface;
|
||||
import com.bernd32.jlyrics.search.SearchLyricsViewModel;
|
||||
import com.bernd32.jlyrics.utils.PreferencesManager;
|
||||
import com.bernd32.romajihenkan.RomajiHenkan;
|
||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static com.bernd32.jlyrics.PaginationListener.PAGE_START;
|
||||
import static com.bernd32.jlyrics.utils.HelperClass.urlBuilder;
|
||||
|
||||
public class SearchActivity extends AppCompatActivity {
|
||||
|
||||
private static final String TAG = "SearchActivity";
|
||||
public static final String NO_IMG = "no_img";
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public RecyclerView mRecyclerView; // must not be private or static
|
||||
private ProgressBar progressBar;
|
||||
private PostRecyclerAdapter adapter;
|
||||
private int currentPage = PAGE_START;
|
||||
private boolean isLastPage = false;
|
||||
private boolean isLoading = false;
|
||||
private String searchInput;
|
||||
private int spinnerPos;
|
||||
private String artistText;
|
||||
private String songText;
|
||||
private String lyricsText;
|
||||
private int artistSpinnerPos;
|
||||
private int songSpinnerPos;
|
||||
private int lyricsSpinnerPos;
|
||||
private boolean ignoreMainSearch;
|
||||
private FloatingActionButton floatingActionButton;
|
||||
private ExtendedFloatingActionButton cancelFAB;
|
||||
private GetDataAsyncTask task;
|
||||
private SearchLyricsViewModel viewModel;
|
||||
private int maxPage;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
// Get intents
|
||||
Bundle extras = getIntent().getExtras();
|
||||
if (extras != null) {
|
||||
intentLoader();
|
||||
}
|
||||
// UI
|
||||
setContentView(R.layout.activity_search);
|
||||
progressBar = findViewById(R.id.progress_bar);
|
||||
mRecyclerView = findViewById(R.id.recyclerv_view);
|
||||
floatingActionButton = findViewById(R.id.floating_action_button);
|
||||
cancelFAB = findViewById(R.id.load_cancel);
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
assert actionBar != null;
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
mRecyclerView.setHasFixedSize(true);
|
||||
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
|
||||
mRecyclerView.setLayoutManager(layoutManager);
|
||||
adapter = new PostRecyclerAdapter(this, new ArrayList<>());
|
||||
mRecyclerView.setAdapter(adapter);
|
||||
// initial load
|
||||
String url = ignoreMainSearch ?
|
||||
urlBuilder(PAGE_START, artistText, artistSpinnerPos, songText,
|
||||
songSpinnerPos, lyricsText, lyricsSpinnerPos) :
|
||||
urlBuilder(PAGE_START, spinnerPos, searchInput);
|
||||
viewModel = new ViewModelProvider(this).get(SearchLyricsViewModel.class);
|
||||
CallbackInterface listener = new CallbackInterface() {
|
||||
|
||||
// Show alert dialog in case when no search results were found
|
||||
@Override
|
||||
public void showAlertDialog() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(SearchActivity.this);
|
||||
builder.setTitle(getString(R.string.not_found_title));
|
||||
builder.setMessage(getString(R.string.not_found_message));
|
||||
builder.setPositiveButton(R.string.ok, (dialog, id) -> {
|
||||
dialog.dismiss();
|
||||
finish();
|
||||
});
|
||||
AlertDialog dialog = builder.create();
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
// Show number of search result found in the action bar
|
||||
@Override
|
||||
public void setActivityTitle(int numberOfSongs) {
|
||||
SearchActivity.this.setTitle(getString(R.string.title_found) +
|
||||
" " + numberOfSongs);
|
||||
}
|
||||
|
||||
// Tell our adapter the search result type we got, so adapter's click listener
|
||||
// will know what activity show be opened when we click on a search result
|
||||
@Override
|
||||
public void setPageType(int pageType) {
|
||||
adapter.setPageType(pageType);
|
||||
}
|
||||
|
||||
// This is basically the main callback method that takes the search
|
||||
// result items from the view model and loads them into the UI via our recycler adapter
|
||||
// This callback method also handles the pagination future, and loads new search
|
||||
// result pages into our adapter
|
||||
@Override
|
||||
public void getSearchResults(ArrayList<Lyric> items) {
|
||||
maxPage = viewModel.getMaxPage();
|
||||
newPageLoader(maxPage, items);
|
||||
/*
|
||||
* add scroll listener while user reach in bottom load more will call
|
||||
*/
|
||||
mRecyclerView.addOnScrollListener(new PaginationListener(layoutManager) {
|
||||
@Override
|
||||
protected void loadMoreItems() {
|
||||
isLoading = true;
|
||||
currentPage++;
|
||||
String url = ignoreMainSearch ?
|
||||
urlBuilder(currentPage, artistText, artistSpinnerPos, songText,
|
||||
songSpinnerPos, lyricsText, lyricsSpinnerPos) :
|
||||
urlBuilder(currentPage, spinnerPos, searchInput);
|
||||
floatingActionButton.setVisibility(View.VISIBLE);
|
||||
// Load search results from a new page
|
||||
viewModel.newSearchRequest(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLastPage() {
|
||||
return isLastPage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLoading() {
|
||||
return isLoading;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void showFAB() {
|
||||
if (floatingActionButton.getVisibility() != View.VISIBLE) {
|
||||
floatingActionButton.show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void hideFAB() {
|
||||
if (floatingActionButton.getVisibility() == View.VISIBLE) {
|
||||
floatingActionButton.hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Showing loading animation when user started searching
|
||||
@Override
|
||||
public void taskStarted() {
|
||||
if (currentPage == 1) {
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
mRecyclerView.setVisibility(View.GONE);
|
||||
cancelFAB.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
// Hide loading animation and show search results
|
||||
@Override
|
||||
public void taskFinished() {
|
||||
Log.d(TAG, "onPostTask: started");
|
||||
if (currentPage == 1) {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
mRecyclerView.setVisibility(View.VISIBLE);
|
||||
cancelFAB.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
// Shows a toast when we got an exception and returns back to main activity
|
||||
@Override
|
||||
public void taskFailed(Exception e, int statusCode) {
|
||||
Toast.makeText(SearchActivity.this,
|
||||
getString(R.string.connection_failed),
|
||||
Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
// TODO: 24.11.2019 log Exception e and int statusCode
|
||||
Log.e(TAG, "onFailure: " + e.toString());
|
||||
}
|
||||
};
|
||||
|
||||
floatingActionButton.setOnClickListener(view -> {
|
||||
mRecyclerView.smoothScrollToPosition(0);
|
||||
});
|
||||
|
||||
viewModel.addListener(listener);
|
||||
// Send a request to parse a search results from an URL and get results back
|
||||
// to activity via callback method getSearchResults()
|
||||
viewModel.newSearchRequest(url);
|
||||
}
|
||||
|
||||
private void newPageLoader(int maxPage, ArrayList<Lyric> items) {
|
||||
if (currentPage != PAGE_START) {
|
||||
mRecyclerView.post(() -> adapter.removeLoading());
|
||||
}
|
||||
mRecyclerView.post(() -> adapter.addItems(items));
|
||||
// check whether is last page or not
|
||||
if (currentPage < maxPage) {
|
||||
mRecyclerView.post(() -> adapter.addLoading());
|
||||
} else {
|
||||
isLastPage = true;
|
||||
}
|
||||
isLoading = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSupportNavigateUp(){
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
Log.d(TAG, "onDestroy: activated");
|
||||
adapter.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu_main, menu);
|
||||
// Get saved data and set value to the checkable menu item
|
||||
MenuItem darkThemeItem = menu.findItem(R.id.dark_theme);
|
||||
PreferencesManager.initializeInstance(this);
|
||||
PreferencesManager pm = PreferencesManager.getInstance();
|
||||
darkThemeItem.setChecked(pm.getDarkThemeSelected());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.toolbar_show_favs:
|
||||
// Open favorites activity
|
||||
Intent intent = new Intent(this, FavoritesActivity.class);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
case R.id.quit:
|
||||
this.finishAffinity();
|
||||
return true;
|
||||
case R.id.dark_theme:
|
||||
// Switch color theme of the app (light/dark)
|
||||
item.setChecked(!item.isChecked());
|
||||
// Save to value
|
||||
PreferencesManager.initializeInstance(this);
|
||||
PreferencesManager pm = PreferencesManager.getInstance();
|
||||
pm.setDarkThemeSelected(item.isChecked());
|
||||
if (item.isChecked()) {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
|
||||
} else {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void intentLoader() {
|
||||
Intent intent = getIntent();
|
||||
searchInput = intent.getStringExtra(LauncherActivity.SEARCH_QUERY_SONG);
|
||||
spinnerPos = intent.getIntExtra(LauncherActivity.SPINNER_LIST, 0);
|
||||
artistText = intent.getStringExtra(LauncherActivity.ARTIST_INPUT);
|
||||
songText = intent.getStringExtra(LauncherActivity.SONG_INPUT);
|
||||
lyricsText = intent.getStringExtra(LauncherActivity.LYRICS_INPUT);
|
||||
artistSpinnerPos = intent.getIntExtra(LauncherActivity.ARTIST_SPINNER, 0);
|
||||
songSpinnerPos = intent.getIntExtra(LauncherActivity.SONG_SPINNER, 0);
|
||||
lyricsSpinnerPos = intent.getIntExtra(LauncherActivity.LYRICS_SPINNER, 0);
|
||||
ignoreMainSearch = intent.getBooleanExtra(LauncherActivity.IGNORE_MAIN_SEARCH_INPUT, false);
|
||||
}
|
||||
|
||||
public void onLoadCancel(View view) {
|
||||
if (task != null) {
|
||||
task.cancel(true);
|
||||
task = null;
|
||||
}
|
||||
finish();
|
||||
}
|
||||
}
|
383
app/src/main/java/com/bernd32/jlyrics/ui/ShowLyricsActivity.java
Normal file
@ -0,0 +1,383 @@
|
||||
/*
|
||||
* Copyright 2019 bernd32
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bernd32.jlyrics.ui;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.Bundle;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.style.StyleSpan;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.appcompat.widget.ShareActionProvider;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.view.MenuItemCompat;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import com.bernd32.jlyrics.R;
|
||||
import com.bernd32.jlyrics.async.AsyncTaskListener;
|
||||
import com.bernd32.jlyrics.async.GetDataAsyncTask;
|
||||
import com.bernd32.jlyrics.async.RomanizeAsyncTask;
|
||||
import com.bernd32.jlyrics.database.FavLyrics;
|
||||
import com.bernd32.jlyrics.database.LyricsViewModel;
|
||||
import com.bernd32.jlyrics.utils.PreferencesManager;
|
||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;
|
||||
|
||||
import org.jsoup.nodes.Document;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import static com.bernd32.jlyrics.utils.HelperClass.addNewLines;
|
||||
|
||||
public class ShowLyricsActivity extends AppCompatActivity implements ChangeFontDialogFragment.OnDialogButtonClick {
|
||||
|
||||
private static final String TAG = "ShowLyricsActivity";
|
||||
private ProgressBar progressBar;
|
||||
public TextView lyricsTV;
|
||||
private String lyrics = "";
|
||||
private String romanizedLyrics = "";
|
||||
private String title;
|
||||
private String songUrl;
|
||||
private String cardDesc;
|
||||
private String cardTitle;
|
||||
private String imgUrl;
|
||||
private LyricsViewModel lyricsViewModel;
|
||||
private boolean hasLyrics;
|
||||
private ExtendedFloatingActionButton cancelFAB;
|
||||
private GetDataAsyncTask task;
|
||||
private boolean romanized = false;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
Log.d(TAG, "onCreate: activated");
|
||||
super.onCreate(savedInstanceState);
|
||||
PreferencesManager.initializeInstance(this);
|
||||
setContentView(R.layout.activity_show_lyrics);
|
||||
lyricsTV = findViewById(R.id.lyrics);
|
||||
progressBar = findViewById(R.id.progress_bar);
|
||||
cancelFAB = findViewById(R.id.load_cancel);
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
assert actionBar != null;
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
// For saving lyrics to favs
|
||||
lyricsViewModel = new ViewModelProvider(this).get(LyricsViewModel.class);
|
||||
loadIntents();
|
||||
try {
|
||||
isLyricsInDB(songUrl);
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// Load lyrics from savedInstanceState, so we don't have to call startAsyncTask
|
||||
// if activity is stopped or destroyed
|
||||
loadLyrics(savedInstanceState);
|
||||
}
|
||||
|
||||
private void loadLyrics(Bundle savedInstanceState) {
|
||||
if (savedInstanceState == null) {
|
||||
startAsyncTask(songUrl);
|
||||
} else {
|
||||
romanized = savedInstanceState.getBoolean("romanized");
|
||||
lyrics = savedInstanceState.getString("saved_lyrics");
|
||||
romanizedLyrics = savedInstanceState.getString("saved_romaji_lyrics");
|
||||
if (!romanized) {
|
||||
lyricsTV.setText(lyrics);
|
||||
} else {
|
||||
lyricsTV.setText(romanizedLyrics);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
Log.d(TAG, "onStop: started");
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
Log.d(TAG, "onSaveInstanceState: start");
|
||||
outState.putString("saved_lyrics", lyrics);
|
||||
outState.putString("saved_romaji_lyrics", romanizedLyrics);
|
||||
outState.putBoolean("romanized", romanized);
|
||||
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
getMenuInflater().inflate(R.menu.menu_lyrics, menu);
|
||||
MenuItem menuShareItem = menu.findItem(R.id.toolbar_share);
|
||||
ShareActionProvider shareActionProvider = (ShareActionProvider)
|
||||
MenuItemCompat.getActionProvider(menuShareItem);
|
||||
// Get saved data and set values
|
||||
MenuItem darkThemeItem = menu.findItem(R.id.dark_theme);
|
||||
PreferencesManager pm = PreferencesManager.getInstance();
|
||||
darkThemeItem.setChecked(pm.getDarkThemeSelected());
|
||||
int fontSize = pm.getFontSize();
|
||||
lyricsTV.setTextSize((float) fontSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.romanize:
|
||||
convertLyrics();
|
||||
return true;
|
||||
case R.id.toolbar_share:
|
||||
Intent sendIntent = new Intent();
|
||||
sendIntent.setAction(Intent.ACTION_SEND);
|
||||
sendIntent.putExtra(Intent.EXTRA_TEXT, lyrics);
|
||||
sendIntent.setType("text/plain");
|
||||
Intent shareIntent = Intent.createChooser(sendIntent, title);
|
||||
startActivity(shareIntent);
|
||||
return true;
|
||||
case R.id.toolbar_furigana:
|
||||
openFuriganaActivity();
|
||||
return true;
|
||||
case R.id.fav_add_remove:
|
||||
saveLyrics();
|
||||
return true;
|
||||
case R.id.dark_theme:
|
||||
item.setChecked(!item.isChecked());
|
||||
PreferencesManager pm = PreferencesManager.getInstance();
|
||||
pm.setDarkThemeSelected(item.isChecked());
|
||||
if (item.isChecked()) {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
|
||||
} else {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
|
||||
}
|
||||
return true;
|
||||
case R.id.font_size:
|
||||
showFontSizeDialog();
|
||||
return true;
|
||||
case R.id.quit:
|
||||
this.finishAffinity();
|
||||
return true;
|
||||
case R.id.copy:
|
||||
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
ClipData clip = ClipData.newPlainText(getString(R.string.lyrics), lyrics);
|
||||
assert clipboard != null;
|
||||
clipboard.setPrimaryClip(clip);
|
||||
Toast.makeText(this, getString(R.string.copied), Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void convertLyrics() {
|
||||
if (!romanized) {
|
||||
RomanizeAsyncTask romanizeTask = new RomanizeAsyncTask(new AsyncTaskListener<String>() {
|
||||
@Override
|
||||
public void onPreTask() {
|
||||
lyricsTV.setText("");
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
cancelFAB.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostTask(String string) {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
cancelFAB.setVisibility(View.GONE);
|
||||
ShowLyricsActivity.this.romanizedLyrics = string;
|
||||
lyricsTV.setText(string);
|
||||
romanized = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e, int statusCode) {
|
||||
Toast.makeText(ShowLyricsActivity.this,
|
||||
getString(R.string.connection_failed),
|
||||
Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
// TODO: 24.11.2019 log Exception e and int statusCode
|
||||
Log.d(TAG, "onFailure: " + e.toString());
|
||||
}
|
||||
});
|
||||
romanizeTask.execute(lyrics);
|
||||
} else {
|
||||
// If the text is already converted to romaji then show original Japanese text
|
||||
lyricsTV.setText(lyrics);
|
||||
romanized = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void openFuriganaActivity() {
|
||||
PreferencesManager pm = PreferencesManager.getInstance();
|
||||
// Create an intent and open a new activity
|
||||
Intent intent = new Intent(this, FuriganaActivity.class);
|
||||
intent.putExtra("lyrics_text", lyrics);
|
||||
intent.putExtra("font_size", lyricsTV.getTextSize());
|
||||
intent.putExtra("theme", pm.getDarkThemeSelected());
|
||||
if (intent.resolveActivity(getPackageManager()) != null) {
|
||||
startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOkClicked(DialogFragment dialog) {
|
||||
Toast.makeText(this, getString(R.string.saved), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancelClicked(DialogFragment dialog) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeFontSize(int i) {
|
||||
// Get data from DialogFragment interface,
|
||||
// change font size of lyric text and save the value
|
||||
lyricsTV.setTextSize((float) i);
|
||||
PreferencesManager pm = PreferencesManager.getInstance();
|
||||
pm.setFontSize(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSupportNavigateUp(){
|
||||
if (task != null)
|
||||
task.cancel(true);
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
if (hasLyrics)
|
||||
menu.findItem(R.id.fav_add_remove).setTitle(getString(R.string.favs_remove));
|
||||
else
|
||||
menu.findItem(R.id.fav_add_remove).setTitle(getString(R.string.favs_add));
|
||||
|
||||
if (romanized) {
|
||||
menu.findItem(R.id.romanize).setTitle(getString(R.string.show_original));
|
||||
} else {
|
||||
menu.findItem(R.id.romanize).setTitle(getString(R.string.romanize));
|
||||
}
|
||||
return super.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
public void onLoadCancel(View view) {
|
||||
if (task != null)
|
||||
task.cancel(true);
|
||||
finish();
|
||||
}
|
||||
|
||||
private void showFontSizeDialog() {
|
||||
DialogFragment changeFontAlert = new ChangeFontDialogFragment();
|
||||
changeFontAlert.show(getSupportFragmentManager(), "changeFontAlert");
|
||||
}
|
||||
|
||||
private void loadIntents() {
|
||||
if (getIntent().hasExtra("song_url")){
|
||||
Log.d(TAG, "getIncomingIntent: found intent extras.");
|
||||
songUrl = getIntent().getStringExtra("song_url");
|
||||
}
|
||||
imgUrl = getIntent().getStringExtra("img_url");
|
||||
cardTitle = getIntent().getStringExtra("title");
|
||||
cardDesc = getIntent().getStringExtra("description");
|
||||
}
|
||||
|
||||
private void isLyricsInDB(String songUrl) throws ExecutionException, InterruptedException {
|
||||
this.hasLyrics = lyricsViewModel.isLyricsExists(songUrl);
|
||||
}
|
||||
|
||||
private void saveLyrics() {
|
||||
if (!hasLyrics) {
|
||||
long timestamp = System.currentTimeMillis();
|
||||
FavLyrics savedLyrics = new FavLyrics(cardTitle, cardDesc, songUrl, imgUrl, timestamp);
|
||||
lyricsViewModel.insert(savedLyrics);
|
||||
Toast.makeText(this, getString(R.string.saved), Toast.LENGTH_SHORT).show();
|
||||
this.hasLyrics = true;
|
||||
} else {
|
||||
// Remove lyrics
|
||||
lyricsViewModel.deleteLyricsByUrl(songUrl);
|
||||
Toast.makeText(this, getString(R.string.removed), Toast.LENGTH_SHORT).show();
|
||||
this.hasLyrics = false;
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
private void startAsyncTask(String url) {
|
||||
Log.d(TAG, "startAsyncTask: " + url);
|
||||
task = new GetDataAsyncTask(new AsyncTaskListener<Document>() {
|
||||
@Override
|
||||
public void onPreTask() {
|
||||
Log.d(TAG, "onPreTask: started");
|
||||
// show progressbar only in initial loading
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
cancelFAB.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostTask(Document doc) {
|
||||
Log.d(TAG, "onPostTask: started");
|
||||
progressBar.setVisibility(View.GONE);
|
||||
cancelFAB.setVisibility(View.GONE);
|
||||
showLyrics(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e, int statusCode) {
|
||||
Toast.makeText(ShowLyricsActivity.this,
|
||||
getString(R.string.connection_failed),
|
||||
Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
// TODO: 24.11.2019 log Exception e and int statusCode
|
||||
}
|
||||
});
|
||||
task.execute(url);
|
||||
}
|
||||
|
||||
private void showLyrics(Document doc) {
|
||||
Log.d(TAG, "showLyrics: activated");
|
||||
lyrics = doc.select("#Lyric").first().html();
|
||||
String songName = doc.select("#mnb > div.cap > h2")
|
||||
.text()
|
||||
.replace(" 歌詞", "");
|
||||
title = String.format(Locale.getDefault(), "「%s」\n\n\n", songName);
|
||||
ShowLyricsActivity.this.setTitle(title);
|
||||
lyrics = addNewLines(lyrics);
|
||||
lyrics = lyrics.replace("(△くり返し)", getText(R.string.repeat));
|
||||
lyrics = lyrics.replace("(※くり返し)", getText(R.string.repeat2));
|
||||
SpannableString songTitle = new SpannableString(title);
|
||||
songTitle.setSpan(new StyleSpan(Typeface.BOLD), 0, title.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
|
||||
lyricsTV.setText(songTitle);
|
||||
lyricsTV.append(lyrics);
|
||||
Log.d(TAG, "Current artist: " + cardDesc);
|
||||
Log.d(TAG, "Current song: " + cardTitle);
|
||||
}
|
||||
}
|
87
app/src/main/java/com/bernd32/jlyrics/utils/HelperClass.java
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2019 bernd32
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bernd32.jlyrics.utils;
|
||||
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.safety.Whitelist;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public class HelperClass {
|
||||
static final List<String> userAgents = Arrays.asList("Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148",
|
||||
"Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1 Mobile/15E148 Safari/604.1",
|
||||
"Mozilla/5.0 (iPhone; CPU iPhone OS 12_1_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16D57",
|
||||
"Mozilla/5.0 (iPhone; CPU iPhone OS 12_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148",
|
||||
"Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko)",
|
||||
"Mozilla/5.0 (iPhone; CPU iPhone OS 12_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1.1 Mobile/15E148 Safari/604.1",
|
||||
"Mozilla/5.0 (iPhone; CPU iPhone OS 11_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Mobile/15E148 Safari/604.1",
|
||||
"Mozilla/5.0 (iPhone; CPU iPhone OS 12_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1.2 Mobile/15E148 Safari/604.1",
|
||||
"Mozilla/5.0 (iPhone; CPU iPhone OS 13_1_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.1 Mobile/15E148 Safari/604.1",
|
||||
"Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1",
|
||||
"Mozilla/5.0 (iPhone; CPU iPhone OS 11_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15G77",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36");
|
||||
|
||||
public static String getUserAgent() {
|
||||
return userAgents.get(ThreadLocalRandom.current().nextInt((userAgents.size())));
|
||||
}
|
||||
|
||||
public static String urlBuilder(int page, int spinnerPos, String searchInput) {
|
||||
// Used for simple search
|
||||
StringBuilder url = new StringBuilder("http://search.j-lyric.net/index.php?&ct=2&ca=2&cl=2&p=");
|
||||
final int SONG_NAME_SELECTED = 0;
|
||||
final int ARTIST_SELECTED = 1;
|
||||
final int LYRICS_SELECTED = 2;
|
||||
switch (spinnerPos) {
|
||||
case SONG_NAME_SELECTED:
|
||||
url.append(page).append("&kt=").append(searchInput);
|
||||
break;
|
||||
case ARTIST_SELECTED:
|
||||
url.append(page).append("&ka=").append(searchInput);
|
||||
break;
|
||||
case LYRICS_SELECTED:
|
||||
url.append(page).append("&kl=").append(searchInput);
|
||||
break;
|
||||
}
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
public static String urlBuilder(int page, String artistText, int artistSpinnerPos, String songText,
|
||||
int songSpinnerPos, String lyricsText, int lyricsSpinnerPos) {
|
||||
// Used for detailed search
|
||||
if (lyricsSpinnerPos > 0) lyricsSpinnerPos += 1;
|
||||
String url = String.format(Locale.getDefault(),
|
||||
"http://search.j-lyric.net/index.php?p=%d&kt=%s&ct=%d&ka=%s&ca=%d&kl=%s&cl=%d",
|
||||
page, songText, songSpinnerPos, artistText, artistSpinnerPos, lyricsText, lyricsSpinnerPos);
|
||||
return url;
|
||||
}
|
||||
|
||||
public static String addNewLines(String html) {
|
||||
// Add new lines to the fetched text
|
||||
Document document = Jsoup.parse(html);
|
||||
// Makes html() preserve linebreaks and spacing
|
||||
document.outputSettings(new Document.OutputSettings().prettyPrint(false));
|
||||
document.select("br").append("\\n");
|
||||
document.select("p").prepend("\\n\\n");
|
||||
String s = document.html().replaceAll("\\\\n", "\n");
|
||||
return Jsoup.clean(s, "", Whitelist.none(), new Document.OutputSettings().prettyPrint(false));
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2019 bernd32
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.bernd32.jlyrics.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
public class PreferencesManager {
|
||||
|
||||
/* a thread-safe singleton class to make the global access method
|
||||
synchronized, so that only one thread can execute this method at a time */
|
||||
|
||||
private static final String APP_PREFS = "com.bernd32.jlyrics.prefs";
|
||||
private static final String FONT_SIZE = "com.example.app.fontsize";
|
||||
private static final String DARK_THEME = "com.example.app.darktheme";
|
||||
|
||||
private static PreferencesManager sInstance;
|
||||
private final SharedPreferences mPref;
|
||||
|
||||
private PreferencesManager(Context context) {
|
||||
mPref = context.getSharedPreferences(APP_PREFS, Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
public static synchronized void initializeInstance(Context context) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new PreferencesManager(context);
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized PreferencesManager getInstance() {
|
||||
if (sInstance == null) {
|
||||
throw new IllegalStateException(PreferencesManager.class.getSimpleName() +
|
||||
" is not initialized, call initializeInstance(..) method first.");
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
public void setFontSize(int value) {
|
||||
mPref.edit()
|
||||
.putInt(FONT_SIZE, value)
|
||||
.apply();
|
||||
}
|
||||
|
||||
public int getFontSize() {
|
||||
return mPref.getInt(FONT_SIZE, 20);
|
||||
}
|
||||
|
||||
public void setDarkThemeSelected(boolean value) {
|
||||
mPref.edit()
|
||||
.putBoolean(DARK_THEME, value)
|
||||
.apply();
|
||||
}
|
||||
|
||||
public boolean getDarkThemeSelected() {
|
||||
return mPref.getBoolean(DARK_THEME, false);
|
||||
}
|
||||
|
||||
public void remove(String key) {
|
||||
mPref.edit()
|
||||
.remove(key)
|
||||
.apply();
|
||||
}
|
||||
|
||||
public boolean clear() {
|
||||
return mPref.edit()
|
||||
.clear()
|
||||
.commit();
|
||||
}
|
||||
}
|
BIN
app/src/main/res/drawable-hdpi/baseline_g_translate_white_24.png
Normal file
After Width: | Height: | Size: 536 B |
BIN
app/src/main/res/drawable-hdpi/baseline_search_white_24.png
Normal file
After Width: | Height: | Size: 373 B |
BIN
app/src/main/res/drawable-hdpi/baseline_share_white_24.png
Normal file
After Width: | Height: | Size: 368 B |
BIN
app/src/main/res/drawable-mdpi/baseline_g_translate_white_24.png
Normal file
After Width: | Height: | Size: 348 B |
BIN
app/src/main/res/drawable-mdpi/baseline_search_white_24.png
Normal file
After Width: | Height: | Size: 244 B |
BIN
app/src/main/res/drawable-mdpi/baseline_share_white_24.png
Normal file
After Width: | Height: | Size: 249 B |
After Width: | Height: | Size: 635 B |
BIN
app/src/main/res/drawable-xhdpi/baseline_search_white_24.png
Normal file
After Width: | Height: | Size: 411 B |
BIN
app/src/main/res/drawable-xhdpi/baseline_share_white_24.png
Normal file
After Width: | Height: | Size: 452 B |
After Width: | Height: | Size: 938 B |
BIN
app/src/main/res/drawable-xxhdpi/baseline_search_white_24.png
Normal file
After Width: | Height: | Size: 624 B |
BIN
app/src/main/res/drawable-xxhdpi/baseline_share_white_24.png
Normal file
After Width: | Height: | Size: 654 B |
After Width: | Height: | Size: 1.2 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/baseline_search_white_24.png
Normal file
After Width: | Height: | Size: 822 B |
BIN
app/src/main/res/drawable-xxxhdpi/baseline_share_white_24.png
Normal file
After Width: | Height: | Size: 848 B |
25
app/src/main/res/drawable/favorite_border_black.xml
Normal file
@ -0,0 +1,25 @@
|
||||
<!--
|
||||
~ Copyright 2019 bernd32
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M16.5,3c-1.74,0 -3.41,0.81 -4.5,2.09C10.91,3.81 9.24,3 7.5,3 4.42,3 2,5.42 2,8.5c0,3.78 3.4,6.86 8.55,11.54L12,21.35l1.45,-1.32C18.6,15.36 22,12.28 22,8.5 22,5.42 19.58,3 16.5,3zM12.1,18.55l-0.1,0.1 -0.1,-0.1C7.14,14.24 4,11.39 4,8.5 4,6.5 5.5,5 7.5,5c1.54,0 3.04,0.99 3.57,2.36h1.87C13.46,5.99 14.96,5 16.5,5c2,0 3.5,1.5 3.5,3.5 0,2.89 -3.14,5.74 -7.9,10.05z"/>
|
||||
</vector>
|
25
app/src/main/res/drawable/ic_cancel_black_24dp.xml
Normal file
@ -0,0 +1,25 @@
|
||||
<!--
|
||||
~ Copyright 2019 bernd32
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2zM17,15.59L15.59,17 12,13.41 8.41,17 7,15.59 10.59,12 7,8.41 8.41,7 12,10.59 15.59,7 17,8.41 13.41,12 17,15.59z"/>
|
||||
</vector>
|
25
app/src/main/res/drawable/ic_filter_list_24dp.xml
Normal file
@ -0,0 +1,25 @@
|
||||
<!--
|
||||
~ Copyright 2019 bernd32
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M10,18h4v-2h-4v2zM3,6v2h18L21,6L3,6zM6,13h12v-2L6,11v2z"/>
|
||||
</vector>
|
@ -0,0 +1,21 @@
|
||||
<!--
|
||||
~ Copyright 2019 bernd32
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M7.41,15.41L12,10.83l4.59,4.58L18,14l-6,-6 -6,6z"/>
|
||||
</vector>
|
182
app/src/main/res/layout-land/activity_main.xml
Normal file
@ -0,0 +1,182 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2019 bernd32
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:fillViewport="false">
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
tools:context=".ui.LauncherActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar"
|
||||
layout="@layout/toolbar_main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:onClick="onLoadLyrics"
|
||||
android:text="@android:string/search_go"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/spinner"
|
||||
android:drawableStart="@drawable/baseline_search_white_24"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/search_input"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="44dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
app:layout_constraintHorizontal_weight="3"
|
||||
android:hint="@string/search"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="textPersonName"
|
||||
app:layout_constraintEnd_toStartOf="@+id/spinner"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/toolbar" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinner"
|
||||
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="44dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/button"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_weight="2"
|
||||
app:layout_constraintStart_toEndOf="@+id/search_input"
|
||||
app:layout_constraintTop_toBottomOf="@+id/toolbar" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/detailed_search_button"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:text="@string/detailed_search_show"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/button"
|
||||
android:onClick="onDetailedSearch" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/artist_input"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="44dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="0dp"
|
||||
android:hint="@string/artist"
|
||||
android:inputType="textPersonName"
|
||||
app:layout_constraintEnd_toStartOf="@+id/artist_spinner"
|
||||
app:layout_constraintHorizontal_weight="3"
|
||||
app:layout_constraintStart_toEndOf="@+id/artist_spinner"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/detailed_search_button"
|
||||
android:importantForAutofill="no" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/artist_spinner"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="44dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_weight="2"
|
||||
app:layout_constraintStart_toEndOf="@+id/artist_input"
|
||||
app:layout_constraintTop_toBottomOf="@+id/detailed_search_button" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/song_input"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="44dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="0dp"
|
||||
android:hint="@string/song"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="textPersonName"
|
||||
app:layout_constraintEnd_toStartOf="@+id/song_spinner"
|
||||
app:layout_constraintHorizontal_weight="3"
|
||||
app:layout_constraintStart_toEndOf="@+id/song_spinner"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/artist_input" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/song_spinner"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="44dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_weight="2"
|
||||
app:layout_constraintStart_toEndOf="@+id/song_input"
|
||||
app:layout_constraintTop_toBottomOf="@+id/artist_spinner" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/lyrics_input"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="44dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="0dp"
|
||||
android:hint="@string/lyrics"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="textPersonName"
|
||||
app:layout_constraintEnd_toStartOf="@+id/lyrics_spinner"
|
||||
app:layout_constraintHorizontal_weight="3"
|
||||
app:layout_constraintStart_toEndOf="@+id/lyrics_spinner"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/song_input" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/lyrics_spinner"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="44dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_weight="2"
|
||||
app:layout_constraintStart_toEndOf="@+id/lyrics_input"
|
||||
app:layout_constraintTop_toBottomOf="@+id/song_spinner" />
|
||||
|
||||
<androidx.constraintlayout.widget.Group
|
||||
android:id="@+id/group"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:constraint_referenced_ids="lyrics_input,song_spinner,song_input,artist_spinner,artist_input,lyrics_spinner" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</ScrollView>
|
57
app/src/main/res/layout/activity_favorites.xml
Normal file
@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2019 bernd32
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.FavoritesActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar"
|
||||
layout="@layout/toolbar_main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_view_favs"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/toolbar" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/empty_message"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
android:text="@string/empty_message"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textStyle="italic"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/toolbar"
|
||||
android:visibility="invisible"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
78
app/src/main/res/layout/activity_furigana.xml
Normal file
@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2019 bernd32
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.FuriganaActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar"
|
||||
layout="@layout/toolbar_main"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress_bar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="313dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/linearLayout"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<include
|
||||
android:id="@+id/load_cancel"
|
||||
layout="@layout/cancel_fab"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
app:layout_anchorGravity="bottom"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/linearLayout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1.0"
|
||||
android:paddingBottom="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/toolbar">
|
||||
|
||||
<WebView
|
||||
android:id="@+id/webview"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/toolbar" />
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
227
app/src/main/res/layout/activity_main.xml
Normal file
@ -0,0 +1,227 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2019 bernd32
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="false"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="24dp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/artist_input"
|
||||
app:layout_constraintStart_toStartOf="@+id/artist_input"
|
||||
tools:context=".ui.LauncherActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar"
|
||||
layout="@layout/toolbar_main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/button"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
app:icon="@drawable/baseline_search_white_24"
|
||||
android:text="@string/search"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:onClick="onLoadLyrics"
|
||||
app:layout_constraintBottom_toTopOf="@+id/detailed_search_button"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_weight="1"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/spinner" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/search_input"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:hint="@string/search"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="textNoSuggestions"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/toolbar" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinner"
|
||||
style="@style/Base.Widget.AppCompat.Spinner.Underlined"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="44dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:spinnerMode="dropdown"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_weight="4"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/search_input" />
|
||||
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/detailed_search_button"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:layout_margin="8dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
app:icon="@drawable/ic_filter_list_24dp"
|
||||
android:onClick="onDetailedSearch"
|
||||
android:text="@string/detailed_search_show"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
app:borderWidth="0dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/button" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/artist_input"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="44dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:hint="@string/artist"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="textNoSuggestions"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_weight="3"
|
||||
app:layout_constraintStart_toEndOf="@+id/artist_spinner"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/detailed_search_button" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/artist_spinner"
|
||||
style="@style/Base.Widget.AppCompat.Spinner.Underlined"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="44dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/song_input"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/artist_input" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/song_input"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="44dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:hint="@string/song"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="textNoSuggestions"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.98"
|
||||
app:layout_constraintHorizontal_weight="3"
|
||||
app:layout_constraintStart_toEndOf="@+id/song_spinner"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/artist_spinner" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/song_spinner"
|
||||
style="@style/Base.Widget.AppCompat.Spinner.Underlined"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="44dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/lyrics_input"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_weight="2"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/song_input" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/lyrics_input"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:hint="@string/lyrics"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="textNoSuggestions"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="1.0"
|
||||
app:layout_constraintHorizontal_weight="3"
|
||||
app:layout_constraintStart_toEndOf="@+id/lyrics_spinner"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/song_spinner" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/lyrics_spinner"
|
||||
style="@style/Base.Widget.AppCompat.Spinner.Underlined"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="44dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_weight="2"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/lyrics_input" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/button2"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
app:icon="@drawable/baseline_search_white_24"
|
||||
android:text="@string/search"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:onClick="onLoadLyrics"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_weight="1"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/lyrics_spinner" />
|
||||
|
||||
<androidx.constraintlayout.widget.Group
|
||||
android:id="@+id/group"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
app:constraint_referenced_ids="lyrics_input,song_spinner,song_input,artist_spinner,artist_input,lyrics_spinner,button2" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</ScrollView>
|
83
app/src/main/res/layout/activity_search.xml
Normal file
@ -0,0 +1,83 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2019 bernd32
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.SearchActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar"
|
||||
layout="@layout/toolbar_main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerv_view"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="?attr/actionBarSize"
|
||||
app:layout_behavior = "@string/appbar_scrolling_view_behavior"/>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress_bar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:visibility="invisible"
|
||||
tools:visibility="visible"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/toolbar" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/floating_action_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="30dp"
|
||||
android:layout_marginEnd="248dp"
|
||||
app:fabSize="normal"
|
||||
android:src="@drawable/ic_keyboard_arrow_up_white_24dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
tools:visibility="visible"
|
||||
app:backgroundTint="@color/colorAccent"
|
||||
app:tint="?android:attr/textColorPrimaryInverse"
|
||||
/>
|
||||
|
||||
<include
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
app:layout_anchorGravity="bottom"
|
||||
layout="@layout/cancel_fab"
|
||||
android:id="@+id/load_cancel"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/recyclerv_view"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
78
app/src/main/res/layout/activity_show_lyrics.xml
Normal file
@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2019 bernd32
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:context=".ui.ShowLyricsActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar"
|
||||
layout="@layout/toolbar_main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/lyrics"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:lineSpacingMultiplier="1.3"
|
||||
android:textAlignment="center"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/toolbar" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress_bar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/toolbar"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<include
|
||||
android:id="@+id/load_cancel"
|
||||
layout="@layout/cancel_fab"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
app:layout_anchorGravity="bottom"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</ScrollView>
|
34
app/src/main/res/layout/cancel_fab.xml
Normal file
@ -0,0 +1,34 @@
|
||||
<!--
|
||||
~ Copyright 2019 bernd32
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:backgroundTint="@color/colorAccent"
|
||||
android:text="@string/cancel"
|
||||
android:textAlignment="center"
|
||||
android:textColor="?android:attr/textColorPrimaryInverse"
|
||||
android:visibility="invisible"
|
||||
app:icon="@drawable/ic_cancel_black_24dp"
|
||||
app:iconTint="?android:attr/textColorPrimaryInverse"
|
||||
tools:visibility="visible"
|
||||
android:onClick="onLoadCancel"
|
||||
android:scaleX="0.7"
|
||||
android:scaleY="0.7"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android" />
|
40
app/src/main/res/layout/dialog_change_fontsize.xml
Normal file
@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2019 bernd32
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
<SeekBar
|
||||
android:max="100"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/seek_bar"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_marginTop="74dp">
|
||||
</SeekBar>
|
||||
<TextView
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/font_size_textview"
|
||||
android:paddingTop="15dp"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:layout_width="wrap_content" android:layout_alignParentTop="true"
|
||||
android:layout_centerHorizontal="true">
|
||||
</TextView>
|
||||
</RelativeLayout>
|
39
app/src/main/res/layout/item_loading.xml
Normal file
@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2019 bernd32
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ProgressBar
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
style="?android:attr/progressBarStyle" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
82
app/src/main/res/layout/layout_listitem.xml
Normal file
@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2019 bernd32
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<com.google.android.material.card.MaterialCardView xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
style="@style/Widget.MaterialComponents.CardView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:id="@+id/parent_layout"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/card_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="Song name"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="20sp"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Headline"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/image"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/card_description"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="Artist"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/image"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/card_title"
|
||||
tools:ignore="HardcodedText" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image"
|
||||
android:layout_width="75dp"
|
||||
android:layout_height="75dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@android:color/darker_gray"
|
||||
android:contentDescription="@string/album_photo" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
23
app/src/main/res/layout/toolbar_main.xml
Normal file
@ -0,0 +1,23 @@
|
||||
<!--
|
||||
~ Copyright 2019 bernd32
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<androidx.appcompat.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:theme="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar"
|
||||
app:popupTheme="@style/ThemeOverlay.MaterialComponents.Light" />
|
23
app/src/main/res/menu/menu_favorites.xml
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2019 bernd32
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item android:id="@+id/delete_all"
|
||||
android:title="@string/delete_all"
|
||||
app:showAsAction="never" />
|
||||
</menu>
|
61
app/src/main/res/menu/menu_lyrics.xml
Normal file
@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2019 bernd32
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item android:id="@+id/fav_add_remove"
|
||||
android:title="@string/add_favorites"
|
||||
app:showAsAction="never" />
|
||||
<item
|
||||
android:id="@+id/romanize"
|
||||
app:showAsAction="never"
|
||||
android:title="@string/romanize" />
|
||||
<item
|
||||
android:id="@+id/toolbar_furigana"
|
||||
android:icon="@drawable/baseline_g_translate_white_24"
|
||||
app:showAsAction="never"
|
||||
android:title="@string/translate">
|
||||
</item>
|
||||
<item
|
||||
android:id="@+id/toolbar_share"
|
||||
android:icon="@drawable/baseline_share_white_24"
|
||||
app:showAsAction="never"
|
||||
android:title="@string/share">
|
||||
</item>
|
||||
<item
|
||||
android:id="@+id/copy"
|
||||
app:showAsAction="never"
|
||||
android:title="@string/copy">
|
||||
</item>
|
||||
<item
|
||||
android:id="@+id/font_size"
|
||||
app:showAsAction="never"
|
||||
android:title="@string/font_size">
|
||||
</item>
|
||||
<item
|
||||
android:id="@+id/dark_theme"
|
||||
app:showAsAction="never"
|
||||
android:title="@string/dark_theme"
|
||||
android:checkable="true">
|
||||
</item>
|
||||
<item
|
||||
android:id="@+id/quit"
|
||||
app:showAsAction="never"
|
||||
android:title="@string/quit">
|
||||
</item>
|
||||
|
||||
</menu>
|
40
app/src/main/res/menu/menu_main.xml
Normal file
@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2019 bernd32
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item android:id="@+id/toolbar_show_favs"
|
||||
android:title="@string/favs"
|
||||
android:icon="@drawable/favorite_border_black"
|
||||
app:showAsAction="ifRoom|withText" />
|
||||
<item
|
||||
android:id="@+id/dark_theme"
|
||||
app:showAsAction="never"
|
||||
android:title="@string/dark_theme"
|
||||
android:checkable="true">
|
||||
</item>
|
||||
<item
|
||||
android:id="@+id/contact"
|
||||
app:showAsAction="never"
|
||||
android:title="@string/contact">
|
||||
</item>
|
||||
<item
|
||||
android:id="@+id/quit"
|
||||
app:showAsAction="never"
|
||||
android:title="@string/quit">
|
||||
</item>
|
||||
</menu>
|
5
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
5
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 6.0 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 11 KiB |
22
app/src/main/res/values/colors.xml
Normal file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2019 bernd32
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<color name="colorPrimary">#295d8a</color>
|
||||
<color name="colorPrimaryDark">#1d4161</color>
|
||||
<color name="colorAccent">#398bd4</color>
|
||||
</resources>
|
20
app/src/main/res/values/ic_launcher_background.xml
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2019 bernd32
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#F1F1F1</color>
|
||||
</resources>
|
79
app/src/main/res/values/strings.xml
Normal file
@ -0,0 +1,79 @@
|
||||
<!--
|
||||
~ Copyright 2019 bernd32
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="app_name">JLyrics</string>
|
||||
<string name="search">Search</string>
|
||||
<string name="share">Share</string>
|
||||
<string name="title_found">Found:</string>
|
||||
<string name="album_photo">Album photo</string>
|
||||
<string name="detailed_search_hide">Hide detailed search</string>
|
||||
<string name="detailed_search_show">Show detailed search</string>
|
||||
<string name="artist">Artist</string>
|
||||
<string name="song">Song</string>
|
||||
<string name="lyrics">Lyrics</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="not_found_title">No result found</string>
|
||||
<string name="repeat"><i>(△Repeat)</i></string>
|
||||
<string name="repeat2"><i>( ※ Repeat)</i></string>
|
||||
<string name="not_found_message">Suggestions:\n\n
|
||||
• Make sure all words are spelled correctly\n
|
||||
• Try searching in Japanese\n
|
||||
• Try different search options\n
|
||||
• Try using detailed search
|
||||
</string>
|
||||
<string name="translate">Show furigana</string>
|
||||
<string name="add_favorites">Add/Remove to favorites</string>
|
||||
<string name="delete_all">Delete all</string>
|
||||
<string name="delete_lyrics_preamble">Removed from favorites</string>
|
||||
<string name="favs_remove">Remove from favs</string>
|
||||
<string name="favs_add">Add to favs</string>
|
||||
<string name="favs">Favorites</string>
|
||||
<string name="copy">Copy</string>
|
||||
<string name="font_size">Change font size</string>
|
||||
<string name="dark_theme">Night mode</string>
|
||||
<string name="quit">Quit</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="change_font">Change font size</string>
|
||||
<string name="saved">Saved</string>
|
||||
<string name="removed">Removed</string>
|
||||
<string name="contact">Contact developer</string>
|
||||
<string name="copied">Copied</string>
|
||||
<string name="connection_failed">Connection failed</string>
|
||||
<string name="romanize">Romanize</string>
|
||||
<string name="show_original">Show original</string>
|
||||
<string name="email_address">fallentides@outlook.com</string>
|
||||
<string name="email_subject_question">Feedback</string>
|
||||
<string name="empty_message">Favorites are empty</string>
|
||||
|
||||
<string-array name="spinner_items">
|
||||
<item>Song name</item>
|
||||
<item>Artist</item>
|
||||
<item>Lyrics</item>
|
||||
</string-array>
|
||||
<string-array name="spinner_search_options">
|
||||
<item>Starts with</item>
|
||||
<item>Full match</item>
|
||||
<item>In the middle</item>
|
||||
<item>Ends with</item>
|
||||
</string-array>
|
||||
<string-array name="lyrics_spinner_options">
|
||||
<item>Starts with</item>
|
||||
<item>In the middle</item>
|
||||
<item>Ends with</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
27
app/src/main/res/values/styles.xml
Normal file
@ -0,0 +1,27 @@
|
||||
<!--
|
||||
~ Copyright 2019 bernd32
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
|
||||
</style>
|
||||
|
||||
</resources>
|
25
app/src/main/res/xml/network_security_config.xml
Normal file
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2019 bernd32
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<network-security-config>
|
||||
<domain-config cleartextTrafficPermitted="true">
|
||||
<domain includeSubdomains="true">j-lyric.net</domain>
|
||||
</domain-config>
|
||||
<domain-config cleartextTrafficPermitted="true">
|
||||
<domain includeSubdomains="true">images-amazon.com</domain>
|
||||
</domain-config>
|
||||
</network-security-config>
|
192
app/src/main/resources/kana_to_romaji.csv
Normal file
@ -0,0 +1,192 @@
|
||||
ア,a
|
||||
イ,i
|
||||
ウ,u
|
||||
エ,e
|
||||
オ,o
|
||||
ー,-
|
||||
ァ,xa
|
||||
ィ,xi
|
||||
ゥ,xu
|
||||
ェ,xe
|
||||
ォ,xo
|
||||
カ,ka
|
||||
キ,ki
|
||||
ク,ku
|
||||
ケ,ke
|
||||
コ,ko
|
||||
ガ,ga
|
||||
ギ,gi
|
||||
グ,gu
|
||||
ゲ,ge
|
||||
ゴ,go
|
||||
サ,sa
|
||||
シ,shi
|
||||
ス,su
|
||||
セ,se
|
||||
ソ,so
|
||||
ザ,za
|
||||
ジ,ji
|
||||
ズ,zu
|
||||
ゼ,ze
|
||||
ゾ,zo
|
||||
ジャ,ja
|
||||
ジュ,ju
|
||||
ジェ,je
|
||||
ジョ,jo
|
||||
タ,ta
|
||||
チ,chi
|
||||
ツ,tsu
|
||||
テ,te
|
||||
ト,to
|
||||
ダ,da
|
||||
ヂ,dji
|
||||
ヅ,dzu
|
||||
デ,de
|
||||
ド,do
|
||||
ナ,na
|
||||
ニ,ni
|
||||
ヌ,nu
|
||||
ネ,ne
|
||||
ノ,no
|
||||
ハ,ha
|
||||
ヒ,hi
|
||||
フ,fu
|
||||
ヘ,he
|
||||
ホ,ho
|
||||
バ,ba
|
||||
ビ,bi
|
||||
ブ,bu
|
||||
ベ,be
|
||||
ボ,bo
|
||||
パ,pa
|
||||
ピ,pi
|
||||
プ,pu
|
||||
ペ,pe
|
||||
ポ,po
|
||||
ヴァ,va
|
||||
ヴィ,vi
|
||||
ヴ,vu
|
||||
ヴェ,ve
|
||||
ヴォ,vo
|
||||
ファ,fa
|
||||
フィ,fi
|
||||
フェ,fe
|
||||
フォ,fo
|
||||
マ,ma
|
||||
ミ,mi
|
||||
ム,mu
|
||||
メ,me
|
||||
モ,mo
|
||||
ヤ,ya
|
||||
ユ,yu
|
||||
イェ,ye
|
||||
ヨ,yo
|
||||
ラ,ra
|
||||
リ,ri
|
||||
ル,ru
|
||||
レ,re
|
||||
ロ,ro
|
||||
ワ,wa
|
||||
ヰ,wi
|
||||
ヱ,we
|
||||
ヲ,wo
|
||||
ン,n
|
||||
ヵ,xka
|
||||
ヶ,ga
|
||||
ヮ,xwa
|
||||
ャ,xya
|
||||
ュ,xyu
|
||||
ョ,xyo
|
||||
キャ,kya
|
||||
キィ,kyi
|
||||
キュ,kyu
|
||||
キェ,kye
|
||||
キョ,kyo
|
||||
ギャ,gya
|
||||
ギィ,gyi
|
||||
ギュ,gyu
|
||||
ギェ,gye
|
||||
ギョ,gyo
|
||||
シャ,sha
|
||||
シィ,syi
|
||||
シュ,shu
|
||||
シェ,she
|
||||
ショ,sho
|
||||
ジィ,jyi
|
||||
チャ,cha
|
||||
チィ,cyi
|
||||
チュ,chu
|
||||
チェ,che
|
||||
チョ,cho
|
||||
テャ,tha
|
||||
ティ,thi
|
||||
テュ,thu
|
||||
テェ,the
|
||||
テョ,tho
|
||||
ヂャ,dya
|
||||
ヂィ,dyi
|
||||
ヂュ,dyu
|
||||
ヂェ,dye
|
||||
ヂョ,dyo
|
||||
デャ,dha
|
||||
ディ,dhi
|
||||
デュ,dhu
|
||||
デェ,dhe
|
||||
デョ,dho
|
||||
ニャ,nya
|
||||
ニィ,nyi
|
||||
ニュ,nyu
|
||||
ニェ,nye
|
||||
ニョ,nyo
|
||||
ヒャ,hya
|
||||
ヒィ,hyi
|
||||
ヒュ,hyu
|
||||
ヒェ,hye
|
||||
ヒョ,hyo
|
||||
ビャ,bya
|
||||
ビィ,byi
|
||||
ビュ,byu
|
||||
ビェ,bye
|
||||
ビョ,byo
|
||||
ピャ,pya
|
||||
ピィ,pyi
|
||||
ピュ,pyu
|
||||
ピェ,pye
|
||||
ピョ,pyo
|
||||
ミャ,mya
|
||||
ミィ,myi
|
||||
ミュ,myu
|
||||
ミェ,mye
|
||||
ミョ,myo
|
||||
リャ,lya
|
||||
リィ,lyi
|
||||
リュ,lyu
|
||||
リェ,lye
|
||||
リョ,lyo
|
||||
−,-
|
||||
゛,"
|
||||
゜,'
|
||||
、,,
|
||||
。,.
|
||||
:,:
|
||||
,
|
||||
@,@
|
||||
(,(
|
||||
),)
|
||||
,
|
||||
ンア,n'a
|
||||
んあ,n'a
|
||||
ンイ,n'i
|
||||
んい,n'i
|
||||
ンウ,n'u
|
||||
んう,n'u
|
||||
ンエ,n'e
|
||||
んえ,n'e
|
||||
ンオ,n'o
|
||||
んお,n'o
|
||||
ンヤ,n'ya
|
||||
んや,n'ya
|
||||
ンユ,n'yu
|
||||
んゆ,n'yu
|
||||
ンヨ,n'yo
|
||||
んよ,n'yo
|
Can't render this file because it contains an unexpected character in line 192 and column 13.
|
48
build.gradle
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2019 bernd32
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.5.2'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
|
||||
ext {
|
||||
roomVersion = '2.2.2'
|
||||
archLifecycleVersion = '2.2.0-rc02'
|
||||
}
|