From ac9f50c0a0e29a21d1b9c31a1b51a198dfa00303 Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Fri, 6 Jan 2023 19:20:56 -0700 Subject: [PATCH] settings: do not use sharedpreference listener Switch back to using settings-specific listeners rather than the SharedPreference listener. Again, this is due to the need to decouple android code from settings. It also allows us to fully obscure the details of what settings we are actually working with. --- CHANGELOG.md | 2 + .../org/oxycblt/auxio/home/HomeSettings.kt | 26 +++++-- .../org/oxycblt/auxio/home/HomeViewModel.kt | 34 ++++----- .../org/oxycblt/auxio/image/ImageSettings.kt | 20 ++++-- .../org/oxycblt/auxio/music/MusicSettings.kt | 72 +++++++++++-------- .../auxio/music/system/IndexerService.kt | 37 ++++------ .../auxio/playback/PlaybackBarFragment.kt | 2 +- .../auxio/playback/PlaybackSettings.kt | 71 +++++++++--------- .../replaygain/ReplayGainAudioProcessor.kt | 26 +++---- .../playback/state/PlaybackStateManager.kt | 4 +- .../playback/system/MediaSessionComponent.kt | 28 ++++---- .../oxycblt/auxio/search/SearchSettings.kt | 9 ++- .../org/oxycblt/auxio/settings/Settings.kt | 60 +++++++++++----- .../settings/prefs/PreferenceFragment.kt | 2 +- .../java/org/oxycblt/auxio/ui/UISettings.kt | 35 +++++---- .../oxycblt/auxio/widgets/WidgetComponent.kt | 26 ++++--- app/src/main/res/values/settings.xml | 20 +++--- app/src/main/res/xml/prefs_main.xml | 6 +- .../oxycblt/auxio/music/FakeMusicSettings.kt | 2 + 19 files changed, 270 insertions(+), 212 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bbbf847e..d974ead12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,13 @@ #### What's Improved - Added ability to edit previously played or currently playing items in the queue +- Added support for date values formatted as "YYYYMMDD" #### What's Fixed - Fixed unreliable ReplayGain adjustment application in certain situations - Fixed crash that would occur in music folders dialog when user does not have a working file manager +- Fixed notification not updating due to settings changes #### What's Changed - Implemented new queue system 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 e581a55a9..c36e9d838 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeSettings.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeSettings.kt @@ -28,30 +28,44 @@ import org.oxycblt.auxio.util.unlikelyToBeNull * User configuration specific to the home UI. * @author Alexander Capehart (OxygenCobalt) */ -interface HomeSettings : Settings { +interface HomeSettings : Settings { /** The tabs to show in the home UI. */ var homeTabs: Array /** Whether to hide artists considered "collaborators" from the home UI. */ val shouldHideCollaborators: Boolean - private class Real(context: Context) : Settings.Real(context), HomeSettings { + interface Listener { + /** Called when the [homeTabs] configuration changes. */ + fun onTabsChanged() + /** Called when the [shouldHideCollaborators] configuration changes. */ + fun onHideCollaboratorsChanged() + } + + private class Real(context: Context) : Settings.Real(context), HomeSettings { override var homeTabs: Array get() = Tab.fromIntCode( sharedPreferences.getInt( - context.getString(R.string.set_key_lib_tabs), Tab.SEQUENCE_DEFAULT)) + getString(R.string.set_key_home_tabs), Tab.SEQUENCE_DEFAULT)) ?: unlikelyToBeNull(Tab.fromIntCode(Tab.SEQUENCE_DEFAULT)) set(value) { sharedPreferences.edit { - putInt(context.getString(R.string.set_key_lib_tabs), Tab.toIntCode(value)) + putInt(getString(R.string.set_key_home_tabs), Tab.toIntCode(value)) apply() } } override val shouldHideCollaborators: Boolean get() = - sharedPreferences.getBoolean( - context.getString(R.string.set_key_hide_collaborators), false) + 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 { diff --git a/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt b/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt index 0283fc579..2798f64f3 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt @@ -18,17 +18,14 @@ package org.oxycblt.auxio.home import android.app.Application -import android.content.SharedPreferences import androidx.lifecycle.AndroidViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import org.oxycblt.auxio.R import org.oxycblt.auxio.home.tabs.Tab import org.oxycblt.auxio.music.* import org.oxycblt.auxio.music.Library import org.oxycblt.auxio.music.MusicStore import org.oxycblt.auxio.music.Sort -import org.oxycblt.auxio.util.context import org.oxycblt.auxio.util.logD /** @@ -36,9 +33,7 @@ import org.oxycblt.auxio.util.logD * @author Alexander Capehart (OxygenCobalt) */ class HomeViewModel(application: Application) : - AndroidViewModel(application), - MusicStore.Listener, - SharedPreferences.OnSharedPreferenceChangeListener { + AndroidViewModel(application), MusicStore.Listener, HomeSettings.Listener { private val musicStore = MusicStore.getInstance() private val homeSettings = HomeSettings.from(application) private val musicSettings = MusicSettings.from(application) @@ -92,13 +87,13 @@ class HomeViewModel(application: Application) : init { musicStore.addListener(this) - homeSettings.addListener(this) + homeSettings.registerListener(this) } override fun onCleared() { super.onCleared() musicStore.removeListener(this) - homeSettings.removeListener(this) + homeSettings.unregisterListener(this) } override fun onLibraryChanged(library: Library?) { @@ -120,19 +115,16 @@ class HomeViewModel(application: Application) : } } - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { - when (key) { - context.getString(R.string.set_key_lib_tabs) -> { - // Tabs changed, update the current tabs and set up a re-create event. - currentTabModes = makeTabModes() - _shouldRecreate.value = true - } - context.getString(R.string.set_key_hide_collaborators) -> { - // Changes in the hide collaborator setting will change the artist contents - // of the library, consider it a library update. - onLibraryChanged(musicStore.library) - } - } + override fun onTabsChanged() { + // Tabs changed, update the current tabs and set up a re-create event. + currentTabModes = makeTabModes() + _shouldRecreate.value = true + } + + override fun onHideCollaboratorsChanged() { + // Changes in the hide collaborator setting will change the artist contents + // of the library, consider it a library update. + onLibraryChanged(musicStore.library) } /** 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 cffa6df22..d5dd32dd1 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/ImageSettings.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/ImageSettings.kt @@ -27,16 +27,20 @@ import org.oxycblt.auxio.util.logD * User configuration specific to image loading. * @author Alexander Capehart (OxygenCobalt) */ -interface ImageSettings : Settings { +interface ImageSettings : Settings { /** The strategy to use when loading album covers. */ val coverMode: CoverMode - private class Real(context: Context) : Settings.Real(context), ImageSettings { + interface Listener { + /** Called when [coverMode] changes. */ + fun onCoverModeChanged() {} + } + + private class Real(context: Context) : Settings.Real(context), ImageSettings { override val coverMode: CoverMode get() = CoverMode.fromIntCode( - sharedPreferences.getInt( - context.getString(R.string.set_key_cover_mode), Int.MIN_VALUE)) + sharedPreferences.getInt(getString(R.string.set_key_cover_mode), Int.MIN_VALUE)) ?: CoverMode.MEDIA_STORE override fun migrate() { @@ -54,13 +58,19 @@ interface ImageSettings : Settings { } sharedPreferences.edit { - putInt(context.getString(R.string.set_key_cover_mode), mode.intCode) + 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" 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 6de1e1a63..465f7c8df 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicSettings.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicSettings.kt @@ -30,7 +30,7 @@ import org.oxycblt.auxio.util.getSystemServiceCompat * User configuration specific to music system. * @author Alexander Capehart (OxygenCobalt) */ -interface MusicSettings : Settings { +interface MusicSettings : Settings { /** The configuration on how to handle particular directories in the music library. */ var musicDirs: MusicDirectories /** Whether to exclude non-music audio files from the music library. */ @@ -54,50 +54,51 @@ interface MusicSettings : Settings { /** The [Sort] mode used in an [Genre]'s [Song] list. */ var genreSongSort: Sort - private class Real(context: Context) : Settings.Real(context), MusicSettings { + interface Listener { + /** Called when a setting controlling how music is loaded has changed. */ + fun onIndexingSettingChanged() {} + /** Called when the [shouldBeObserving] configuration has changed. */ + 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( - context.getString(R.string.set_key_music_dirs), null) + (sharedPreferences.getStringSet(getString(R.string.set_key_music_dirs), null) ?: emptySet()) .mapNotNull { Directory.fromDocumentTreeUri(storageManager, it) } return MusicDirectories( dirs, sharedPreferences.getBoolean( - context.getString(R.string.set_key_music_dirs_include), false)) + getString(R.string.set_key_music_dirs_include), false)) } set(value) { sharedPreferences.edit { putStringSet( - context.getString(R.string.set_key_music_dirs), + getString(R.string.set_key_music_dirs), value.dirs.map(Directory::toDocumentTreeUri).toSet()) - putBoolean( - context.getString(R.string.set_key_music_dirs_include), value.shouldInclude) + putBoolean(getString(R.string.set_key_music_dirs_include), value.shouldInclude) apply() } } override val excludeNonMusic: Boolean get() = - sharedPreferences.getBoolean( - context.getString(R.string.set_key_exclude_non_music), true) + sharedPreferences.getBoolean(getString(R.string.set_key_exclude_non_music), true) override val shouldBeObserving: Boolean - get() = - sharedPreferences.getBoolean(context.getString(R.string.set_key_observing), false) + 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(context.getString(R.string.set_key_separators), "") - ?: "" + get() = sharedPreferences.getString(getString(R.string.set_key_separators), "") ?: "" set(value) { sharedPreferences.edit { - putString(context.getString(R.string.set_key_separators), value) + putString(getString(R.string.set_key_separators), value) apply() } } @@ -105,12 +106,11 @@ interface MusicSettings : Settings { override var songSort: Sort get() = Sort.fromIntCode( - sharedPreferences.getInt( - context.getString(R.string.set_key_lib_songs_sort), Int.MIN_VALUE)) + sharedPreferences.getInt(getString(R.string.set_key_songs_sort), Int.MIN_VALUE)) ?: Sort(Sort.Mode.ByName, true) set(value) { sharedPreferences.edit { - putInt(context.getString(R.string.set_key_lib_songs_sort), value.intCode) + putInt(getString(R.string.set_key_songs_sort), value.intCode) apply() } } @@ -119,11 +119,11 @@ interface MusicSettings : Settings { get() = Sort.fromIntCode( sharedPreferences.getInt( - context.getString(R.string.set_key_lib_albums_sort), Int.MIN_VALUE)) + getString(R.string.set_key_albums_sort), Int.MIN_VALUE)) ?: Sort(Sort.Mode.ByName, true) set(value) { sharedPreferences.edit { - putInt(context.getString(R.string.set_key_lib_albums_sort), value.intCode) + putInt(getString(R.string.set_key_albums_sort), value.intCode) apply() } } @@ -132,11 +132,11 @@ interface MusicSettings : Settings { get() = Sort.fromIntCode( sharedPreferences.getInt( - context.getString(R.string.set_key_lib_artists_sort), Int.MIN_VALUE)) + getString(R.string.set_key_artists_sort), Int.MIN_VALUE)) ?: Sort(Sort.Mode.ByName, true) set(value) { sharedPreferences.edit { - putInt(context.getString(R.string.set_key_lib_artists_sort), value.intCode) + putInt(getString(R.string.set_key_artists_sort), value.intCode) apply() } } @@ -145,11 +145,11 @@ interface MusicSettings : Settings { get() = Sort.fromIntCode( sharedPreferences.getInt( - context.getString(R.string.set_key_lib_genres_sort), Int.MIN_VALUE)) + getString(R.string.set_key_genres_sort), Int.MIN_VALUE)) ?: Sort(Sort.Mode.ByName, true) set(value) { sharedPreferences.edit { - putInt(context.getString(R.string.set_key_lib_genres_sort), value.intCode) + putInt(getString(R.string.set_key_genres_sort), value.intCode) apply() } } @@ -159,7 +159,7 @@ interface MusicSettings : Settings { var sort = Sort.fromIntCode( sharedPreferences.getInt( - context.getString(R.string.set_key_detail_album_sort), Int.MIN_VALUE)) + getString(R.string.set_key_album_songs_sort), Int.MIN_VALUE)) ?: Sort(Sort.Mode.ByDisc, true) // Correct legacy album sort modes to Disc @@ -171,7 +171,7 @@ interface MusicSettings : Settings { } set(value) { sharedPreferences.edit { - putInt(context.getString(R.string.set_key_detail_album_sort), value.intCode) + putInt(getString(R.string.set_key_album_songs_sort), value.intCode) apply() } } @@ -180,11 +180,11 @@ interface MusicSettings : Settings { get() = Sort.fromIntCode( sharedPreferences.getInt( - context.getString(R.string.set_key_detail_artist_sort), Int.MIN_VALUE)) + getString(R.string.set_key_artist_songs_sort), Int.MIN_VALUE)) ?: Sort(Sort.Mode.ByDate, false) set(value) { sharedPreferences.edit { - putInt(context.getString(R.string.set_key_detail_artist_sort), value.intCode) + putInt(getString(R.string.set_key_artist_songs_sort), value.intCode) apply() } } @@ -193,14 +193,24 @@ interface MusicSettings : Settings { get() = Sort.fromIntCode( sharedPreferences.getInt( - context.getString(R.string.set_key_detail_genre_sort), Int.MIN_VALUE)) + getString(R.string.set_key_genre_songs_sort), Int.MIN_VALUE)) ?: Sort(Sort.Mode.ByName, true) set(value) { sharedPreferences.edit { - putInt(context.getString(R.string.set_key_detail_genre_sort), value.intCode) + 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 { diff --git a/app/src/main/java/org/oxycblt/auxio/music/system/IndexerService.kt b/app/src/main/java/org/oxycblt/auxio/music/system/IndexerService.kt index 51bdd9465..6358cb9ce 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/system/IndexerService.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/system/IndexerService.kt @@ -19,7 +19,6 @@ package org.oxycblt.auxio.music.system import android.app.Service import android.content.Intent -import android.content.SharedPreferences import android.database.ContentObserver import android.os.Handler import android.os.IBinder @@ -32,7 +31,6 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.launch import org.oxycblt.auxio.BuildConfig -import org.oxycblt.auxio.R import org.oxycblt.auxio.music.MusicSettings import org.oxycblt.auxio.music.MusicStore import org.oxycblt.auxio.music.storage.contentResolverSafe @@ -55,8 +53,7 @@ import org.oxycblt.auxio.util.logD * * @author Alexander Capehart (OxygenCobalt) */ -class IndexerService : - Service(), Indexer.Controller, SharedPreferences.OnSharedPreferenceChangeListener { +class IndexerService : Service(), Indexer.Controller, MusicSettings.Listener { private val indexer = Indexer.getInstance() private val musicStore = MusicStore.getInstance() private val playbackManager = PlaybackStateManager.getInstance() @@ -84,7 +81,7 @@ class IndexerService : // condition to cause us to load music before we were fully initialize. indexerContentObserver = SystemContentObserver() settings = MusicSettings.from(this) - settings.addListener(this) + settings.registerListener(this) indexer.registerController(this) // An indeterminate indexer and a missing library implies we are extremely early // in app initialization so start loading music. @@ -108,7 +105,7 @@ class IndexerService : // Then cancel the listener-dependent components to ensure that stray reloading // events will not occur. indexerContentObserver.release() - settings.removeListener(this) + settings.unregisterListener(this) indexer.unregisterController(this) // Then cancel any remaining music loading jobs. serviceJob.cancel() @@ -230,22 +227,18 @@ class IndexerService : // --- SETTING CALLBACKS --- - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { - when (key) { - // Hook changes in music settings to a new music loading event. - 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) -> onStartIndexing(true) - getString(R.string.set_key_observing) -> { - // Make sure we don't override the service state with the observing - // notification if we were actively loading when the automatic rescanning - // setting changed. In such a case, the state will still be updated when - // the music loading process ends. - if (!indexer.isIndexing) { - updateIdleSession() - } - } + override fun onIndexingSettingChanged() { + // Music loading configuration changed, need to reload music. + onStartIndexing(true) + } + + override fun onObservingChanged() { + // Make sure we don't override the service state with the observing + // notification if we were actively loading when the automatic rescanning + // setting changed. In such a case, the state will still be updated when + // the music loading process ends. + if (!indexer.isIndexing) { + updateIdleSession() } } diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBarFragment.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBarFragment.kt index 1ca050570..040240308 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBarFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackBarFragment.kt @@ -65,7 +65,7 @@ class PlaybackBarFragment : ViewBindingFragment() { // Set up actions binding.playbackPlayPause.setOnClickListener { playbackModel.toggleIsPlaying() } - setupSecondaryActions(binding, PlaybackSettings.from(context).playbackBarAction) + setupSecondaryActions(binding, PlaybackSettings.from(context).barAction) // Load the track color in manually as it's unclear whether the track actually supports // using a ColorStateList in the resources. diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackSettings.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackSettings.kt index 8832de932..9e46e5946 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackSettings.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackSettings.kt @@ -31,11 +31,11 @@ import org.oxycblt.auxio.util.logD * User configuration specific to the playback system. * @author Alexander Capehart (OxygenCobalt) */ -interface PlaybackSettings : Settings { +interface PlaybackSettings : Settings { /** The action to display on the playback bar. */ - val playbackBarAction: ActionMode + val barAction: ActionMode /** The action to display in the playback notification. */ - val playbackNotificationAction: ActionMode + val notificationAction: ActionMode /** Whether to start playback when a headset is plugged in. */ val headsetAutoplay: Boolean /** The current ReplayGain configuration. */ @@ -59,75 +59,72 @@ interface PlaybackSettings : Settings { /** Whether a song should pause after every repeat. */ val pauseOnRepeat: Boolean - private class Real(context: Context) : Settings.Real(context), PlaybackSettings { + interface Listener { + /** Called when one of the ReplayGain configurations have changed. */ + fun onReplayGainSettingsChanged() {} + /** Called when [notificationAction] has changed. */ + fun onNotificationActionChanged() {} + } + + private class Real(context: Context) : Settings.Real(context), PlaybackSettings { override val inListPlaybackMode: MusicMode get() = MusicMode.fromIntCode( sharedPreferences.getInt( - context.getString(R.string.set_key_library_song_playback_mode), - Int.MIN_VALUE)) + getString(R.string.set_key_in_list_playback_mode), Int.MIN_VALUE)) ?: MusicMode.SONGS override val inParentPlaybackMode: MusicMode? get() = MusicMode.fromIntCode( sharedPreferences.getInt( - context.getString(R.string.set_key_detail_song_playback_mode), - Int.MIN_VALUE)) + getString(R.string.set_key_in_parent_playback_mode), Int.MIN_VALUE)) - override val playbackBarAction: ActionMode + override val barAction: ActionMode get() = ActionMode.fromIntCode( - sharedPreferences.getInt( - context.getString(R.string.set_key_bar_action), Int.MIN_VALUE)) + sharedPreferences.getInt(getString(R.string.set_key_bar_action), Int.MIN_VALUE)) ?: ActionMode.NEXT - override val playbackNotificationAction: ActionMode + override val notificationAction: ActionMode get() = ActionMode.fromIntCode( sharedPreferences.getInt( - context.getString(R.string.set_key_notif_action), Int.MIN_VALUE)) + getString(R.string.set_key_notif_action), Int.MIN_VALUE)) ?: ActionMode.REPEAT override val headsetAutoplay: Boolean get() = - sharedPreferences.getBoolean( - context.getString(R.string.set_key_headset_autoplay), false) + sharedPreferences.getBoolean(getString(R.string.set_key_headset_autoplay), false) override val replayGainMode: ReplayGainMode get() = ReplayGainMode.fromIntCode( sharedPreferences.getInt( - context.getString(R.string.set_key_replay_gain), Int.MIN_VALUE)) + getString(R.string.set_key_replay_gain), Int.MIN_VALUE)) ?: ReplayGainMode.DYNAMIC override var replayGainPreAmp: ReplayGainPreAmp get() = ReplayGainPreAmp( - sharedPreferences.getFloat( - context.getString(R.string.set_key_pre_amp_with), 0f), - sharedPreferences.getFloat( - context.getString(R.string.set_key_pre_amp_without), 0f)) + sharedPreferences.getFloat(getString(R.string.set_key_pre_amp_with), 0f), + sharedPreferences.getFloat(getString(R.string.set_key_pre_amp_without), 0f)) set(value) { sharedPreferences.edit { - putFloat(context.getString(R.string.set_key_pre_amp_with), value.with) - putFloat(context.getString(R.string.set_key_pre_amp_without), value.without) + putFloat(getString(R.string.set_key_pre_amp_with), value.with) + putFloat(getString(R.string.set_key_pre_amp_without), value.without) apply() } } override val keepShuffle: Boolean - get() = - sharedPreferences.getBoolean(context.getString(R.string.set_key_keep_shuffle), true) + get() = sharedPreferences.getBoolean(getString(R.string.set_key_keep_shuffle), true) override val rewindWithPrev: Boolean - get() = - sharedPreferences.getBoolean(context.getString(R.string.set_key_rewind_prev), true) + get() = sharedPreferences.getBoolean(getString(R.string.set_key_rewind_prev), true) override val pauseOnRepeat: Boolean - get() = - sharedPreferences.getBoolean( - context.getString(R.string.set_key_repeat_pause), false) + get() = sharedPreferences.getBoolean(getString(R.string.set_key_repeat_pause), false) override fun migrate() { // "Use alternate notification action" was converted to an ActionMode setting in 3.0.0. @@ -142,7 +139,7 @@ interface PlaybackSettings : Settings { } sharedPreferences.edit { - putInt(context.getString(R.string.set_key_notif_action), mode.intCode) + putInt(getString(R.string.set_key_notif_action), mode.intCode) remove(OLD_KEY_ALT_NOTIF_ACTION) apply() } @@ -170,9 +167,7 @@ interface PlaybackSettings : Settings { ?: MusicMode.SONGS sharedPreferences.edit { - putInt( - context.getString(R.string.set_key_library_song_playback_mode), - mode.intCode) + putInt(getString(R.string.set_key_in_list_playback_mode), mode.intCode) remove(OLD_KEY_LIB_PLAYBACK_MODE) apply() } @@ -188,7 +183,7 @@ interface PlaybackSettings : Settings { sharedPreferences.edit { putInt( - context.getString(R.string.set_key_detail_song_playback_mode), + getString(R.string.set_key_in_parent_playback_mode), mode?.intCode ?: Int.MIN_VALUE) remove(OLD_KEY_DETAIL_PLAYBACK_MODE) apply() @@ -196,6 +191,14 @@ interface PlaybackSettings : Settings { } } + override fun onSettingChanged(key: String, listener: Listener) { + if (key == getString(R.string.set_key_replay_gain) || + key == getString(R.string.set_key_pre_amp_with) || + key == getString(R.string.set_key_pre_amp_without)) { + listener.onReplayGainSettingsChanged() + } + } + companion object { const val OLD_KEY_ALT_NOTIF_ACTION = "KEY_ALT_NOTIF_ACTION" const val OLD_KEY_LIB_PLAYBACK_MODE = "KEY_SONG_PLAY_MODE2" diff --git a/app/src/main/java/org/oxycblt/auxio/playback/replaygain/ReplayGainAudioProcessor.kt b/app/src/main/java/org/oxycblt/auxio/playback/replaygain/ReplayGainAudioProcessor.kt index 8461eb6a1..3a2a39893 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/replaygain/ReplayGainAudioProcessor.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/replaygain/ReplayGainAudioProcessor.kt @@ -18,7 +18,6 @@ package org.oxycblt.auxio.playback.replaygain import android.content.Context -import android.content.SharedPreferences import com.google.android.exoplayer2.C import com.google.android.exoplayer2.Format import com.google.android.exoplayer2.Player @@ -28,7 +27,6 @@ import com.google.android.exoplayer2.audio.BaseAudioProcessor import com.google.android.exoplayer2.util.MimeTypes import java.nio.ByteBuffer import kotlin.math.pow -import org.oxycblt.auxio.R import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.extractor.TextTags import org.oxycblt.auxio.playback.PlaybackSettings @@ -45,10 +43,10 @@ import org.oxycblt.auxio.util.logD * * @author Alexander Capehart (OxygenCobalt) */ -class ReplayGainAudioProcessor(private val context: Context) : - BaseAudioProcessor(), Player.Listener, SharedPreferences.OnSharedPreferenceChangeListener { +class ReplayGainAudioProcessor(context: Context) : + BaseAudioProcessor(), Player.Listener, PlaybackSettings.Listener { private val playbackManager = PlaybackStateManager.getInstance() - private val settings = PlaybackSettings.from(context) + private val playbackSettings = PlaybackSettings.from(context) private var lastFormat: Format? = null private var volume = 1f @@ -65,7 +63,7 @@ class ReplayGainAudioProcessor(private val context: Context) : */ fun addToListeners(player: Player) { player.addListener(this) - settings.addListener(this) + playbackSettings.registerListener(this) } /** @@ -75,7 +73,7 @@ class ReplayGainAudioProcessor(private val context: Context) : */ fun releaseFromListeners(player: Player) { player.removeListener(this) - settings.removeListener(this) + playbackSettings.unregisterListener(this) } // --- OVERRIDES --- @@ -98,13 +96,9 @@ class ReplayGainAudioProcessor(private val context: Context) : applyReplayGain(null) } - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { - if (key == context.getString(R.string.set_key_replay_gain) || - key == context.getString(R.string.set_key_pre_amp_with) || - key == context.getString(R.string.set_key_pre_amp_without)) { - // ReplayGain changed, we need to set it up again. - applyReplayGain(lastFormat) - } + override fun onReplayGainSettingsChanged() { + // ReplayGain config changed, we need to set it up again. + applyReplayGain(lastFormat) } // --- REPLAYGAIN PARSING --- @@ -116,14 +110,14 @@ class ReplayGainAudioProcessor(private val context: Context) : private fun applyReplayGain(format: Format?) { lastFormat = format val gain = parseReplayGain(format ?: return) - val preAmp = settings.replayGainPreAmp + val preAmp = playbackSettings.replayGainPreAmp val adjust = if (gain != null) { logD("Found ReplayGain adjustment $gain") // ReplayGain is configurable, so determine what to do based off of the mode. val useAlbumGain = - when (settings.replayGainMode) { + when (playbackSettings.replayGainMode) { // User wants track gain to be preferred. Default to album gain only if // there is no track gain. ReplayGainMode.TRACK -> gain.track == 0f diff --git a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt index 8a88c400e..d404b92f1 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt @@ -116,7 +116,7 @@ class PlaybackStateManager private constructor() { */ @Synchronized fun registerInternalPlayer(internalPlayer: InternalPlayer) { - if (BuildConfig.DEBUG && this.internalPlayer != null) { + if (this.internalPlayer != null) { logW("Internal player is already registered") return } @@ -141,7 +141,7 @@ class PlaybackStateManager private constructor() { */ @Synchronized fun unregisterInternalPlayer(internalPlayer: InternalPlayer) { - if (BuildConfig.DEBUG && this.internalPlayer !== internalPlayer) { + if (this.internalPlayer !== internalPlayer) { logW("Given internal player did not match current internal player") return } diff --git a/app/src/main/java/org/oxycblt/auxio/playback/system/MediaSessionComponent.kt b/app/src/main/java/org/oxycblt/auxio/playback/system/MediaSessionComponent.kt index c00b943b6..bd6900c51 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/system/MediaSessionComponent.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/system/MediaSessionComponent.kt @@ -19,7 +19,6 @@ package org.oxycblt.auxio.playback.system import android.content.Context import android.content.Intent -import android.content.SharedPreferences import android.graphics.Bitmap import android.net.Uri import android.os.Bundle @@ -31,6 +30,7 @@ import androidx.media.session.MediaButtonReceiver import org.oxycblt.auxio.BuildConfig import org.oxycblt.auxio.R import org.oxycblt.auxio.image.BitmapProvider +import org.oxycblt.auxio.image.ImageSettings import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.playback.ActionMode @@ -51,7 +51,8 @@ import org.oxycblt.auxio.util.logD class MediaSessionComponent(private val context: Context, private val listener: Listener) : MediaSessionCompat.Callback(), PlaybackStateManager.Listener, - SharedPreferences.OnSharedPreferenceChangeListener { + ImageSettings.Listener, + PlaybackSettings.Listener { private val mediaSession = MediaSessionCompat(context, context.packageName).apply { isActive = true @@ -59,13 +60,14 @@ class MediaSessionComponent(private val context: Context, private val listener: } private val playbackManager = PlaybackStateManager.getInstance() - private val settings = PlaybackSettings.from(context) + private val playbackSettings = PlaybackSettings.from(context) private val notification = NotificationComponent(context, mediaSession.sessionToken) private val provider = BitmapProvider(context) init { playbackManager.addListener(this) + playbackSettings.registerListener(this) mediaSession.setCallback(this) } @@ -83,7 +85,7 @@ class MediaSessionComponent(private val context: Context, private val listener: */ fun release() { provider.release() - settings.removeListener(this) + playbackSettings.unregisterListener(this) playbackManager.removeListener(this) mediaSession.apply { isActive = false @@ -150,12 +152,14 @@ class MediaSessionComponent(private val context: Context, private val listener: // --- SETTINGS OVERRIDES --- - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { - when (key) { - context.getString(R.string.set_key_cover_mode) -> - updateMediaMetadata(playbackManager.queue.currentSong, playbackManager.parent) - context.getString(R.string.set_key_notif_action) -> invalidateSecondaryAction() - } + override fun onCoverModeChanged() { + // Need to reload the metadata cover. + updateMediaMetadata(playbackManager.queue.currentSong, playbackManager.parent) + } + + override fun onNotificationActionChanged() { + // Need to re-load the action shown in the notification. + invalidateSecondaryAction() } // --- MEDIASESSION OVERRIDES --- @@ -359,7 +363,7 @@ class MediaSessionComponent(private val context: Context, private val listener: // Add the secondary action (either repeat/shuffle depending on the configuration) val secondaryAction = - when (settings.playbackNotificationAction) { + when (playbackSettings.notificationAction) { ActionMode.SHUFFLE -> PlaybackStateCompat.CustomAction.Builder( PlaybackService.ACTION_INVERT_SHUFFLE, @@ -393,7 +397,7 @@ class MediaSessionComponent(private val context: Context, private val listener: private fun invalidateSecondaryAction() { invalidateSessionState() - when (settings.playbackNotificationAction) { + when (playbackSettings.notificationAction) { ActionMode.SHUFFLE -> notification.updateShuffled(playbackManager.queue.isShuffled) else -> notification.updateRepeatMode(playbackManager.repeatMode) } 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 05dac481a..881bc8940 100644 --- a/app/src/main/java/org/oxycblt/auxio/search/SearchSettings.kt +++ b/app/src/main/java/org/oxycblt/auxio/search/SearchSettings.kt @@ -27,21 +27,20 @@ import org.oxycblt.auxio.settings.Settings * User configuration specific to the search UI. * @author Alexander Capehart (OxygenCobalt) */ -interface SearchSettings : Settings { +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 { + private class Real(context: Context) : Settings.Real(context), SearchSettings { override var searchFilterMode: MusicMode? get() = MusicMode.fromIntCode( sharedPreferences.getInt( - context.getString(R.string.set_key_search_filter), Int.MIN_VALUE)) + getString(R.string.set_key_search_filter), Int.MIN_VALUE)) set(value) { sharedPreferences.edit { putInt( - context.getString(R.string.set_key_search_filter), - value?.intCode ?: Int.MIN_VALUE) + getString(R.string.set_key_search_filter), value?.intCode ?: Int.MIN_VALUE) apply() } } diff --git a/app/src/main/java/org/oxycblt/auxio/settings/Settings.kt b/app/src/main/java/org/oxycblt/auxio/settings/Settings.kt index f9a82fca7..c1804d859 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/Settings.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/Settings.kt @@ -19,49 +19,75 @@ package org.oxycblt.auxio.settings import android.content.Context import android.content.SharedPreferences +import androidx.annotation.StringRes import androidx.preference.PreferenceManager +import org.oxycblt.auxio.util.logW +import org.oxycblt.auxio.util.unlikelyToBeNull /** * Abstract user configuration information. This interface has no functionality whatsoever. Concrete * implementations should be preferred instead. * @author Alexander Capehart (OxygenCobalt) */ -interface Settings { - /** Migrate any settings fields from older versions into their new counterparts. */ +interface Settings { + /** + * Migrate any settings fields from older versions into their new counterparts. + * @throws NotImplementedError If there is nothing to migrate. + */ fun migrate() { throw NotImplementedError() } /** - * Add a [SharedPreferences.OnSharedPreferenceChangeListener] to monitor for settings updates. - * @param listener The [SharedPreferences.OnSharedPreferenceChangeListener] to add. + * Add a listener to monitor for settings updates. Will do nothing if + * @param listener The listener to add. */ - fun addListener(listener: SharedPreferences.OnSharedPreferenceChangeListener) { - throw NotImplementedError() - } + fun registerListener(listener: L) /** - * Unregister a [SharedPreferences.OnSharedPreferenceChangeListener], preventing any further - * settings updates from being sent to ti.t + * Unregister a listener, preventing any further settings updates from being sent to it. + * @param listener The listener to unregister, must be the same as the current listener. */ - fun removeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener) { - throw NotImplementedError() - } + fun unregisterListener(listener: L) /** * A framework-backed [Settings] implementation. * @param context [Context] required. */ - abstract class Real(protected val context: Context) : Settings { + abstract class Real(private val context: Context) : + Settings, SharedPreferences.OnSharedPreferenceChangeListener { protected val sharedPreferences: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context.applicationContext) - override fun addListener(listener: SharedPreferences.OnSharedPreferenceChangeListener) { - sharedPreferences.registerOnSharedPreferenceChangeListener(listener) + /** @see [Context.getString] */ + protected fun getString(@StringRes stringRes: Int) = context.getString(stringRes) + + private var listener: L? = null + + override fun registerListener(listener: L) { + if (this.listener == null) { + // Registering a listener when it was null prior, attach the callback. + sharedPreferences.registerOnSharedPreferenceChangeListener(this) + } + this.listener = listener } - override fun removeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener) { - sharedPreferences.unregisterOnSharedPreferenceChangeListener(listener) + override fun unregisterListener(listener: L) { + if (this.listener !== listener) { + logW("Given listener was not the current listener.") + } + this.listener = null + // No longer have a listener, detach from the preferences instance. + sharedPreferences.unregisterOnSharedPreferenceChangeListener(this) } + + final override fun onSharedPreferenceChanged( + sharedPreferences: SharedPreferences, + key: String + ) { + onSettingChanged(key, unlikelyToBeNull(listener)) + } + + open fun onSettingChanged(key: String, listener: L) {} } } diff --git a/app/src/main/java/org/oxycblt/auxio/settings/prefs/PreferenceFragment.kt b/app/src/main/java/org/oxycblt/auxio/settings/prefs/PreferenceFragment.kt index cb7bdc82c..b8daa3c7a 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/prefs/PreferenceFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/prefs/PreferenceFragment.kt @@ -87,7 +87,7 @@ class PreferenceFragment : PreferenceFragmentCompat() { when (preference.key) { getString(R.string.set_key_accent) -> SettingsFragmentDirections.goToAccentDialog() - getString(R.string.set_key_lib_tabs) -> + getString(R.string.set_key_home_tabs) -> SettingsFragmentDirections.goToTabDialog() getString(R.string.set_key_pre_amp) -> SettingsFragmentDirections.goToPreAmpDialog() 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 0faf91fbc..dedc5efc4 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/UISettings.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/UISettings.kt @@ -26,7 +26,11 @@ import org.oxycblt.auxio.settings.Settings import org.oxycblt.auxio.ui.accent.Accent import org.oxycblt.auxio.util.logD -interface UISettings : Settings { +/** + * User configuration for the general app UI. + * @author Alexander Capehart (OxygenCobalt) + */ +interface UISettings : Settings { /** The current theme. Represented by the AppCompatDelegate constants. */ val theme: Int /** Whether to use a black background when a dark theme is currently used. */ @@ -36,32 +40,33 @@ interface UISettings : Settings { /** Whether to round additional UI elements that require album covers to be rounded. */ val roundMode: Boolean - private class Real(context: Context) : Settings.Real(context), UISettings { + interface Listener { + /** Called when [roundMode] changes. */ + fun onRoundModeChanged() + } + + private class Real(context: Context) : Settings.Real(context), UISettings { override val theme: Int get() = sharedPreferences.getInt( - context.getString(R.string.set_key_theme), - AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) + getString(R.string.set_key_theme), AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) override val useBlackTheme: Boolean - get() = - sharedPreferences.getBoolean(context.getString(R.string.set_key_black_theme), false) + get() = sharedPreferences.getBoolean(getString(R.string.set_key_black_theme), false) override var accent: Accent get() = Accent.from( - sharedPreferences.getInt( - context.getString(R.string.set_key_accent), Accent.DEFAULT)) + sharedPreferences.getInt(getString(R.string.set_key_accent), Accent.DEFAULT)) set(value) { sharedPreferences.edit { - putInt(context.getString(R.string.set_key_accent), value.index) + putInt(getString(R.string.set_key_accent), value.index) apply() } } override val roundMode: Boolean - get() = - sharedPreferences.getBoolean(context.getString(R.string.set_key_round_mode), false) + get() = sharedPreferences.getBoolean(getString(R.string.set_key_round_mode), false) override fun migrate() { if (sharedPreferences.contains(OLD_KEY_ACCENT3)) { @@ -78,13 +83,19 @@ interface UISettings : Settings { } sharedPreferences.edit { - putInt(context.getString(R.string.set_key_accent), accent) + 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() + } + } + companion object { const val OLD_KEY_ACCENT3 = "auxio_accent" } diff --git a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt index a4c62022d..180165d97 100644 --- a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt +++ b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt @@ -18,13 +18,13 @@ package org.oxycblt.auxio.widgets import android.content.Context -import android.content.SharedPreferences import android.graphics.Bitmap import android.os.Build import coil.request.ImageRequest import coil.transform.RoundedCornersTransformation import org.oxycblt.auxio.R import org.oxycblt.auxio.image.BitmapProvider +import org.oxycblt.auxio.image.ImageSettings import org.oxycblt.auxio.image.extractor.SquareFrameTransform import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.Song @@ -43,15 +43,17 @@ import org.oxycblt.auxio.util.logD * @author Alexander Capehart (OxygenCobalt) */ class WidgetComponent(private val context: Context) : - PlaybackStateManager.Listener, SharedPreferences.OnSharedPreferenceChangeListener { + PlaybackStateManager.Listener, UISettings.Listener, ImageSettings.Listener { private val playbackManager = PlaybackStateManager.getInstance() - private val settings = UISettings.from(context) + private val uiSettings = UISettings.from(context) + private val imageSettings = ImageSettings.from(context) private val widgetProvider = WidgetProvider() private val provider = BitmapProvider(context) init { playbackManager.addListener(this) - settings.addListener(this) + uiSettings.registerListener(this) + imageSettings.registerListener(this) } /** Update [WidgetProvider] with the current playback state. */ @@ -76,7 +78,7 @@ class WidgetComponent(private val context: Context) : if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // Android 12, always round the cover with the widget's inner radius context.getDimenPixels(android.R.dimen.system_app_widget_inner_radius) - } else if (settings.roundMode) { + } else if (uiSettings.roundMode) { // < Android 12, but the user still enabled round mode. context.getDimenPixels(R.dimen.size_corners_medium) } else { @@ -107,27 +109,23 @@ class WidgetComponent(private val context: Context) : /** Release this instance, preventing any further events from updating the widget instances. */ fun release() { provider.release() - settings.removeListener(this) + uiSettings.unregisterListener(this) widgetProvider.reset(context) playbackManager.removeListener(this) } // --- CALLBACKS --- - // Hook all the major song-changing updates + the major player state updates - // to updating the "Now Playing" widget. + // Respond to all major song or player changes that will affect the widget override fun onIndexMoved(queue: Queue) = update() override fun onQueueReordered(queue: Queue) = update() override fun onNewPlayback(queue: Queue, parent: MusicParent?) = update() override fun onStateChanged(state: InternalPlayer.State) = update() override fun onRepeatChanged(repeatMode: RepeatMode) = update() - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { - if (key == context.getString(R.string.set_key_cover_mode) || - key == context.getString(R.string.set_key_round_mode)) { - update() - } - } + // Respond to settings changes that will affect the widget + override fun onRoundModeChanged() = update() + override fun onCoverModeChanged() = update() /** * A condensed form of the playback state that is safe to use in AppWidgets. diff --git a/app/src/main/res/values/settings.xml b/app/src/main/res/values/settings.xml index b96505ed8..ff0dbbe2e 100644 --- a/app/src/main/res/values/settings.xml +++ b/app/src/main/res/values/settings.xml @@ -20,8 +20,8 @@ auxio_pre_amp_with auxio_pre_amp_without - auxio_library_playback_mode - auxio_detail_playback_mode + auxio_library_playback_mode + auxio_detail_playback_mode KEY_KEEP_SHUFFLE KEY_PREV_REWIND KEY_LOOP_PAUSE @@ -29,7 +29,7 @@ auxio_wipe_state auxio_restore_state - auxio_lib_tabs + auxio_lib_tabs auxio_hide_collaborators auxio_round_covers auxio_bar_action @@ -37,14 +37,14 @@ KEY_SEARCH_FILTER - auxio_songs_sort - auxio_albums_sort - auxio_artists_sort - auxio_genres_sort + auxio_songs_sort + auxio_albums_sort + auxio_artists_sort + auxio_genres_sort - auxio_album_sort - auxio_artist_sort - auxio_genre_sort + auxio_album_sort + auxio_artist_sort + auxio_genre_sort @string/set_theme_auto diff --git a/app/src/main/res/xml/prefs_main.xml b/app/src/main/res/xml/prefs_main.xml index 433581aa9..7e04cd41c 100644 --- a/app/src/main/res/xml/prefs_main.xml +++ b/app/src/main/res/xml/prefs_main.xml @@ -27,7 +27,7 @@ @@ -86,7 +86,7 @@ app:defaultValue="@integer/music_mode_songs" app:entries="@array/entries_library_song_playback_mode" app:entryValues="@array/values_library_song_playback_mode" - app:key="@string/set_key_library_song_playback_mode" + app:key="@string/set_key_in_list_playback_mode" app:title="@string/set_library_song_playback_mode" app:useSimpleSummaryProvider="true" /> @@ -94,7 +94,7 @@ app:defaultValue="@integer/music_mode_none" app:entries="@array/entries_detail_song_playback_mode" app:entryValues="@array/values_detail_song_playback_mode" - app:key="@string/set_key_detail_song_playback_mode" + app:key="@string/set_key_in_parent_playback_mode" app:title="@string/set_detail_song_playback_mode" app:useSimpleSummaryProvider="true" /> diff --git a/app/src/test/java/org/oxycblt/auxio/music/FakeMusicSettings.kt b/app/src/test/java/org/oxycblt/auxio/music/FakeMusicSettings.kt index 795e7b29c..a0a3096a6 100644 --- a/app/src/test/java/org/oxycblt/auxio/music/FakeMusicSettings.kt +++ b/app/src/test/java/org/oxycblt/auxio/music/FakeMusicSettings.kt @@ -20,6 +20,8 @@ package org.oxycblt.auxio.music import org.oxycblt.auxio.music.storage.MusicDirectories interface FakeMusicSettings : MusicSettings { + override fun registerListener(listener: MusicSettings.Listener) = throw NotImplementedError() + override fun unregisterListener(listener: MusicSettings.Listener) = throw NotImplementedError() override var musicDirs: MusicDirectories get() = throw NotImplementedError() set(_) = throw NotImplementedError()