From 43d71636af445abb758a48a157aa145287b3894a Mon Sep 17 00:00:00 2001 From: Marc Date: Sun, 9 Dec 2018 13:23:21 +0000 Subject: [PATCH 01/18] Change selectableItemBackground to selectableItemBackgroundBorderless --- .gitignore | 2 ++ app/build.gradle | 4 ++-- app/src/main/res/layout/activity_licenses.xml | 2 +- app/src/main/res/layout/dialog_add_item.xml | 3 +++ app/src/main/res/layout/toolbar_filter.xml | 4 ++-- app/src/main/res/layout/toolbar_main.xml | 2 +- app/src/main/res/layout/toolbar_settings.xml | 2 +- 7 files changed, 12 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index bd39932..badd818 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,8 @@ captures/ .idea/libraries .idea/caches .idea/sonarlint +.idea/markdown-navigator.xml +.idea/markdown-navigator # Keystore files # Uncomment the following line if you do not want to check your keystore files in. diff --git a/app/build.gradle b/app/build.gradle index 109feca..7a14bf7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,8 +12,8 @@ android { applicationId "app.marcdev.earworm" minSdkVersion 23 targetSdkVersion 28 - versionCode 12 - versionName "1.0.0" + versionCode 13 + versionName "1.0.1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { diff --git a/app/src/main/res/layout/activity_licenses.xml b/app/src/main/res/layout/activity_licenses.xml index f828643..79d7e6c 100644 --- a/app/src/main/res/layout/activity_licenses.xml +++ b/app/src/main/res/layout/activity_licenses.xml @@ -193,7 +193,7 @@ app:layout_constraintTop_toTopOf="parent" /> Date: Thu, 13 Dec 2018 18:25:02 +0000 Subject: [PATCH 02/18] Convert ImageButtons to ImageViews --- .../earworm/additem/AddItemBottomSheet.kt | 39 +++++++------- .../mainscreen/MainFragmentViewImpl.kt | 14 ++--- .../settingsscreen/LicensesActivity.kt | 8 +-- .../settingsscreen/SettingsActivity.kt | 8 +-- .../app/marcdev/earworm/utils/EarwormUtils.kt | 6 +-- app/src/main/res/layout/dialog_add_item.xml | 6 +-- app/src/main/res/layout/toolbar_filter.xml | 20 +++---- app/src/main/res/layout/toolbar_main.xml | 54 +++++++++---------- app/src/main/res/layout/toolbar_settings.xml | 4 +- app/src/main/res/values/dimens.xml | 3 +- 10 files changed, 83 insertions(+), 79 deletions(-) diff --git a/app/src/main/java/app/marcdev/earworm/additem/AddItemBottomSheet.kt b/app/src/main/java/app/marcdev/earworm/additem/AddItemBottomSheet.kt index 27b8660..9252673 100644 --- a/app/src/main/java/app/marcdev/earworm/additem/AddItemBottomSheet.kt +++ b/app/src/main/java/app/marcdev/earworm/additem/AddItemBottomSheet.kt @@ -12,7 +12,10 @@ import android.preference.PreferenceManager import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.* +import android.widget.DatePicker +import android.widget.EditText +import android.widget.ImageView +import android.widget.Toast import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import app.marcdev.earworm.R @@ -33,9 +36,9 @@ class AddItemBottomSheet : RoundedBottomDialogFragment(), AddItemView { private lateinit var saveButton: MaterialButton private lateinit var primaryInput: EditText private lateinit var secondaryInput: EditText - private lateinit var songButton: ImageButton - private lateinit var albumButton: ImageButton - private lateinit var artistButton: ImageButton + private lateinit var songButton: ImageView + private lateinit var albumButton: ImageView + private lateinit var artistButton: ImageView private lateinit var presenter: AddItemPresenter private lateinit var datePickerDialog: Dialog private lateinit var datePicker: DatePicker @@ -253,13 +256,13 @@ class AddItemBottomSheet : RoundedBottomDialogFragment(), AddItemView { private fun setupDefaults() { Timber.d("Log: setupDefaults: Started") type = SONG - changeColorOfImageButtonDrawable(activity!!.applicationContext, songButton, true) - changeColorOfImageButtonDrawable(activity!!.applicationContext, albumButton, false) - changeColorOfImageButtonDrawable(activity!!.applicationContext, artistButton, false) + changeColorOfImageViewDrawable(activity!!.applicationContext, songButton, true) + changeColorOfImageViewDrawable(activity!!.applicationContext, albumButton, false) + changeColorOfImageViewDrawable(activity!!.applicationContext, artistButton, false) dateChip.text = resources.getString(R.string.today) } - private fun activateButtonIfNecessary(button: ImageButton) { + private fun activateButtonIfNecessary(button: ImageView) { Timber.d("Log: activateButtonIfNecessary: Started") if(type == SONG && button == songButton @@ -272,32 +275,32 @@ class AddItemBottomSheet : RoundedBottomDialogFragment(), AddItemView { } } - private fun activateButton(button: ImageButton) { + private fun activateButton(button: ImageView) { Timber.d("Log: activateButtonIfNecessary: Activating button $button") when(button) { songButton -> { - changeColorOfImageButtonDrawable(activity!!.applicationContext, songButton, true) - changeColorOfImageButtonDrawable(activity!!.applicationContext, albumButton, false) - changeColorOfImageButtonDrawable(activity!!.applicationContext, artistButton, false) + changeColorOfImageViewDrawable(activity!!.applicationContext, songButton, true) + changeColorOfImageViewDrawable(activity!!.applicationContext, albumButton, false) + changeColorOfImageViewDrawable(activity!!.applicationContext, artistButton, false) type = SONG primaryInput.hint = resources.getString(R.string.song_name) secondaryInput.hint = resources.getString(R.string.artist) } albumButton -> { - changeColorOfImageButtonDrawable(activity!!.applicationContext, songButton, false) - changeColorOfImageButtonDrawable(activity!!.applicationContext, albumButton, true) - changeColorOfImageButtonDrawable(activity!!.applicationContext, artistButton, false) + changeColorOfImageViewDrawable(activity!!.applicationContext, songButton, false) + changeColorOfImageViewDrawable(activity!!.applicationContext, albumButton, true) + changeColorOfImageViewDrawable(activity!!.applicationContext, artistButton, false) type = ALBUM primaryInput.hint = resources.getString(R.string.album) secondaryInput.hint = resources.getString(R.string.artist) } artistButton -> { - changeColorOfImageButtonDrawable(activity!!.applicationContext, songButton, false) - changeColorOfImageButtonDrawable(activity!!.applicationContext, albumButton, false) - changeColorOfImageButtonDrawable(activity!!.applicationContext, artistButton, true) + changeColorOfImageViewDrawable(activity!!.applicationContext, songButton, false) + changeColorOfImageViewDrawable(activity!!.applicationContext, albumButton, false) + changeColorOfImageViewDrawable(activity!!.applicationContext, artistButton, true) type = ARTIST primaryInput.hint = resources.getString(R.string.artist) secondaryInput.hint = resources.getString(R.string.genre) diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewImpl.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewImpl.kt index 0024ef0..71ec9c4 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewImpl.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewImpl.kt @@ -33,9 +33,9 @@ class MainFragmentViewImpl : Fragment(), MainFragmentView, RecyclerUpdateView { private lateinit var noFilteredResultsWarningImage: ImageView private lateinit var progressBar: ProgressBar private lateinit var searchInput: EditText - private lateinit var searchButton: ImageButton - private lateinit var filterButton: ImageButton - private lateinit var settingsButton: ImageButton + private lateinit var searchButton: ImageView + private lateinit var filterButton: ImageView + private lateinit var settingsButton: ImageView private lateinit var filterDialog: FilterDialog private lateinit var recyclerAdapter: MainRecyclerAdapter private lateinit var presenter: MainFragmentPresenter @@ -260,13 +260,13 @@ class MainFragmentViewImpl : Fragment(), MainFragmentView, RecyclerUpdateView { override fun activateFilterIcon(isActive: Boolean) { Timber.d("Log: activateFilterIcon: Started with isActive = $isActive") - changeColorOfImageButtonDrawable(context!!, filterButton, isActive) + changeColorOfImageViewDrawable(context!!, filterButton, isActive) } private fun convertToDarkMode() { - changeColorOfImageButtonDrawable(requireContext(), filterButton, false) - changeColorOfImageButtonDrawable(requireContext(), settingsButton, false) - changeColorOfImageButtonDrawable(requireContext(), searchButton, false) + changeColorOfImageViewDrawable(requireContext(), filterButton, false) + changeColorOfImageViewDrawable(requireContext(), settingsButton, false) + changeColorOfImageViewDrawable(requireContext(), searchButton, false) changeColorOfDrawable(requireContext(), noEntriesWarningImage.drawable, false) changeColorOfDrawable(requireContext(), noFilteredResultsWarningImage.drawable, false) } diff --git a/app/src/main/java/app/marcdev/earworm/settingsscreen/LicensesActivity.kt b/app/src/main/java/app/marcdev/earworm/settingsscreen/LicensesActivity.kt index d910e87..c782c25 100644 --- a/app/src/main/java/app/marcdev/earworm/settingsscreen/LicensesActivity.kt +++ b/app/src/main/java/app/marcdev/earworm/settingsscreen/LicensesActivity.kt @@ -4,13 +4,13 @@ import android.content.Intent import android.net.Uri import android.os.Bundle import android.view.View -import android.widget.ImageButton +import android.widget.ImageView import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.cardview.widget.CardView import app.marcdev.earworm.R import app.marcdev.earworm.utils.DARK_THEME -import app.marcdev.earworm.utils.changeColorOfImageButtonDrawable +import app.marcdev.earworm.utils.changeColorOfImageViewDrawable import app.marcdev.earworm.utils.getTheme import timber.log.Timber @@ -41,10 +41,10 @@ class LicensesActivity : AppCompatActivity() { private fun bindViews() { Timber.v("Log: bindViews: Started") - val backButton = findViewById(R.id.img_backFromSettings) + val backButton = findViewById(R.id.img_backFromSettings) backButton.setOnClickListener(backOnClickListener) if(isDarkMode) { - changeColorOfImageButtonDrawable(applicationContext, backButton, false) + changeColorOfImageViewDrawable(applicationContext, backButton, false) } val toolbarTitle = findViewById(R.id.txt_settingsToolbarTitle) diff --git a/app/src/main/java/app/marcdev/earworm/settingsscreen/SettingsActivity.kt b/app/src/main/java/app/marcdev/earworm/settingsscreen/SettingsActivity.kt index d39ae06..48e8332 100644 --- a/app/src/main/java/app/marcdev/earworm/settingsscreen/SettingsActivity.kt +++ b/app/src/main/java/app/marcdev/earworm/settingsscreen/SettingsActivity.kt @@ -2,11 +2,11 @@ package app.marcdev.earworm.settingsscreen import android.os.Bundle import android.view.View -import android.widget.ImageButton +import android.widget.ImageView import androidx.appcompat.app.AppCompatActivity import app.marcdev.earworm.R import app.marcdev.earworm.utils.DARK_THEME -import app.marcdev.earworm.utils.changeColorOfImageButtonDrawable +import app.marcdev.earworm.utils.changeColorOfImageViewDrawable import app.marcdev.earworm.utils.getTheme import app.marcdev.earworm.utils.setFragment import timber.log.Timber @@ -33,12 +33,12 @@ class SettingsActivity : AppCompatActivity() { private fun bindViews() { Timber.v("Log: bindViews: Started") - val backButton = findViewById(R.id.img_backFromSettings) + val backButton = findViewById(R.id.img_backFromSettings) backButton.setOnClickListener(backOnClickListener) if(getTheme(applicationContext) == DARK_THEME) { Timber.v("Log: bindViews: Converting to dark mode") - changeColorOfImageButtonDrawable(applicationContext, backButton, false) + changeColorOfImageViewDrawable(applicationContext, backButton, false) } } diff --git a/app/src/main/java/app/marcdev/earworm/utils/EarwormUtils.kt b/app/src/main/java/app/marcdev/earworm/utils/EarwormUtils.kt index 9078c1f..55093dc 100644 --- a/app/src/main/java/app/marcdev/earworm/utils/EarwormUtils.kt +++ b/app/src/main/java/app/marcdev/earworm/utils/EarwormUtils.kt @@ -4,7 +4,7 @@ import android.content.Context import android.graphics.PorterDuff import android.graphics.drawable.Drawable import android.preference.PreferenceManager -import android.widget.ImageButton +import android.widget.ImageView import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import app.marcdev.earworm.R @@ -63,8 +63,8 @@ fun formatDateForDisplay(day: Int, month: Int, year: Int): String { * @param button The button to change the color of * @param isActivated Whether or not the button should be put into the activated state */ -fun changeColorOfImageButtonDrawable(context: Context, button: ImageButton, isActivated: Boolean) { - Timber.v("Log: changeColorOfImageButtonDrawable: Started") +fun changeColorOfImageViewDrawable(context: Context, button: ImageView, isActivated: Boolean) { + Timber.v("Log: changeColorOfImageViewDrawable: Started") when { isActivated -> button.setColorFilter(context.getColor(R.color.colorAccent)) diff --git a/app/src/main/res/layout/dialog_add_item.xml b/app/src/main/res/layout/dialog_add_item.xml index 23766a1..a9db2cd 100644 --- a/app/src/main/res/layout/dialog_add_item.xml +++ b/app/src/main/res/layout/dialog_add_item.xml @@ -72,7 +72,7 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/edt_item_secondary_input" /> - - - - @@ -40,26 +40,26 @@ android:layout_marginTop="@dimen/toolbarIconMargin" android:layout_marginEnd="@dimen/toolbarIconMarginSmall" android:layout_marginBottom="@dimen/toolbarIconMargin" - android:inputType="text" - android:hint="@string/search" android:autofillHints="@string/search" + android:hint="@string/search" + android:inputType="text" android:singleLine="true" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@id/img_search" app:layout_constraintStart_toEndOf="@id/img_filter" app:layout_constraintTop_toTopOf="parent" /> - diff --git a/app/src/main/res/layout/toolbar_main.xml b/app/src/main/res/layout/toolbar_main.xml index 35e1aee..4cb736e 100644 --- a/app/src/main/res/layout/toolbar_main.xml +++ b/app/src/main/res/layout/toolbar_main.xml @@ -1,44 +1,44 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/toolbar_main" + android:layout_width="match_parent" + android:layout_height="@dimen/appBarHeight" + android:background="@color/colorPrimary" + app:contentInsetEnd="0dp" + app:contentInsetLeft="0dp" + app:contentInsetRight="0dp" + app:contentInsetStart="0dp" + app:layout_scrollFlags="scroll|snap|enterAlways"> + android:layout_width="match_parent" + android:layout_height="match_parent"> + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> - diff --git a/app/src/main/res/layout/toolbar_settings.xml b/app/src/main/res/layout/toolbar_settings.xml index 4bed8f5..3419cb7 100644 --- a/app/src/main/res/layout/toolbar_settings.xml +++ b/app/src/main/res/layout/toolbar_settings.xml @@ -28,7 +28,7 @@ app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" /> - 4dp 16dp 56dp - 48dp + 36dp 16dp 8dp + 6dp 16dp 8dp 8dp From a94c7afde2fde609eff5f663728474600e6727bd Mon Sep 17 00:00:00 2001 From: Marc Date: Thu, 13 Dec 2018 18:38:06 +0000 Subject: [PATCH 03/18] Fix Accent/Secondary color on AddItemBottomSheet --- app/src/main/res/layout/dialog_add_item.xml | 2 +- app/src/main/res/layout/dialog_delete_image.xml | 4 ++-- .../main/res/layout/dialog_edit_or_delete.xml | 2 +- app/src/main/res/layout/dialog_filter.xml | 2 +- app/src/main/res/values/attrs.xml | 2 ++ app/src/main/res/values/styles.xml | 16 ++++++++++++++++ 6 files changed, 23 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/layout/dialog_add_item.xml b/app/src/main/res/layout/dialog_add_item.xml index a9db2cd..f9d6f1d 100644 --- a/app/src/main/res/layout/dialog_add_item.xml +++ b/app/src/main/res/layout/dialog_add_item.xml @@ -56,7 +56,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="@dimen/marginStandard" - android:backgroundTint="@color/positive" + style="@style/PositiveButton" android:text="@string/save" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" diff --git a/app/src/main/res/layout/dialog_delete_image.xml b/app/src/main/res/layout/dialog_delete_image.xml index 9dbdfe9..84bb75f 100644 --- a/app/src/main/res/layout/dialog_delete_image.xml +++ b/app/src/main/res/layout/dialog_delete_image.xml @@ -21,7 +21,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="@dimen/marginStandard" - android:backgroundTint="@color/negative" + style="@style/NegativeButton" android:text="@string/delete" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" @@ -33,7 +33,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="@dimen/marginStandard" - android:backgroundTint="@color/colorAccent" + style="@style/PositiveButton" android:text="@string/cancel" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" diff --git a/app/src/main/res/layout/dialog_edit_or_delete.xml b/app/src/main/res/layout/dialog_edit_or_delete.xml index 47ec010..3482b10 100644 --- a/app/src/main/res/layout/dialog_edit_or_delete.xml +++ b/app/src/main/res/layout/dialog_edit_or_delete.xml @@ -21,7 +21,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="@dimen/marginStandard" - android:backgroundTint="@color/positive" + style="@style/PositiveButton" android:text="@string/edit" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" diff --git a/app/src/main/res/layout/dialog_filter.xml b/app/src/main/res/layout/dialog_filter.xml index cd957db..8eeddb0 100644 --- a/app/src/main/res/layout/dialog_filter.xml +++ b/app/src/main/res/layout/dialog_filter.xml @@ -187,7 +187,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="@dimen/marginStandard" - android:backgroundTint="@color/positive" + style="@style/PositiveButton" android:text="@string/filter" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 38ecd6e..837ea8d 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -13,5 +13,7 @@ + + \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index ab964e1..77a2e54 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -17,6 +17,8 @@ @color/lightThemeColorPrimary @style/Earworm.LightToolbar @color/lightThemeColorPrimaryDark + @color/positive + @color/negative @@ -39,6 +41,8 @@ @color/darkThemeColorPrimaryDark @color/darkThemeColorPrimary ?attr/navigationBarColor + @color/positive + @color/negative @@ -74,8 +78,18 @@ ?attr/transparentButtonBackground + + + + From 0684e154bdb47eabc5f506c210d180c1e5aeab88 Mon Sep 17 00:00:00 2001 From: Marc Date: Fri, 14 Dec 2018 13:52:27 +0000 Subject: [PATCH 04/18] Potential fix for button style resetting occasionally --- app/build.gradle | 4 ++-- app/src/main/res/values/styles.xml | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 7a14bf7..9eb4300 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,8 +12,8 @@ android { applicationId "app.marcdev.earworm" minSdkVersion 23 targetSdkVersion 28 - versionCode 13 - versionName "1.0.1" + versionCode 14 + versionName "1.0.2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 77a2e54..534022c 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -90,6 +90,8 @@ From ba8b9a1d27f22bf88f5e22758634241fdd33a994 Mon Sep 17 00:00:00 2001 From: Marc Date: Tue, 15 Jan 2019 13:16:23 +0000 Subject: [PATCH 05/18] Update dependencies --- app/build.gradle | 6 +++--- build.gradle | 4 ++-- gradle/wrapper/gradle-wrapper.properties | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 9eb4300..d4bd792 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -33,11 +33,11 @@ dependencies { implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'androidx.preference:preference:1.0.0' - implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha2' + implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha3' implementation 'com.google.android.material:material:1.0.0' testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.0' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' + androidTestImplementation 'androidx.test:runner:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' // Timber for logging implementation('com.jakewharton.timber:timber:4.7.0') diff --git a/build.gradle b/build.gradle index ff630b8..ee486a6 100644 --- a/build.gradle +++ b/build.gradle @@ -1,13 +1,13 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.3.0' + ext.kotlin_version = '1.3.11' repositories { google() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.2.1' + classpath 'com.android.tools.build:gradle:3.3.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9a4163a..5285468 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Tue Jan 15 13:13:13 GMT 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip From 4e7c75ddde3a67b8c8f3a22a5498185dd07e7e8b Mon Sep 17 00:00:00 2001 From: Marc Date: Fri, 31 May 2019 19:59:00 +0100 Subject: [PATCH 06/18] Add Kodein & MVVM dependencies and convert database to use DI --- .idea/codeStyles/Project.xml | 253 ++++++++++++++++-- .idea/codeStyles/codeStyleConfig.xml | 5 + .idea/encodings.xml | 4 + app/build.gradle | 27 +- .../earworm/{ => data}/database/DAOTest.kt | 40 +-- .../repository/FavouriteItemRepositoryTest.kt | 44 +-- .../main/java/app/marcdev/earworm/Earworm.kt | 23 +- .../earworm/additem/AddItemBottomSheet.kt | 2 +- .../marcdev/earworm/additem/AddItemModel.kt | 2 +- .../earworm/additem/AddItemModelImpl.kt | 12 +- .../earworm/additem/AddItemPresenter.kt | 2 +- .../earworm/additem/AddItemPresenterImpl.kt | 2 +- .../marcdev/earworm/additem/AddItemView.kt | 2 +- .../earworm/data/database/AppDatabase.kt | 5 + .../app/marcdev/earworm/data/database/DAO.kt | 25 ++ .../{ => data}/database/FavouriteItem.kt | 6 +- .../data/database/ProductionAppDatabase.kt | 54 ++++ .../repository/FavouriteItemRepository.kt | 6 +- .../repository/FavouriteItemRepositoryImpl.kt | 56 ++++ .../marcdev/earworm/database/AppDatabase.kt | 34 --- .../java/app/marcdev/earworm/database/DAO.kt | 25 -- .../earworm/mainscreen/MainFragmentModel.kt | 2 +- .../mainscreen/MainFragmentModelImpl.kt | 12 +- .../mainscreen/MainFragmentPresenter.kt | 2 +- .../mainscreen/MainFragmentPresenterImpl.kt | 2 +- .../earworm/mainscreen/MainFragmentView.kt | 2 +- .../mainscreen/MainFragmentViewImpl.kt | 6 +- .../mainrecycler/MainRecyclerAdapter.kt | 2 +- .../mainrecycler/MainRecyclerView.kt | 2 +- .../mainrecycler/MainRecyclerViewHolder.kt | 4 +- .../MainRecyclerViewHolderAlbum.kt | 2 +- .../MainRecyclerViewHolderArtist.kt | 2 +- .../MainRecyclerViewHolderGenre.kt | 2 +- .../MainRecyclerViewHolderHeader.kt | 2 +- .../MainRecyclerViewHolderSong.kt | 2 +- .../repository/FavouriteItemRepositoryImpl.kt | 27 -- .../app/marcdev/earworm/utils/ListUtils.kt | 4 +- 37 files changed, 500 insertions(+), 204 deletions(-) create mode 100644 .idea/codeStyles/codeStyleConfig.xml create mode 100644 .idea/encodings.xml rename app/src/androidTest/java/app/marcdev/earworm/{ => data}/database/DAOTest.kt (88%) rename app/src/androidTest/java/app/marcdev/earworm/{ => data}/repository/FavouriteItemRepositoryTest.kt (87%) create mode 100644 app/src/main/java/app/marcdev/earworm/data/database/AppDatabase.kt create mode 100644 app/src/main/java/app/marcdev/earworm/data/database/DAO.kt rename app/src/main/java/app/marcdev/earworm/{ => data}/database/FavouriteItem.kt (76%) create mode 100644 app/src/main/java/app/marcdev/earworm/data/database/ProductionAppDatabase.kt rename app/src/main/java/app/marcdev/earworm/{ => data}/repository/FavouriteItemRepository.kt (63%) create mode 100644 app/src/main/java/app/marcdev/earworm/data/repository/FavouriteItemRepositoryImpl.kt delete mode 100644 app/src/main/java/app/marcdev/earworm/database/AppDatabase.kt delete mode 100644 app/src/main/java/app/marcdev/earworm/database/DAO.kt delete mode 100644 app/src/main/java/app/marcdev/earworm/repository/FavouriteItemRepositoryImpl.kt diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 30aa626..4edc5b9 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -1,29 +1,232 @@ - - - - - - - - - - + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..15a15b2 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index d4bd792..099bf37 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,8 +12,8 @@ android { applicationId "app.marcdev.earworm" minSdkVersion 23 targetSdkVersion 28 - versionCode 14 - versionName "1.0.2" + versionCode 15 + versionName "1.1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { @@ -30,11 +30,20 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'androidx.appcompat:appcompat:1.0.2' + // Kotlin + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1' + + // AndroidX + implementation 'androidx.appcompat:appcompat:1.1.0-alpha02' + implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha5' implementation 'androidx.preference:preference:1.0.0' - implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha3' implementation 'com.google.android.material:material:1.0.0' + implementation "androidx.lifecycle:lifecycle-extensions:2.2.0-alpha01" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0-alpha01" + + // Testing testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' @@ -47,14 +56,14 @@ dependencies { kapt 'androidx.room:room-compiler:2.0.0' androidTestImplementation 'androidx.room:room-testing:2.0.0' - // Kotlin co-routines for asynchronous code - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.0' + // Kodein + implementation 'org.kodein.di:kodein-di-generic-jvm:6.0.1' + implementation 'org.kodein.di:kodein-di-framework-android-x:6.0.1' // Glide for image loading and caching implementation 'com.github.bumptech.glide:glide:4.8.0' kapt 'com.github.bumptech.glide:compiler:4.8.0' // Android File Picker for choosing an image - implementation 'com.droidninja:filepicker:2.2.0' + implementation 'com.droidninja:filepicker:2.2.1' } diff --git a/app/src/androidTest/java/app/marcdev/earworm/database/DAOTest.kt b/app/src/androidTest/java/app/marcdev/earworm/data/database/DAOTest.kt similarity index 88% rename from app/src/androidTest/java/app/marcdev/earworm/database/DAOTest.kt rename to app/src/androidTest/java/app/marcdev/earworm/data/database/DAOTest.kt index f7311c2..1c09362 100644 --- a/app/src/androidTest/java/app/marcdev/earworm/database/DAOTest.kt +++ b/app/src/androidTest/java/app/marcdev/earworm/data/database/DAOTest.kt @@ -1,4 +1,4 @@ -package app.marcdev.earworm.database +package app.marcdev.earworm.data.database import androidx.room.Room import androidx.test.platform.app.InstrumentationRegistry @@ -10,7 +10,7 @@ import org.junit.Test class DAOTest { - private var database: AppDatabase? = null + private var database: ProductionAppDatabase? = null private var dao: DAO? = null // Default values @@ -27,7 +27,7 @@ class DAOTest { @Before fun setUp() { database = - Room.inMemoryDatabaseBuilder(InstrumentationRegistry.getInstrumentation().context, AppDatabase::class.java) + Room.inMemoryDatabaseBuilder(InstrumentationRegistry.getInstrumentation().context, ProductionAppDatabase::class.java) .allowMainThreadQueries().build() dao = database!!.dao() } @@ -48,7 +48,7 @@ class DAOTest { val returnedItemsWhenNothingInserted: MutableList = database?.dao()!!.getAllItems() Assert.assertEquals(0, returnedItemsWhenNothingInserted.size) - database?.dao()!!.insertOrUpdateItem(testItem) + database?.dao()!!.insertItem(testItem) val returnedItemsWhenOneInserted: MutableList = database?.dao()!!.getAllItems() Assert.assertEquals(1, returnedItemsWhenOneInserted.size) @@ -62,8 +62,8 @@ class DAOTest { val returnedItemsWhenNothingInserted: MutableList = database?.dao()!!.getAllItems() Assert.assertEquals(0, returnedItemsWhenNothingInserted.size) - database?.dao()!!.insertOrUpdateItem(testItem1) - database?.dao()!!.insertOrUpdateItem(testItem2) + database?.dao()!!.insertItem(testItem1) + database?.dao()!!.insertItem(testItem2) val returnedItemsWhenOneInserted: MutableList = database?.dao()!!.getAllItems() Assert.assertEquals(2, returnedItemsWhenOneInserted.size) @@ -79,7 +79,7 @@ class DAOTest { val returnedItemsWhenNothingInserted: MutableList = database?.dao()!!.getItemById(testId) Assert.assertEquals(0, returnedItemsWhenNothingInserted.size) - database?.dao()!!.insertOrUpdateItem(testItem) + database?.dao()!!.insertItem(testItem) val returnedItemsWhenOneInserted: MutableList = database?.dao()!!.getItemById(testId) Assert.assertEquals(1, returnedItemsWhenOneInserted.size) @@ -103,8 +103,8 @@ class DAOTest { val returnedItemsWhenNothingInserted: MutableList = database?.dao()!!.getAllItems() Assert.assertEquals(0, returnedItemsWhenNothingInserted.size) - database?.dao()!!.insertOrUpdateItem(testItem1) - database?.dao()!!.insertOrUpdateItem(testItem2) + database?.dao()!!.insertItem(testItem1) + database?.dao()!!.insertItem(testItem2) val returnedItemsWhenTwoInserted: MutableList = database?.dao()!!.getAllItems() Assert.assertEquals(2, returnedItemsWhenTwoInserted.size) @@ -131,8 +131,8 @@ class DAOTest { val returnedItemsWhenNothingInserted: MutableList = database?.dao()!!.getAllItems() Assert.assertEquals(0, returnedItemsWhenNothingInserted.size) - database?.dao()!!.insertOrUpdateItem(testItem1) - database?.dao()!!.insertOrUpdateItem(testItem2) + database?.dao()!!.insertItem(testItem1) + database?.dao()!!.insertItem(testItem2) val returnedAllItemsWhenTwoInserted: MutableList = database?.dao()!!.getAllItems() Assert.assertEquals(2, returnedAllItemsWhenTwoInserted.size) @@ -155,9 +155,9 @@ class DAOTest { val testItem3 = createTestItem() testItem3.imageName = testImage2 - database?.dao()!!.insertOrUpdateItem(testItem1) - database?.dao()!!.insertOrUpdateItem(testItem2) - database?.dao()!!.insertOrUpdateItem(testItem3) + database?.dao()!!.insertItem(testItem1) + database?.dao()!!.insertItem(testItem2) + database?.dao()!!.insertItem(testItem3) val returnedValueWhenSearchedForTestImage1: Int = database?.dao()!!.getNumberOfEntriesUsingImage(testImage1) Assert.assertEquals(1, returnedValueWhenSearchedForTestImage1) @@ -186,9 +186,9 @@ class DAOTest { testItem3.imageName = testImage2 testItem3.id = testId3 - database?.dao()!!.insertOrUpdateItem(testItem1) - database?.dao()!!.insertOrUpdateItem(testItem2) - database?.dao()!!.insertOrUpdateItem(testItem3) + database?.dao()!!.insertItem(testItem1) + database?.dao()!!.insertItem(testItem2) + database?.dao()!!.insertItem(testItem3) val returnedValueWhenSearchedForTestImage1: Int = database?.dao()!!.getNumberOfEntriesUsingImage(testImage1) Assert.assertEquals(1, returnedValueWhenSearchedForTestImage1) @@ -225,9 +225,9 @@ class DAOTest { testItem3.imageName = testImage2 testItem3.id = testId3 - database?.dao()!!.insertOrUpdateItem(testItem1) - database?.dao()!!.insertOrUpdateItem(testItem2) - database?.dao()!!.insertOrUpdateItem(testItem3) + database?.dao()!!.insertItem(testItem1) + database?.dao()!!.insertItem(testItem2) + database?.dao()!!.insertItem(testItem3) val returnedValueWhenSearchedForTestImage1: Int = database?.dao()!!.getNumberOfEntriesUsingImage(testImage1) Assert.assertEquals(1, returnedValueWhenSearchedForTestImage1) diff --git a/app/src/androidTest/java/app/marcdev/earworm/repository/FavouriteItemRepositoryTest.kt b/app/src/androidTest/java/app/marcdev/earworm/data/repository/FavouriteItemRepositoryTest.kt similarity index 87% rename from app/src/androidTest/java/app/marcdev/earworm/repository/FavouriteItemRepositoryTest.kt rename to app/src/androidTest/java/app/marcdev/earworm/data/repository/FavouriteItemRepositoryTest.kt index d56cfce..beabca3 100644 --- a/app/src/androidTest/java/app/marcdev/earworm/repository/FavouriteItemRepositoryTest.kt +++ b/app/src/androidTest/java/app/marcdev/earworm/data/repository/FavouriteItemRepositoryTest.kt @@ -1,10 +1,10 @@ -package app.marcdev.earworm.repository +package app.marcdev.earworm.data.repository import androidx.room.Room import androidx.test.platform.app.InstrumentationRegistry -import app.marcdev.earworm.database.AppDatabase -import app.marcdev.earworm.database.DAO -import app.marcdev.earworm.database.FavouriteItem +import app.marcdev.earworm.data.database.ProductionAppDatabase +import app.marcdev.earworm.data.database.DAO +import app.marcdev.earworm.data.database.FavouriteItem import app.marcdev.earworm.utils.SONG import kotlinx.coroutines.runBlocking import org.junit.After @@ -14,7 +14,7 @@ import org.junit.Test class FavouriteItemRepositoryTest { - private var database: AppDatabase? = null + private var database: ProductionAppDatabase? = null private var repository: FavouriteItemRepository? = null private var dao: DAO? = null @@ -32,7 +32,7 @@ class FavouriteItemRepositoryTest { @Before fun setUp() { database = - Room.inMemoryDatabaseBuilder(InstrumentationRegistry.getInstrumentation().context, AppDatabase::class.java) + Room.inMemoryDatabaseBuilder(InstrumentationRegistry.getInstrumentation().context, ProductionAppDatabase::class.java) .allowMainThreadQueries().build() dao = database!!.dao() @@ -56,8 +56,8 @@ class FavouriteItemRepositoryTest { val returnedItemsWhenNothingInserted: MutableList = repository!!.getAllItems() Assert.assertEquals(0, returnedItemsWhenNothingInserted.size) - repository!!.insertOrUpdateItem(testItem1) - repository!!.insertOrUpdateItem(testItem2) + repository!!.addItem(testItem1) + repository!!.addItem(testItem2) val returnedItemsWhenOneInserted: MutableList = repository!!.getAllItems() Assert.assertEquals(2, returnedItemsWhenOneInserted.size) @@ -73,7 +73,7 @@ class FavouriteItemRepositoryTest { val returnedItemsWhenNothingInserted: MutableList = repository!!.getItem(testId) Assert.assertEquals(0, returnedItemsWhenNothingInserted.size) - repository!!.insertOrUpdateItem(testItem) + repository!!.addItem(testItem) val returnedItemsWhenOneInserted: MutableList = repository!!.getItem(testId) Assert.assertEquals(1, returnedItemsWhenOneInserted.size) @@ -97,8 +97,8 @@ class FavouriteItemRepositoryTest { val returnedItemsWhenNothingInserted: MutableList = repository!!.getAllItems() Assert.assertEquals(0, returnedItemsWhenNothingInserted.size) - repository!!.insertOrUpdateItem(testItem1) - repository!!.insertOrUpdateItem(testItem2) + repository!!.addItem(testItem1) + repository!!.addItem(testItem2) val returnedItemsWhenTwoInserted: MutableList = repository!!.getAllItems() Assert.assertEquals(2, returnedItemsWhenTwoInserted.size) @@ -125,8 +125,8 @@ class FavouriteItemRepositoryTest { val returnedItemsWhenNothingInserted: MutableList = repository!!.getAllItems() Assert.assertEquals(0, returnedItemsWhenNothingInserted.size) - repository!!.insertOrUpdateItem(testItem1) - repository!!.insertOrUpdateItem(testItem2) + repository!!.addItem(testItem1) + repository!!.addItem(testItem2) val returnedAllItemsWhenTwoInserted: MutableList = repository!!.getAllItems() Assert.assertEquals(2, returnedAllItemsWhenTwoInserted.size) @@ -149,9 +149,9 @@ class FavouriteItemRepositoryTest { val testItem3 = createTestItem() testItem3.imageName = testImage2 - repository!!.insertOrUpdateItem(testItem1) - repository!!.insertOrUpdateItem(testItem2) - repository!!.insertOrUpdateItem(testItem3) + repository!!.addItem(testItem1) + repository!!.addItem(testItem2) + repository!!.addItem(testItem3) val returnedValueWhenSearchedForTestImage1: Int = repository!!.countUsesOfImage(testImage1) Assert.assertEquals(1, returnedValueWhenSearchedForTestImage1) @@ -180,9 +180,9 @@ class FavouriteItemRepositoryTest { testItem3.imageName = testImage2 testItem3.id = testId3 - repository!!.insertOrUpdateItem(testItem1) - repository!!.insertOrUpdateItem(testItem2) - repository!!.insertOrUpdateItem(testItem3) + repository!!.addItem(testItem1) + repository!!.addItem(testItem2) + repository!!.addItem(testItem3) val returnedValueWhenSearchedForTestImage1: Int = repository!!.countUsesOfImage(testImage1) Assert.assertEquals(1, returnedValueWhenSearchedForTestImage1) @@ -219,9 +219,9 @@ class FavouriteItemRepositoryTest { testItem3.imageName = testImage2 testItem3.id = testId3 - repository!!.insertOrUpdateItem(testItem1) - repository!!.insertOrUpdateItem(testItem2) - repository!!.insertOrUpdateItem(testItem3) + repository!!.addItem(testItem1) + repository!!.addItem(testItem2) + repository!!.addItem(testItem3) val returnedValueWhenSearchedForTestImage1: Int = repository!!.countUsesOfImage(testImage1) Assert.assertEquals(1, returnedValueWhenSearchedForTestImage1) diff --git a/app/src/main/java/app/marcdev/earworm/Earworm.kt b/app/src/main/java/app/marcdev/earworm/Earworm.kt index ccbdf72..1037076 100644 --- a/app/src/main/java/app/marcdev/earworm/Earworm.kt +++ b/app/src/main/java/app/marcdev/earworm/Earworm.kt @@ -1,9 +1,30 @@ package app.marcdev.earworm import android.app.Application +import app.marcdev.earworm.data.database.AppDatabase +import app.marcdev.earworm.data.database.DAO +import app.marcdev.earworm.data.database.ProductionAppDatabase +import app.marcdev.earworm.data.repository.FavouriteItemRepository +import app.marcdev.earworm.data.repository.FavouriteItemRepositoryImpl +import org.kodein.di.Kodein +import org.kodein.di.KodeinAware +import org.kodein.di.android.x.androidXModule +import org.kodein.di.generic.bind +import org.kodein.di.generic.instance +import org.kodein.di.generic.singleton import timber.log.Timber -class Earworm : Application() { +class Earworm : Application(), KodeinAware { + override val kodein = Kodein.lazy { + import(androidXModule(this@Earworm)) + + // + bind() with singleton { ProductionAppDatabase.invoke(applicationContext) } + bind() with singleton { instance().dao() } + bind() with singleton { FavouriteItemRepositoryImpl.getInstance(instance()) } + // + + } override fun onCreate() { super.onCreate() diff --git a/app/src/main/java/app/marcdev/earworm/additem/AddItemBottomSheet.kt b/app/src/main/java/app/marcdev/earworm/additem/AddItemBottomSheet.kt index 9252673..a28f308 100644 --- a/app/src/main/java/app/marcdev/earworm/additem/AddItemBottomSheet.kt +++ b/app/src/main/java/app/marcdev/earworm/additem/AddItemBottomSheet.kt @@ -19,7 +19,7 @@ import android.widget.Toast import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import app.marcdev.earworm.R -import app.marcdev.earworm.database.FavouriteItem +import app.marcdev.earworm.data.database.FavouriteItem import app.marcdev.earworm.uicomponents.RoundedBottomDialogFragment import app.marcdev.earworm.utils.* import com.bumptech.glide.Glide diff --git a/app/src/main/java/app/marcdev/earworm/additem/AddItemModel.kt b/app/src/main/java/app/marcdev/earworm/additem/AddItemModel.kt index 28f1c8e..d2bf346 100644 --- a/app/src/main/java/app/marcdev/earworm/additem/AddItemModel.kt +++ b/app/src/main/java/app/marcdev/earworm/additem/AddItemModel.kt @@ -1,6 +1,6 @@ package app.marcdev.earworm.additem -import app.marcdev.earworm.database.FavouriteItem +import app.marcdev.earworm.data.database.FavouriteItem import java.io.File interface AddItemModel { diff --git a/app/src/main/java/app/marcdev/earworm/additem/AddItemModelImpl.kt b/app/src/main/java/app/marcdev/earworm/additem/AddItemModelImpl.kt index 75a5600..d3b4f1f 100644 --- a/app/src/main/java/app/marcdev/earworm/additem/AddItemModelImpl.kt +++ b/app/src/main/java/app/marcdev/earworm/additem/AddItemModelImpl.kt @@ -1,10 +1,10 @@ package app.marcdev.earworm.additem import android.content.Context -import app.marcdev.earworm.database.AppDatabase -import app.marcdev.earworm.database.FavouriteItem -import app.marcdev.earworm.repository.FavouriteItemRepository -import app.marcdev.earworm.repository.FavouriteItemRepositoryImpl +import app.marcdev.earworm.data.database.ProductionAppDatabase +import app.marcdev.earworm.data.database.FavouriteItem +import app.marcdev.earworm.data.repository.FavouriteItemRepository +import app.marcdev.earworm.data.repository.FavouriteItemRepositoryImpl import app.marcdev.earworm.utils.getArtworkDirectory import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope @@ -18,7 +18,7 @@ class AddItemModelImpl(private val presenter: AddItemPresenter, private val cont private var repository: FavouriteItemRepository init { - val db: AppDatabase = AppDatabase.getDatabase(context) + val db: ProductionAppDatabase = ProductionAppDatabase.invoke(context) repository = FavouriteItemRepositoryImpl(db.dao()) } @@ -27,7 +27,7 @@ class AddItemModelImpl(private val presenter: AddItemPresenter, private val cont GlobalScope.launch(Dispatchers.Main) { async(Dispatchers.IO) { - repository.insertOrUpdateItem(item) + repository.addItem(item) }.await() presenter.addItemCallback() diff --git a/app/src/main/java/app/marcdev/earworm/additem/AddItemPresenter.kt b/app/src/main/java/app/marcdev/earworm/additem/AddItemPresenter.kt index 3361d06..688246a 100644 --- a/app/src/main/java/app/marcdev/earworm/additem/AddItemPresenter.kt +++ b/app/src/main/java/app/marcdev/earworm/additem/AddItemPresenter.kt @@ -1,6 +1,6 @@ package app.marcdev.earworm.additem -import app.marcdev.earworm.database.FavouriteItem +import app.marcdev.earworm.data.database.FavouriteItem import java.util.* interface AddItemPresenter { diff --git a/app/src/main/java/app/marcdev/earworm/additem/AddItemPresenterImpl.kt b/app/src/main/java/app/marcdev/earworm/additem/AddItemPresenterImpl.kt index d7ff254..dc6487a 100644 --- a/app/src/main/java/app/marcdev/earworm/additem/AddItemPresenterImpl.kt +++ b/app/src/main/java/app/marcdev/earworm/additem/AddItemPresenterImpl.kt @@ -1,7 +1,7 @@ package app.marcdev.earworm.additem import android.content.Context -import app.marcdev.earworm.database.FavouriteItem +import app.marcdev.earworm.data.database.FavouriteItem import app.marcdev.earworm.utils.ALBUM import app.marcdev.earworm.utils.ARTIST import app.marcdev.earworm.utils.SONG diff --git a/app/src/main/java/app/marcdev/earworm/additem/AddItemView.kt b/app/src/main/java/app/marcdev/earworm/additem/AddItemView.kt index aa06a9d..37d3bed 100644 --- a/app/src/main/java/app/marcdev/earworm/additem/AddItemView.kt +++ b/app/src/main/java/app/marcdev/earworm/additem/AddItemView.kt @@ -1,6 +1,6 @@ package app.marcdev.earworm.additem -import app.marcdev.earworm.database.FavouriteItem +import app.marcdev.earworm.data.database.FavouriteItem interface AddItemView { diff --git a/app/src/main/java/app/marcdev/earworm/data/database/AppDatabase.kt b/app/src/main/java/app/marcdev/earworm/data/database/AppDatabase.kt new file mode 100644 index 0000000..bf21434 --- /dev/null +++ b/app/src/main/java/app/marcdev/earworm/data/database/AppDatabase.kt @@ -0,0 +1,5 @@ +package app.marcdev.earworm.data.database + +interface AppDatabase { + fun dao(): DAO +} \ No newline at end of file diff --git a/app/src/main/java/app/marcdev/earworm/data/database/DAO.kt b/app/src/main/java/app/marcdev/earworm/data/database/DAO.kt new file mode 100644 index 0000000..97db863 --- /dev/null +++ b/app/src/main/java/app/marcdev/earworm/data/database/DAO.kt @@ -0,0 +1,25 @@ +package app.marcdev.earworm.data.database + +import androidx.room.* + +@Dao +interface DAO { + + @Insert(onConflict = OnConflictStrategy.FAIL) + fun insertItem(item: FavouriteItem) + + @Update + fun updateItem(item: FavouriteItem) + + @Query("SELECT * FROM FavouriteItems") + fun getAllItems(): MutableList + + @Query("SELECT * FROM FavouriteItems where id = :id") + fun getItemById(id: Int): MutableList + + @Query("DELETE FROM FavouriteItems where id = :id") + fun deleteItemById(id: Int) + + @Query("SELECT COUNT(*) FROM FavouriteItems WHERE imageName = :imageName") + fun getNumberOfEntriesUsingImage(imageName: String): Int +} \ No newline at end of file diff --git a/app/src/main/java/app/marcdev/earworm/database/FavouriteItem.kt b/app/src/main/java/app/marcdev/earworm/data/database/FavouriteItem.kt similarity index 76% rename from app/src/main/java/app/marcdev/earworm/database/FavouriteItem.kt rename to app/src/main/java/app/marcdev/earworm/data/database/FavouriteItem.kt index 45fb289..cecacb4 100644 --- a/app/src/main/java/app/marcdev/earworm/database/FavouriteItem.kt +++ b/app/src/main/java/app/marcdev/earworm/data/database/FavouriteItem.kt @@ -1,9 +1,9 @@ -package app.marcdev.earworm.database +package app.marcdev.earworm.data.database import androidx.room.Entity import androidx.room.PrimaryKey -@Entity(tableName = "favourite_items") +@Entity(tableName = "FavouriteItems") data class FavouriteItem( var songName: String, var albumName: String, @@ -17,5 +17,5 @@ data class FavouriteItem( ) { @PrimaryKey(autoGenerate = true) - var id: Int? = null + var id: Int = 0 } \ No newline at end of file diff --git a/app/src/main/java/app/marcdev/earworm/data/database/ProductionAppDatabase.kt b/app/src/main/java/app/marcdev/earworm/data/database/ProductionAppDatabase.kt new file mode 100644 index 0000000..737dc4d --- /dev/null +++ b/app/src/main/java/app/marcdev/earworm/data/database/ProductionAppDatabase.kt @@ -0,0 +1,54 @@ +package app.marcdev.earworm.data.database + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase +import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase + +@Database(entities = [FavouriteItem::class], version = 5) +abstract class ProductionAppDatabase : RoomDatabase(), AppDatabase { + abstract override fun dao(): DAO + + companion object { + @Volatile + private var INSTANCE: ProductionAppDatabase? = null + private val LOCK = Any() + + operator fun invoke(context: Context) = INSTANCE + ?: synchronized(LOCK) { + INSTANCE + ?: buildDatabase(context).also { INSTANCE = it } + } + + private fun buildDatabase(context: Context) = + Room.databaseBuilder( + context.applicationContext, + ProductionAppDatabase::class.java, + "ProductionAppDatabase.db" + ) + .setJournalMode(JournalMode.TRUNCATE) + .addMigrations(MIGRATION_4_TO_5()) + .build() + } + + class MIGRATION_4_TO_5 : Migration(4, 5) { + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("ALTER TABLE favourite_items RENAME TO favourite_items_old") + database.execSQL("CREATE TABLE FavouriteItems(" + + "id INTEGER PRIMARY KEY NOT NULL," + + "songName TEXT NOT NULL," + + "albumName TEXT NOT NULL," + + "artistName TEXT NOT NULL," + + "genre TEXT NOT NULL," + + "day INTEGER NOT NULL," + + "month INTEGER NOT NULL," + + "year INTEGER NOT NULL," + + "type INTEGER NOT NULL," + + "imageName TEXT NOT NULL)") + database.execSQL("INSERT INTO FavouriteItems SELECT * FROM favourite_items_old") + database.execSQL("DROP TABLE favourite_items_old") + } + } +} \ No newline at end of file diff --git a/app/src/main/java/app/marcdev/earworm/repository/FavouriteItemRepository.kt b/app/src/main/java/app/marcdev/earworm/data/repository/FavouriteItemRepository.kt similarity index 63% rename from app/src/main/java/app/marcdev/earworm/repository/FavouriteItemRepository.kt rename to app/src/main/java/app/marcdev/earworm/data/repository/FavouriteItemRepository.kt index 1b9cebe..543cabd 100644 --- a/app/src/main/java/app/marcdev/earworm/repository/FavouriteItemRepository.kt +++ b/app/src/main/java/app/marcdev/earworm/data/repository/FavouriteItemRepository.kt @@ -1,10 +1,10 @@ -package app.marcdev.earworm.repository +package app.marcdev.earworm.data.repository -import app.marcdev.earworm.database.FavouriteItem +import app.marcdev.earworm.data.database.FavouriteItem interface FavouriteItemRepository { - suspend fun insertOrUpdateItem(item: FavouriteItem) + suspend fun addItem(item: FavouriteItem) suspend fun getAllItems(): MutableList diff --git a/app/src/main/java/app/marcdev/earworm/data/repository/FavouriteItemRepositoryImpl.kt b/app/src/main/java/app/marcdev/earworm/data/repository/FavouriteItemRepositoryImpl.kt new file mode 100644 index 0000000..ad0d9f7 --- /dev/null +++ b/app/src/main/java/app/marcdev/earworm/data/repository/FavouriteItemRepositoryImpl.kt @@ -0,0 +1,56 @@ +package app.marcdev.earworm.data.repository + +import android.database.sqlite.SQLiteConstraintException +import app.marcdev.earworm.data.database.DAO +import app.marcdev.earworm.data.database.FavouriteItem +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import timber.log.Timber + +class FavouriteItemRepositoryImpl(private val dao: DAO) : FavouriteItemRepository { + + override suspend fun addItem(item: FavouriteItem) { + withContext(Dispatchers.IO) { + try { + Timber.d("Log: addItem: Item doesn't exist, adding new") + dao.insertItem(item) + } catch(exception: SQLiteConstraintException) { + Timber.d("Log: addItem: Item already exists, updating existing") + dao.updateItem(item) + } + } + } + + override suspend fun getAllItems(): MutableList { + return withContext(Dispatchers.IO) { + return@withContext dao.getAllItems() + } + } + + override suspend fun getItem(id: Int): MutableList { + return withContext(Dispatchers.IO) { + return@withContext dao.getItemById(id) + } + } + + override suspend fun deleteItem(id: Int) { + withContext(Dispatchers.IO) { + dao.deleteItemById(id) + } + } + + override suspend fun countUsesOfImage(imageName: String): Int { + return withContext(Dispatchers.IO) { + return@withContext dao.getNumberOfEntriesUsingImage(imageName) + } + } + + companion object { + @Volatile private var instance: FavouriteItemRepositoryImpl? = null + + fun getInstance(dao: DAO) = + instance ?: synchronized(this) { + instance ?: FavouriteItemRepositoryImpl(dao).also { instance = it } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/app/marcdev/earworm/database/AppDatabase.kt b/app/src/main/java/app/marcdev/earworm/database/AppDatabase.kt deleted file mode 100644 index 3cb8774..0000000 --- a/app/src/main/java/app/marcdev/earworm/database/AppDatabase.kt +++ /dev/null @@ -1,34 +0,0 @@ -package app.marcdev.earworm.database - -import android.content.Context -import androidx.room.Database -import androidx.room.Room -import androidx.room.RoomDatabase - -@Database(entities = [FavouriteItem::class], version = 4) -abstract class AppDatabase : RoomDatabase() { - - abstract fun dao(): DAO - - companion object { - @Volatile - private var INSTANCE: AppDatabase? = null - - fun getDatabase(context: Context): AppDatabase { - val tempInstance = INSTANCE - - if(tempInstance != null) { - return tempInstance - } - - synchronized(this) { - - val instance = Room.databaseBuilder(context.applicationContext, AppDatabase::class.java, "AppDatabase.db") - .fallbackToDestructiveMigration().build() - - INSTANCE = instance - return instance - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/app/marcdev/earworm/database/DAO.kt b/app/src/main/java/app/marcdev/earworm/database/DAO.kt deleted file mode 100644 index b799ce7..0000000 --- a/app/src/main/java/app/marcdev/earworm/database/DAO.kt +++ /dev/null @@ -1,25 +0,0 @@ -package app.marcdev.earworm.database - -import androidx.room.Dao -import androidx.room.Insert -import androidx.room.OnConflictStrategy -import androidx.room.Query - -@Dao -interface DAO { - - @Insert(onConflict = OnConflictStrategy.REPLACE) - fun insertOrUpdateItem(item: FavouriteItem) - - @Query("SELECT * FROM favourite_items") - fun getAllItems(): MutableList - - @Query("SELECT * FROM favourite_items where id = :id") - fun getItemById(id: Int): MutableList - - @Query("DELETE FROM favourite_items where id = :id") - fun deleteItemById(id: Int) - - @Query("SELECT COUNT(*) FROM favourite_items WHERE imageName = :imageName") - fun getNumberOfEntriesUsingImage(imageName: String): Int -} \ No newline at end of file diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentModel.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentModel.kt index b6ac979..6bb6b5f 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentModel.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentModel.kt @@ -1,6 +1,6 @@ package app.marcdev.earworm.mainscreen -import app.marcdev.earworm.database.FavouriteItem +import app.marcdev.earworm.data.database.FavouriteItem import app.marcdev.earworm.utils.ItemFilter interface MainFragmentModel { diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentModelImpl.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentModelImpl.kt index 27eccdd..e269e21 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentModelImpl.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentModelImpl.kt @@ -1,10 +1,10 @@ package app.marcdev.earworm.mainscreen import android.content.Context -import app.marcdev.earworm.database.AppDatabase -import app.marcdev.earworm.database.FavouriteItem -import app.marcdev.earworm.repository.FavouriteItemRepository -import app.marcdev.earworm.repository.FavouriteItemRepositoryImpl +import app.marcdev.earworm.data.database.ProductionAppDatabase +import app.marcdev.earworm.data.database.FavouriteItem +import app.marcdev.earworm.data.repository.FavouriteItemRepository +import app.marcdev.earworm.data.repository.FavouriteItemRepositoryImpl import app.marcdev.earworm.utils.ItemFilter import app.marcdev.earworm.utils.getArtworkDirectory import kotlinx.coroutines.Dispatchers @@ -19,7 +19,7 @@ class MainFragmentModelImpl(private val presenter: MainFragmentPresenter, privat private var repository: FavouriteItemRepository init { - val db: AppDatabase = AppDatabase.getDatabase(context) + val db: ProductionAppDatabase = ProductionAppDatabase.invoke(context) repository = FavouriteItemRepositoryImpl(db.dao()) } @@ -52,7 +52,7 @@ class MainFragmentModelImpl(private val presenter: MainFragmentPresenter, privat GlobalScope.launch(Dispatchers.Main) { async(Dispatchers.IO) { - repository.deleteItem(item.id!!) + repository.deleteItem(item.id) }.await() presenter.deleteItemCallback() diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentPresenter.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentPresenter.kt index 8aae525..ec7789a 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentPresenter.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentPresenter.kt @@ -1,6 +1,6 @@ package app.marcdev.earworm.mainscreen -import app.marcdev.earworm.database.FavouriteItem +import app.marcdev.earworm.data.database.FavouriteItem import app.marcdev.earworm.utils.ItemFilter interface MainFragmentPresenter { diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentPresenterImpl.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentPresenterImpl.kt index b8cd93c..220ff48 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentPresenterImpl.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentPresenterImpl.kt @@ -1,7 +1,7 @@ package app.marcdev.earworm.mainscreen import android.content.Context -import app.marcdev.earworm.database.FavouriteItem +import app.marcdev.earworm.data.database.FavouriteItem import app.marcdev.earworm.utils.* import timber.log.Timber diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentView.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentView.kt index 86660e2..fcbaff9 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentView.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentView.kt @@ -1,6 +1,6 @@ package app.marcdev.earworm.mainscreen -import app.marcdev.earworm.database.FavouriteItem +import app.marcdev.earworm.data.database.FavouriteItem import app.marcdev.earworm.utils.ItemFilter interface MainFragmentView { diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewImpl.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewImpl.kt index 71ec9c4..ec85d3f 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewImpl.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewImpl.kt @@ -16,7 +16,7 @@ import androidx.recyclerview.widget.RecyclerView import app.marcdev.earworm.R import app.marcdev.earworm.additem.AddItemBottomSheet import app.marcdev.earworm.additem.RecyclerUpdateView -import app.marcdev.earworm.database.FavouriteItem +import app.marcdev.earworm.data.database.FavouriteItem import app.marcdev.earworm.mainscreen.mainrecycler.MainRecyclerAdapter import app.marcdev.earworm.settingsscreen.SettingsActivity import app.marcdev.earworm.uicomponents.FilterDialog @@ -104,7 +104,7 @@ class MainFragmentViewImpl : Fragment(), MainFragmentView, RecyclerUpdateView { Timber.d("Log: Fab Clicked") val addDialog = AddItemBottomSheet() addDialog.bindRecyclerUpdateView(this) - addDialog.show(fragmentManager, "Add Item Bottom Sheet Dialog") + addDialog.show(requireFragmentManager(), "Add Item Bottom Sheet Dialog") } private val settingsOnClickListener = View.OnClickListener { @@ -226,7 +226,7 @@ class MainFragmentViewImpl : Fragment(), MainFragmentView, RecyclerUpdateView { args.putInt("item_id", itemId) addDialog.arguments = args - addDialog.show(fragmentManager, "Add Item Bottom Sheet Dialog") + addDialog.show(requireFragmentManager(), "Add Item Bottom Sheet Dialog") } override fun displayNoFilteredResultsWarning(display: Boolean) { diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerAdapter.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerAdapter.kt index 7c6bce7..5c3d4a7 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerAdapter.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerAdapter.kt @@ -5,7 +5,7 @@ import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import app.marcdev.earworm.R -import app.marcdev.earworm.database.FavouriteItem +import app.marcdev.earworm.data.database.FavouriteItem import app.marcdev.earworm.mainscreen.MainFragmentPresenter import app.marcdev.earworm.utils.* import timber.log.Timber diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerView.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerView.kt index 27a2735..163e44a 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerView.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerView.kt @@ -1,6 +1,6 @@ package app.marcdev.earworm.mainscreen.mainrecycler -import app.marcdev.earworm.database.FavouriteItem +import app.marcdev.earworm.data.database.FavouriteItem interface MainRecyclerView { fun updateItems(items: List) diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolder.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolder.kt index ae2a229..6187265 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolder.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolder.kt @@ -7,7 +7,7 @@ import android.preference.PreferenceManager import android.view.View import androidx.recyclerview.widget.RecyclerView import app.marcdev.earworm.R -import app.marcdev.earworm.database.FavouriteItem +import app.marcdev.earworm.data.database.FavouriteItem import app.marcdev.earworm.mainscreen.MainFragmentPresenter import com.google.android.material.button.MaterialButton import com.google.android.material.snackbar.Snackbar @@ -41,7 +41,7 @@ open class MainRecyclerViewHolder(itemView: View) : RecyclerView.ViewHolder(item private val editOnClickListener = View.OnClickListener { Timber.d("Log: editOnClickListener: Clicked") editDialog.dismiss() - presenter.editItemClick(displayedItem.id!!) + presenter.editItemClick(displayedItem.id) } private val deleteOnClickListener = View.OnClickListener { diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderAlbum.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderAlbum.kt index b883c48..fb499ce 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderAlbum.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderAlbum.kt @@ -4,7 +4,7 @@ import android.view.View import android.widget.ImageView import android.widget.TextView import app.marcdev.earworm.R -import app.marcdev.earworm.database.FavouriteItem +import app.marcdev.earworm.data.database.FavouriteItem import app.marcdev.earworm.utils.formatDateForDisplay import app.marcdev.earworm.utils.getArtworkDirectory import com.bumptech.glide.Glide diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderArtist.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderArtist.kt index d733aee..e5c4d56 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderArtist.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderArtist.kt @@ -4,7 +4,7 @@ import android.view.View import android.widget.ImageView import android.widget.TextView import app.marcdev.earworm.R -import app.marcdev.earworm.database.FavouriteItem +import app.marcdev.earworm.data.database.FavouriteItem import app.marcdev.earworm.utils.formatDateForDisplay import app.marcdev.earworm.utils.getArtworkDirectory import com.bumptech.glide.Glide diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderGenre.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderGenre.kt index b51afc8..c25c1d6 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderGenre.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderGenre.kt @@ -3,7 +3,7 @@ package app.marcdev.earworm.mainscreen.mainrecycler import android.view.View import android.widget.TextView import app.marcdev.earworm.R -import app.marcdev.earworm.database.FavouriteItem +import app.marcdev.earworm.data.database.FavouriteItem import app.marcdev.earworm.utils.formatDateForDisplay import timber.log.Timber diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderHeader.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderHeader.kt index 19420dc..e71a0c1 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderHeader.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderHeader.kt @@ -3,7 +3,7 @@ package app.marcdev.earworm.mainscreen.mainrecycler import android.view.View import android.widget.TextView import app.marcdev.earworm.R -import app.marcdev.earworm.database.FavouriteItem +import app.marcdev.earworm.data.database.FavouriteItem import app.marcdev.earworm.utils.getMonthName import timber.log.Timber diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderSong.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderSong.kt index 0611378..58987c9 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderSong.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderSong.kt @@ -4,7 +4,7 @@ import android.view.View import android.widget.ImageView import android.widget.TextView import app.marcdev.earworm.R -import app.marcdev.earworm.database.FavouriteItem +import app.marcdev.earworm.data.database.FavouriteItem import app.marcdev.earworm.utils.formatDateForDisplay import app.marcdev.earworm.utils.getArtworkDirectory import com.bumptech.glide.Glide diff --git a/app/src/main/java/app/marcdev/earworm/repository/FavouriteItemRepositoryImpl.kt b/app/src/main/java/app/marcdev/earworm/repository/FavouriteItemRepositoryImpl.kt deleted file mode 100644 index 80407c4..0000000 --- a/app/src/main/java/app/marcdev/earworm/repository/FavouriteItemRepositoryImpl.kt +++ /dev/null @@ -1,27 +0,0 @@ -package app.marcdev.earworm.repository - -import app.marcdev.earworm.database.DAO -import app.marcdev.earworm.database.FavouriteItem - -class FavouriteItemRepositoryImpl(private val dao: DAO) : FavouriteItemRepository { - - override suspend fun insertOrUpdateItem(item: FavouriteItem) { - return dao.insertOrUpdateItem(item) - } - - override suspend fun getAllItems(): MutableList { - return dao.getAllItems() - } - - override suspend fun getItem(id: Int): MutableList { - return dao.getItemById(id) - } - - override suspend fun deleteItem(id: Int) { - return dao.deleteItemById(id) - } - - override suspend fun countUsesOfImage(imageName: String): Int { - return dao.getNumberOfEntriesUsingImage(imageName) - } -} \ No newline at end of file diff --git a/app/src/main/java/app/marcdev/earworm/utils/ListUtils.kt b/app/src/main/java/app/marcdev/earworm/utils/ListUtils.kt index 563e2d4..1ffafd6 100644 --- a/app/src/main/java/app/marcdev/earworm/utils/ListUtils.kt +++ b/app/src/main/java/app/marcdev/earworm/utils/ListUtils.kt @@ -1,6 +1,6 @@ package app.marcdev.earworm.utils -import app.marcdev.earworm.database.FavouriteItem +import app.marcdev.earworm.data.database.FavouriteItem import timber.log.Timber /** @@ -96,7 +96,7 @@ fun sortByDateDescending(items: MutableList): MutableList Date: Fri, 31 May 2019 20:39:10 +0100 Subject: [PATCH 07/18] Display all entries on Main Fragment --- .../main/java/app/marcdev/earworm/Earworm.kt | 5 + .../earworm/additem/AddItemBottomSheet.kt | 2 +- .../earworm/additem/RecyclerUpdateView.kt | 2 +- .../app/marcdev/earworm/data/database/DAO.kt | 3 +- .../repository/FavouriteItemRepository.kt | 5 +- .../repository/FavouriteItemRepositoryImpl.kt | 10 +- .../mainscreen/MainFragmentModelImpl.kt | 8 +- .../mainscreen/MainFragmentPresenterImpl.kt | 219 +++++++++--------- .../earworm/mainscreen/MainFragmentView.kt | 38 +-- .../mainscreen/MainFragmentViewImpl.kt | 140 +++++------ .../mainscreen/MainFragmentViewModel.kt | 45 ++++ .../MainFragmentViewModelFactory.kt | 14 ++ .../mainrecycler/MainRecyclerAdapter.kt | 3 +- .../mainrecycler/MainRecyclerViewHolder.kt | 10 +- 14 files changed, 287 insertions(+), 217 deletions(-) create mode 100644 app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewModel.kt create mode 100644 app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewModelFactory.kt diff --git a/app/src/main/java/app/marcdev/earworm/Earworm.kt b/app/src/main/java/app/marcdev/earworm/Earworm.kt index 1037076..799b5e8 100644 --- a/app/src/main/java/app/marcdev/earworm/Earworm.kt +++ b/app/src/main/java/app/marcdev/earworm/Earworm.kt @@ -6,11 +6,13 @@ import app.marcdev.earworm.data.database.DAO import app.marcdev.earworm.data.database.ProductionAppDatabase import app.marcdev.earworm.data.repository.FavouriteItemRepository import app.marcdev.earworm.data.repository.FavouriteItemRepositoryImpl +import app.marcdev.earworm.mainscreen.MainFragmentViewModelFactory import org.kodein.di.Kodein import org.kodein.di.KodeinAware import org.kodein.di.android.x.androidXModule import org.kodein.di.generic.bind import org.kodein.di.generic.instance +import org.kodein.di.generic.provider import org.kodein.di.generic.singleton import timber.log.Timber @@ -24,6 +26,9 @@ class Earworm : Application(), KodeinAware { bind() with singleton { FavouriteItemRepositoryImpl.getInstance(instance()) } // + // + bind() from provider { MainFragmentViewModelFactory(instance()) } + // } override fun onCreate() { diff --git a/app/src/main/java/app/marcdev/earworm/additem/AddItemBottomSheet.kt b/app/src/main/java/app/marcdev/earworm/additem/AddItemBottomSheet.kt index a28f308..53af662 100644 --- a/app/src/main/java/app/marcdev/earworm/additem/AddItemBottomSheet.kt +++ b/app/src/main/java/app/marcdev/earworm/additem/AddItemBottomSheet.kt @@ -350,7 +350,7 @@ class AddItemBottomSheet : RoundedBottomDialogFragment(), AddItemView { if(recyclerUpdateView == null) { Timber.e("Log: saveCallback: RecyclerUpdateView is null, cannot update recycler") } else { - recyclerUpdateView!!.fillData() +// recyclerUpdateView!!.fillData() } Toast.makeText(activity, resources.getString(R.string.item_added), Toast.LENGTH_SHORT).show() dismiss() diff --git a/app/src/main/java/app/marcdev/earworm/additem/RecyclerUpdateView.kt b/app/src/main/java/app/marcdev/earworm/additem/RecyclerUpdateView.kt index 55045bc..07bfb70 100644 --- a/app/src/main/java/app/marcdev/earworm/additem/RecyclerUpdateView.kt +++ b/app/src/main/java/app/marcdev/earworm/additem/RecyclerUpdateView.kt @@ -1,5 +1,5 @@ package app.marcdev.earworm.additem interface RecyclerUpdateView { - fun fillData() +// fun fillData() } \ No newline at end of file diff --git a/app/src/main/java/app/marcdev/earworm/data/database/DAO.kt b/app/src/main/java/app/marcdev/earworm/data/database/DAO.kt index 97db863..cc9fbf3 100644 --- a/app/src/main/java/app/marcdev/earworm/data/database/DAO.kt +++ b/app/src/main/java/app/marcdev/earworm/data/database/DAO.kt @@ -1,5 +1,6 @@ package app.marcdev.earworm.data.database +import androidx.lifecycle.LiveData import androidx.room.* @Dao @@ -12,7 +13,7 @@ interface DAO { fun updateItem(item: FavouriteItem) @Query("SELECT * FROM FavouriteItems") - fun getAllItems(): MutableList + fun getAllItems(): LiveData> @Query("SELECT * FROM FavouriteItems where id = :id") fun getItemById(id: Int): MutableList diff --git a/app/src/main/java/app/marcdev/earworm/data/repository/FavouriteItemRepository.kt b/app/src/main/java/app/marcdev/earworm/data/repository/FavouriteItemRepository.kt index 543cabd..cb0e0aa 100644 --- a/app/src/main/java/app/marcdev/earworm/data/repository/FavouriteItemRepository.kt +++ b/app/src/main/java/app/marcdev/earworm/data/repository/FavouriteItemRepository.kt @@ -1,12 +1,13 @@ package app.marcdev.earworm.data.repository +import androidx.lifecycle.LiveData import app.marcdev.earworm.data.database.FavouriteItem interface FavouriteItemRepository { - suspend fun addItem(item: FavouriteItem) + val allItems: LiveData> - suspend fun getAllItems(): MutableList + suspend fun addItem(item: FavouriteItem) suspend fun getItem(id: Int): MutableList diff --git a/app/src/main/java/app/marcdev/earworm/data/repository/FavouriteItemRepositoryImpl.kt b/app/src/main/java/app/marcdev/earworm/data/repository/FavouriteItemRepositoryImpl.kt index ad0d9f7..f77fdf7 100644 --- a/app/src/main/java/app/marcdev/earworm/data/repository/FavouriteItemRepositoryImpl.kt +++ b/app/src/main/java/app/marcdev/earworm/data/repository/FavouriteItemRepositoryImpl.kt @@ -1,6 +1,7 @@ package app.marcdev.earworm.data.repository import android.database.sqlite.SQLiteConstraintException +import androidx.lifecycle.LiveData import app.marcdev.earworm.data.database.DAO import app.marcdev.earworm.data.database.FavouriteItem import kotlinx.coroutines.Dispatchers @@ -9,6 +10,10 @@ import timber.log.Timber class FavouriteItemRepositoryImpl(private val dao: DAO) : FavouriteItemRepository { + override val allItems: LiveData> by lazy { + dao.getAllItems() + } + override suspend fun addItem(item: FavouriteItem) { withContext(Dispatchers.IO) { try { @@ -21,11 +26,6 @@ class FavouriteItemRepositoryImpl(private val dao: DAO) : FavouriteItemRepositor } } - override suspend fun getAllItems(): MutableList { - return withContext(Dispatchers.IO) { - return@withContext dao.getAllItems() - } - } override suspend fun getItem(id: Int): MutableList { return withContext(Dispatchers.IO) { diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentModelImpl.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentModelImpl.kt index e269e21..1e2ead0 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentModelImpl.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentModelImpl.kt @@ -28,10 +28,10 @@ class MainFragmentModelImpl(private val presenter: MainFragmentPresenter, privat GlobalScope.launch(Dispatchers.Main) { val allItems = async(Dispatchers.IO) { - repository.getAllItems() +// repository.getAllItems() }.await() - presenter.getAllItemsCallback(allItems) +// presenter.getAllItemsCallback(allItems) } } @@ -40,10 +40,10 @@ class MainFragmentModelImpl(private val presenter: MainFragmentPresenter, privat GlobalScope.launch(Dispatchers.Main) { val allItems = async(Dispatchers.IO) { - repository.getAllItems() +// repository.getAllItems() }.await() - presenter.getAllItemsCallback(allItems, filter) +// presenter.getAllItemsCallback(allItems, filter) } } diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentPresenterImpl.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentPresenterImpl.kt index 220ff48..7864f11 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentPresenterImpl.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentPresenterImpl.kt @@ -1,109 +1,110 @@ -package app.marcdev.earworm.mainscreen - -import android.content.Context -import app.marcdev.earworm.data.database.FavouriteItem -import app.marcdev.earworm.utils.* -import timber.log.Timber - -class MainFragmentPresenterImpl(val view: MainFragmentView, val context: Context) : MainFragmentPresenter { - private var model = MainFragmentModelImpl(this, context) - - override fun getAllItems() { - Timber.d("Log: getAllItems: Started") - model.getAllItemsAsync() - } - - override fun getAllItems(filter: ItemFilter) { - Timber.d("Log: getAllItems with Filter: Started") - Timber.i("Log: getAllItems: Input Filter = $filter") - if(filter != DEFAULT_FILTER.copy()) { - view.activateFilterIcon(true) - } else { - view.activateFilterIcon(false) - } - model.getAllItemsAsync(filter) - } - - override fun getAllItemsCallback(items: MutableList) { - Timber.d("Log: getAllItemsCallback: Started") - - val sortedItems = sortByDateDescending(items) - val itemsWithHeaders = addListHeaders(sortedItems) - - view.updateRecycler(itemsWithHeaders) - view.displayProgress(false) - - if(itemsWithHeaders.isEmpty()) { - view.displayNoEntriesWarning(true) - } else { - view.displayNoEntriesWarning(false) - } - } - - override fun getAllItemsCallback(items: MutableList, filter: ItemFilter) { - Timber.d("Log: getAllItemsCallback: Started with filter = $filter") - - val sortedItems = applyFilter(items, filter) - val itemsWithHeaders = addListHeaders(sortedItems) - - view.updateRecycler(itemsWithHeaders) - view.displayProgress(false) - - if(itemsWithHeaders.isEmpty()) { - view.displayNoFilteredResultsWarning(true) - } else { - view.displayNoFilteredResultsWarning(false) - } - } - - override fun deleteItem(item: FavouriteItem) { - Timber.d("Log: deleteItem: Started") - if(item.imageName != "") { - Timber.d("Log: deleteItem: Item has an image, checking if used elsewhere") - model.countUsesOfImage(item) - } else { - Timber.d("Log: deleteItem: Item does not have an image, deleting item") - model.deleteItemAsync(item) - } - } - - override fun deleteItemCallback() { - Timber.d("Log: deleteItemCallback: Started") - if(view.getActiveFilter() != DEFAULT_FILTER.copy()) { - getAllItems(view.getActiveFilter()) - } else { - getAllItems() - } - } - - override fun countUsesOfImageCallback(item: FavouriteItem, uses: Int) { - Timber.d("Log: countUsesOfImageCallback: Started with imageName = ${item.imageName} and uses = $uses") - - if(uses <= 1) { - val filePath = getArtworkDirectory(context) + item.imageName - model.deleteImage(filePath) - } - - model.deleteItemAsync(item) - } - - override fun editItemClick(itemId: Int) { - Timber.d("Log: editItemClick: Started") - view.displayEditItemSheet(itemId) - } - - override fun search(input: String) { - Timber.d("Log: search: Started with input = $input") - if(input.isBlank()) { - val inputFilter = view.getActiveFilter() - inputFilter.searchTerm = "" - model.getAllItemsAsync(inputFilter) - view.changeSearchIcon(true) - } else { - val inputFilter = view.getActiveFilter() - inputFilter.searchTerm = input.trim() - model.getAllItemsAsync(inputFilter) - view.changeSearchIcon(false) - } - } -} \ No newline at end of file +//package app.marcdev.earworm.mainscreen +// +//import android.content.Context +//import app.marcdev.earworm.data.database.FavouriteItem +//import app.marcdev.earworm.utils.* +//import timber.log.Timber +// +//class MainFragmentPresenterImpl(val view: MainFragmentView, val context: Context) : MainFragmentPresenter { +// private var model = MainFragmentModelImpl(this, context) +// +// override fun getAllItems() { +// Timber.d("Log: getAllItems: Started") +// model.getAllItemsAsync() +// } +// +// override fun getAllItems(filter: ItemFilter) { +// Timber.d("Log: getAllItems with Filter: Started") +// Timber.i("Log: getAllItems: Input Filter = $filter") +// if(filter != DEFAULT_FILTER.copy()) { +// view.activateFilterIcon(true) +// } else { +// view.activateFilterIcon(false) +// } +// model.getAllItemsAsync(filter) +// // TODO +// } +// +// override fun getAllItemsCallback(items: MutableList) { +// Timber.d("Log: getAllItemsCallback: Started") +// +//// val sortedItems = sortByDateDescending(items) +//// val itemsWithHeaders = addListHeaders(sortedItems) +//// +//// view.updateRecycler(itemsWithHeaders) +//// view.displayProgress(false) +//// +//// if(itemsWithHeaders.isEmpty()) { +//// view.displayNoEntriesWarning(true) +//// } else { +//// view.displayNoEntriesWarning(false) +//// } +// } +// +// override fun getAllItemsCallback(items: MutableList, filter: ItemFilter) { +// Timber.d("Log: getAllItemsCallback: Started with filter = $filter") +// +// val sortedItems = applyFilter(items, filter) +// val itemsWithHeaders = addListHeaders(sortedItems) +// +// view.updateRecycler(itemsWithHeaders) +// view.displayProgress(false) +// +// if(itemsWithHeaders.isEmpty()) { +// view.displayNoFilteredResultsWarning(true) +// } else { +// view.displayNoFilteredResultsWarning(false) +// } +// } +// +// override fun deleteItem(item: FavouriteItem) { +// Timber.d("Log: deleteItem: Started") +// if(item.imageName != "") { +// Timber.d("Log: deleteItem: Item has an image, checking if used elsewhere") +// model.countUsesOfImage(item) +// } else { +// Timber.d("Log: deleteItem: Item does not have an image, deleting item") +// model.deleteItemAsync(item) +// } +// } +// +// override fun deleteItemCallback() { +// Timber.d("Log: deleteItemCallback: Started") +// if(view.getActiveFilter() != DEFAULT_FILTER.copy()) { +// getAllItems(view.getActiveFilter()) +// } else { +// getAllItems() +// } +// } +// +// override fun countUsesOfImageCallback(item: FavouriteItem, uses: Int) { +// Timber.d("Log: countUsesOfImageCallback: Started with imageName = ${item.imageName} and uses = $uses") +// +// if(uses <= 1) { +// val filePath = getArtworkDirectory(context) + item.imageName +// model.deleteImage(filePath) +// } +// +// model.deleteItemAsync(item) +// } +// +// override fun editItemClick(itemId: Int) { +// Timber.d("Log: editItemClick: Started") +// view.displayEditItemSheet(itemId) +// } +// +// override fun search(input: String) { +// Timber.d("Log: search: Started with input = $input") +// if(input.isBlank()) { +// val inputFilter = view.getActiveFilter() +// inputFilter.searchTerm = "" +// model.getAllItemsAsync(inputFilter) +// view.changeSearchIcon(true) +// } else { +// val inputFilter = view.getActiveFilter() +// inputFilter.searchTerm = input.trim() +// model.getAllItemsAsync(inputFilter) +// view.changeSearchIcon(false) +// } +// } +//} \ No newline at end of file diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentView.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentView.kt index fcbaff9..c45fb53 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentView.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentView.kt @@ -5,23 +5,23 @@ import app.marcdev.earworm.utils.ItemFilter interface MainFragmentView { - fun displayNoEntriesWarning(display: Boolean) - - fun displayNoFilteredResultsWarning(display: Boolean) - - fun displayAddedToast() - - fun displayItemDeletedToast() - - fun updateRecycler(items: List) - - fun displayProgress(isVisible: Boolean) - - fun displayEditItemSheet(itemId: Int) - - fun getActiveFilter(): ItemFilter - - fun changeSearchIcon(isSearch: Boolean) - - fun activateFilterIcon(isActive: Boolean) +// fun displayNoEntriesWarning(display: Boolean) +// +// fun displayNoFilteredResultsWarning(display: Boolean) +// +// fun displayAddedToast() +// +// fun displayItemDeletedToast() +// +// fun updateRecycler(items: List) +// +// fun displayProgress(isVisible: Boolean) +// +// fun displayEditItemSheet(itemId: Int) +// +// fun getActiveFilter(): ItemFilter +// +// fun changeSearchIcon(isSearch: Boolean) +// +// fun activateFilterIcon(isActive: Boolean) } \ No newline at end of file diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewImpl.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewImpl.kt index ec85d3f..8704750 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewImpl.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewImpl.kt @@ -11,6 +11,8 @@ import android.view.ViewGroup import android.widget.* import androidx.core.widget.NestedScrollView import androidx.fragment.app.Fragment +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProviders import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import app.marcdev.earworm.R @@ -22,10 +24,20 @@ import app.marcdev.earworm.settingsscreen.SettingsActivity import app.marcdev.earworm.uicomponents.FilterDialog import app.marcdev.earworm.utils.* import com.google.android.material.floatingactionbutton.FloatingActionButton +import org.kodein.di.KodeinAware +import org.kodein.di.android.x.closestKodein +import org.kodein.di.generic.instance import timber.log.Timber -class MainFragmentViewImpl : Fragment(), MainFragmentView, RecyclerUpdateView { +class MainFragmentViewImpl : Fragment(), MainFragmentView, RecyclerUpdateView, KodeinAware { + override val kodein by closestKodein() + // + private val viewModelFactory: MainFragmentViewModelFactory by instance() + private lateinit var viewModel: MainFragmentViewModel + // + + // private lateinit var fab: FloatingActionButton private lateinit var noEntriesWarning: TextView private lateinit var noEntriesWarningImage: ImageView @@ -38,24 +50,28 @@ class MainFragmentViewImpl : Fragment(), MainFragmentView, RecyclerUpdateView { private lateinit var settingsButton: ImageView private lateinit var filterDialog: FilterDialog private lateinit var recyclerAdapter: MainRecyclerAdapter - private lateinit var presenter: MainFragmentPresenter + // + private var isSearchMode = true + override fun onCreate(savedInstanceState: Bundle?) { + Timber.v("Log: onCreate: Started") + super.onCreate(savedInstanceState) + viewModel = ViewModelProviders.of(this, viewModelFactory).get(MainFragmentViewModel::class.java) + } + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { Timber.d("Log: onCreateView: Started") val view = inflater.inflate(R.layout.fragment_mainscreen, container, false) - - presenter = MainFragmentPresenterImpl(this, activity!!.applicationContext) bindViews(view) + setupRecycler(view) + setupObservers() if(getTheme(requireContext()) == DARK_THEME) { Timber.d("Log: onCreateView: Is dark mode, converting") convertToDarkMode() } - setupRecycler(view) - fillData() - // If arguments is not null, see if the app has been opened from an app shortcut arguments?.let { if(arguments!!.getBoolean("add_item", false)) { @@ -94,7 +110,7 @@ class MainFragmentViewImpl : Fragment(), MainFragmentView, RecyclerUpdateView { val nestedScrollView: NestedScrollView = view.findViewById(R.id.scroll_main) nestedScrollView.setOnScrollChangeListener(scrollViewOnScrollChangeListener) - this.filterDialog = FilterDialog(requireActivity(), presenter) +// this.filterDialog = FilterDialog(requireActivity(), presenter) this.settingsButton = view.findViewById(R.id.img_settings) settingsButton.setOnClickListener(settingsOnClickListener) @@ -126,7 +142,7 @@ class MainFragmentViewImpl : Fragment(), MainFragmentView, RecyclerUpdateView { override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { if(s.isNullOrBlank()) { - presenter.search("") +// presenter.search("") } } } @@ -134,7 +150,7 @@ class MainFragmentViewImpl : Fragment(), MainFragmentView, RecyclerUpdateView { private fun testIfSubmitButtonClicked(keyEvent: KeyEvent, keyCode: Int): Boolean { Timber.d("Log: testIfSubmitButtonClicked: Submit button clicked") if((keyEvent.action == KeyEvent.ACTION_DOWN) && keyCode == KeyEvent.KEYCODE_ENTER) { - presenter.search(searchInput.text.toString()) +// presenter.search(searchInput.text.toString()) return true } return false @@ -143,7 +159,7 @@ class MainFragmentViewImpl : Fragment(), MainFragmentView, RecyclerUpdateView { private val searchOnClickListener = View.OnClickListener { Timber.d("Log: Search Clicked") if(isSearchMode) { - presenter.search(searchInput.text.toString()) +// presenter.search(searchInput.text.toString()) } else { searchInput.setText("") } @@ -165,59 +181,70 @@ class MainFragmentViewImpl : Fragment(), MainFragmentView, RecyclerUpdateView { } private fun setupRecycler(view: View) { - Timber.v("Log: setupRecycler: Started") val recycler: RecyclerView = view.findViewById(R.id.recycler_main) - this.recyclerAdapter = MainRecyclerAdapter(context, presenter) + this.recyclerAdapter = MainRecyclerAdapter(requireContext()) recycler.adapter = recyclerAdapter recycler.layoutManager = LinearLayoutManager(context) } - override fun fillData() { - Timber.d("Log: fillData: Started") - displayProgress(true) - displayNoEntriesWarning(false) - presenter.getAllItems() - } + private fun setupObservers() { + viewModel.displayLoading.observe(this, Observer { value -> + value?.let { show -> + progressBar.visibility = if(show) View.VISIBLE else View.GONE + } + }) - override fun displayNoEntriesWarning(display: Boolean) { - Timber.d("Log: displayNoEntriesWarning: Started with display = $display") + viewModel.displayNoEntries.observe(this, Observer { value -> + value?.let { show -> + noEntriesWarning.visibility = if(show) View.VISIBLE else View.GONE + noEntriesWarningImage.visibility = if(show) View.VISIBLE else View.GONE + } + }) - if(display) { - Timber.d("Log: displayNoEntriesWarning: Displaying") - noEntriesWarning.visibility = View.VISIBLE - noEntriesWarningImage.visibility = View.VISIBLE - } else { - Timber.d("Log: displayNoEntriesWarning: Hiding") - noEntriesWarning.visibility = View.GONE - noEntriesWarningImage.visibility = View.GONE - } - } + viewModel.displayNoFilteredResults.observe(this, Observer { value -> + value?.let { show -> + noFilteredResultsWarning.visibility = if(show) View.VISIBLE else View.GONE + noFilteredResultsWarningImage.visibility = if(show) View.VISIBLE else View.GONE + } + }) - override fun updateRecycler(items: List) { - Timber.d("Log: updateRecycler: Started") - recyclerAdapter.updateItems(items) + viewModel.displayData.observe(this, Observer { items -> + items?.let { + recyclerAdapter.updateItems(items) + viewModel.listReceived(items.isEmpty()) + } + }) + + viewModel.colorFilterIcon.observe(this, Observer { value -> + value?.let { colorIt -> + changeColorOfImageViewDrawable(context!!, filterButton, colorIt) + } + }) + + viewModel.displaySearchIcon.observe(this, Observer { value -> + value?.let { show -> + if(show) { + searchButton.setImageDrawable(resources.getDrawable(R.drawable.ic_search_24px, null)) + this.isSearchMode = true + } else { + searchButton.setImageDrawable(resources.getDrawable(R.drawable.ic_close_24px, null)) + this.isSearchMode = false + } + } + }) } - override fun displayAddedToast() { + fun displayAddedToast() { Timber.d("Log: displayAddedToast: Started") Toast.makeText(activity, resources.getString(R.string.item_added), Toast.LENGTH_SHORT).show() } - override fun displayItemDeletedToast() { + fun displayItemDeletedToast() { Timber.d("Log: displayItemDeletedToast: Started") Toast.makeText(activity, resources.getString(R.string.item_deleted), Toast.LENGTH_SHORT).show() } - override fun displayProgress(isVisible: Boolean) { - Timber.d("Log: displayProgress: Started with isVisible = $isVisible") - if(isVisible) { - progressBar.visibility = View.VISIBLE - } else { - progressBar.visibility = View.GONE - } - } - - override fun displayEditItemSheet(itemId: Int) { + fun displayEditItemSheet(itemId: Int) { Timber.d("Log: displayEditItemSheet: Started with itemId = $itemId") val addDialog = AddItemBottomSheet() addDialog.bindRecyclerUpdateView(this) @@ -229,7 +256,7 @@ class MainFragmentViewImpl : Fragment(), MainFragmentView, RecyclerUpdateView { addDialog.show(requireFragmentManager(), "Add Item Bottom Sheet Dialog") } - override fun displayNoFilteredResultsWarning(display: Boolean) { + fun displayNoFilteredResultsWarning(display: Boolean) { Timber.d("Log: displayNoFilteredResultsWarning: Started with display = $display") if(display && (noEntriesWarning.visibility == View.GONE)) { @@ -241,28 +268,11 @@ class MainFragmentViewImpl : Fragment(), MainFragmentView, RecyclerUpdateView { } } - override fun getActiveFilter(): ItemFilter { + fun getActiveFilter(): ItemFilter { Timber.d("Log: getActiveFilter: Started") return filterDialog.activeFilter } - override fun changeSearchIcon(isSearch: Boolean) { - Timber.d("Log: changeSearchIcon: Started") - if(isSearch) { - searchButton.setImageDrawable(resources.getDrawable(R.drawable.ic_search_24px, null)) - this.isSearchMode = true - } else { - searchButton.setImageDrawable(resources.getDrawable(R.drawable.ic_close_24px, null)) - this.isSearchMode = false - } - } - - override fun activateFilterIcon(isActive: Boolean) { - Timber.d("Log: activateFilterIcon: Started with isActive = $isActive") - - changeColorOfImageViewDrawable(context!!, filterButton, isActive) - } - private fun convertToDarkMode() { changeColorOfImageViewDrawable(requireContext(), filterButton, false) changeColorOfImageViewDrawable(requireContext(), settingsButton, false) diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewModel.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewModel.kt new file mode 100644 index 0000000..288a5d8 --- /dev/null +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewModel.kt @@ -0,0 +1,45 @@ +package app.marcdev.earworm.mainscreen + +import androidx.lifecycle.* +import app.marcdev.earworm.data.repository.FavouriteItemRepository +import app.marcdev.earworm.utils.addListHeaders +import app.marcdev.earworm.utils.sortByDateDescending + +class MainFragmentViewModel(private val repository: FavouriteItemRepository) : ViewModel() { + + val displayData = Transformations.map(repository.allItems) { list -> + val sortedItems = sortByDateDescending(list.toMutableList()) + return@map addListHeaders(sortedItems) + } + + private val _displayLoading = MutableLiveData() + val displayLoading: LiveData + get() = _displayLoading + + private val _displayNoEntries = MutableLiveData() + val displayNoEntries: LiveData + get() = _displayNoEntries + + private val _displayNoFilteredResults = MutableLiveData() + val displayNoFilteredResults: LiveData + get() = _displayNoFilteredResults + + private val _colorFilterIcon = MutableLiveData() + val colorFilterIcon: LiveData + get() = _colorFilterIcon + + private val _displaySearchIcon = MutableLiveData() + val displaySearchIcon: LiveData + get() = _displaySearchIcon + + init { + _displayLoading.value = true + _displayNoEntries.value = false + _displayNoFilteredResults.value = false + } + + fun listReceived(isEmpty: Boolean) { + _displayLoading.value = false + _displayNoEntries.value = isEmpty + } +} \ No newline at end of file diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewModelFactory.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewModelFactory.kt new file mode 100644 index 0000000..1b0a989 --- /dev/null +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewModelFactory.kt @@ -0,0 +1,14 @@ +package app.marcdev.earworm.mainscreen + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import app.marcdev.earworm.data.repository.FavouriteItemRepository + +class MainFragmentViewModelFactory(private val favouriteItemRepository: FavouriteItemRepository) + : ViewModelProvider.NewInstanceFactory() { + + @Suppress("UNCHECKED_CAST") + override fun create(modelClass: Class): T { + return MainFragmentViewModel(favouriteItemRepository) as T + } +} \ No newline at end of file diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerAdapter.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerAdapter.kt index 5c3d4a7..4a972ad 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerAdapter.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerAdapter.kt @@ -10,7 +10,7 @@ import app.marcdev.earworm.mainscreen.MainFragmentPresenter import app.marcdev.earworm.utils.* import timber.log.Timber -class MainRecyclerAdapter(context: Context?, private val presenter: MainFragmentPresenter) : RecyclerView.Adapter(), MainRecyclerView { +class MainRecyclerAdapter(context: Context) : RecyclerView.Adapter(), MainRecyclerView { private var items: List = mutableListOf() private var inflater: LayoutInflater = LayoutInflater.from(context) @@ -62,7 +62,6 @@ class MainRecyclerAdapter(context: Context?, private val presenter: MainFragment override fun onBindViewHolder(holder: MainRecyclerViewHolder, position: Int) { Timber.v("Log: onBindViewHolder: $position") holder.display(items[position]) - holder.bindPresenterAndItem(presenter, items[position]) } override fun getItemCount(): Int { diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolder.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolder.kt index 6187265..2916d32 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolder.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolder.kt @@ -16,7 +16,6 @@ import timber.log.Timber open class MainRecyclerViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { private lateinit var displayedItem: FavouriteItem - private lateinit var presenter: MainFragmentPresenter private lateinit var editDialog: Dialog private val prefs = PreferenceManager.getDefaultSharedPreferences(itemView.context) @@ -41,12 +40,12 @@ open class MainRecyclerViewHolder(itemView: View) : RecyclerView.ViewHolder(item private val editOnClickListener = View.OnClickListener { Timber.d("Log: editOnClickListener: Clicked") editDialog.dismiss() - presenter.editItemClick(displayedItem.id) +// presenter.editItemClick(displayedItem.id) } private val deleteOnClickListener = View.OnClickListener { Timber.d("Log: deleteOnClickListener: Clicked") - presenter.deleteItem(displayedItem) +// presenter.deleteItem(displayedItem) editDialog.dismiss() } @@ -60,11 +59,6 @@ open class MainRecyclerViewHolder(itemView: View) : RecyclerView.ViewHolder(item // TO BE OVERRIDDEN } - fun bindPresenterAndItem(presenter: MainFragmentPresenter, item: FavouriteItem) { - this.presenter = presenter - this.displayedItem = item - } - private fun initEditDialog() { this.editDialog = Dialog(itemView.context) editDialog.setContentView(R.layout.dialog_edit_or_delete) From 1b6425f75a9bc000288d5f3bdb9c62420e9c0fd9 Mon Sep 17 00:00:00 2001 From: Marc Date: Sat, 1 Jun 2019 21:47:40 +0100 Subject: [PATCH 08/18] Added edit and delete click functionality + FileUtils --- .../main/java/app/marcdev/earworm/Earworm.kt | 15 ++- .../java/app/marcdev/earworm/MainActivity.kt | 4 +- ...ainFragmentViewImpl.kt => MainFragment.kt} | 18 +-- .../earworm/mainscreen/MainFragmentModel.kt | 17 --- .../mainscreen/MainFragmentModelImpl.kt | 89 -------------- .../mainscreen/MainFragmentPresenter.kt | 25 ---- .../mainscreen/MainFragmentPresenterImpl.kt | 110 ++++++------------ .../earworm/mainscreen/MainFragmentView.kt | 27 ----- .../mainscreen/MainFragmentViewModel.kt | 31 +++-- .../MainFragmentViewModelFactory.kt | 5 +- .../mainrecycler/MainRecyclerAdapter.kt | 28 ++--- .../mainrecycler/MainRecyclerView.kt | 7 -- .../mainrecycler/MainRecyclerViewHolder.kt | 19 +-- .../MainRecyclerViewHolderAlbum.kt | 11 +- .../MainRecyclerViewHolderArtist.kt | 11 +- .../MainRecyclerViewHolderGenre.kt | 7 +- .../MainRecyclerViewHolderHeader.kt | 4 +- .../MainRecyclerViewHolderSong.kt | 10 +- .../earworm/uicomponents/FilterDialog.kt | 5 +- .../app/marcdev/earworm/utils/FileUtils.kt | 5 + .../marcdev/earworm/utils/FileUtilsImpl.kt | 18 +++ 21 files changed, 149 insertions(+), 317 deletions(-) rename app/src/main/java/app/marcdev/earworm/mainscreen/{MainFragmentViewImpl.kt => MainFragment.kt} (95%) delete mode 100644 app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentModel.kt delete mode 100644 app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentModelImpl.kt delete mode 100644 app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentPresenter.kt delete mode 100644 app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentView.kt delete mode 100644 app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerView.kt create mode 100644 app/src/main/java/app/marcdev/earworm/utils/FileUtils.kt create mode 100644 app/src/main/java/app/marcdev/earworm/utils/FileUtilsImpl.kt diff --git a/app/src/main/java/app/marcdev/earworm/Earworm.kt b/app/src/main/java/app/marcdev/earworm/Earworm.kt index 799b5e8..0218be2 100644 --- a/app/src/main/java/app/marcdev/earworm/Earworm.kt +++ b/app/src/main/java/app/marcdev/earworm/Earworm.kt @@ -7,13 +7,12 @@ import app.marcdev.earworm.data.database.ProductionAppDatabase import app.marcdev.earworm.data.repository.FavouriteItemRepository import app.marcdev.earworm.data.repository.FavouriteItemRepositoryImpl import app.marcdev.earworm.mainscreen.MainFragmentViewModelFactory +import app.marcdev.earworm.utils.FileUtilsImpl +import app.marcdev.earworm.utils.FileUtils import org.kodein.di.Kodein import org.kodein.di.KodeinAware import org.kodein.di.android.x.androidXModule -import org.kodein.di.generic.bind -import org.kodein.di.generic.instance -import org.kodein.di.generic.provider -import org.kodein.di.generic.singleton +import org.kodein.di.generic.* import timber.log.Timber class Earworm : Application(), KodeinAware { @@ -26,14 +25,18 @@ class Earworm : Application(), KodeinAware { bind() with singleton { FavouriteItemRepositoryImpl.getInstance(instance()) } // + // + bind() with provider { FileUtilsImpl(instance()) } + // + // - bind() from provider { MainFragmentViewModelFactory(instance()) } + bind() from provider { MainFragmentViewModelFactory(instance(), instance()) } // } override fun onCreate() { super.onCreate() - if (BuildConfig.DEBUG) { + if(BuildConfig.DEBUG) { Timber.plant(Timber.DebugTree()) Timber.i("Log: Timber Debug Tree planted") } diff --git a/app/src/main/java/app/marcdev/earworm/MainActivity.kt b/app/src/main/java/app/marcdev/earworm/MainActivity.kt index 4a56954..6104173 100644 --- a/app/src/main/java/app/marcdev/earworm/MainActivity.kt +++ b/app/src/main/java/app/marcdev/earworm/MainActivity.kt @@ -3,7 +3,7 @@ package app.marcdev.earworm import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.coordinatorlayout.widget.CoordinatorLayout -import app.marcdev.earworm.mainscreen.MainFragmentViewImpl +import app.marcdev.earworm.mainscreen.MainFragment import app.marcdev.earworm.utils.DARK_THEME import app.marcdev.earworm.utils.LIGHT_THEME import app.marcdev.earworm.utils.getTheme @@ -45,7 +45,7 @@ class MainActivity : AppCompatActivity() { private fun setDefaultFragment() { Timber.v("Log: setDefaultFragment: Started") - val fragment = MainFragmentViewImpl() + val fragment = MainFragment() if(intent.action == "app.marcdev.earworm.intent.ADD_ITEM") { Timber.d("Log: onCreate: Started from Add Item app shortcut") diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewImpl.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragment.kt similarity index 95% rename from app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewImpl.kt rename to app/src/main/java/app/marcdev/earworm/mainscreen/MainFragment.kt index 8704750..ccb5c48 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewImpl.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragment.kt @@ -17,7 +17,6 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import app.marcdev.earworm.R import app.marcdev.earworm.additem.AddItemBottomSheet -import app.marcdev.earworm.additem.RecyclerUpdateView import app.marcdev.earworm.data.database.FavouriteItem import app.marcdev.earworm.mainscreen.mainrecycler.MainRecyclerAdapter import app.marcdev.earworm.settingsscreen.SettingsActivity @@ -29,7 +28,7 @@ import org.kodein.di.android.x.closestKodein import org.kodein.di.generic.instance import timber.log.Timber -class MainFragmentViewImpl : Fragment(), MainFragmentView, RecyclerUpdateView, KodeinAware { +class MainFragment : Fragment(), KodeinAware { override val kodein by closestKodein() // @@ -119,7 +118,6 @@ class MainFragmentViewImpl : Fragment(), MainFragmentView, RecyclerUpdateView, K private val fabOnClickListener = View.OnClickListener { Timber.d("Log: Fab Clicked") val addDialog = AddItemBottomSheet() - addDialog.bindRecyclerUpdateView(this) addDialog.show(requireFragmentManager(), "Add Item Bottom Sheet Dialog") } @@ -182,7 +180,7 @@ class MainFragmentViewImpl : Fragment(), MainFragmentView, RecyclerUpdateView, K private fun setupRecycler(view: View) { val recycler: RecyclerView = view.findViewById(R.id.recycler_main) - this.recyclerAdapter = MainRecyclerAdapter(requireContext()) + this.recyclerAdapter = MainRecyclerAdapter(requireContext(), ::editClick, ::deleteClick) recycler.adapter = recyclerAdapter recycler.layoutManager = LinearLayoutManager(context) } @@ -211,7 +209,6 @@ class MainFragmentViewImpl : Fragment(), MainFragmentView, RecyclerUpdateView, K viewModel.displayData.observe(this, Observer { items -> items?.let { recyclerAdapter.updateItems(items) - viewModel.listReceived(items.isEmpty()) } }) @@ -244,18 +241,21 @@ class MainFragmentViewImpl : Fragment(), MainFragmentView, RecyclerUpdateView, K Toast.makeText(activity, resources.getString(R.string.item_deleted), Toast.LENGTH_SHORT).show() } - fun displayEditItemSheet(itemId: Int) { - Timber.d("Log: displayEditItemSheet: Started with itemId = $itemId") + private fun editClick(favouriteItem: FavouriteItem) { val addDialog = AddItemBottomSheet() - addDialog.bindRecyclerUpdateView(this) val args = Bundle() - args.putInt("item_id", itemId) + args.putInt("item_id", favouriteItem.id) addDialog.arguments = args addDialog.show(requireFragmentManager(), "Add Item Bottom Sheet Dialog") } + private fun deleteClick(favouriteItem: FavouriteItem) { + viewModel.deleteItem(favouriteItem) + } + + fun displayNoFilteredResultsWarning(display: Boolean) { Timber.d("Log: displayNoFilteredResultsWarning: Started with display = $display") diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentModel.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentModel.kt deleted file mode 100644 index 6bb6b5f..0000000 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentModel.kt +++ /dev/null @@ -1,17 +0,0 @@ -package app.marcdev.earworm.mainscreen - -import app.marcdev.earworm.data.database.FavouriteItem -import app.marcdev.earworm.utils.ItemFilter - -interface MainFragmentModel { - - fun getAllItemsAsync() - - fun getAllItemsAsync(filter: ItemFilter) - - fun deleteItemAsync(item: FavouriteItem) - - fun countUsesOfImage(item: FavouriteItem) - - fun deleteImage(filePath: String) -} \ No newline at end of file diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentModelImpl.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentModelImpl.kt deleted file mode 100644 index 1e2ead0..0000000 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentModelImpl.kt +++ /dev/null @@ -1,89 +0,0 @@ -package app.marcdev.earworm.mainscreen - -import android.content.Context -import app.marcdev.earworm.data.database.ProductionAppDatabase -import app.marcdev.earworm.data.database.FavouriteItem -import app.marcdev.earworm.data.repository.FavouriteItemRepository -import app.marcdev.earworm.data.repository.FavouriteItemRepositoryImpl -import app.marcdev.earworm.utils.ItemFilter -import app.marcdev.earworm.utils.getArtworkDirectory -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.async -import kotlinx.coroutines.launch -import timber.log.Timber -import java.io.File - -class MainFragmentModelImpl(private val presenter: MainFragmentPresenter, private val context: Context) : MainFragmentModel { - - private var repository: FavouriteItemRepository - - init { - val db: ProductionAppDatabase = ProductionAppDatabase.invoke(context) - repository = FavouriteItemRepositoryImpl(db.dao()) - } - - override fun getAllItemsAsync() { - Timber.d("Log: getAllItemsAsync: Started") - - GlobalScope.launch(Dispatchers.Main) { - val allItems = async(Dispatchers.IO) { -// repository.getAllItems() - }.await() - -// presenter.getAllItemsCallback(allItems) - } - } - - override fun getAllItemsAsync(filter: ItemFilter) { - Timber.d("Log: getAllItemsAsync: Started") - - GlobalScope.launch(Dispatchers.Main) { - val allItems = async(Dispatchers.IO) { -// repository.getAllItems() - }.await() - -// presenter.getAllItemsCallback(allItems, filter) - } - } - - override fun deleteItemAsync(item: FavouriteItem) { - Timber.d("Log: deleteItemAsync: Started") - - GlobalScope.launch(Dispatchers.Main) { - async(Dispatchers.IO) { - repository.deleteItem(item.id) - }.await() - - presenter.deleteItemCallback() - } - } - - override fun countUsesOfImage(item: FavouriteItem) { - Timber.d("Log: countUsesOfImage: Started with item = $item") - val filePath = getArtworkDirectory(context) + item.imageName - val file = File(filePath) - val fileName = file.name - - GlobalScope.launch(Dispatchers.Main) { - val uses = async(Dispatchers.IO) { - repository.countUsesOfImage(fileName) - }.await() - - presenter.countUsesOfImageCallback(item, uses) - } - } - - override fun deleteImage(filePath: String) { - Timber.d("Log: deleteImage: Started with filePath = $filePath") - - val file = File(filePath) - if(file.exists()) { - Timber.d("Log: deleteImage: File exists, deleting") - val deletionStatus = file.delete() - Timber.d("Log: deleteImage: Deletion: $deletionStatus") - } else { - Timber.w("Log: deleteImage: File doesn't exist") - } - } -} \ No newline at end of file diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentPresenter.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentPresenter.kt deleted file mode 100644 index ec7789a..0000000 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentPresenter.kt +++ /dev/null @@ -1,25 +0,0 @@ -package app.marcdev.earworm.mainscreen - -import app.marcdev.earworm.data.database.FavouriteItem -import app.marcdev.earworm.utils.ItemFilter - -interface MainFragmentPresenter { - - fun getAllItems() - - fun getAllItems(filter: ItemFilter) - - fun getAllItemsCallback(items: MutableList) - - fun getAllItemsCallback(items: MutableList, filter: ItemFilter) - - fun deleteItem(item: FavouriteItem) - - fun deleteItemCallback() - - fun editItemClick(itemId: Int) - - fun search(input: String) - - fun countUsesOfImageCallback(item: FavouriteItem, uses: Int) -} \ No newline at end of file diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentPresenterImpl.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentPresenterImpl.kt index 7864f11..446e581 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentPresenterImpl.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentPresenterImpl.kt @@ -1,19 +1,13 @@ -//package app.marcdev.earworm.mainscreen -// -//import android.content.Context -//import app.marcdev.earworm.data.database.FavouriteItem -//import app.marcdev.earworm.utils.* -//import timber.log.Timber -// -//class MainFragmentPresenterImpl(val view: MainFragmentView, val context: Context) : MainFragmentPresenter { -// private var model = MainFragmentModelImpl(this, context) -// -// override fun getAllItems() { -// Timber.d("Log: getAllItems: Started") -// model.getAllItemsAsync() -// } -// -// override fun getAllItems(filter: ItemFilter) { +package app.marcdev.earworm.mainscreen + +import android.content.Context +import app.marcdev.earworm.data.database.FavouriteItem +import app.marcdev.earworm.utils.* +import timber.log.Timber + +class MainFragmentPresenterImpl(val context: Context) { + + fun getAllItems(filter: ItemFilter) { // Timber.d("Log: getAllItems with Filter: Started") // Timber.i("Log: getAllItems: Input Filter = $filter") // if(filter != DEFAULT_FILTER.copy()) { @@ -22,26 +16,25 @@ // view.activateFilterIcon(false) // } // model.getAllItemsAsync(filter) -// // TODO -// } -// -// override fun getAllItemsCallback(items: MutableList) { -// Timber.d("Log: getAllItemsCallback: Started") + } + + fun getAllItemsCallback(items: MutableList) { + Timber.d("Log: getAllItemsCallback: Started") + +// val sortedItems = sortByDateDescending(items) +// val itemsWithHeaders = addListHeaders(sortedItems) // -//// val sortedItems = sortByDateDescending(items) -//// val itemsWithHeaders = addListHeaders(sortedItems) -//// -//// view.updateRecycler(itemsWithHeaders) -//// view.displayProgress(false) -//// -//// if(itemsWithHeaders.isEmpty()) { -//// view.displayNoEntriesWarning(true) -//// } else { -//// view.displayNoEntriesWarning(false) -//// } -// } +// view.updateRecycler(itemsWithHeaders) +// view.displayProgress(false) // -// override fun getAllItemsCallback(items: MutableList, filter: ItemFilter) { +// if(itemsWithHeaders.isEmpty()) { +// view.displayNoEntriesWarning(true) +// } else { +// view.displayNoEntriesWarning(false) +// } + } + + fun getAllItemsCallback(items: MutableList, filter: ItemFilter) { // Timber.d("Log: getAllItemsCallback: Started with filter = $filter") // // val sortedItems = applyFilter(items, filter) @@ -55,45 +48,14 @@ // } else { // view.displayNoFilteredResultsWarning(false) // } -// } -// -// override fun deleteItem(item: FavouriteItem) { -// Timber.d("Log: deleteItem: Started") -// if(item.imageName != "") { -// Timber.d("Log: deleteItem: Item has an image, checking if used elsewhere") -// model.countUsesOfImage(item) -// } else { -// Timber.d("Log: deleteItem: Item does not have an image, deleting item") -// model.deleteItemAsync(item) -// } -// } -// -// override fun deleteItemCallback() { -// Timber.d("Log: deleteItemCallback: Started") -// if(view.getActiveFilter() != DEFAULT_FILTER.copy()) { -// getAllItems(view.getActiveFilter()) -// } else { -// getAllItems() -// } -// } -// -// override fun countUsesOfImageCallback(item: FavouriteItem, uses: Int) { -// Timber.d("Log: countUsesOfImageCallback: Started with imageName = ${item.imageName} and uses = $uses") -// -// if(uses <= 1) { -// val filePath = getArtworkDirectory(context) + item.imageName -// model.deleteImage(filePath) -// } -// -// model.deleteItemAsync(item) -// } -// -// override fun editItemClick(itemId: Int) { + } + + fun editItemClick(itemId: Int) { // Timber.d("Log: editItemClick: Started") -// view.displayEditItemSheet(itemId) -// } -// -// override fun search(input: String) { +// view.editClick(itemId) + } + + fun search(input: String) { // Timber.d("Log: search: Started with input = $input") // if(input.isBlank()) { // val inputFilter = view.getActiveFilter() @@ -105,6 +67,6 @@ // inputFilter.searchTerm = input.trim() // model.getAllItemsAsync(inputFilter) // view.changeSearchIcon(false) -// } // } -//} \ No newline at end of file + } +} \ No newline at end of file diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentView.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentView.kt deleted file mode 100644 index c45fb53..0000000 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentView.kt +++ /dev/null @@ -1,27 +0,0 @@ -package app.marcdev.earworm.mainscreen - -import app.marcdev.earworm.data.database.FavouriteItem -import app.marcdev.earworm.utils.ItemFilter - -interface MainFragmentView { - -// fun displayNoEntriesWarning(display: Boolean) -// -// fun displayNoFilteredResultsWarning(display: Boolean) -// -// fun displayAddedToast() -// -// fun displayItemDeletedToast() -// -// fun updateRecycler(items: List) -// -// fun displayProgress(isVisible: Boolean) -// -// fun displayEditItemSheet(itemId: Int) -// -// fun getActiveFilter(): ItemFilter -// -// fun changeSearchIcon(isSearch: Boolean) -// -// fun activateFilterIcon(isActive: Boolean) -} \ No newline at end of file diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewModel.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewModel.kt index 288a5d8..3bf456f 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewModel.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewModel.kt @@ -1,15 +1,21 @@ package app.marcdev.earworm.mainscreen import androidx.lifecycle.* +import app.marcdev.earworm.data.database.FavouriteItem import app.marcdev.earworm.data.repository.FavouriteItemRepository -import app.marcdev.earworm.utils.addListHeaders -import app.marcdev.earworm.utils.sortByDateDescending +import app.marcdev.earworm.utils.* +import kotlinx.coroutines.launch -class MainFragmentViewModel(private val repository: FavouriteItemRepository) : ViewModel() { +class MainFragmentViewModel(private val repository: FavouriteItemRepository, + private val fileUtils: FileUtils) + : ViewModel() { val displayData = Transformations.map(repository.allItems) { list -> val sortedItems = sortByDateDescending(list.toMutableList()) - return@map addListHeaders(sortedItems) + val listWithHeaders = addListHeaders(sortedItems) + _displayLoading.value = false + _displayNoEntries.value = listWithHeaders.isEmpty() + return@map listWithHeaders } private val _displayLoading = MutableLiveData() @@ -38,8 +44,19 @@ class MainFragmentViewModel(private val repository: FavouriteItemRepository) : V _displayNoFilteredResults.value = false } - fun listReceived(isEmpty: Boolean) { - _displayLoading.value = false - _displayNoEntries.value = isEmpty + fun deleteItem(item: FavouriteItem) { + viewModelScope.launch { + repository.deleteItem(item.id) + deleteImageIfNecessary(item.imageName) + } + } + + private suspend fun deleteImageIfNecessary(imageName: String) { + if(imageName.isNotBlank()) { + val uses = repository.countUsesOfImage(imageName) + if(uses == 0) { + fileUtils.deleteImage(imageName) + } + } } } \ No newline at end of file diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewModelFactory.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewModelFactory.kt index 1b0a989..4330abf 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewModelFactory.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewModelFactory.kt @@ -3,12 +3,13 @@ package app.marcdev.earworm.mainscreen import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import app.marcdev.earworm.data.repository.FavouriteItemRepository +import app.marcdev.earworm.utils.FileUtils -class MainFragmentViewModelFactory(private val favouriteItemRepository: FavouriteItemRepository) +class MainFragmentViewModelFactory(private val favouriteItemRepository: FavouriteItemRepository, private val fileUtils: FileUtils) : ViewModelProvider.NewInstanceFactory() { @Suppress("UNCHECKED_CAST") override fun create(modelClass: Class): T { - return MainFragmentViewModel(favouriteItemRepository) as T + return MainFragmentViewModel(favouriteItemRepository, fileUtils) as T } } \ No newline at end of file diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerAdapter.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerAdapter.kt index 4a972ad..2f1b5c8 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerAdapter.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerAdapter.kt @@ -6,53 +6,46 @@ import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import app.marcdev.earworm.R import app.marcdev.earworm.data.database.FavouriteItem -import app.marcdev.earworm.mainscreen.MainFragmentPresenter import app.marcdev.earworm.utils.* -import timber.log.Timber -class MainRecyclerAdapter(context: Context) : RecyclerView.Adapter(), MainRecyclerView { +class MainRecyclerAdapter(context: Context, + private val editClick: (FavouriteItem) -> Unit, + private val deleteClick: (FavouriteItem) -> Unit) + : RecyclerView.Adapter() { private var items: List = mutableListOf() private var inflater: LayoutInflater = LayoutInflater.from(context) override fun getItemViewType(position: Int): Int { - Timber.v("Log: getItemViewType: Started") return items[position].type } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainRecyclerViewHolder { - Timber.v("Log: onCreateViewHolder: Started") - lateinit var viewHolder: MainRecyclerViewHolder when(viewType) { HEADER -> { - Timber.v("Log: onCreateViewHolder: Type == Header") val view = inflater.inflate(R.layout.item_header, parent, false) viewHolder = MainRecyclerViewHolderHeader(view) } SONG -> { - Timber.v("Log: onCreateViewHolder: Type == Song") val view = inflater.inflate(R.layout.item_mainrecycler_song, parent, false) - viewHolder = MainRecyclerViewHolderSong(view) + viewHolder = MainRecyclerViewHolderSong(view, editClick, deleteClick) } ALBUM -> { - Timber.v("Log: onCreateViewHolder: Type == Album") val view = inflater.inflate(R.layout.item_mainrecycler_album, parent, false) - viewHolder = MainRecyclerViewHolderAlbum(view) + viewHolder = MainRecyclerViewHolderAlbum(view, editClick, deleteClick) } ARTIST -> { - Timber.v("Log: onCreateViewHolder: Type == Artist") val view = inflater.inflate(R.layout.item_mainrecycler_artist, parent, false) - viewHolder = MainRecyclerViewHolderArtist(view) + viewHolder = MainRecyclerViewHolderArtist(view, editClick, deleteClick) } GENRE -> { - Timber.v("Log: onCreateViewHolder: Type == Genre") val view = inflater.inflate(R.layout.item_mainrecycler_genre, parent, false) - viewHolder = MainRecyclerViewHolderGenre(view) + viewHolder = MainRecyclerViewHolderGenre(view, editClick, deleteClick) } } @@ -60,17 +53,14 @@ class MainRecyclerAdapter(context: Context) : RecyclerView.Adapter) { - Timber.d("Log: updateItems: Started") + fun updateItems(items: List) { this.items = items notifyDataSetChanged() } diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerView.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerView.kt deleted file mode 100644 index 163e44a..0000000 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerView.kt +++ /dev/null @@ -1,7 +0,0 @@ -package app.marcdev.earworm.mainscreen.mainrecycler - -import app.marcdev.earworm.data.database.FavouriteItem - -interface MainRecyclerView { - fun updateItems(items: List) -} \ No newline at end of file diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolder.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolder.kt index 2916d32..403fdce 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolder.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolder.kt @@ -8,19 +8,20 @@ import android.view.View import androidx.recyclerview.widget.RecyclerView import app.marcdev.earworm.R import app.marcdev.earworm.data.database.FavouriteItem -import app.marcdev.earworm.mainscreen.MainFragmentPresenter import com.google.android.material.button.MaterialButton import com.google.android.material.snackbar.Snackbar import timber.log.Timber -open class MainRecyclerViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { +open class MainRecyclerViewHolder(itemView: View, + private val editClick: (FavouriteItem) -> Unit, + private val deleteClick: (FavouriteItem) -> Unit) + : RecyclerView.ViewHolder(itemView) { - private lateinit var displayedItem: FavouriteItem + protected var displayedItem: FavouriteItem? = null private lateinit var editDialog: Dialog private val prefs = PreferenceManager.getDefaultSharedPreferences(itemView.context) private val snackbarActionListener = View.OnClickListener { - Timber.d("Log: snackbarActionListener: Clicked") prefs.edit().putBoolean("pref_show_tips", false).apply() } @@ -38,15 +39,17 @@ open class MainRecyclerViewHolder(itemView: View) : RecyclerView.ViewHolder(item } private val editOnClickListener = View.OnClickListener { - Timber.d("Log: editOnClickListener: Clicked") editDialog.dismiss() -// presenter.editItemClick(displayedItem.id) + displayedItem?.let { displayedItem -> + editClick(displayedItem) + } } private val deleteOnClickListener = View.OnClickListener { - Timber.d("Log: deleteOnClickListener: Clicked") -// presenter.deleteItem(displayedItem) editDialog.dismiss() + displayedItem?.let { displayedItem -> + deleteClick(displayedItem) + } } init { diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderAlbum.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderAlbum.kt index fb499ce..807ef12 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderAlbum.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderAlbum.kt @@ -11,7 +11,10 @@ import com.bumptech.glide.Glide import com.bumptech.glide.request.RequestOptions import timber.log.Timber -class MainRecyclerViewHolderAlbum(itemView: View) : MainRecyclerViewHolder(itemView) { +class MainRecyclerViewHolderAlbum(itemView: View, + editClick: (FavouriteItem) -> Unit, + deleteClick: (FavouriteItem) -> Unit) + : MainRecyclerViewHolder(itemView, editClick, deleteClick) { private val albumNameDisplay: TextView = itemView.findViewById(R.id.txt_albumName) private val albumDateDisplay: TextView = itemView.findViewById(R.id.txt_albumDate) @@ -19,23 +22,19 @@ class MainRecyclerViewHolderAlbum(itemView: View) : MainRecyclerViewHolder(itemV private var albumImageDisplay: ImageView = itemView.findViewById(R.id.img_album_icon) override fun display(favouriteItemToDisplay: FavouriteItem) { - Timber.d("Log: display: $favouriteItemToDisplay") + displayedItem = favouriteItemToDisplay albumNameDisplay.text = favouriteItemToDisplay.albumName albumArtistDisplay.text = favouriteItemToDisplay.artistName val date = formatDateForDisplay(favouriteItemToDisplay.day, favouriteItemToDisplay.month, favouriteItemToDisplay.year) albumDateDisplay.text = date if(favouriteItemToDisplay.imageName.isNotBlank()) { - Timber.d("Log: display: ${favouriteItemToDisplay.imageName}") - Glide.with(itemView) .load(getArtworkDirectory(itemView.context) + favouriteItemToDisplay.imageName) .apply(RequestOptions().centerCrop()) .apply(RequestOptions().error(itemView.resources.getDrawable(R.drawable.ic_error_24px, null))) .into(albumImageDisplay) } else { - Timber.d("Log: display: No image to display") - Glide.with(itemView) .load(itemView.resources.getDrawable(R.drawable.ic_album_24px, null)) .apply(RequestOptions().centerCrop()) diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderArtist.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderArtist.kt index e5c4d56..88f3515 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderArtist.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderArtist.kt @@ -11,7 +11,10 @@ import com.bumptech.glide.Glide import com.bumptech.glide.request.RequestOptions import timber.log.Timber -class MainRecyclerViewHolderArtist(itemView: View) : MainRecyclerViewHolder(itemView) { +class MainRecyclerViewHolderArtist(itemView: View, + editClick: (FavouriteItem) -> Unit, + deleteClick: (FavouriteItem) -> Unit) + : MainRecyclerViewHolder(itemView, editClick, deleteClick) { private val artistNameDisplay: TextView = itemView.findViewById(R.id.txt_artistName) private val artistGenreDisplay: TextView = itemView.findViewById(R.id.txt_artistGenre) @@ -19,23 +22,19 @@ class MainRecyclerViewHolderArtist(itemView: View) : MainRecyclerViewHolder(item private val artistImageDisplay: ImageView = itemView.findViewById(R.id.img_artist_icon) override fun display(favouriteItemToDisplay: FavouriteItem) { - Timber.d("Log: display: $favouriteItemToDisplay") + displayedItem = favouriteItemToDisplay artistNameDisplay.text = favouriteItemToDisplay.artistName artistGenreDisplay.text = favouriteItemToDisplay.genre val date = formatDateForDisplay(favouriteItemToDisplay.day, favouriteItemToDisplay.month, favouriteItemToDisplay.year) artistDateDisplay.text = date if(favouriteItemToDisplay.imageName.isNotBlank()) { - Timber.d("Log: display: imageName = ${favouriteItemToDisplay.imageName}") - Glide.with(itemView) .load(getArtworkDirectory(itemView.context) + favouriteItemToDisplay.imageName) .apply(RequestOptions().centerCrop()) .apply(RequestOptions().error(itemView.resources.getDrawable(R.drawable.ic_error_24px, null))) .into(artistImageDisplay) } else { - Timber.d("Log: display: No image to display") - Glide.with(itemView) .load(itemView.resources.getDrawable(R.drawable.ic_person_24px, null)) .apply(RequestOptions().centerCrop()) diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderGenre.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderGenre.kt index c25c1d6..b4ec7ee 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderGenre.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderGenre.kt @@ -7,13 +7,16 @@ import app.marcdev.earworm.data.database.FavouriteItem import app.marcdev.earworm.utils.formatDateForDisplay import timber.log.Timber -class MainRecyclerViewHolderGenre(itemView: View) : MainRecyclerViewHolder(itemView) { +class MainRecyclerViewHolderGenre(itemView: View, + editClick: (FavouriteItem) -> Unit, + deleteClick: (FavouriteItem) -> Unit) + : MainRecyclerViewHolder(itemView, editClick, deleteClick) { private var genreNameDisplay: TextView = itemView.findViewById(R.id.txt_genreName) private var genreDateDisplay: TextView = itemView.findViewById(R.id.txt_genreDate) override fun display(favouriteItemToDisplay: FavouriteItem) { - Timber.d("Log: display: $favouriteItemToDisplay") + displayedItem = favouriteItemToDisplay genreNameDisplay.text = favouriteItemToDisplay.genre val date = formatDateForDisplay(favouriteItemToDisplay.day, favouriteItemToDisplay.month, favouriteItemToDisplay.year) genreDateDisplay.text = date diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderHeader.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderHeader.kt index e71a0c1..f98530e 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderHeader.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderHeader.kt @@ -7,7 +7,7 @@ import app.marcdev.earworm.data.database.FavouriteItem import app.marcdev.earworm.utils.getMonthName import timber.log.Timber -open class MainRecyclerViewHolderHeader(itemView: View) : MainRecyclerViewHolder(itemView) { +open class MainRecyclerViewHolderHeader(itemView: View) : MainRecyclerViewHolder(itemView, {}, {}) { private var dateDisplay: TextView = itemView.findViewById(R.id.txt_header_title) @@ -26,8 +26,6 @@ open class MainRecyclerViewHolderHeader(itemView: View) : MainRecyclerViewHolder } override fun display(favouriteItemToDisplay: FavouriteItem) { - Timber.d("Log: display: $favouriteItemToDisplay") - dateDisplay.text = ("${getMonthName(favouriteItemToDisplay.month, itemView.context)} ${favouriteItemToDisplay.year}") } } diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderSong.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderSong.kt index 58987c9..4706848 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderSong.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/mainrecycler/MainRecyclerViewHolderSong.kt @@ -11,7 +11,10 @@ import com.bumptech.glide.Glide import com.bumptech.glide.request.RequestOptions import timber.log.Timber -class MainRecyclerViewHolderSong(itemView: View) : MainRecyclerViewHolder(itemView) { +class MainRecyclerViewHolderSong(itemView: View, + editClick: (FavouriteItem) -> Unit, + deleteClick: (FavouriteItem) -> Unit) + : MainRecyclerViewHolder(itemView, editClick, deleteClick) { private val songNameDisplay: TextView = itemView.findViewById(R.id.txt_songName) private val songDateDisplay: TextView = itemView.findViewById(R.id.txt_songDate) @@ -19,22 +22,19 @@ class MainRecyclerViewHolderSong(itemView: View) : MainRecyclerViewHolder(itemVi private val songImageDisplay: ImageView = itemView.findViewById(R.id.img_song_icon) override fun display(favouriteItemToDisplay: FavouriteItem) { - Timber.d("Log: display: $favouriteItemToDisplay") + displayedItem = favouriteItemToDisplay songNameDisplay.text = favouriteItemToDisplay.songName songArtistDisplay.text = favouriteItemToDisplay.artistName val date = formatDateForDisplay(favouriteItemToDisplay.day, favouriteItemToDisplay.month, favouriteItemToDisplay.year) songDateDisplay.text = date if(favouriteItemToDisplay.imageName.isNotBlank()) { - Timber.d("Log: display: ${favouriteItemToDisplay.imageName}") Glide.with(itemView) .load(getArtworkDirectory(itemView.context) + favouriteItemToDisplay.imageName) .apply(RequestOptions().centerCrop()) .apply(RequestOptions().error(itemView.resources.getDrawable(R.drawable.ic_error_24px, null))) .into(songImageDisplay) } else { - Timber.d("Log: display: No image to display") - Glide.with(itemView) .load(itemView.resources.getDrawable(R.drawable.ic_music_note_24px, null)) .apply(RequestOptions().centerCrop()) diff --git a/app/src/main/java/app/marcdev/earworm/uicomponents/FilterDialog.kt b/app/src/main/java/app/marcdev/earworm/uicomponents/FilterDialog.kt index f1c2394..7b55fbb 100644 --- a/app/src/main/java/app/marcdev/earworm/uicomponents/FilterDialog.kt +++ b/app/src/main/java/app/marcdev/earworm/uicomponents/FilterDialog.kt @@ -8,7 +8,6 @@ import android.widget.CheckBox import android.widget.CompoundButton import android.widget.DatePicker import app.marcdev.earworm.R -import app.marcdev.earworm.mainscreen.MainFragmentPresenter import app.marcdev.earworm.utils.DEFAULT_FILTER import app.marcdev.earworm.utils.ItemFilter import app.marcdev.earworm.utils.formatDateForDisplay @@ -17,7 +16,7 @@ import com.google.android.material.chip.Chip import timber.log.Timber import java.util.* -class FilterDialog(context: Context, private val presenter: MainFragmentPresenter) : Dialog(context) { +class FilterDialog(context: Context) : Dialog(context) { private lateinit var displaySongCheckbox: CheckBox private lateinit var displayAlbumCheckbox: CheckBox @@ -72,7 +71,7 @@ class FilterDialog(context: Context, private val presenter: MainFragmentPresente val submitButton: MaterialButton = findViewById(R.id.btn_filter_ok) submitButton.setOnClickListener { Timber.d("Log: submitButtonOnClickListener: Started") - presenter.getAllItems(activeFilter) +// presenter.getAllItems(activeFilter) dismiss() } } diff --git a/app/src/main/java/app/marcdev/earworm/utils/FileUtils.kt b/app/src/main/java/app/marcdev/earworm/utils/FileUtils.kt new file mode 100644 index 0000000..0f04d3d --- /dev/null +++ b/app/src/main/java/app/marcdev/earworm/utils/FileUtils.kt @@ -0,0 +1,5 @@ +package app.marcdev.earworm.utils + +interface FileUtils { + fun deleteImage(imageName: String) +} \ No newline at end of file diff --git a/app/src/main/java/app/marcdev/earworm/utils/FileUtilsImpl.kt b/app/src/main/java/app/marcdev/earworm/utils/FileUtilsImpl.kt new file mode 100644 index 0000000..a18ce92 --- /dev/null +++ b/app/src/main/java/app/marcdev/earworm/utils/FileUtilsImpl.kt @@ -0,0 +1,18 @@ +package app.marcdev.earworm.utils + +import android.content.Context +import timber.log.Timber +import java.io.File + +class FileUtilsImpl(private val context: Context): FileUtils { + + override fun deleteImage(imageName: String) { + val filePath = getArtworkDirectory(context) + imageName + val file = File(filePath) + if(file.exists()) { + file.delete() + } else { + Timber.w("Log: deleteImage: File doesn't exist") + } + } +} \ No newline at end of file From 3e74a6ec04ff8a0276ab84c3b047180998d59bc6 Mon Sep 17 00:00:00 2001 From: Marc Date: Sun, 2 Jun 2019 13:09:47 +0100 Subject: [PATCH 09/18] Add search functionality and upgrade Gradle to 3.5.0-beta03 --- .../earworm/mainscreen/MainFragment.kt | 48 +++---------- .../mainscreen/MainFragmentPresenterImpl.kt | 72 ------------------- .../mainscreen/MainFragmentViewModel.kt | 65 ++++++++++++++--- .../app/marcdev/earworm/utils/EarwormUtils.kt | 8 --- .../app/marcdev/earworm/utils/ListUtils.kt | 7 +- build.gradle | 4 +- gradle/wrapper/gradle-wrapper.properties | 4 +- 7 files changed, 73 insertions(+), 135 deletions(-) delete mode 100644 app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentPresenterImpl.kt diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragment.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragment.kt index ccb5c48..7b8e166 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragment.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragment.kt @@ -51,16 +51,12 @@ class MainFragment : Fragment(), KodeinAware { private lateinit var recyclerAdapter: MainRecyclerAdapter // - private var isSearchMode = true - override fun onCreate(savedInstanceState: Bundle?) { - Timber.v("Log: onCreate: Started") super.onCreate(savedInstanceState) viewModel = ViewModelProviders.of(this, viewModelFactory).get(MainFragmentViewModel::class.java) } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - Timber.d("Log: onCreateView: Started") val view = inflater.inflate(R.layout.fragment_mainscreen, container, false) bindViews(view) setupRecycler(view) @@ -82,7 +78,6 @@ class MainFragment : Fragment(), KodeinAware { } private fun bindViews(view: View) { - Timber.v("Log: bindViews: Started") this.fab = view.findViewById(R.id.fab_main) fab.setOnClickListener(fabOnClickListener) @@ -116,13 +111,11 @@ class MainFragment : Fragment(), KodeinAware { } private val fabOnClickListener = View.OnClickListener { - Timber.d("Log: Fab Clicked") val addDialog = AddItemBottomSheet() addDialog.show(requireFragmentManager(), "Add Item Bottom Sheet Dialog") } private val settingsOnClickListener = View.OnClickListener { - Timber.d("Log: Settings Clicked") val intent = Intent(requireContext(), SettingsActivity::class.java) startActivity(intent) } @@ -140,31 +133,28 @@ class MainFragment : Fragment(), KodeinAware { override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { if(s.isNullOrBlank()) { -// presenter.search("") + viewModel.search("") } } } private fun testIfSubmitButtonClicked(keyEvent: KeyEvent, keyCode: Int): Boolean { - Timber.d("Log: testIfSubmitButtonClicked: Submit button clicked") if((keyEvent.action == KeyEvent.ACTION_DOWN) && keyCode == KeyEvent.KEYCODE_ENTER) { -// presenter.search(searchInput.text.toString()) + viewModel.search(searchInput.text.toString()) return true } return false } private val searchOnClickListener = View.OnClickListener { - Timber.d("Log: Search Clicked") - if(isSearchMode) { -// presenter.search(searchInput.text.toString()) - } else { - searchInput.setText("") - } + viewModel.search(searchInput.text.toString()) + } + + private val clearSearchClickListener = View.OnClickListener { + searchInput.setText("") } private val filterOnClickListener = View.OnClickListener { - Timber.d("Log: Filter Clicked") filterDialog.show() } @@ -222,22 +212,20 @@ class MainFragment : Fragment(), KodeinAware { value?.let { show -> if(show) { searchButton.setImageDrawable(resources.getDrawable(R.drawable.ic_search_24px, null)) - this.isSearchMode = true + searchButton.setOnClickListener(searchOnClickListener) } else { searchButton.setImageDrawable(resources.getDrawable(R.drawable.ic_close_24px, null)) - this.isSearchMode = false + searchButton.setOnClickListener(clearSearchClickListener) } } }) } fun displayAddedToast() { - Timber.d("Log: displayAddedToast: Started") Toast.makeText(activity, resources.getString(R.string.item_added), Toast.LENGTH_SHORT).show() } fun displayItemDeletedToast() { - Timber.d("Log: displayItemDeletedToast: Started") Toast.makeText(activity, resources.getString(R.string.item_deleted), Toast.LENGTH_SHORT).show() } @@ -255,24 +243,6 @@ class MainFragment : Fragment(), KodeinAware { viewModel.deleteItem(favouriteItem) } - - fun displayNoFilteredResultsWarning(display: Boolean) { - Timber.d("Log: displayNoFilteredResultsWarning: Started with display = $display") - - if(display && (noEntriesWarning.visibility == View.GONE)) { - this.noFilteredResultsWarning.visibility = View.VISIBLE - this.noFilteredResultsWarningImage.visibility = View.VISIBLE - } else { - this.noFilteredResultsWarning.visibility = View.GONE - this.noFilteredResultsWarningImage.visibility = View.GONE - } - } - - fun getActiveFilter(): ItemFilter { - Timber.d("Log: getActiveFilter: Started") - return filterDialog.activeFilter - } - private fun convertToDarkMode() { changeColorOfImageViewDrawable(requireContext(), filterButton, false) changeColorOfImageViewDrawable(requireContext(), settingsButton, false) diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentPresenterImpl.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentPresenterImpl.kt deleted file mode 100644 index 446e581..0000000 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentPresenterImpl.kt +++ /dev/null @@ -1,72 +0,0 @@ -package app.marcdev.earworm.mainscreen - -import android.content.Context -import app.marcdev.earworm.data.database.FavouriteItem -import app.marcdev.earworm.utils.* -import timber.log.Timber - -class MainFragmentPresenterImpl(val context: Context) { - - fun getAllItems(filter: ItemFilter) { -// Timber.d("Log: getAllItems with Filter: Started") -// Timber.i("Log: getAllItems: Input Filter = $filter") -// if(filter != DEFAULT_FILTER.copy()) { -// view.activateFilterIcon(true) -// } else { -// view.activateFilterIcon(false) -// } -// model.getAllItemsAsync(filter) - } - - fun getAllItemsCallback(items: MutableList) { - Timber.d("Log: getAllItemsCallback: Started") - -// val sortedItems = sortByDateDescending(items) -// val itemsWithHeaders = addListHeaders(sortedItems) -// -// view.updateRecycler(itemsWithHeaders) -// view.displayProgress(false) -// -// if(itemsWithHeaders.isEmpty()) { -// view.displayNoEntriesWarning(true) -// } else { -// view.displayNoEntriesWarning(false) -// } - } - - fun getAllItemsCallback(items: MutableList, filter: ItemFilter) { -// Timber.d("Log: getAllItemsCallback: Started with filter = $filter") -// -// val sortedItems = applyFilter(items, filter) -// val itemsWithHeaders = addListHeaders(sortedItems) -// -// view.updateRecycler(itemsWithHeaders) -// view.displayProgress(false) -// -// if(itemsWithHeaders.isEmpty()) { -// view.displayNoFilteredResultsWarning(true) -// } else { -// view.displayNoFilteredResultsWarning(false) -// } - } - - fun editItemClick(itemId: Int) { -// Timber.d("Log: editItemClick: Started") -// view.editClick(itemId) - } - - fun search(input: String) { -// Timber.d("Log: search: Started with input = $input") -// if(input.isBlank()) { -// val inputFilter = view.getActiveFilter() -// inputFilter.searchTerm = "" -// model.getAllItemsAsync(inputFilter) -// view.changeSearchIcon(true) -// } else { -// val inputFilter = view.getActiveFilter() -// inputFilter.searchTerm = input.trim() -// model.getAllItemsAsync(inputFilter) -// view.changeSearchIcon(false) -// } - } -} \ No newline at end of file diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewModel.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewModel.kt index 3bf456f..696abff 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewModel.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewModel.kt @@ -10,13 +10,12 @@ class MainFragmentViewModel(private val repository: FavouriteItemRepository, private val fileUtils: FileUtils) : ViewModel() { - val displayData = Transformations.map(repository.allItems) { list -> - val sortedItems = sortByDateDescending(list.toMutableList()) - val listWithHeaders = addListHeaders(sortedItems) - _displayLoading.value = false - _displayNoEntries.value = listWithHeaders.isEmpty() - return@map listWithHeaders - } + private val activeFilter = MutableLiveData() + private val allItems = repository.allItems + + private val _displayData = MediatorLiveData>() + val displayData: LiveData> + get() = _displayData private val _displayLoading = MutableLiveData() val displayLoading: LiveData @@ -39,9 +38,49 @@ class MainFragmentViewModel(private val repository: FavouriteItemRepository, get() = _displaySearchIcon init { - _displayLoading.value = true _displayNoEntries.value = false _displayNoFilteredResults.value = false + _displayData.addSource(activeFilter) { filter -> + workOutDisplayData(allItems.value, filter) + } + _displayData.addSource(allItems) { items -> + workOutDisplayData(items, activeFilter.value) + } + } + + private fun workOutDisplayData(allItems: List?, filter: ItemFilter?) { + _displayLoading.value = true + displaySearchIconIfNeeded(filter) + var finalList: List? = null + + allItems?.let { fullList -> + _displayNoEntries.value = fullList.isEmpty() + + val filteredList = if(filter != null) { + filterResults(fullList, filter) + } else { + fullList + } + val sortedList = sortByDateDescending(filteredList) + finalList = addListHeaders(sortedList) + } + + _displayData.value = finalList?.toList() + _displayLoading.value = false + } + + private fun filterResults(allItems: List, filter: ItemFilter): List { + val finalList = applyFilter(allItems, filter) + _displayNoFilteredResults.value = finalList.isEmpty() + return finalList + } + + private fun displaySearchIconIfNeeded(filter: ItemFilter?) { + if(filter == null) { + _displaySearchIcon.value = true + } else { + _displaySearchIcon.value = filter.searchTerm.isBlank() + } } fun deleteItem(item: FavouriteItem) { @@ -51,6 +90,16 @@ class MainFragmentViewModel(private val repository: FavouriteItemRepository, } } + fun search(searchTermArg: String) { + val newFilter: ItemFilter? = if(activeFilter.value == null) + DEFAULT_FILTER.copy() + else + activeFilter.value + + newFilter?.searchTerm = searchTermArg + activeFilter.value = newFilter + } + private suspend fun deleteImageIfNecessary(imageName: String) { if(imageName.isNotBlank()) { val uses = repository.countUsesOfImage(imageName) diff --git a/app/src/main/java/app/marcdev/earworm/utils/EarwormUtils.kt b/app/src/main/java/app/marcdev/earworm/utils/EarwormUtils.kt index 55093dc..6f6691c 100644 --- a/app/src/main/java/app/marcdev/earworm/utils/EarwormUtils.kt +++ b/app/src/main/java/app/marcdev/earworm/utils/EarwormUtils.kt @@ -38,7 +38,6 @@ const val PREF_CLEAR_INPUTS = "pref_clear_inputs_on_type_change" * @param frameId The ID of the frame to display the new fragment in */ fun setFragment(fragment: Fragment, fragmentManager: FragmentManager, frameId: Int) { - Timber.d("Log: setFragment: Replacing frame $frameId with fragment $fragment") val fragmentTransaction = fragmentManager.beginTransaction() fragmentTransaction.replace(frameId, fragment) fragmentTransaction.commit() @@ -51,7 +50,6 @@ fun setFragment(fragment: Fragment, fragmentManager: FragmentManager, frameId: I * @param year The year */ fun formatDateForDisplay(day: Int, month: Int, year: Int): String { - Timber.d("Log: formatDateForDisplay: Started with day = $day, month = $month, year = $year") // Add 1 to month to make it non-zero indexed (January will now be 1 rather than 0) return "$day/${month + 1}/$year" } @@ -64,8 +62,6 @@ fun formatDateForDisplay(day: Int, month: Int, year: Int): String { * @param isActivated Whether or not the button should be put into the activated state */ fun changeColorOfImageViewDrawable(context: Context, button: ImageView, isActivated: Boolean) { - Timber.v("Log: changeColorOfImageViewDrawable: Started") - when { isActivated -> button.setColorFilter(context.getColor(R.color.colorAccent)) (getTheme(context) == DARK_THEME && !isActivated) -> button.setColorFilter(context.getColor(R.color.white60)) @@ -81,8 +77,6 @@ fun changeColorOfImageViewDrawable(context: Context, button: ImageView, isActiva * @param isActivated Whether or not the button should be put into the activated state */ fun changeColorOfDrawable(context: Context, drawable: Drawable, isActivated: Boolean) { - Timber.v("Log: changeColorOfDrawable: Started") - when { isActivated -> drawable.setColorFilter(context.getColor(R.color.colorAccent), PorterDuff.Mode.SRC_IN) (getTheme(context) == DARK_THEME && !isActivated) -> drawable.setColorFilter((context.getColor(R.color.white60)), PorterDuff.Mode.SRC_IN) @@ -106,9 +100,7 @@ fun getMonthName(month: Int, context: Context): String { * @param context Context */ fun getArtworkDirectory(context: Context): String { - Timber.d("Log: getArtworkDirectory: Started") val returnValue = context.filesDir.path + "/artwork/" - Timber.d("Log: getArtworkDirectory: Returning $returnValue") return returnValue } diff --git a/app/src/main/java/app/marcdev/earworm/utils/ListUtils.kt b/app/src/main/java/app/marcdev/earworm/utils/ListUtils.kt index 1ffafd6..dcb3888 100644 --- a/app/src/main/java/app/marcdev/earworm/utils/ListUtils.kt +++ b/app/src/main/java/app/marcdev/earworm/utils/ListUtils.kt @@ -9,7 +9,7 @@ import timber.log.Timber * @param filter The filter to apply * @return Filtered list */ -fun applyFilter(allItems: MutableList, filter: ItemFilter): MutableList { +fun applyFilter(allItems: List, filter: ItemFilter): MutableList { val filteredItems = mutableListOf() filteredItems.addAll(allItems) @@ -90,7 +90,7 @@ fun applyFilter(allItems: MutableList, filter: ItemFilter): Mutab * @param items List to sort * @return Sorted list of FavouriteItems */ -fun sortByDateDescending(items: MutableList): MutableList { +fun sortByDateDescending(items: List): MutableList { val filteredItems = items.sortedWith( compareBy( { -it.year }, @@ -106,7 +106,7 @@ fun sortByDateDescending(items: MutableList): MutableList): List { +fun addListHeaders(allItems: List): List { val listWithHeaders = mutableListOf() listWithHeaders.addAll(allItems) @@ -124,7 +124,6 @@ fun addListHeaders(allItems: MutableList): List { || (allItems[x].month > lastMonth) && (allItems[x].year < lastYear) || (allItems[x].year < lastYear) ) { - Timber.v("Log: addListHeaders: x = $x") val header = FavouriteItem("", "", "", "", 0, allItems[x].month, allItems[x].year, HEADER, "") lastMonth = allItems[x].month lastYear = allItems[x].year diff --git a/build.gradle b/build.gradle index ee486a6..0f9f410 100644 --- a/build.gradle +++ b/build.gradle @@ -1,13 +1,13 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.3.11' + ext.kotlin_version = '1.3.31' repositories { google() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.3.0' + classpath 'com.android.tools.build:gradle:3.5.0-beta03' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 5285468..a304ea5 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Jan 15 13:13:13 GMT 2019 +#Sun Jun 02 12:58:59 BST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip From d3f87ae227b7461f8ca9ffb767c415bbb30a9684 Mon Sep 17 00:00:00 2001 From: Marc Date: Sun, 2 Jun 2019 14:19:22 +0100 Subject: [PATCH 10/18] Add filter functionality --- .../java/app/marcdev/earworm/MainActivity.kt | 13 +- .../earworm/additem/AddItemBottomSheet.kt | 4 +- .../base/EarwormBottomSheetDialogFragment.kt} | 4 +- .../internal/base/EarwormDialogFragment.kt | 11 ++ .../earworm/mainscreen/MainFragment.kt | 8 +- .../mainscreen/MainFragmentViewModel.kt | 20 +++ .../uicomponents/FilterDatePickerDialog.kt | 74 ++++++++ .../earworm/uicomponents/FilterDialog.kt | 167 +++++++----------- app/src/main/res/layout/dialog_datepicker.xml | 3 +- .../res/layout/dialog_datepicker_filter.xml | 3 +- .../main/res/layout/dialog_delete_image.xml | 1 - .../main/res/layout/dialog_edit_or_delete.xml | 1 - app/src/main/res/layout/dialog_filter.xml | 1 - app/src/main/res/values/styles.xml | 8 - 14 files changed, 187 insertions(+), 131 deletions(-) rename app/src/main/java/app/marcdev/earworm/{uicomponents/RoundedBottomDialogFragment.kt => internal/base/EarwormBottomSheetDialogFragment.kt} (77%) create mode 100644 app/src/main/java/app/marcdev/earworm/internal/base/EarwormDialogFragment.kt create mode 100644 app/src/main/java/app/marcdev/earworm/uicomponents/FilterDatePickerDialog.kt diff --git a/app/src/main/java/app/marcdev/earworm/MainActivity.kt b/app/src/main/java/app/marcdev/earworm/MainActivity.kt index 6104173..2f3d3de 100644 --- a/app/src/main/java/app/marcdev/earworm/MainActivity.kt +++ b/app/src/main/java/app/marcdev/earworm/MainActivity.kt @@ -16,18 +16,14 @@ class MainActivity : AppCompatActivity() { private var activityTheme: Int = -1 override fun onCreate(savedInstanceState: Bundle?) { - Timber.d("Log: onCreate: Started") - /* Theme changes must be done before super.onCreate otherwise it will be overridden with the value in the manifest */ - if(getTheme(applicationContext) == DARK_THEME) { - Timber.v("Log: onCreate: Is dark mode") + activityTheme = if(getTheme(applicationContext) == DARK_THEME) { setTheme(R.style.Earworm_DarkTheme) - activityTheme = DARK_THEME + DARK_THEME } else { - Timber.v("Log: onCreate: Is not dark mode") setTheme(R.style.Earworm_LightTheme) - activityTheme = LIGHT_THEME + LIGHT_THEME } super.onCreate(savedInstanceState) @@ -39,12 +35,10 @@ class MainActivity : AppCompatActivity() { } private fun bindViews() { - Timber.v("Log: bindViews: Started") this.mainFrame = findViewById(R.id.frame_main) } private fun setDefaultFragment() { - Timber.v("Log: setDefaultFragment: Started") val fragment = MainFragment() if(intent.action == "app.marcdev.earworm.intent.ADD_ITEM") { @@ -60,7 +54,6 @@ class MainActivity : AppCompatActivity() { override fun onResume() { super.onResume() if(getTheme(applicationContext) != activityTheme) { - Timber.d("Log: onResume: Theme was changed, recreating activity") recreate() } } diff --git a/app/src/main/java/app/marcdev/earworm/additem/AddItemBottomSheet.kt b/app/src/main/java/app/marcdev/earworm/additem/AddItemBottomSheet.kt index 53af662..a574f57 100644 --- a/app/src/main/java/app/marcdev/earworm/additem/AddItemBottomSheet.kt +++ b/app/src/main/java/app/marcdev/earworm/additem/AddItemBottomSheet.kt @@ -20,7 +20,7 @@ import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import app.marcdev.earworm.R import app.marcdev.earworm.data.database.FavouriteItem -import app.marcdev.earworm.uicomponents.RoundedBottomDialogFragment +import app.marcdev.earworm.internal.base.EarwormBottomSheetDialogFragment import app.marcdev.earworm.utils.* import com.bumptech.glide.Glide import com.bumptech.glide.request.RequestOptions @@ -31,7 +31,7 @@ import droidninja.filepicker.FilePickerConst import timber.log.Timber import java.util.* -class AddItemBottomSheet : RoundedBottomDialogFragment(), AddItemView { +class AddItemBottomSheet : EarwormBottomSheetDialogFragment(), AddItemView { private lateinit var saveButton: MaterialButton private lateinit var primaryInput: EditText diff --git a/app/src/main/java/app/marcdev/earworm/uicomponents/RoundedBottomDialogFragment.kt b/app/src/main/java/app/marcdev/earworm/internal/base/EarwormBottomSheetDialogFragment.kt similarity index 77% rename from app/src/main/java/app/marcdev/earworm/uicomponents/RoundedBottomDialogFragment.kt rename to app/src/main/java/app/marcdev/earworm/internal/base/EarwormBottomSheetDialogFragment.kt index f8eb9c1..9f00774 100644 --- a/app/src/main/java/app/marcdev/earworm/uicomponents/RoundedBottomDialogFragment.kt +++ b/app/src/main/java/app/marcdev/earworm/internal/base/EarwormBottomSheetDialogFragment.kt @@ -1,4 +1,4 @@ -package app.marcdev.earworm.uicomponents +package app.marcdev.earworm.internal.base import android.app.Dialog import android.os.Bundle @@ -6,7 +6,7 @@ import app.marcdev.earworm.R import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialogFragment -open class RoundedBottomDialogFragment : BottomSheetDialogFragment() { +abstract class EarwormBottomSheetDialogFragment : BottomSheetDialogFragment() { override fun getTheme(): Int { return R.style.Earworm_BottomSheetDialogTheme diff --git a/app/src/main/java/app/marcdev/earworm/internal/base/EarwormDialogFragment.kt b/app/src/main/java/app/marcdev/earworm/internal/base/EarwormDialogFragment.kt new file mode 100644 index 0000000..d6b545e --- /dev/null +++ b/app/src/main/java/app/marcdev/earworm/internal/base/EarwormDialogFragment.kt @@ -0,0 +1,11 @@ +package app.marcdev.earworm.internal.base + +import androidx.fragment.app.DialogFragment +import app.marcdev.earworm.R + +abstract class EarwormDialogFragment: DialogFragment() { + override fun onStart() { + super.onStart() + requireDialog().window?.setBackgroundDrawableResource(R.drawable.rounded_dialog_background) + } +} \ No newline at end of file diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragment.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragment.kt index 7b8e166..f43c04a 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragment.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragment.kt @@ -104,7 +104,7 @@ class MainFragment : Fragment(), KodeinAware { val nestedScrollView: NestedScrollView = view.findViewById(R.id.scroll_main) nestedScrollView.setOnScrollChangeListener(scrollViewOnScrollChangeListener) -// this.filterDialog = FilterDialog(requireActivity(), presenter) + this.filterDialog = FilterDialog(::filterOkClick) this.settingsButton = view.findViewById(R.id.img_settings) settingsButton.setOnClickListener(settingsOnClickListener) @@ -155,7 +155,7 @@ class MainFragment : Fragment(), KodeinAware { } private val filterOnClickListener = View.OnClickListener { - filterDialog.show() + filterDialog.show(requireFragmentManager(), "Filter Dialog") } private var scrollViewOnScrollChangeListener = { _: View, _: Int, scrollY: Int, _: Int, oldScrollY: Int -> hideFabOnScroll(scrollY, oldScrollY) } @@ -168,6 +168,10 @@ class MainFragment : Fragment(), KodeinAware { } } + private fun filterOkClick(filter: ItemFilter) { + viewModel.applyFilter(filter) + } + private fun setupRecycler(view: View) { val recycler: RecyclerView = view.findViewById(R.id.recycler_main) this.recyclerAdapter = MainRecyclerAdapter(requireContext(), ::editClick, ::deleteClick) diff --git a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewModel.kt b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewModel.kt index 696abff..98864b5 100644 --- a/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewModel.kt +++ b/app/src/main/java/app/marcdev/earworm/mainscreen/MainFragmentViewModel.kt @@ -5,6 +5,7 @@ import app.marcdev.earworm.data.database.FavouriteItem import app.marcdev.earworm.data.repository.FavouriteItemRepository import app.marcdev.earworm.utils.* import kotlinx.coroutines.launch +import timber.log.Timber class MainFragmentViewModel(private val repository: FavouriteItemRepository, private val fileUtils: FileUtils) @@ -100,6 +101,25 @@ class MainFragmentViewModel(private val repository: FavouriteItemRepository, activeFilter.value = newFilter } + fun applyFilter(filter: ItemFilter) { + val newFilter: ItemFilter? = if(activeFilter.value == null) + DEFAULT_FILTER.copy() + else + activeFilter.value + if(newFilter != null) { + newFilter.endDay = filter.endDay + newFilter.endMonth = filter.endMonth + newFilter.endYear = filter.endYear + newFilter.startDay = filter.startDay + newFilter.startMonth = filter.startMonth + newFilter.startYear = filter.startYear + newFilter.includeAlbums = filter.includeAlbums + newFilter.includeArtists = filter.includeArtists + newFilter.includeSongs = filter.includeSongs + } + activeFilter.value = newFilter + } + private suspend fun deleteImageIfNecessary(imageName: String) { if(imageName.isNotBlank()) { val uses = repository.countUsesOfImage(imageName) diff --git a/app/src/main/java/app/marcdev/earworm/uicomponents/FilterDatePickerDialog.kt b/app/src/main/java/app/marcdev/earworm/uicomponents/FilterDatePickerDialog.kt new file mode 100644 index 0000000..bc2b77f --- /dev/null +++ b/app/src/main/java/app/marcdev/earworm/uicomponents/FilterDatePickerDialog.kt @@ -0,0 +1,74 @@ +package app.marcdev.earworm.uicomponents + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.DatePicker +import app.marcdev.earworm.R +import app.marcdev.earworm.internal.base.EarwormDialogFragment +import app.marcdev.earworm.utils.DEFAULT_FILTER +import com.google.android.material.button.MaterialButton +import java.util.* + +class FilterDatePickerDialog(private val okClick: (Int, Int, Int) -> Unit, + private val isStart: Boolean, + private val calendar: Calendar?) + : EarwormDialogFragment() { + + // + private lateinit var datePicker: DatePicker + private lateinit var cancelButton: MaterialButton + private lateinit var okButton: MaterialButton + private lateinit var startEndButton: MaterialButton + // + + private val day: Int + get() = datePicker.dayOfMonth + private val month: Int + get() = datePicker.month + private val year: Int + get() = datePicker.year + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + val view = inflater.inflate(R.layout.dialog_datepicker_filter, container, false) + bindViews(view) + setDate() + return view + } + + private fun bindViews(view: View) { + datePicker = view.findViewById(R.id.datepicker_filter) + cancelButton = view.findViewById(R.id.btn_datepicker_filter_cancel) + cancelButton.setOnClickListener { dismiss() } + okButton = view.findViewById(R.id.btn_datepicker_filter_ok) + okButton.setOnClickListener { + okClick(day, month, year) + } + startEndButton = view.findViewById(R.id.btn_datepicker_filter_start_end) + startEndButton.setOnClickListener { + if(isStart) { + okClick(DEFAULT_FILTER.startDay, DEFAULT_FILTER.startMonth, DEFAULT_FILTER.startYear) + } else { + okClick(DEFAULT_FILTER.endDay, DEFAULT_FILTER.endMonth, DEFAULT_FILTER.endYear) + } + resetDate() + } + + if(isStart) + startEndButton.text = resources.getString(R.string.start) + else + startEndButton.text = resources.getString(R.string.end) + } + + private fun resetDate() { + val today = Calendar.getInstance() + datePicker.updateDate(today.get(Calendar.YEAR), today.get(Calendar.MONTH), today.get(Calendar.DAY_OF_MONTH)) + } + + private fun setDate() { + calendar?.let { calendar -> + datePicker.updateDate(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH)) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/app/marcdev/earworm/uicomponents/FilterDialog.kt b/app/src/main/java/app/marcdev/earworm/uicomponents/FilterDialog.kt index 7b55fbb..76fd843 100644 --- a/app/src/main/java/app/marcdev/earworm/uicomponents/FilterDialog.kt +++ b/app/src/main/java/app/marcdev/earworm/uicomponents/FilterDialog.kt @@ -1,160 +1,127 @@ package app.marcdev.earworm.uicomponents -import android.app.Dialog -import android.content.Context -import android.graphics.Color -import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup import android.widget.CheckBox import android.widget.CompoundButton -import android.widget.DatePicker import app.marcdev.earworm.R +import app.marcdev.earworm.internal.base.EarwormDialogFragment import app.marcdev.earworm.utils.DEFAULT_FILTER import app.marcdev.earworm.utils.ItemFilter import app.marcdev.earworm.utils.formatDateForDisplay import com.google.android.material.button.MaterialButton import com.google.android.material.chip.Chip -import timber.log.Timber import java.util.* -class FilterDialog(context: Context) : Dialog(context) { +class FilterDialog(private val okClick: (ItemFilter) -> Unit) : EarwormDialogFragment() { private lateinit var displaySongCheckbox: CheckBox private lateinit var displayAlbumCheckbox: CheckBox private lateinit var displayArtistCheckbox: CheckBox private lateinit var startDateDisplay: Chip private lateinit var endDateDisplay: Chip - private lateinit var startDatePickerDialog: Dialog - private lateinit var endDatePickerDialog: Dialog - var activeFilter: ItemFilter = DEFAULT_FILTER.copy() - - init { - Timber.d("Log: FilterDialog Init: Started") - setContentView(R.layout.dialog_filter) - window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) - bindViews() + private lateinit var startDatePickerDialog: FilterDatePickerDialog + private lateinit var endDatePickerDialog: FilterDatePickerDialog + private var activeFilter: ItemFilter = DEFAULT_FILTER.copy() + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + val view = inflater.inflate(R.layout.dialog_filter, container, false) + bindViews(view) initCheckboxes() + return view } - private fun bindViews() { - Timber.d("Log: bindViews: Started") - - initStartDatePickerDialog() - initEndDatePickerDialog() - - this.startDateDisplay = findViewById(R.id.chip_filter_start) + private fun bindViews(view: View) { + startDateDisplay = view.findViewById(R.id.chip_filter_start) startDateDisplay.setOnClickListener { - Timber.d("Log: startDateClickListener: Started") - startDatePickerDialog.show() + startDatePickerDialog.show(requireFragmentManager(), "Start Date Picker") } - this.endDateDisplay = findViewById(R.id.chip_filter_end) + this.endDateDisplay = view.findViewById(R.id.chip_filter_end) endDateDisplay.setOnClickListener { - Timber.d("Log: endDateClickListener: Started") - endDatePickerDialog.show() + endDatePickerDialog.show(requireFragmentManager(), "End Date Picker") } - this.displaySongCheckbox = findViewById(R.id.chk_filter_song) + this.displaySongCheckbox = view.findViewById(R.id.chk_filter_song) displaySongCheckbox.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean -> activeFilter.includeSongs = isChecked } - this.displayAlbumCheckbox = findViewById(R.id.chk_filter_album) + this.displayAlbumCheckbox = view.findViewById(R.id.chk_filter_album) displayAlbumCheckbox.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean -> activeFilter.includeAlbums = isChecked } - this.displayArtistCheckbox = findViewById(R.id.chk_filter_artist) + this.displayArtistCheckbox = view.findViewById(R.id.chk_filter_artist) displayArtistCheckbox.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean -> activeFilter.includeArtists = isChecked } - val submitButton: MaterialButton = findViewById(R.id.btn_filter_ok) + val submitButton: MaterialButton = view.findViewById(R.id.btn_filter_ok) submitButton.setOnClickListener { - Timber.d("Log: submitButtonOnClickListener: Started") -// presenter.getAllItems(activeFilter) + okClick(activeFilter) dismiss() } + + initStartDatePickerDialog() + initEndDatePickerDialog() } private fun initStartDatePickerDialog() { - Timber.d("Log: initStartDatePickerDialog: Started") - - this.startDatePickerDialog = Dialog(context) - startDatePickerDialog.setContentView(R.layout.dialog_datepicker_filter) - startDatePickerDialog.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) - - val datePicker: DatePicker = startDatePickerDialog.findViewById(R.id.datepicker_filter) - - val cancelButton: MaterialButton = startDatePickerDialog.findViewById(R.id.btn_datepicker_filter_cancel) - cancelButton.setOnClickListener { - Timber.d("Log: cancelButtonOnClickListener: Started") - startDatePickerDialog.dismiss() - } - - val okButton: MaterialButton = startDatePickerDialog.findViewById(R.id.btn_datepicker_filter_ok) - okButton.setOnClickListener { - Timber.d("Log: okButtonOnClickListener: Started") - activeFilter.startDay = datePicker.dayOfMonth - activeFilter.startMonth = datePicker.month - activeFilter.startYear = datePicker.year - startDateDisplay.text = formatDateForDisplay(datePicker.dayOfMonth, datePicker.month, datePicker.year) - startDatePickerDialog.dismiss() - } - - val startButton: MaterialButton = startDatePickerDialog.findViewById(R.id.btn_datepicker_filter_start_end) - startButton.setOnClickListener { - Timber.d("Log: startButtonOnClickListener: Started") - activeFilter.startDay = DEFAULT_FILTER.startDay - activeFilter.startMonth = DEFAULT_FILTER.startMonth - activeFilter.startYear = DEFAULT_FILTER.startYear - startDateDisplay.text = context.resources.getString(R.string.start) - val todayCalendar = Calendar.getInstance() - datePicker.updateDate(todayCalendar.get(Calendar.YEAR), todayCalendar.get(Calendar.MONTH), todayCalendar.get(Calendar.DAY_OF_MONTH)) - startDatePickerDialog.dismiss() + if(activeFilter.startDay == DEFAULT_FILTER.startDay && activeFilter.startMonth == DEFAULT_FILTER.startMonth && activeFilter.startYear == DEFAULT_FILTER.startYear) { + startDateDisplay.text = resources.getString(R.string.start) + this.startDatePickerDialog = FilterDatePickerDialog(::startDatePickerOkClick, true, null) + } else { + startDateDisplay.text = formatDateForDisplay(activeFilter.startDay, activeFilter.startMonth, activeFilter.startYear) + val calendar = Calendar.getInstance() + calendar.set(Calendar.DAY_OF_MONTH, activeFilter.startDay) + calendar.set(Calendar.MONTH, activeFilter.startMonth) + calendar.set(Calendar.YEAR, activeFilter.startYear) + this.startDatePickerDialog = FilterDatePickerDialog(::startDatePickerOkClick, true, calendar) } } private fun initEndDatePickerDialog() { - Timber.d("Log: initEndDatePickerDialog: Started") - - this.endDatePickerDialog = Dialog(context) - endDatePickerDialog.setContentView(R.layout.dialog_datepicker_filter) - endDatePickerDialog.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) - - val datePicker: DatePicker = endDatePickerDialog.findViewById(R.id.datepicker_filter) - - val cancelButton: MaterialButton = endDatePickerDialog.findViewById(R.id.btn_datepicker_filter_cancel) - cancelButton.setOnClickListener { - Timber.d("Log: cancelButtonOnClickListener: Started") - endDatePickerDialog.dismiss() + if(activeFilter.endDay == DEFAULT_FILTER.endDay && activeFilter.endMonth == DEFAULT_FILTER.endMonth && activeFilter.endYear == DEFAULT_FILTER.endYear) { + endDateDisplay.text = resources.getString(R.string.end) + this.endDatePickerDialog = FilterDatePickerDialog(::endDatePickerOkClick, false, null) + } else { + endDateDisplay.text = formatDateForDisplay(activeFilter.endDay, activeFilter.endMonth, activeFilter.endYear) + val calendar = Calendar.getInstance() + calendar.set(Calendar.DAY_OF_MONTH, activeFilter.endDay) + calendar.set(Calendar.MONTH, activeFilter.endMonth) + calendar.set(Calendar.YEAR, activeFilter.endYear) + this.endDatePickerDialog = FilterDatePickerDialog(::endDatePickerOkClick, false, calendar) } + } - val okButton: MaterialButton = endDatePickerDialog.findViewById(R.id.btn_datepicker_filter_ok) - okButton.setOnClickListener { - Timber.d("Log: okButtonOnClickListener: Started") - activeFilter.endDay = datePicker.dayOfMonth - activeFilter.endMonth = datePicker.month - activeFilter.endYear = datePicker.year - endDateDisplay.text = formatDateForDisplay(datePicker.dayOfMonth, datePicker.month, datePicker.year) - endDatePickerDialog.dismiss() + private fun startDatePickerOkClick(day: Int, month: Int, year: Int) { + activeFilter.startDay = day + activeFilter.startMonth = month + activeFilter.startYear = year + if(day == DEFAULT_FILTER.startDay && month == DEFAULT_FILTER.startMonth && year == DEFAULT_FILTER.startYear) { + startDateDisplay.text = resources.getString(R.string.start) + } else { + startDateDisplay.text = formatDateForDisplay(activeFilter.startDay, activeFilter.startMonth, activeFilter.startYear) } + startDatePickerDialog.dismiss() + } - val endButton: MaterialButton = endDatePickerDialog.findViewById(R.id.btn_datepicker_filter_start_end) - endButton.text = context.resources.getString(R.string.end) - endButton.setOnClickListener { - Timber.d("Log: startButtonOnClickListener: Started") - activeFilter.endDay = DEFAULT_FILTER.endDay - activeFilter.endMonth = DEFAULT_FILTER.endMonth - activeFilter.endYear = DEFAULT_FILTER.endYear - endDateDisplay.text = context.resources.getString(R.string.end) - val todayCalendar = Calendar.getInstance() - datePicker.updateDate(todayCalendar.get(Calendar.YEAR), todayCalendar.get(Calendar.MONTH), todayCalendar.get(Calendar.DAY_OF_MONTH)) - endDatePickerDialog.dismiss() + private fun endDatePickerOkClick(day: Int, month: Int, year: Int) { + activeFilter.endDay = day + activeFilter.endMonth = month + activeFilter.endYear = year + if(day == DEFAULT_FILTER.endDay && month == DEFAULT_FILTER.endMonth && year == DEFAULT_FILTER.endYear) { + endDateDisplay.text = resources.getString(R.string.end) + } else { + endDateDisplay.text = formatDateForDisplay(activeFilter.endDay, activeFilter.endMonth, activeFilter.endYear) } + endDatePickerDialog.dismiss() } private fun initCheckboxes() { - Timber.d("Log: initCheckboxes: Started") displaySongCheckbox.isChecked = activeFilter.includeSongs displayAlbumCheckbox.isChecked = activeFilter.includeAlbums displayArtistCheckbox.isChecked = activeFilter.includeArtists diff --git a/app/src/main/res/layout/dialog_datepicker.xml b/app/src/main/res/layout/dialog_datepicker.xml index b91904d..e908d2b 100644 --- a/app/src/main/res/layout/dialog_datepicker.xml +++ b/app/src/main/res/layout/dialog_datepicker.xml @@ -2,8 +2,7 @@ + xmlns:app="http://schemas.android.com/apk/res-auto"> + xmlns:app="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/layout/dialog_edit_or_delete.xml b/app/src/main/res/layout/dialog_edit_or_delete.xml index 3482b10..d8615c9 100644 --- a/app/src/main/res/layout/dialog_edit_or_delete.xml +++ b/app/src/main/res/layout/dialog_edit_or_delete.xml @@ -1,7 +1,6 @@ diff --git a/app/src/main/res/layout/dialog_filter.xml b/app/src/main/res/layout/dialog_filter.xml index 8eeddb0..12148d0 100644 --- a/app/src/main/res/layout/dialog_filter.xml +++ b/app/src/main/res/layout/dialog_filter.xml @@ -1,7 +1,6 @@ diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 534022c..2894833 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -103,14 +103,6 @@ ?attr/bottomSheetBackground - -