diff --git a/app/src/main/java/org/oxycblt/auxio/home/HomeSettings.kt b/app/src/main/java/org/oxycblt/auxio/home/HomeSettings.kt index c36e9d838..ff946df1a 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeSettings.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeSettings.kt @@ -41,38 +41,37 @@ interface HomeSettings : Settings { fun onHideCollaboratorsChanged() } - private class Real(context: Context) : Settings.Real(context), HomeSettings { - override var homeTabs: Array - get() = - Tab.fromIntCode( - sharedPreferences.getInt( - getString(R.string.set_key_home_tabs), Tab.SEQUENCE_DEFAULT)) - ?: unlikelyToBeNull(Tab.fromIntCode(Tab.SEQUENCE_DEFAULT)) - set(value) { - sharedPreferences.edit { - putInt(getString(R.string.set_key_home_tabs), Tab.toIntCode(value)) - apply() - } - } - - override val shouldHideCollaborators: Boolean - get() = - sharedPreferences.getBoolean(getString(R.string.set_key_hide_collaborators), false) - - override fun onSettingChanged(key: String, listener: Listener) { - when (key) { - getString(R.string.set_key_home_tabs) -> listener.onTabsChanged() - getString(R.string.set_key_hide_collaborators) -> - listener.onHideCollaboratorsChanged() - } - } - } - companion object { /** * Get a framework-backed implementation. * @param context [Context] required. */ - fun from(context: Context): HomeSettings = Real(context) + fun from(context: Context): HomeSettings = RealHomeSettings(context) + } +} + +private class RealHomeSettings(context: Context) : + Settings.Real(context), HomeSettings { + override var homeTabs: Array + get() = + Tab.fromIntCode( + sharedPreferences.getInt( + getString(R.string.set_key_home_tabs), Tab.SEQUENCE_DEFAULT)) + ?: unlikelyToBeNull(Tab.fromIntCode(Tab.SEQUENCE_DEFAULT)) + set(value) { + sharedPreferences.edit { + putInt(getString(R.string.set_key_home_tabs), Tab.toIntCode(value)) + apply() + } + } + + override val shouldHideCollaborators: Boolean + get() = sharedPreferences.getBoolean(getString(R.string.set_key_hide_collaborators), false) + + override fun onSettingChanged(key: String, listener: HomeSettings.Listener) { + when (key) { + getString(R.string.set_key_home_tabs) -> listener.onTabsChanged() + getString(R.string.set_key_hide_collaborators) -> listener.onHideCollaboratorsChanged() + } } } diff --git a/app/src/main/java/org/oxycblt/auxio/image/ImageSettings.kt b/app/src/main/java/org/oxycblt/auxio/image/ImageSettings.kt index d5dd32dd1..bfc679150 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/ImageSettings.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/ImageSettings.kt @@ -36,52 +36,53 @@ interface ImageSettings : Settings { fun onCoverModeChanged() {} } - private class Real(context: Context) : Settings.Real(context), ImageSettings { - override val coverMode: CoverMode - get() = - CoverMode.fromIntCode( - sharedPreferences.getInt(getString(R.string.set_key_cover_mode), Int.MIN_VALUE)) - ?: CoverMode.MEDIA_STORE - - override fun migrate() { - // Show album covers and Ignore MediaStore covers were unified in 3.0.0 - if (sharedPreferences.contains(OLD_KEY_SHOW_COVERS) || - sharedPreferences.contains(OLD_KEY_QUALITY_COVERS)) { - logD("Migrating cover settings") - - val mode = - when { - !sharedPreferences.getBoolean(OLD_KEY_SHOW_COVERS, true) -> CoverMode.OFF - !sharedPreferences.getBoolean(OLD_KEY_QUALITY_COVERS, true) -> - CoverMode.MEDIA_STORE - else -> CoverMode.QUALITY - } - - sharedPreferences.edit { - putInt(getString(R.string.set_key_cover_mode), mode.intCode) - remove(OLD_KEY_SHOW_COVERS) - remove(OLD_KEY_QUALITY_COVERS) - } - } - } - - override fun onSettingChanged(key: String, listener: Listener) { - if (key == getString(R.string.set_key_cover_mode)) { - listOf(key, listener) - } - } - - private companion object { - const val OLD_KEY_SHOW_COVERS = "KEY_SHOW_COVERS" - const val OLD_KEY_QUALITY_COVERS = "KEY_QUALITY_COVERS" - } - } - companion object { /** * Get a framework-backed implementation. * @param context [Context] required. */ - fun from(context: Context): ImageSettings = Real(context) + fun from(context: Context): ImageSettings = RealImageSettings(context) + } +} + +private class RealImageSettings(context: Context) : + Settings.Real(context), ImageSettings { + override val coverMode: CoverMode + get() = + CoverMode.fromIntCode( + sharedPreferences.getInt(getString(R.string.set_key_cover_mode), Int.MIN_VALUE)) + ?: CoverMode.MEDIA_STORE + + override fun migrate() { + // Show album covers and Ignore MediaStore covers were unified in 3.0.0 + if (sharedPreferences.contains(OLD_KEY_SHOW_COVERS) || + sharedPreferences.contains(OLD_KEY_QUALITY_COVERS)) { + logD("Migrating cover settings") + + val mode = + when { + !sharedPreferences.getBoolean(OLD_KEY_SHOW_COVERS, true) -> CoverMode.OFF + !sharedPreferences.getBoolean(OLD_KEY_QUALITY_COVERS, true) -> + CoverMode.MEDIA_STORE + else -> CoverMode.QUALITY + } + + sharedPreferences.edit { + putInt(getString(R.string.set_key_cover_mode), mode.intCode) + remove(OLD_KEY_SHOW_COVERS) + remove(OLD_KEY_QUALITY_COVERS) + } + } + } + + override fun onSettingChanged(key: String, listener: ImageSettings.Listener) { + if (key == getString(R.string.set_key_cover_mode)) { + listener.onCoverModeChanged() + } + } + + private companion object { + const val OLD_KEY_SHOW_COVERS = "KEY_SHOW_COVERS" + const val OLD_KEY_QUALITY_COVERS = "KEY_QUALITY_COVERS" } } diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicSettings.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicSettings.kt index b96a97fbd..330a6e4c8 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicSettings.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicSettings.kt @@ -62,163 +62,159 @@ interface MusicSettings : Settings { fun onObservingChanged() {} } - private class Real(context: Context) : Settings.Real(context), MusicSettings { - private val storageManager = context.getSystemServiceCompat(StorageManager::class) - - override var musicDirs: MusicDirectories - get() { - val dirs = - (sharedPreferences.getStringSet(getString(R.string.set_key_music_dirs), null) - ?: emptySet()) - .mapNotNull { Directory.fromDocumentTreeUri(storageManager, it) } - return MusicDirectories( - dirs, - sharedPreferences.getBoolean( - getString(R.string.set_key_music_dirs_include), false)) - } - set(value) { - sharedPreferences.edit { - putStringSet( - getString(R.string.set_key_music_dirs), - value.dirs.map(Directory::toDocumentTreeUri).toSet()) - putBoolean(getString(R.string.set_key_music_dirs_include), value.shouldInclude) - apply() - } - } - - override val excludeNonMusic: Boolean - get() = - sharedPreferences.getBoolean(getString(R.string.set_key_exclude_non_music), true) - - override val shouldBeObserving: Boolean - get() = sharedPreferences.getBoolean(getString(R.string.set_key_observing), false) - - override var multiValueSeparators: String - // Differ from convention and store a string of separator characters instead of an int - // code. This makes it easier to use and more extendable. - get() = sharedPreferences.getString(getString(R.string.set_key_separators), "") ?: "" - set(value) { - sharedPreferences.edit { - putString(getString(R.string.set_key_separators), value) - apply() - } - } - - override var songSort: Sort - get() = - Sort.fromIntCode( - sharedPreferences.getInt(getString(R.string.set_key_songs_sort), Int.MIN_VALUE)) - ?: Sort(Sort.Mode.ByName, true) - set(value) { - sharedPreferences.edit { - putInt(getString(R.string.set_key_songs_sort), value.intCode) - apply() - } - } - - override var albumSort: Sort - get() = - Sort.fromIntCode( - sharedPreferences.getInt( - getString(R.string.set_key_albums_sort), Int.MIN_VALUE)) - ?: Sort(Sort.Mode.ByName, true) - set(value) { - sharedPreferences.edit { - putInt(getString(R.string.set_key_albums_sort), value.intCode) - apply() - } - } - - override var artistSort: Sort - get() = - Sort.fromIntCode( - sharedPreferences.getInt( - getString(R.string.set_key_artists_sort), Int.MIN_VALUE)) - ?: Sort(Sort.Mode.ByName, true) - set(value) { - sharedPreferences.edit { - putInt(getString(R.string.set_key_artists_sort), value.intCode) - apply() - } - } - - override var genreSort: Sort - get() = - Sort.fromIntCode( - sharedPreferences.getInt( - getString(R.string.set_key_genres_sort), Int.MIN_VALUE)) - ?: Sort(Sort.Mode.ByName, true) - set(value) { - sharedPreferences.edit { - putInt(getString(R.string.set_key_genres_sort), value.intCode) - apply() - } - } - - override var albumSongSort: Sort - get() { - var sort = - Sort.fromIntCode( - sharedPreferences.getInt( - getString(R.string.set_key_album_songs_sort), Int.MIN_VALUE)) - ?: Sort(Sort.Mode.ByDisc, true) - - // Correct legacy album sort modes to Disc - if (sort.mode is Sort.Mode.ByName) { - sort = sort.withMode(Sort.Mode.ByDisc) - } - - return sort - } - set(value) { - sharedPreferences.edit { - putInt(getString(R.string.set_key_album_songs_sort), value.intCode) - apply() - } - } - - override var artistSongSort: Sort - get() = - Sort.fromIntCode( - sharedPreferences.getInt( - getString(R.string.set_key_artist_songs_sort), Int.MIN_VALUE)) - ?: Sort(Sort.Mode.ByDate, false) - set(value) { - sharedPreferences.edit { - putInt(getString(R.string.set_key_artist_songs_sort), value.intCode) - apply() - } - } - - override var genreSongSort: Sort - get() = - Sort.fromIntCode( - sharedPreferences.getInt( - getString(R.string.set_key_genre_songs_sort), Int.MIN_VALUE)) - ?: Sort(Sort.Mode.ByName, true) - set(value) { - sharedPreferences.edit { - putInt(getString(R.string.set_key_genre_songs_sort), value.intCode) - apply() - } - } - - override fun onSettingChanged(key: String, listener: Listener) { - when (key) { - getString(R.string.set_key_exclude_non_music), - getString(R.string.set_key_music_dirs), - getString(R.string.set_key_music_dirs_include), - getString(R.string.set_key_separators) -> listener.onIndexingSettingChanged() - getString(R.string.set_key_observing) -> listener.onObservingChanged() - } - } - } - companion object { /** * Get a framework-backed implementation. * @param context [Context] required. */ - fun from(context: Context): MusicSettings = Real(context) + fun from(context: Context): MusicSettings = RealMusicSettings(context) + } +} + +private class RealMusicSettings(context: Context) : + Settings.Real(context), MusicSettings { + private val storageManager = context.getSystemServiceCompat(StorageManager::class) + + override var musicDirs: MusicDirectories + get() { + val dirs = + (sharedPreferences.getStringSet(getString(R.string.set_key_music_dirs), null) + ?: emptySet()) + .mapNotNull { Directory.fromDocumentTreeUri(storageManager, it) } + return MusicDirectories( + dirs, + sharedPreferences.getBoolean(getString(R.string.set_key_music_dirs_include), false)) + } + set(value) { + sharedPreferences.edit { + putStringSet( + getString(R.string.set_key_music_dirs), + value.dirs.map(Directory::toDocumentTreeUri).toSet()) + putBoolean(getString(R.string.set_key_music_dirs_include), value.shouldInclude) + apply() + } + } + + override val excludeNonMusic: Boolean + get() = sharedPreferences.getBoolean(getString(R.string.set_key_exclude_non_music), true) + + override val shouldBeObserving: Boolean + get() = sharedPreferences.getBoolean(getString(R.string.set_key_observing), false) + + override var multiValueSeparators: String + // Differ from convention and store a string of separator characters instead of an int + // code. This makes it easier to use and more extendable. + get() = sharedPreferences.getString(getString(R.string.set_key_separators), "") ?: "" + set(value) { + sharedPreferences.edit { + putString(getString(R.string.set_key_separators), value) + apply() + } + } + + override var songSort: Sort + get() = + Sort.fromIntCode( + sharedPreferences.getInt(getString(R.string.set_key_songs_sort), Int.MIN_VALUE)) + ?: Sort(Sort.Mode.ByName, true) + set(value) { + sharedPreferences.edit { + putInt(getString(R.string.set_key_songs_sort), value.intCode) + apply() + } + } + + override var albumSort: Sort + get() = + Sort.fromIntCode( + sharedPreferences.getInt(getString(R.string.set_key_albums_sort), Int.MIN_VALUE)) + ?: Sort(Sort.Mode.ByName, true) + set(value) { + sharedPreferences.edit { + putInt(getString(R.string.set_key_albums_sort), value.intCode) + apply() + } + } + + override var artistSort: Sort + get() = + Sort.fromIntCode( + sharedPreferences.getInt(getString(R.string.set_key_artists_sort), Int.MIN_VALUE)) + ?: Sort(Sort.Mode.ByName, true) + set(value) { + sharedPreferences.edit { + putInt(getString(R.string.set_key_artists_sort), value.intCode) + apply() + } + } + + override var genreSort: Sort + get() = + Sort.fromIntCode( + sharedPreferences.getInt(getString(R.string.set_key_genres_sort), Int.MIN_VALUE)) + ?: Sort(Sort.Mode.ByName, true) + set(value) { + sharedPreferences.edit { + putInt(getString(R.string.set_key_genres_sort), value.intCode) + apply() + } + } + + override var albumSongSort: Sort + get() { + var sort = + Sort.fromIntCode( + sharedPreferences.getInt( + getString(R.string.set_key_album_songs_sort), Int.MIN_VALUE)) + ?: Sort(Sort.Mode.ByDisc, true) + + // Correct legacy album sort modes to Disc + if (sort.mode is Sort.Mode.ByName) { + sort = sort.withMode(Sort.Mode.ByDisc) + } + + return sort + } + set(value) { + sharedPreferences.edit { + putInt(getString(R.string.set_key_album_songs_sort), value.intCode) + apply() + } + } + + override var artistSongSort: Sort + get() = + Sort.fromIntCode( + sharedPreferences.getInt( + getString(R.string.set_key_artist_songs_sort), Int.MIN_VALUE)) + ?: Sort(Sort.Mode.ByDate, false) + set(value) { + sharedPreferences.edit { + putInt(getString(R.string.set_key_artist_songs_sort), value.intCode) + apply() + } + } + + override var genreSongSort: Sort + get() = + Sort.fromIntCode( + sharedPreferences.getInt( + getString(R.string.set_key_genre_songs_sort), Int.MIN_VALUE)) + ?: Sort(Sort.Mode.ByName, true) + set(value) { + sharedPreferences.edit { + putInt(getString(R.string.set_key_genre_songs_sort), value.intCode) + apply() + } + } + + override fun onSettingChanged(key: String, listener: MusicSettings.Listener) { + when (key) { + getString(R.string.set_key_exclude_non_music), + getString(R.string.set_key_music_dirs), + getString(R.string.set_key_music_dirs_include), + getString(R.string.set_key_separators) -> listener.onIndexingSettingChanged() + getString(R.string.set_key_observing) -> listener.onObservingChanged() + } } } diff --git a/app/src/main/java/org/oxycblt/auxio/music/storage/Filesystem.kt b/app/src/main/java/org/oxycblt/auxio/music/storage/Filesystem.kt index 5536e46df..1ca010d92 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/storage/Filesystem.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/storage/Filesystem.kt @@ -53,7 +53,7 @@ class Directory private constructor(val volume: StorageVolume, val relativePath: /** * Converts this [Directory] instance into an opaque document tree path. This is a huge * violation of the document tree URI contract, but it's also the only one can sensibly work - * with these uris in the UI, and it doesn't exactly matter since we never write or read + * with these uris in the UI, and it doesn't exactly matter since we never write or read to * directory. * @return A URI [String] abiding by the document tree specification, or null if the [Directory] * is not valid. diff --git a/app/src/main/java/org/oxycblt/auxio/search/SearchEngine.kt b/app/src/main/java/org/oxycblt/auxio/search/SearchEngine.kt index 831f758f9..59aba052e 100644 --- a/app/src/main/java/org/oxycblt/auxio/search/SearchEngine.kt +++ b/app/src/main/java/org/oxycblt/auxio/search/SearchEngine.kt @@ -52,72 +52,71 @@ interface SearchEngine { val genres: List? ) - private class Real(private val context: Context) : SearchEngine { - override suspend fun search(items: Items, query: String) = - Items( - songs = - items.songs?.searchListImpl(query) { q, song -> song.path.name.contains(q) }, - albums = items.albums?.searchListImpl(query), - artists = items.artists?.searchListImpl(query), - genres = items.genres?.searchListImpl(query)) - - /** - * Search a given [Music] list. - * @param query The query to search for. The routine will compare this query to the names of - * each object in the list and - * @param fallback Additional comparison code to run if the item does not match the query - * initially. This can be used to compare against additional attributes to improve search - * result quality. - */ - private inline fun List.searchListImpl( - query: String, - fallback: (String, T) -> Boolean = { _, _ -> false } - ) = - filter { - // See if the plain resolved name matches the query. This works for most - // situations. - val name = it.resolveName(context) - if (name.contains(query, ignoreCase = true)) { - return@filter true - } - - // See if the sort name matches. This can sometimes be helpful as certain - // libraries - // will tag sort names to have a alphabetized version of the title. - val sortName = it.rawSortName - if (sortName != null && sortName.contains(query, ignoreCase = true)) { - return@filter true - } - - // As a last-ditch effort, see if the normalized name matches. This will replace - // any non-alphabetical characters with their alphabetical representations, - // which - // could make it match the query. - val normalizedName = - NORMALIZATION_SANITIZE_REGEX.replace( - Normalizer.normalize(name, Normalizer.Form.NFKD), "") - if (normalizedName.contains(query, ignoreCase = true)) { - return@filter true - } - - fallback(query, it) - } - .ifEmpty { null } - - private companion object { - /** - * Converts the output of [Normalizer] to remove any junk characters added by it's - * replacements. - */ - val NORMALIZATION_SANITIZE_REGEX = Regex("\\p{InCombiningDiacriticalMarks}+") - } - } - companion object { /** * Get a framework-backed implementation. * @param context [Context] required. */ - fun from(context: Context): SearchEngine = Real(context) + fun from(context: Context): SearchEngine = RealSearchEngine(context) + } +} + +private class RealSearchEngine(private val context: Context) : SearchEngine { + override suspend fun search(items: SearchEngine.Items, query: String) = + SearchEngine.Items( + songs = items.songs?.searchListImpl(query) { q, song -> song.path.name.contains(q) }, + albums = items.albums?.searchListImpl(query), + artists = items.artists?.searchListImpl(query), + genres = items.genres?.searchListImpl(query)) + + /** + * Search a given [Music] list. + * @param query The query to search for. The routine will compare this query to the names of + * each object in the list and + * @param fallback Additional comparison code to run if the item does not match the query + * initially. This can be used to compare against additional attributes to improve search result + * quality. + */ + private inline fun List.searchListImpl( + query: String, + fallback: (String, T) -> Boolean = { _, _ -> false } + ) = + filter { + // See if the plain resolved name matches the query. This works for most + // situations. + val name = it.resolveName(context) + if (name.contains(query, ignoreCase = true)) { + return@filter true + } + + // See if the sort name matches. This can sometimes be helpful as certain + // libraries + // will tag sort names to have a alphabetized version of the title. + val sortName = it.rawSortName + if (sortName != null && sortName.contains(query, ignoreCase = true)) { + return@filter true + } + + // As a last-ditch effort, see if the normalized name matches. This will replace + // any non-alphabetical characters with their alphabetical representations, + // which + // could make it match the query. + val normalizedName = + NORMALIZATION_SANITIZE_REGEX.replace( + Normalizer.normalize(name, Normalizer.Form.NFKD), "") + if (normalizedName.contains(query, ignoreCase = true)) { + return@filter true + } + + fallback(query, it) + } + .ifEmpty { null } + + private companion object { + /** + * Converts the output of [Normalizer] to remove any junk characters added by it's + * replacements. + */ + val NORMALIZATION_SANITIZE_REGEX = Regex("\\p{InCombiningDiacriticalMarks}+") } } diff --git a/app/src/main/java/org/oxycblt/auxio/search/SearchSettings.kt b/app/src/main/java/org/oxycblt/auxio/search/SearchSettings.kt index 881bc8940..700d1b586 100644 --- a/app/src/main/java/org/oxycblt/auxio/search/SearchSettings.kt +++ b/app/src/main/java/org/oxycblt/auxio/search/SearchSettings.kt @@ -31,26 +31,25 @@ interface SearchSettings : Settings { /** The type of Music the search view is currently filtering to. */ var searchFilterMode: MusicMode? - private class Real(context: Context) : Settings.Real(context), SearchSettings { - override var searchFilterMode: MusicMode? - get() = - MusicMode.fromIntCode( - sharedPreferences.getInt( - getString(R.string.set_key_search_filter), Int.MIN_VALUE)) - set(value) { - sharedPreferences.edit { - putInt( - getString(R.string.set_key_search_filter), value?.intCode ?: Int.MIN_VALUE) - apply() - } - } - } - companion object { /** * Get a framework-backed implementation. * @param context [Context] required. */ - fun from(context: Context): SearchSettings = Real(context) + fun from(context: Context): SearchSettings = RealSearchSettings(context) } } + +private class RealSearchSettings(context: Context) : + Settings.Real(context), SearchSettings { + override var searchFilterMode: MusicMode? + get() = + MusicMode.fromIntCode( + sharedPreferences.getInt(getString(R.string.set_key_search_filter), Int.MIN_VALUE)) + set(value) { + sharedPreferences.edit { + putInt(getString(R.string.set_key_search_filter), value?.intCode ?: Int.MIN_VALUE) + apply() + } + } +} diff --git a/app/src/main/java/org/oxycblt/auxio/ui/UISettings.kt b/app/src/main/java/org/oxycblt/auxio/ui/UISettings.kt index 5e9de4b83..826207549 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/UISettings.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/UISettings.kt @@ -45,65 +45,66 @@ interface UISettings : Settings { fun onRoundModeChanged() } - private class Real(context: Context) : Settings.Real(context), UISettings { - override val theme: Int - get() = - sharedPreferences.getInt( - getString(R.string.set_key_theme), AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) - - override val useBlackTheme: Boolean - get() = sharedPreferences.getBoolean(getString(R.string.set_key_black_theme), false) - - override var accent: Accent - get() = - Accent.from( - sharedPreferences.getInt(getString(R.string.set_key_accent), Accent.DEFAULT)) - set(value) { - sharedPreferences.edit { - putInt(getString(R.string.set_key_accent), value.index) - apply() - } - } - - override val roundMode: Boolean - get() = sharedPreferences.getBoolean(getString(R.string.set_key_round_mode), false) - - override fun migrate() { - if (sharedPreferences.contains(OLD_KEY_ACCENT3)) { - logD("Migrating $OLD_KEY_ACCENT3") - - var accent = sharedPreferences.getInt(OLD_KEY_ACCENT3, 5) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - // Accents were previously frozen as soon as the OS was updated to android - // twelve, as dynamic colors were enabled by default. This is no longer the - // case, so we need to re-update the setting to dynamic colors here. - accent = 16 - } - - sharedPreferences.edit { - putInt(getString(R.string.set_key_accent), accent) - remove(OLD_KEY_ACCENT3) - apply() - } - } - } - - override fun onSettingChanged(key: String, listener: Listener) { - if (key == getString(R.string.set_key_round_mode)) { - listener.onRoundModeChanged() - } - } - - private companion object { - const val OLD_KEY_ACCENT3 = "auxio_accent" - } - } - companion object { /** * Get a framework-backed implementation. * @param context [Context] required. */ - fun from(context: Context): UISettings = Real(context) + fun from(context: Context): UISettings = RealUISettings(context) + } +} + +private class RealUISettings(context: Context) : + Settings.Real(context), UISettings { + override val theme: Int + get() = + sharedPreferences.getInt( + getString(R.string.set_key_theme), AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) + + override val useBlackTheme: Boolean + get() = sharedPreferences.getBoolean(getString(R.string.set_key_black_theme), false) + + override var accent: Accent + get() = + Accent.from( + sharedPreferences.getInt(getString(R.string.set_key_accent), Accent.DEFAULT)) + set(value) { + sharedPreferences.edit { + putInt(getString(R.string.set_key_accent), value.index) + apply() + } + } + + override val roundMode: Boolean + get() = sharedPreferences.getBoolean(getString(R.string.set_key_round_mode), false) + + override fun migrate() { + if (sharedPreferences.contains(OLD_KEY_ACCENT3)) { + logD("Migrating $OLD_KEY_ACCENT3") + + var accent = sharedPreferences.getInt(OLD_KEY_ACCENT3, 5) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + // Accents were previously frozen as soon as the OS was updated to android + // twelve, as dynamic colors were enabled by default. This is no longer the + // case, so we need to re-update the setting to dynamic colors here. + accent = 16 + } + + sharedPreferences.edit { + putInt(getString(R.string.set_key_accent), accent) + remove(OLD_KEY_ACCENT3) + apply() + } + } + } + + override fun onSettingChanged(key: String, listener: UISettings.Listener) { + if (key == getString(R.string.set_key_round_mode)) { + listener.onRoundModeChanged() + } + } + + private companion object { + const val OLD_KEY_ACCENT3 = "auxio_accent" } } diff --git a/app/src/test/java/org/oxycblt/auxio/music/tags/DiscTest.kt b/app/src/test/java/org/oxycblt/auxio/music/tags/DiscTest.kt index eff1131d7..622216922 100644 --- a/app/src/test/java/org/oxycblt/auxio/music/tags/DiscTest.kt +++ b/app/src/test/java/org/oxycblt/auxio/music/tags/DiscTest.kt @@ -17,10 +17,18 @@ package org.oxycblt.auxio.music.tags +import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Test class DiscTest { + @Test + fun disc_compare() { + val a = Disc(1, "Part I") + val b = Disc(2, "Part II") + assertEquals(-1, a.compareTo(b)) + } + @Test fun disc_equals_correct() { val a = Disc(1, "Part I")