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.
This commit is contained in:
parent
1b19b698a1
commit
ac9f50c0a0
19 changed files with 270 additions and 212 deletions
|
@ -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
|
||||
|
|
|
@ -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<HomeSettings.Listener> {
|
||||
/** The tabs to show in the home UI. */
|
||||
var homeTabs: Array<Tab>
|
||||
/** 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<Listener>(context), HomeSettings {
|
||||
override var homeTabs: Array<Tab>
|
||||
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 {
|
||||
|
|
|
@ -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,20 +115,17 @@ class HomeViewModel(application: Application) :
|
|||
}
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
||||
when (key) {
|
||||
context.getString(R.string.set_key_lib_tabs) -> {
|
||||
override fun onTabsChanged() {
|
||||
// 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) -> {
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update [currentTabMode] to reflect a new ViewPager2 position
|
||||
|
|
|
@ -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<ImageSettings.Listener> {
|
||||
/** 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<Listener>(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"
|
||||
|
|
|
@ -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<MusicSettings.Listener> {
|
||||
/** 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<Listener>(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 {
|
||||
|
|
|
@ -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,14 +227,12 @@ 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) -> {
|
||||
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
|
||||
|
@ -246,8 +241,6 @@ class IndexerService :
|
|||
updateIdleSession()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A [ContentObserver] that observes the [MediaStore] music database for changes, a behavior
|
||||
|
|
|
@ -65,7 +65,7 @@ class PlaybackBarFragment : ViewBindingFragment<FragmentPlaybackBarBinding>() {
|
|||
|
||||
// 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.
|
||||
|
|
|
@ -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<PlaybackSettings.Listener> {
|
||||
/** 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<Listener>(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"
|
||||
|
|
|
@ -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,14 +96,10 @@ 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.
|
||||
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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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) ->
|
||||
override fun onCoverModeChanged() {
|
||||
// Need to reload the metadata cover.
|
||||
updateMediaMetadata(playbackManager.queue.currentSong, playbackManager.parent)
|
||||
context.getString(R.string.set_key_notif_action) -> invalidateSecondaryAction()
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -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<Nothing> {
|
||||
/** 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<Nothing>(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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<L> {
|
||||
/**
|
||||
* 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<L>(private val context: Context) :
|
||||
Settings<L>, 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) {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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<UISettings.Listener> {
|
||||
/** 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<Listener>(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"
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
<string name="set_key_pre_amp_with" translatable="false">auxio_pre_amp_with</string>
|
||||
<string name="set_key_pre_amp_without" translatable="false">auxio_pre_amp_without</string>
|
||||
|
||||
<string name="set_key_library_song_playback_mode" translatable="false">auxio_library_playback_mode</string>
|
||||
<string name="set_key_detail_song_playback_mode" translatable="false">auxio_detail_playback_mode</string>
|
||||
<string name="set_key_in_list_playback_mode" translatable="false">auxio_library_playback_mode</string>
|
||||
<string name="set_key_in_parent_playback_mode" translatable="false">auxio_detail_playback_mode</string>
|
||||
<string name="set_key_keep_shuffle" translatable="false">KEY_KEEP_SHUFFLE</string>
|
||||
<string name="set_key_rewind_prev" translatable="false">KEY_PREV_REWIND</string>
|
||||
<string name="set_key_repeat_pause" translatable="false">KEY_LOOP_PAUSE</string>
|
||||
|
@ -29,7 +29,7 @@
|
|||
<string name="set_key_wipe_state" translatable="false">auxio_wipe_state</string>
|
||||
<string name="set_key_restore_state" translatable="false">auxio_restore_state</string>
|
||||
|
||||
<string name="set_key_lib_tabs" translatable="false">auxio_lib_tabs</string>
|
||||
<string name="set_key_home_tabs" translatable="false">auxio_lib_tabs</string>
|
||||
<string name="set_key_hide_collaborators" translatable="false">auxio_hide_collaborators</string>
|
||||
<string name="set_key_round_mode" translatable="false">auxio_round_covers</string>
|
||||
<string name="set_key_bar_action" translatable="false">auxio_bar_action</string>
|
||||
|
@ -37,14 +37,14 @@
|
|||
|
||||
<string name="set_key_search_filter" translatable="false">KEY_SEARCH_FILTER</string>
|
||||
|
||||
<string name="set_key_lib_songs_sort" translatable="false">auxio_songs_sort</string>
|
||||
<string name="set_key_lib_albums_sort" translatable="false">auxio_albums_sort</string>
|
||||
<string name="set_key_lib_artists_sort" translatable="false">auxio_artists_sort</string>
|
||||
<string name="set_key_lib_genres_sort" translatable="false">auxio_genres_sort</string>
|
||||
<string name="set_key_songs_sort" translatable="false">auxio_songs_sort</string>
|
||||
<string name="set_key_albums_sort" translatable="false">auxio_albums_sort</string>
|
||||
<string name="set_key_artists_sort" translatable="false">auxio_artists_sort</string>
|
||||
<string name="set_key_genres_sort" translatable="false">auxio_genres_sort</string>
|
||||
|
||||
<string name="set_key_detail_album_sort" translatable="false">auxio_album_sort</string>
|
||||
<string name="set_key_detail_artist_sort" translatable="false">auxio_artist_sort</string>
|
||||
<string name="set_key_detail_genre_sort" translatable="false">auxio_genre_sort</string>
|
||||
<string name="set_key_album_songs_sort" translatable="false">auxio_album_sort</string>
|
||||
<string name="set_key_artist_songs_sort" translatable="false">auxio_artist_sort</string>
|
||||
<string name="set_key_genre_songs_sort" translatable="false">auxio_genre_sort</string>
|
||||
|
||||
<string-array name="entries_theme">
|
||||
<item>@string/set_theme_auto</item>
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
<PreferenceCategory app:title="@string/set_display">
|
||||
|
||||
<org.oxycblt.auxio.settings.prefs.WrappedDialogPreference
|
||||
app:key="@string/set_key_lib_tabs"
|
||||
app:key="@string/set_key_home_tabs"
|
||||
app:summary="@string/set_lib_tabs_desc"
|
||||
app:title="@string/set_lib_tabs" />
|
||||
|
||||
|
@ -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" />
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in a new issue