Cleanup settings code

Do some post-setting refactor cleanup:
- Make some extension functions for SettingsManager for convienence
- Remove dead code from before the int migration
- Update semantics here and there
This commit is contained in:
OxygenCobalt 2021-04-03 11:43:23 -06:00
parent eb56068f80
commit 2b047f0d2c
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
15 changed files with 59 additions and 84 deletions

View file

@ -2,7 +2,6 @@ package org.oxycblt.auxio.database
import android.database.Cursor import android.database.Cursor
import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.os.Looper import android.os.Looper
/** /**
@ -15,7 +14,7 @@ fun <R> SQLiteDatabase.queryAll(tableName: String, block: (Cursor) -> R) =
/** /**
* Assert that we are on a background thread. * Assert that we are on a background thread.
*/ */
fun SQLiteOpenHelper.assertBackgroundThread() { fun assertBackgroundThread() {
check(Looper.myLooper() != Looper.getMainLooper()) { check(Looper.myLooper() != Looper.getMainLooper()) {
"Database operations must be ran on a background thread." "Database operations must be ran on a background thread."
} }

View file

@ -4,7 +4,7 @@ import android.net.Uri
// --- MUSIC MODELS --- // --- MUSIC MODELS ---
// TODO: Implement some kind of hash system, removing the need to redundant names but alsow without the volitility of id // TODO: Implement some kind of hash system, removing the need to redundant names but also without the volatility of id
// They need to be completely unique, however, and from whatever information I have about them on creation // They need to be completely unique, however, and from whatever information I have about them on creation
/** /**

View file

@ -48,19 +48,5 @@ enum class PlaybackMode {
} }
} }
/**
* Get the value of a [PlaybackMode] from a string. Returns [ALL_SONGS] as a fallback.
*/
fun valueOfOrFallback(value: String?): PlaybackMode {
if (value == null) {
return ALL_SONGS
}
return try {
valueOf(value)
} catch (e: IllegalArgumentException) {
ALL_SONGS
}
}
} }
} }

View file

@ -27,6 +27,7 @@ import org.oxycblt.auxio.settings.SettingsManager
* All access should be done with [PlaybackStateManager.getInstance]. * All access should be done with [PlaybackStateManager.getInstance].
* *
* TODO: Queues should reflect sort mode * TODO: Queues should reflect sort mode
* TODO: Update loop mode to actually make sense [#13]
* @author OxygenCobalt * @author OxygenCobalt
*/ */
class PlaybackStateManager private constructor() { class PlaybackStateManager private constructor() {
@ -810,10 +811,6 @@ class PlaybackStateManager private constructor() {
companion object { companion object {
private const val REWIND_THRESHOLD = 3000L private const val REWIND_THRESHOLD = 3000L
const val AT_END_LOOP_PAUSE = 0
const val AT_END_LOOP = 1
const val AT_END_STOP = 2
@Volatile @Volatile
private var INSTANCE: PlaybackStateManager? = null private var INSTANCE: PlaybackStateManager? = null

View file

@ -45,21 +45,6 @@ enum class DisplayMode(@DrawableRes val iconRes: Int) {
const val CONST_SHOW_ALBUMS = 0xA10A const val CONST_SHOW_ALBUMS = 0xA10A
const val CONST_SHOW_SONGS = 0xA10B const val CONST_SHOW_SONGS = 0xA10B
/**
* A valueOf wrapper that will return a default value if given a null/invalid string.
*/
fun valueOfOrFallback(value: String?, fallback: DisplayMode = SHOW_ARTISTS): DisplayMode {
if (value == null) {
return fallback
}
return try {
valueOf(value)
} catch (e: IllegalArgumentException) {
fallback
}
}
fun fromId(@IdRes id: Int): DisplayMode { fun fromId(@IdRes id: Int): DisplayMode {
return when (id) { return when (id) {
R.id.option_filter_all -> SHOW_ALL R.id.option_filter_all -> SHOW_ALL

View file

@ -49,8 +49,6 @@ class AboutDialog : BottomSheetDialogFragment() {
* in [AboutDialog.Companion.LINKS]. * in [AboutDialog.Companion.LINKS].
*/ */
private fun openLinkInBrowser(link: String) { private fun openLinkInBrowser(link: String) {
check(link in LINKS) { "Invalid link." }
try { try {
val uri = link.toUri() val uri = link.toUri()
@ -84,6 +82,6 @@ class AboutDialog : BottomSheetDialogFragment() {
private const val LINK_FAQ = "$LINK_CODEBASE/blob/master/info/FAQ.md" private const val LINK_FAQ = "$LINK_CODEBASE/blob/master/info/FAQ.md"
private const val LINK_LICENSES = "$LINK_CODEBASE/blob/master/info/LICENSES.md" private const val LINK_LICENSES = "$LINK_CODEBASE/blob/master/info/LICENSES.md"
val LINKS = arrayOf(LINK_CODEBASE, LINK_FAQ, LINK_LICENSES) const val TAG = "TAG_ABOUT_DIALOG"
} }
} }

View file

@ -1,12 +1,12 @@
package org.oxycblt.auxio.settings package org.oxycblt.auxio.settings
import android.content.SharedPreferences
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
/** /**
* Convert an theme integer into an icon that can be used. * Convert an theme integer into an icon that can be used.
* @return An icon for this theme.
*/ */
@DrawableRes @DrawableRes
fun Int.toThemeIcon(): Int { fun Int.toThemeIcon(): Int {
@ -18,3 +18,19 @@ fun Int.toThemeIcon(): Int {
else -> R.drawable.ic_auto else -> R.drawable.ic_auto
} }
} }
/**
* A verbose shortcut for getString(key, null). Used during string pref migrations
*/
fun SharedPreferences.getStringOrNull(key: String): String? = getString(key, null)
/**
* Converts an int preference under [key] to [T] through a [convert] function.
* This is only intended for use for the enums with fromInt functions.
*
* NOTE: If one of your constant values uses Int.MIN_VALUE, this function may return an
* unexpected result.
*/
fun <T> SharedPreferences.getData(key: String, convert: (Int) -> T?): T? {
return convert(getInt(key, Int.MIN_VALUE))
}

View file

@ -15,12 +15,12 @@ fun handleThemeCompat(prefs: SharedPreferences): Int {
if (prefs.contains(OldKeys.KEY_THEME)) { if (prefs.contains(OldKeys.KEY_THEME)) {
// Before the creation of IntListPreference, I used strings to represent the themes. // Before the creation of IntListPreference, I used strings to represent the themes.
// I no longer need to do this. // I no longer need to do this.
val newValue = when (prefs.getString(OldKeys.KEY_THEME, EntryValues.THEME_AUTO)) { val newValue = when (prefs.getStringOrNull(OldKeys.KEY_THEME)) {
EntryValues.THEME_AUTO -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM EntryValues.THEME_AUTO -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
EntryValues.THEME_LIGHT -> AppCompatDelegate.MODE_NIGHT_NO EntryValues.THEME_LIGHT -> AppCompatDelegate.MODE_NIGHT_NO
EntryValues.THEME_DARK -> AppCompatDelegate.MODE_NIGHT_YES EntryValues.THEME_DARK -> AppCompatDelegate.MODE_NIGHT_YES
else -> error("Invalid theme") else -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
} }
prefs.edit { prefs.edit {
@ -68,9 +68,7 @@ fun handleAccentCompat(prefs: SharedPreferences): Accent {
fun handleLibDisplayCompat(prefs: SharedPreferences): DisplayMode { fun handleLibDisplayCompat(prefs: SharedPreferences): DisplayMode {
if (prefs.contains(OldKeys.KEY_LIB_MODE)) { if (prefs.contains(OldKeys.KEY_LIB_MODE)) {
val mode = handleStringDisplayMode( val mode = prefs.handleOldDisplayMode(OldKeys.KEY_LIB_MODE) ?: DisplayMode.SHOW_ARTISTS
prefs.getString(OldKeys.KEY_LIB_MODE, EntryValues.SHOW_ARTISTS),
) ?: DisplayMode.SHOW_ARTISTS
prefs.edit { prefs.edit {
putInt(SettingsManager.KEY_LIB_DISPLAY_MODE, mode.toInt()) putInt(SettingsManager.KEY_LIB_DISPLAY_MODE, mode.toInt())
@ -81,14 +79,13 @@ fun handleLibDisplayCompat(prefs: SharedPreferences): DisplayMode {
return mode return mode
} }
return DisplayMode.fromInt( return prefs.getData(SettingsManager.KEY_LIB_DISPLAY_MODE, DisplayMode::fromInt)
prefs.getInt(SettingsManager.KEY_LIB_DISPLAY_MODE, DisplayMode.CONST_SHOW_ARTISTS) ?: DisplayMode.SHOW_ARTISTS
) ?: DisplayMode.SHOW_ARTISTS
} }
fun handleSongPlayModeCompat(prefs: SharedPreferences): PlaybackMode { fun handleSongPlayModeCompat(prefs: SharedPreferences): PlaybackMode {
if (prefs.contains(OldKeys.KEY_SONG_PLAYBACK_MODE)) { if (prefs.contains(OldKeys.KEY_SONG_PLAYBACK_MODE)) {
val mode = when (prefs.getString(OldKeys.KEY_SONG_PLAYBACK_MODE, EntryValues.ALL_SONGS)) { val mode = when (prefs.getStringOrNull(OldKeys.KEY_SONG_PLAYBACK_MODE)) {
EntryValues.IN_GENRE -> PlaybackMode.IN_GENRE EntryValues.IN_GENRE -> PlaybackMode.IN_GENRE
EntryValues.IN_ARTIST -> PlaybackMode.IN_ARTIST EntryValues.IN_ARTIST -> PlaybackMode.IN_ARTIST
EntryValues.IN_ALBUM -> PlaybackMode.IN_ALBUM EntryValues.IN_ALBUM -> PlaybackMode.IN_ALBUM
@ -106,16 +103,13 @@ fun handleSongPlayModeCompat(prefs: SharedPreferences): PlaybackMode {
return mode return mode
} }
return PlaybackMode.fromInt( return prefs.getData(SettingsManager.KEY_SONG_PLAYBACK_MODE, PlaybackMode::fromInt)
prefs.getInt(SettingsManager.KEY_SONG_PLAYBACK_MODE, PlaybackMode.CONST_ALL_SONGS) ?: PlaybackMode.ALL_SONGS
) ?: PlaybackMode.ALL_SONGS
} }
fun handleSearchModeCompat(prefs: SharedPreferences): DisplayMode { fun handleSearchModeCompat(prefs: SharedPreferences): DisplayMode {
if (prefs.contains(OldKeys.KEY_SEARCH_FILTER)) { if (prefs.contains(OldKeys.KEY_SEARCH_FILTER)) {
val mode = handleStringDisplayMode( val mode = prefs.handleOldDisplayMode(OldKeys.KEY_SEARCH_FILTER) ?: DisplayMode.SHOW_ALL
prefs.getString(OldKeys.KEY_SEARCH_FILTER, EntryValues.SHOW_ALL)
) ?: DisplayMode.SHOW_ALL
prefs.edit { prefs.edit {
putInt(SettingsManager.KEY_SEARCH_FILTER_MODE, mode.toInt()) putInt(SettingsManager.KEY_SEARCH_FILTER_MODE, mode.toInt())
@ -126,13 +120,12 @@ fun handleSearchModeCompat(prefs: SharedPreferences): DisplayMode {
return mode return mode
} }
return DisplayMode.fromInt( return prefs.getData(SettingsManager.KEY_SEARCH_FILTER_MODE, DisplayMode::fromInt)
prefs.getInt(SettingsManager.KEY_SEARCH_FILTER_MODE, DisplayMode.CONST_SHOW_ALL) ?: DisplayMode.SHOW_ALL
) ?: DisplayMode.SHOW_ARTISTS
} }
private fun handleStringDisplayMode(string: String?): DisplayMode? { private fun SharedPreferences.handleOldDisplayMode(key: String): DisplayMode? {
return when (string) { return when (getStringOrNull(key)) {
EntryValues.SHOW_GENRES -> DisplayMode.SHOW_GENRES EntryValues.SHOW_GENRES -> DisplayMode.SHOW_GENRES
EntryValues.SHOW_ARTISTS -> DisplayMode.SHOW_ARTISTS EntryValues.SHOW_ARTISTS -> DisplayMode.SHOW_ARTISTS
EntryValues.SHOW_ALBUMS -> DisplayMode.SHOW_ALBUMS EntryValues.SHOW_ALBUMS -> DisplayMode.SHOW_ALBUMS

View file

@ -20,14 +20,10 @@ class SettingsFragment : Fragment() {
val binding = FragmentSettingsBinding.inflate(inflater) val binding = FragmentSettingsBinding.inflate(inflater)
binding.settingsToolbar.setOnMenuItemClickListener { binding.settingsToolbar.setOnMenuItemClickListener {
AboutDialog().show(childFragmentManager, TAG_ABOUT_DIALOG) AboutDialog().show(childFragmentManager, AboutDialog.TAG)
true true
} }
return binding.root return binding.root
} }
companion object {
private const val TAG_ABOUT_DIALOG = "TAG_ABOUT_DIALOG"
}
} }

View file

@ -32,8 +32,8 @@ class SettingsListFragment : PreferenceFragmentCompat() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
preferenceScreen.children.forEach { preferenceScreen.children.forEach { pref ->
recursivelyHandleChildren(it) recursivelyHandleChildren(pref)
} }
preferenceManager.onDisplayPreferenceDialogListener = this preferenceManager.onDisplayPreferenceDialogListener = this

View file

@ -102,12 +102,12 @@ class SettingsManager private constructor(context: Context) :
/** The current [SortMode] of the library. */ /** The current [SortMode] of the library. */
var librarySortMode: SortMode var librarySortMode: SortMode
get() = SortMode.fromInt( get() = sharedPrefs.getData(KEY_LIB_SORT_MODE, SortMode::fromInt)
sharedPrefs.getInt(KEY_LIBRARY_SORT_MODE, SortMode.CONST_ALPHA_DOWN) ?: SortMode.ALPHA_DOWN
) ?: SortMode.ALPHA_DOWN
set(value) { set(value) {
sharedPrefs.edit { sharedPrefs.edit {
putInt(KEY_LIBRARY_SORT_MODE, value.toInt()) putInt(KEY_LIB_SORT_MODE, value.toInt())
apply() apply()
} }
} }
@ -207,7 +207,7 @@ class SettingsManager private constructor(context: Context) :
const val KEY_SAVE_STATE = "KEY_SAVE_STATE" const val KEY_SAVE_STATE = "KEY_SAVE_STATE"
const val KEY_BLACKLIST = "KEY_BLACKLIST" const val KEY_BLACKLIST = "KEY_BLACKLIST"
const val KEY_LIBRARY_SORT_MODE = "KEY_LIBRARY_SORT_MODE" const val KEY_LIB_SORT_MODE = "KEY_LIBRARY_SORT_MODE"
const val KEY_SEARCH_FILTER_MODE = "KEY_SEARCH_FILTER" const val KEY_SEARCH_FILTER_MODE = "KEY_SEARCH_FILTER"
@Volatile @Volatile

View file

@ -7,7 +7,7 @@ class IntListPrefDialog(private val pref: IntListPreference) : LifecycleDialog()
builder.setTitle(pref.title) builder.setTitle(pref.title)
builder.setSingleChoiceItems(pref.entries, pref.getValueIndex()) { _, index -> builder.setSingleChoiceItems(pref.entries, pref.getValueIndex()) { _, index ->
pref.setValue(pref.values[index]) pref.setValueIndex(index)
dismiss() dismiss()
} }

View file

@ -15,10 +15,9 @@ class IntListPreference @JvmOverloads constructor(
) : DialogPreference(context, attrs, defStyleAttr, defStyleRes) { ) : DialogPreference(context, attrs, defStyleAttr, defStyleRes) {
val entries: Array<CharSequence> val entries: Array<CharSequence>
val values: IntArray val values: IntArray
var currentValue: Int? = null
private set
private val default: Int private var currentValue: Int? = null
private val defValue: Int
init { init {
val prefAttrs = context.obtainStyledAttributes( val prefAttrs = context.obtainStyledAttributes(
@ -31,7 +30,7 @@ class IntListPreference @JvmOverloads constructor(
prefAttrs.getResourceId(R.styleable.IntListPreference_entryValues, -1) prefAttrs.getResourceId(R.styleable.IntListPreference_entryValues, -1)
) )
default = prefAttrs.getInt(prefR.styleable.Preference_defaultValue, Int.MIN_VALUE) defValue = prefAttrs.getInt(prefR.styleable.Preference_defaultValue, Int.MIN_VALUE)
prefAttrs.recycle() prefAttrs.recycle()
@ -47,7 +46,7 @@ class IntListPreference @JvmOverloads constructor(
// If were given a default value, we need to assign it. // If were given a default value, we need to assign it.
setValue(defaultValue as Int) setValue(defaultValue as Int)
} else { } else {
currentValue = getPersistedInt(default) currentValue = getPersistedInt(defValue)
} }
} }
@ -61,7 +60,14 @@ class IntListPreference @JvmOverloads constructor(
return -1 return -1
} }
fun setValue(value: Int) { /**
* Set a value using the index of it in [values]
*/
fun setValueIndex(index: Int) {
setValue(values[index])
}
private fun setValue(value: Int) {
if (value != currentValue) { if (value != currentValue) {
currentValue = value currentValue = value

View file

@ -65,7 +65,7 @@ data class Accent(@ColorRes val color: Int, @StyleRes val theme: Int, @StringRes
companion object { companion object {
@Volatile @Volatile
private var current: Accent? = null private var CURRENT: Accent? = null
/** /**
* Get the current accent. * Get the current accent.
@ -73,7 +73,7 @@ data class Accent(@ColorRes val color: Int, @StyleRes val theme: Int, @StringRes
* @throws IllegalStateException When the accent has not been set. * @throws IllegalStateException When the accent has not been set.
*/ */
fun get(): Accent { fun get(): Accent {
val cur = current val cur = CURRENT
if (cur != null) { if (cur != null) {
return cur return cur
@ -88,7 +88,7 @@ data class Accent(@ColorRes val color: Int, @StyleRes val theme: Int, @StringRes
*/ */
fun set(accent: Accent): Accent { fun set(accent: Accent): Accent {
synchronized(this) { synchronized(this) {
current = accent CURRENT = accent
} }
return accent return accent

View file

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto" <PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
xmlns:tools="http://schemas.android.com/tools">
<PreferenceCategory <PreferenceCategory
app:layout="@layout/item_header" app:layout="@layout/item_header"
app:title="@string/setting_ui"> app:title="@string/setting_ui">