From d4e64018d24f26f51297becabc6921f5217f86b0 Mon Sep 17 00:00:00 2001 From: denizk0461 Date: Sun, 14 May 2023 13:10:47 +0200 Subject: [PATCH] Refactored preference functions so that view models cannot access preferences directly, instead having to use get/set methods, which also solves a potential bug source of defining different default values for certain properties in different view models --- .../denizk0461/weserplaner/data/StwParser.kt | 2 +- .../weserplaner/db/AppRepository.kt | 185 +++++++++++++++--- .../viewmodel/AllergenConfigViewModel.kt | 8 +- .../viewmodel/CanteenPageViewModel.kt | 10 +- .../weserplaner/viewmodel/CanteenViewModel.kt | 8 +- .../viewmodel/EventPageViewModel.kt | 6 +- .../weserplaner/viewmodel/EventViewModel.kt | 13 +- .../weserplaner/viewmodel/MainViewModel.kt | 3 +- .../viewmodel/SettingsViewModel.kt | 46 ++--- app/src/main/res/layout/fragment_canteen.xml | 4 +- app/src/main/res/layout/fragment_settings.xml | 4 +- 11 files changed, 199 insertions(+), 90 deletions(-) diff --git a/app/src/main/java/com/denizk0461/weserplaner/data/StwParser.kt b/app/src/main/java/com/denizk0461/weserplaner/data/StwParser.kt index 49f5216..e9573d5 100644 --- a/app/src/main/java/com/denizk0461/weserplaner/data/StwParser.kt +++ b/app/src/main/java/com/denizk0461/weserplaner/data/StwParser.kt @@ -198,7 +198,7 @@ class StwParser(application: Application) { * * Hence, getIntPreference() + 2 */ - repo.getIntPreference(SettingsPreferences.PRICING) + 2 + repo.getPreferencePricing() + 2 ), dietaryPreferences = prefs.deconstruct(), allergens = filteredText.second, diff --git a/app/src/main/java/com/denizk0461/weserplaner/db/AppRepository.kt b/app/src/main/java/com/denizk0461/weserplaner/db/AppRepository.kt index ab48ed4..d6120a4 100644 --- a/app/src/main/java/com/denizk0461/weserplaner/db/AppRepository.kt +++ b/app/src/main/java/com/denizk0461/weserplaner/db/AppRepository.kt @@ -46,7 +46,9 @@ class AppRepository(app: Application) { */ fun getRepositoryInstance(app: Application): AppRepository { if (!::repo.isInitialized) { - repo = AppRepository(app) + synchronized(Object::class.java) { + repo = AppRepository(app) + } } return repo } @@ -251,7 +253,144 @@ class AppRepository(app: Application) { */ fun insertItems(items: List) { dao.insertItems(items) } - // --- settings preferences --- // + // --- user-set preferences --- // + + /** + * This value determines which allergens the user wants to have displayed or hidden. + */ + fun getPreferenceAllergenConfig(): String = getStringPreference( + SettingsPreferences.ALLERGEN_CONFIG, + defaultValue = AllergenPreferences.TEMPLATE, + ) + /** + * This value determines how many allergens the user wants to have displayed or hidden. + */ + fun getPreferenceAllergenConfigCount(): Int = getPreferenceAllergenConfig().run { + if (isBlank()) 0 else split(",").count() + } + fun setPreferenceAllergenConfig(newValue: String) { + setPreference(SettingsPreferences.ALLERGEN_CONFIG, newValue) + } + + /** + * This value determines whether the user wants to have allergens marked. + */ + fun getPreferenceAllergen(): Boolean = getBooleanPreference( + SettingsPreferences.ALLERGEN, + defaultValue = true, + ) + fun setPreferenceAllergen(newValue: Boolean) { + setPreference(SettingsPreferences.ALLERGEN, newValue) + } + + /** + * This value determines which canteen the user has selected. + */ + fun getPreferenceColour(): Boolean = getBooleanPreference( + SettingsPreferences.COLOUR_PREFS, + defaultValue = true, + ) + fun setPreferenceColour(newValue: Boolean) { + setPreference(SettingsPreferences.COLOUR_PREFS, newValue) + } + + /** + * This value determines which canteen the user has selected. + */ + fun getPreferenceCanteen(): Int = getIntPreference( + SettingsPreferences.CANTEEN, + ) + fun setPreferenceCanteen(newValue: Int) { + setPreference(SettingsPreferences.CANTEEN, newValue) + } + + /** + * This value determines whether the user has opened the canteen fragment before. + */ + fun getPreferenceHasOpenedCanteen(): Boolean = getBooleanPreference( + SettingsPreferences.HAS_OPENED_CANTEEN, + ) + fun setPreferenceHasOpenedCanteen(newValue: Boolean) { + setPreference(SettingsPreferences.HAS_OPENED_CANTEEN, newValue) + } + + /** + * This value determines whether the user wants to have the next course in their schedule + * highlighted. + */ + fun getPreferenceCourseHighlighting(): Boolean = getBooleanPreference( + SettingsPreferences.COURSE_HIGHLIGHTING, + defaultValue = true, + ) + fun setPreferenceCourseHighlighting(newValue: Boolean) { + setPreference(SettingsPreferences.COURSE_HIGHLIGHTING, newValue) + } + + /** + * This value determines whether the user wants their timetable to launch with the current day. + */ + fun getPreferenceCurrentDay(): Boolean = getBooleanPreference( + SettingsPreferences.CURRENT_DAY, + defaultValue = true, + ) + fun setPreferenceCurrentDay(newValue: Boolean) { + setPreference(SettingsPreferences.CURRENT_DAY, newValue) + } + + /** + * Determines whether the user is launching the app for the first time. + */ + fun getPreferenceFirstLaunch(): Boolean = getBooleanPreference( + SettingsPreferences.FIRST_LAUNCH, + defaultValue = true, + ) + fun setPreferenceFirstLaunch(newValue: Boolean) { + setPreference(SettingsPreferences.FIRST_LAUNCH, newValue) + } + + /** + * This value determines which fragment the user wants the app to start with. Order is equal to + * the order that the items are arranged in in the bottom nav bar. + */ + fun getPreferenceLaunchFragment(): Int = getIntPreference( + SettingsPreferences.LAUNCH_FRAGMENT_ON_START, + ) + fun setPreferenceLaunchFragment(newValue: Int) { + setPreference(SettingsPreferences.LAUNCH_FRAGMENT_ON_START, newValue) + } + + /** + * This value determines which fragment the user wants the app to start with. Order is equal to + * the order that the items are arranged in in the bottom nav bar. + */ + fun getPreferencePricing(): Int = getIntPreference( + SettingsPreferences.PRICING, + ) + fun setPreferencePricing(newValue: Int) { + setPreference(SettingsPreferences.PRICING, newValue) + } + + /** + * This value determines whether the user opts into submitting crash reports. + */ + fun getPreferenceDataHandling(): Boolean = getBooleanPreference( + SettingsPreferences.DATA_HANDLING, + ) + fun setPreferenceDataHandling(newValue: Boolean) { + setPreference(SettingsPreferences.DATA_HANDLING, newValue) + } + + /** + * This value determines whether the user has enabled experimental settings. + */ + fun getPreferenceExperimentalSettingsEnabled(): Boolean = getBooleanPreference( + SettingsPreferences.EXPERIMENTAL_ENABLED, + ) + fun setPreferenceExperimentalSettingsEnabled(newValue: Boolean) { + setPreference(SettingsPreferences.EXPERIMENTAL_ENABLED, newValue) + } + + // --- private preference handlers preferences --- // /** * Retrieves a user-set boolean preference. @@ -259,53 +398,53 @@ class AppRepository(app: Application) { * @param pref preference to retrieve * @return whether the user set this preference */ - fun getBooleanPreference(pref: SettingsPreferences, defaultValue: Boolean = false): Boolean = + private fun getBooleanPreference(pref: SettingsPreferences, defaultValue: Boolean = false): Boolean = prefs.getBoolean(pref.key, defaultValue) - /** - * Retrieves a user-set string preference. - * - * @param pref preference to retrieve - * @return string that was set - */ - fun getStringPreference(pref: SettingsPreferences, defaultValue: String = ""): String = - prefs.getString(pref.key, defaultValue) ?: "" - - /** - * Retrieves a user-set integer preference. - * - * @param pref preference to retrieve - * @return whether the user set this preference - */ - fun getIntPreference(pref: SettingsPreferences): Int = prefs.getInt(pref.key, 0) - /** * Updates a user-set boolean preference. * * @param pref preference to set * @param newValue new value to set the preference to */ - fun setPreference(pref: SettingsPreferences, newValue: Boolean) { + private fun setPreference(pref: SettingsPreferences, newValue: Boolean) { prefs.edit().putBoolean(pref.key, newValue).apply() } + /** + * Retrieves a user-set string preference. + * + * @param pref preference to retrieve + * @return string that was set + */ + private fun getStringPreference(pref: SettingsPreferences, defaultValue: String = ""): String = + prefs.getString(pref.key, defaultValue) ?: "" + /** * Updates a user-set string preference. * * @param pref preference to set * @param newValue new value to set the preference to */ - fun setPreference(pref: SettingsPreferences, newValue: String) { + private fun setPreference(pref: SettingsPreferences, newValue: String) { prefs.edit().putString(pref.key, newValue).apply() } + /** + * Retrieves a user-set integer preference. + * + * @param pref preference to retrieve + * @return whether the user set this preference + */ + private fun getIntPreference(pref: SettingsPreferences): Int = prefs.getInt(pref.key, 0) + /** * Updates a user-set integer preference. * * @param pref preference to set * @param newValue new value to set the preference to */ - fun setPreference(pref: SettingsPreferences, newValue: Int) { + private fun setPreference(pref: SettingsPreferences, newValue: Int) { prefs.edit().putInt(pref.key, newValue).apply() } } \ No newline at end of file diff --git a/app/src/main/java/com/denizk0461/weserplaner/viewmodel/AllergenConfigViewModel.kt b/app/src/main/java/com/denizk0461/weserplaner/viewmodel/AllergenConfigViewModel.kt index d36d06d..9d7e8a0 100644 --- a/app/src/main/java/com/denizk0461/weserplaner/viewmodel/AllergenConfigViewModel.kt +++ b/app/src/main/java/com/denizk0461/weserplaner/viewmodel/AllergenConfigViewModel.kt @@ -1,8 +1,6 @@ package com.denizk0461.weserplaner.viewmodel import android.app.Application -import com.denizk0461.weserplaner.model.AllergenPreferences -import com.denizk0461.weserplaner.model.SettingsPreferences class AllergenConfigViewModel(application: Application) : AppViewModel(application) { @@ -10,8 +8,6 @@ class AllergenConfigViewModel(application: Application) : AppViewModel(applicati * This value determines which allergens the user wants to have displayed or hidden. */ var preferenceAllergenConfig: String - get() = repo.getStringPreference( - SettingsPreferences.ALLERGEN_CONFIG, defaultValue = AllergenPreferences.TEMPLATE - ) - set(newValue) { repo.setPreference(SettingsPreferences.ALLERGEN_CONFIG, newValue) } + get() = repo.getPreferenceAllergenConfig() + set(value) { repo.setPreferenceAllergenConfig(value) } } \ No newline at end of file diff --git a/app/src/main/java/com/denizk0461/weserplaner/viewmodel/CanteenPageViewModel.kt b/app/src/main/java/com/denizk0461/weserplaner/viewmodel/CanteenPageViewModel.kt index 7431409..f87f851 100644 --- a/app/src/main/java/com/denizk0461/weserplaner/viewmodel/CanteenPageViewModel.kt +++ b/app/src/main/java/com/denizk0461/weserplaner/viewmodel/CanteenPageViewModel.kt @@ -2,10 +2,8 @@ package com.denizk0461.weserplaner.viewmodel import android.app.Application import androidx.lifecycle.LiveData -import com.denizk0461.weserplaner.model.AllergenPreferences import com.denizk0461.weserplaner.model.CanteenOffer import com.denizk0461.weserplaner.model.DietaryPreferences -import com.denizk0461.weserplaner.model.SettingsPreferences class CanteenPageViewModel(app: Application) : AppViewModel(app) { @@ -33,19 +31,17 @@ class CanteenPageViewModel(app: Application) : AppViewModel(app) { * This value determines which allergens the user wants to have displayed or hidden. */ val preferenceAllergenConfig: String - get() = repo.getStringPreference( - SettingsPreferences.ALLERGEN_CONFIG, defaultValue = AllergenPreferences.TEMPLATE - ) + get() = repo.getPreferenceAllergenConfig() /** * This value determines whether the user wants to have allergens marked. */ val preferenceAllergen: Boolean - get() = repo.getBooleanPreference(SettingsPreferences.ALLERGEN, defaultValue = true) + get() = repo.getPreferenceAllergen() /** * This value determines which canteen the user has selected. */ val preferenceColour: Boolean - get() = repo.getBooleanPreference(SettingsPreferences.COLOUR_PREFS, defaultValue = true) + get() = repo.getPreferenceColour() } \ No newline at end of file diff --git a/app/src/main/java/com/denizk0461/weserplaner/viewmodel/CanteenViewModel.kt b/app/src/main/java/com/denizk0461/weserplaner/viewmodel/CanteenViewModel.kt index c69b3c4..c01cbd0 100644 --- a/app/src/main/java/com/denizk0461/weserplaner/viewmodel/CanteenViewModel.kt +++ b/app/src/main/java/com/denizk0461/weserplaner/viewmodel/CanteenViewModel.kt @@ -78,13 +78,13 @@ class CanteenViewModel(app: Application) : AppViewModel(app) { * This value determines which canteen the user has selected. */ var preferenceCanteen: Int - get() = repo.getIntPreference(SettingsPreferences.CANTEEN) - set(newValue) { repo.setPreference(SettingsPreferences.CANTEEN, newValue) } + get() = repo.getPreferenceCanteen() + set(newValue) { repo.setPreferenceCanteen(newValue) } /** * This value determines whether the user has opened the canteen fragment before. */ var preferenceHasOpenedCanteen: Boolean - get() = repo.getBooleanPreference(SettingsPreferences.HAS_OPENED_CANTEEN) - set(newValue) { repo.setPreference(SettingsPreferences.HAS_OPENED_CANTEEN, newValue) } + get() = repo.getPreferenceHasOpenedCanteen() + set(newValue) { repo.setPreferenceHasOpenedCanteen(newValue) } } \ No newline at end of file diff --git a/app/src/main/java/com/denizk0461/weserplaner/viewmodel/EventPageViewModel.kt b/app/src/main/java/com/denizk0461/weserplaner/viewmodel/EventPageViewModel.kt index 1a0300b..8089953 100644 --- a/app/src/main/java/com/denizk0461/weserplaner/viewmodel/EventPageViewModel.kt +++ b/app/src/main/java/com/denizk0461/weserplaner/viewmodel/EventPageViewModel.kt @@ -2,7 +2,6 @@ package com.denizk0461.weserplaner.viewmodel import android.app.Application import androidx.lifecycle.LiveData -import com.denizk0461.weserplaner.model.SettingsPreferences import com.denizk0461.weserplaner.model.StudIPEvent /** @@ -24,8 +23,5 @@ class EventPageViewModel(app: Application) : AppViewModel(app) { * highlighted. */ val preferenceCourseHighlighting: Boolean - get() = repo.getBooleanPreference( - SettingsPreferences.COURSE_HIGHLIGHTING, - defaultValue = true - ) + get() = repo.getPreferenceCourseHighlighting() } \ No newline at end of file diff --git a/app/src/main/java/com/denizk0461/weserplaner/viewmodel/EventViewModel.kt b/app/src/main/java/com/denizk0461/weserplaner/viewmodel/EventViewModel.kt index bd95445..6e85f93 100644 --- a/app/src/main/java/com/denizk0461/weserplaner/viewmodel/EventViewModel.kt +++ b/app/src/main/java/com/denizk0461/weserplaner/viewmodel/EventViewModel.kt @@ -2,7 +2,6 @@ package com.denizk0461.weserplaner.viewmodel import android.app.Application import androidx.lifecycle.LiveData -import com.denizk0461.weserplaner.model.SettingsPreferences /** * View model for [com.denizk0461.weserplaner.fragment.EventFragment] @@ -22,18 +21,12 @@ class EventViewModel(app: Application) : AppViewModel(app) { * This value determines whether the user wants their timetable to launch with the current day. */ val preferenceCurrentDay: Boolean - get() = repo.getBooleanPreference( - SettingsPreferences.CURRENT_DAY, - defaultValue = true, - ) + get() = repo.getPreferenceCurrentDay() /** * Determines whether the user is launching the app for the first time. */ var preferenceFirstLaunch: Boolean - get() = repo.getBooleanPreference( - SettingsPreferences.FIRST_LAUNCH, - defaultValue = true, - ) - set(value) { repo.setPreference(SettingsPreferences.FIRST_LAUNCH, value) } + get() = repo.getPreferenceFirstLaunch() + set(value) { repo.setPreferenceFirstLaunch(value) } } \ No newline at end of file diff --git a/app/src/main/java/com/denizk0461/weserplaner/viewmodel/MainViewModel.kt b/app/src/main/java/com/denizk0461/weserplaner/viewmodel/MainViewModel.kt index 99793ed..d831ef3 100644 --- a/app/src/main/java/com/denizk0461/weserplaner/viewmodel/MainViewModel.kt +++ b/app/src/main/java/com/denizk0461/weserplaner/viewmodel/MainViewModel.kt @@ -1,7 +1,6 @@ package com.denizk0461.weserplaner.viewmodel import android.app.Application -import com.denizk0461.weserplaner.model.SettingsPreferences /** * View model for [com.denizk0461.weserplaner.activity.MainActivity] @@ -15,5 +14,5 @@ class MainViewModel(application: Application) : AppViewModel(application) { * the order that the items are arranged in in the bottom nav bar. */ val preferenceLaunchFragment: Int - get() = repo.getIntPreference(SettingsPreferences.LAUNCH_FRAGMENT_ON_START) + get() = repo.getPreferenceLaunchFragment() } \ No newline at end of file diff --git a/app/src/main/java/com/denizk0461/weserplaner/viewmodel/SettingsViewModel.kt b/app/src/main/java/com/denizk0461/weserplaner/viewmodel/SettingsViewModel.kt index 8bcd164..533a35c 100644 --- a/app/src/main/java/com/denizk0461/weserplaner/viewmodel/SettingsViewModel.kt +++ b/app/src/main/java/com/denizk0461/weserplaner/viewmodel/SettingsViewModel.kt @@ -1,8 +1,6 @@ package com.denizk0461.weserplaner.viewmodel import android.app.Application -import com.denizk0461.weserplaner.model.AllergenPreferences -import com.denizk0461.weserplaner.model.SettingsPreferences /** * View model for [com.denizk0461.weserplaner.fragment.SettingsFragment] @@ -15,76 +13,66 @@ class SettingsViewModel(app: Application) : AppViewModel(app) { * This value determines whether the user wants their timetable to launch with the current day. */ var preferenceCurrentDay: Boolean - get() = repo.getBooleanPreference( - SettingsPreferences.CURRENT_DAY, - defaultValue = true, - ) - set(newValue) { repo.setPreference(SettingsPreferences.CURRENT_DAY, newValue) } + get() = repo.getPreferenceCurrentDay() + set(newValue) { repo.setPreferenceCurrentDay(newValue) } /** * This value determines whether the user wants to have the next course in their schedule * highlighted. */ var preferenceCourseHighlighting: Boolean - get() = repo.getBooleanPreference( - SettingsPreferences.COURSE_HIGHLIGHTING, - defaultValue = true - ) - set(newValue) { repo.setPreference(SettingsPreferences.COURSE_HIGHLIGHTING, newValue) } + get() = repo.getPreferenceCourseHighlighting() + set(newValue) { repo.setPreferenceCourseHighlighting(newValue) } /** * This value determines whether the user wants to have allergens marked. */ var preferenceAllergen: Boolean - get() = repo.getBooleanPreference(SettingsPreferences.ALLERGEN, defaultValue = true) - set(newValue) { repo.setPreference(SettingsPreferences.ALLERGEN, newValue) } + get() = repo.getPreferenceAllergen() + set(newValue) { repo.setPreferenceAllergen(newValue) } /** * This value determines how many allergens the user wants to have displayed or hidden. */ val preferenceAllergenConfigCount: Int - get() = repo.getStringPreference( - SettingsPreferences.ALLERGEN_CONFIG, defaultValue = AllergenPreferences.TEMPLATE - ).run { - if (isBlank()) 0 else split(",").count() - } + get() = repo.getPreferenceAllergenConfigCount() /** * This value determines which fragment the user wants the app to start with. Order is equal to * the order that the items are arranged in in the bottom nav bar. */ var preferencePricing: Int - get() = repo.getIntPreference(SettingsPreferences.PRICING) - set(newValue) { repo.setPreference(SettingsPreferences.PRICING, newValue) } + get() = repo.getPreferencePricing() + set(newValue) { repo.setPreferencePricing(newValue) } /** * This value determines which fragment the user wants the app to start with. Order is equal to * the order that the items are arranged in in the bottom nav bar. */ var preferenceLaunchFragment: Int - get() = repo.getIntPreference(SettingsPreferences.LAUNCH_FRAGMENT_ON_START) - set(newValue) { repo.setPreference(SettingsPreferences.LAUNCH_FRAGMENT_ON_START, newValue) } + get() = repo.getPreferenceLaunchFragment() + set(newValue) { repo.setPreferenceLaunchFragment(newValue) } /** * This value determines which canteen the user has selected. */ var preferenceColour: Boolean - get() = repo.getBooleanPreference(SettingsPreferences.COLOUR_PREFS, defaultValue = true) - set(newValue) { repo.setPreference(SettingsPreferences.COLOUR_PREFS, newValue) } + get() = repo.getPreferenceColour() + set(newValue) { repo.setPreferenceColour(newValue) } /** * This value determines whether the user opts into submitting crash reports. */ var preferenceDataHandling: Boolean - get() = repo.getBooleanPreference(SettingsPreferences.DATA_HANDLING) - set(newValue) { repo.setPreference(SettingsPreferences.DATA_HANDLING, newValue) } + get() = repo.getPreferenceDataHandling() + set(newValue) { repo.setPreferenceDataHandling(newValue) } /** * This value determines whether the user has enabled experimental settings. */ var preferenceExperimentalSettingsEnabled: Boolean - get() = repo.getBooleanPreference(SettingsPreferences.EXPERIMENTAL_ENABLED) - set(newValue) { repo.setPreference(SettingsPreferences.EXPERIMENTAL_ENABLED, newValue) } + get() = repo.getPreferenceExperimentalSettingsEnabled() + set(newValue) { repo.setPreferenceExperimentalSettingsEnabled(newValue) } // --- functions for dev codes --- // diff --git a/app/src/main/res/layout/fragment_canteen.xml b/app/src/main/res/layout/fragment_canteen.xml index 6719631..1960263 100644 --- a/app/src/main/res/layout/fragment_canteen.xml +++ b/app/src/main/res/layout/fragment_canteen.xml @@ -20,7 +20,8 @@ + android:layout_marginStart="16dp" + android:layout_marginEnd="8dp"> + android:textSize="16sp"/> + android:textSize="16sp"/>