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
|
#### What's Improved
|
||||||
- Added ability to edit previously played or currently playing items in the queue
|
- Added ability to edit previously played or currently playing items in the queue
|
||||||
|
- Added support for date values formatted as "YYYYMMDD"
|
||||||
|
|
||||||
#### What's Fixed
|
#### What's Fixed
|
||||||
- Fixed unreliable ReplayGain adjustment application in certain situations
|
- Fixed unreliable ReplayGain adjustment application in certain situations
|
||||||
- Fixed crash that would occur in music folders dialog when user does not have a working
|
- Fixed crash that would occur in music folders dialog when user does not have a working
|
||||||
file manager
|
file manager
|
||||||
|
- Fixed notification not updating due to settings changes
|
||||||
|
|
||||||
#### What's Changed
|
#### What's Changed
|
||||||
- Implemented new queue system
|
- Implemented new queue system
|
||||||
|
|
|
@ -28,30 +28,44 @@ import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||||
* User configuration specific to the home UI.
|
* User configuration specific to the home UI.
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
interface HomeSettings : Settings {
|
interface HomeSettings : Settings<HomeSettings.Listener> {
|
||||||
/** The tabs to show in the home UI. */
|
/** The tabs to show in the home UI. */
|
||||||
var homeTabs: Array<Tab>
|
var homeTabs: Array<Tab>
|
||||||
/** Whether to hide artists considered "collaborators" from the home UI. */
|
/** Whether to hide artists considered "collaborators" from the home UI. */
|
||||||
val shouldHideCollaborators: Boolean
|
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>
|
override var homeTabs: Array<Tab>
|
||||||
get() =
|
get() =
|
||||||
Tab.fromIntCode(
|
Tab.fromIntCode(
|
||||||
sharedPreferences.getInt(
|
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))
|
?: unlikelyToBeNull(Tab.fromIntCode(Tab.SEQUENCE_DEFAULT))
|
||||||
set(value) {
|
set(value) {
|
||||||
sharedPreferences.edit {
|
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()
|
apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val shouldHideCollaborators: Boolean
|
override val shouldHideCollaborators: Boolean
|
||||||
get() =
|
get() =
|
||||||
sharedPreferences.getBoolean(
|
sharedPreferences.getBoolean(getString(R.string.set_key_hide_collaborators), false)
|
||||||
context.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 {
|
companion object {
|
||||||
|
|
|
@ -18,17 +18,14 @@
|
||||||
package org.oxycblt.auxio.home
|
package org.oxycblt.auxio.home
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.SharedPreferences
|
|
||||||
import androidx.lifecycle.AndroidViewModel
|
import androidx.lifecycle.AndroidViewModel
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import org.oxycblt.auxio.R
|
|
||||||
import org.oxycblt.auxio.home.tabs.Tab
|
import org.oxycblt.auxio.home.tabs.Tab
|
||||||
import org.oxycblt.auxio.music.*
|
import org.oxycblt.auxio.music.*
|
||||||
import org.oxycblt.auxio.music.Library
|
import org.oxycblt.auxio.music.Library
|
||||||
import org.oxycblt.auxio.music.MusicStore
|
import org.oxycblt.auxio.music.MusicStore
|
||||||
import org.oxycblt.auxio.music.Sort
|
import org.oxycblt.auxio.music.Sort
|
||||||
import org.oxycblt.auxio.util.context
|
|
||||||
import org.oxycblt.auxio.util.logD
|
import org.oxycblt.auxio.util.logD
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,9 +33,7 @@ import org.oxycblt.auxio.util.logD
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
class HomeViewModel(application: Application) :
|
class HomeViewModel(application: Application) :
|
||||||
AndroidViewModel(application),
|
AndroidViewModel(application), MusicStore.Listener, HomeSettings.Listener {
|
||||||
MusicStore.Listener,
|
|
||||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
|
||||||
private val musicStore = MusicStore.getInstance()
|
private val musicStore = MusicStore.getInstance()
|
||||||
private val homeSettings = HomeSettings.from(application)
|
private val homeSettings = HomeSettings.from(application)
|
||||||
private val musicSettings = MusicSettings.from(application)
|
private val musicSettings = MusicSettings.from(application)
|
||||||
|
@ -92,13 +87,13 @@ class HomeViewModel(application: Application) :
|
||||||
|
|
||||||
init {
|
init {
|
||||||
musicStore.addListener(this)
|
musicStore.addListener(this)
|
||||||
homeSettings.addListener(this)
|
homeSettings.registerListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCleared() {
|
override fun onCleared() {
|
||||||
super.onCleared()
|
super.onCleared()
|
||||||
musicStore.removeListener(this)
|
musicStore.removeListener(this)
|
||||||
homeSettings.removeListener(this)
|
homeSettings.unregisterListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onLibraryChanged(library: Library?) {
|
override fun onLibraryChanged(library: Library?) {
|
||||||
|
@ -120,19 +115,16 @@ class HomeViewModel(application: Application) :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
override fun onTabsChanged() {
|
||||||
when (key) {
|
// Tabs changed, update the current tabs and set up a re-create event.
|
||||||
context.getString(R.string.set_key_lib_tabs) -> {
|
currentTabModes = makeTabModes()
|
||||||
// Tabs changed, update the current tabs and set up a re-create event.
|
_shouldRecreate.value = true
|
||||||
currentTabModes = makeTabModes()
|
}
|
||||||
_shouldRecreate.value = true
|
|
||||||
}
|
override fun onHideCollaboratorsChanged() {
|
||||||
context.getString(R.string.set_key_hide_collaborators) -> {
|
// Changes in the hide collaborator setting will change the artist contents
|
||||||
// Changes in the hide collaborator setting will change the artist contents
|
// of the library, consider it a library update.
|
||||||
// of the library, consider it a library update.
|
onLibraryChanged(musicStore.library)
|
||||||
onLibraryChanged(musicStore.library)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -27,16 +27,20 @@ import org.oxycblt.auxio.util.logD
|
||||||
* User configuration specific to image loading.
|
* User configuration specific to image loading.
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
interface ImageSettings : Settings {
|
interface ImageSettings : Settings<ImageSettings.Listener> {
|
||||||
/** The strategy to use when loading album covers. */
|
/** The strategy to use when loading album covers. */
|
||||||
val coverMode: CoverMode
|
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
|
override val coverMode: CoverMode
|
||||||
get() =
|
get() =
|
||||||
CoverMode.fromIntCode(
|
CoverMode.fromIntCode(
|
||||||
sharedPreferences.getInt(
|
sharedPreferences.getInt(getString(R.string.set_key_cover_mode), Int.MIN_VALUE))
|
||||||
context.getString(R.string.set_key_cover_mode), Int.MIN_VALUE))
|
|
||||||
?: CoverMode.MEDIA_STORE
|
?: CoverMode.MEDIA_STORE
|
||||||
|
|
||||||
override fun migrate() {
|
override fun migrate() {
|
||||||
|
@ -54,13 +58,19 @@ interface ImageSettings : Settings {
|
||||||
}
|
}
|
||||||
|
|
||||||
sharedPreferences.edit {
|
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_SHOW_COVERS)
|
||||||
remove(OLD_KEY_QUALITY_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 {
|
private companion object {
|
||||||
const val OLD_KEY_SHOW_COVERS = "KEY_SHOW_COVERS"
|
const val OLD_KEY_SHOW_COVERS = "KEY_SHOW_COVERS"
|
||||||
const val OLD_KEY_QUALITY_COVERS = "KEY_QUALITY_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.
|
* User configuration specific to music system.
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
interface MusicSettings : Settings {
|
interface MusicSettings : Settings<MusicSettings.Listener> {
|
||||||
/** The configuration on how to handle particular directories in the music library. */
|
/** The configuration on how to handle particular directories in the music library. */
|
||||||
var musicDirs: MusicDirectories
|
var musicDirs: MusicDirectories
|
||||||
/** Whether to exclude non-music audio files from the music library. */
|
/** 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. */
|
/** The [Sort] mode used in an [Genre]'s [Song] list. */
|
||||||
var genreSongSort: Sort
|
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)
|
private val storageManager = context.getSystemServiceCompat(StorageManager::class)
|
||||||
|
|
||||||
override var musicDirs: MusicDirectories
|
override var musicDirs: MusicDirectories
|
||||||
get() {
|
get() {
|
||||||
val dirs =
|
val dirs =
|
||||||
(sharedPreferences.getStringSet(
|
(sharedPreferences.getStringSet(getString(R.string.set_key_music_dirs), null)
|
||||||
context.getString(R.string.set_key_music_dirs), null)
|
|
||||||
?: emptySet())
|
?: emptySet())
|
||||||
.mapNotNull { Directory.fromDocumentTreeUri(storageManager, it) }
|
.mapNotNull { Directory.fromDocumentTreeUri(storageManager, it) }
|
||||||
return MusicDirectories(
|
return MusicDirectories(
|
||||||
dirs,
|
dirs,
|
||||||
sharedPreferences.getBoolean(
|
sharedPreferences.getBoolean(
|
||||||
context.getString(R.string.set_key_music_dirs_include), false))
|
getString(R.string.set_key_music_dirs_include), false))
|
||||||
}
|
}
|
||||||
set(value) {
|
set(value) {
|
||||||
sharedPreferences.edit {
|
sharedPreferences.edit {
|
||||||
putStringSet(
|
putStringSet(
|
||||||
context.getString(R.string.set_key_music_dirs),
|
getString(R.string.set_key_music_dirs),
|
||||||
value.dirs.map(Directory::toDocumentTreeUri).toSet())
|
value.dirs.map(Directory::toDocumentTreeUri).toSet())
|
||||||
putBoolean(
|
putBoolean(getString(R.string.set_key_music_dirs_include), value.shouldInclude)
|
||||||
context.getString(R.string.set_key_music_dirs_include), value.shouldInclude)
|
|
||||||
apply()
|
apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val excludeNonMusic: Boolean
|
override val excludeNonMusic: Boolean
|
||||||
get() =
|
get() =
|
||||||
sharedPreferences.getBoolean(
|
sharedPreferences.getBoolean(getString(R.string.set_key_exclude_non_music), true)
|
||||||
context.getString(R.string.set_key_exclude_non_music), true)
|
|
||||||
|
|
||||||
override val shouldBeObserving: Boolean
|
override val shouldBeObserving: Boolean
|
||||||
get() =
|
get() = sharedPreferences.getBoolean(getString(R.string.set_key_observing), false)
|
||||||
sharedPreferences.getBoolean(context.getString(R.string.set_key_observing), false)
|
|
||||||
|
|
||||||
override var multiValueSeparators: String
|
override var multiValueSeparators: String
|
||||||
// Differ from convention and store a string of separator characters instead of an int
|
// Differ from convention and store a string of separator characters instead of an int
|
||||||
// code. This makes it easier to use and more extendable.
|
// code. This makes it easier to use and more extendable.
|
||||||
get() =
|
get() = sharedPreferences.getString(getString(R.string.set_key_separators), "") ?: ""
|
||||||
sharedPreferences.getString(context.getString(R.string.set_key_separators), "")
|
|
||||||
?: ""
|
|
||||||
set(value) {
|
set(value) {
|
||||||
sharedPreferences.edit {
|
sharedPreferences.edit {
|
||||||
putString(context.getString(R.string.set_key_separators), value)
|
putString(getString(R.string.set_key_separators), value)
|
||||||
apply()
|
apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,12 +106,11 @@ interface MusicSettings : Settings {
|
||||||
override var songSort: Sort
|
override var songSort: Sort
|
||||||
get() =
|
get() =
|
||||||
Sort.fromIntCode(
|
Sort.fromIntCode(
|
||||||
sharedPreferences.getInt(
|
sharedPreferences.getInt(getString(R.string.set_key_songs_sort), Int.MIN_VALUE))
|
||||||
context.getString(R.string.set_key_lib_songs_sort), Int.MIN_VALUE))
|
|
||||||
?: Sort(Sort.Mode.ByName, true)
|
?: Sort(Sort.Mode.ByName, true)
|
||||||
set(value) {
|
set(value) {
|
||||||
sharedPreferences.edit {
|
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()
|
apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,11 +119,11 @@ interface MusicSettings : Settings {
|
||||||
get() =
|
get() =
|
||||||
Sort.fromIntCode(
|
Sort.fromIntCode(
|
||||||
sharedPreferences.getInt(
|
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)
|
?: Sort(Sort.Mode.ByName, true)
|
||||||
set(value) {
|
set(value) {
|
||||||
sharedPreferences.edit {
|
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()
|
apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,11 +132,11 @@ interface MusicSettings : Settings {
|
||||||
get() =
|
get() =
|
||||||
Sort.fromIntCode(
|
Sort.fromIntCode(
|
||||||
sharedPreferences.getInt(
|
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)
|
?: Sort(Sort.Mode.ByName, true)
|
||||||
set(value) {
|
set(value) {
|
||||||
sharedPreferences.edit {
|
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()
|
apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,11 +145,11 @@ interface MusicSettings : Settings {
|
||||||
get() =
|
get() =
|
||||||
Sort.fromIntCode(
|
Sort.fromIntCode(
|
||||||
sharedPreferences.getInt(
|
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)
|
?: Sort(Sort.Mode.ByName, true)
|
||||||
set(value) {
|
set(value) {
|
||||||
sharedPreferences.edit {
|
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()
|
apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,7 +159,7 @@ interface MusicSettings : Settings {
|
||||||
var sort =
|
var sort =
|
||||||
Sort.fromIntCode(
|
Sort.fromIntCode(
|
||||||
sharedPreferences.getInt(
|
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)
|
?: Sort(Sort.Mode.ByDisc, true)
|
||||||
|
|
||||||
// Correct legacy album sort modes to Disc
|
// Correct legacy album sort modes to Disc
|
||||||
|
@ -171,7 +171,7 @@ interface MusicSettings : Settings {
|
||||||
}
|
}
|
||||||
set(value) {
|
set(value) {
|
||||||
sharedPreferences.edit {
|
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()
|
apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,11 +180,11 @@ interface MusicSettings : Settings {
|
||||||
get() =
|
get() =
|
||||||
Sort.fromIntCode(
|
Sort.fromIntCode(
|
||||||
sharedPreferences.getInt(
|
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)
|
?: Sort(Sort.Mode.ByDate, false)
|
||||||
set(value) {
|
set(value) {
|
||||||
sharedPreferences.edit {
|
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()
|
apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,14 +193,24 @@ interface MusicSettings : Settings {
|
||||||
get() =
|
get() =
|
||||||
Sort.fromIntCode(
|
Sort.fromIntCode(
|
||||||
sharedPreferences.getInt(
|
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)
|
?: Sort(Sort.Mode.ByName, true)
|
||||||
set(value) {
|
set(value) {
|
||||||
sharedPreferences.edit {
|
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()
|
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 {
|
companion object {
|
||||||
|
|
|
@ -19,7 +19,6 @@ package org.oxycblt.auxio.music.system
|
||||||
|
|
||||||
import android.app.Service
|
import android.app.Service
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.SharedPreferences
|
|
||||||
import android.database.ContentObserver
|
import android.database.ContentObserver
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
|
@ -32,7 +31,6 @@ import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.oxycblt.auxio.BuildConfig
|
import org.oxycblt.auxio.BuildConfig
|
||||||
import org.oxycblt.auxio.R
|
|
||||||
import org.oxycblt.auxio.music.MusicSettings
|
import org.oxycblt.auxio.music.MusicSettings
|
||||||
import org.oxycblt.auxio.music.MusicStore
|
import org.oxycblt.auxio.music.MusicStore
|
||||||
import org.oxycblt.auxio.music.storage.contentResolverSafe
|
import org.oxycblt.auxio.music.storage.contentResolverSafe
|
||||||
|
@ -55,8 +53,7 @@ import org.oxycblt.auxio.util.logD
|
||||||
*
|
*
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
class IndexerService :
|
class IndexerService : Service(), Indexer.Controller, MusicSettings.Listener {
|
||||||
Service(), Indexer.Controller, SharedPreferences.OnSharedPreferenceChangeListener {
|
|
||||||
private val indexer = Indexer.getInstance()
|
private val indexer = Indexer.getInstance()
|
||||||
private val musicStore = MusicStore.getInstance()
|
private val musicStore = MusicStore.getInstance()
|
||||||
private val playbackManager = PlaybackStateManager.getInstance()
|
private val playbackManager = PlaybackStateManager.getInstance()
|
||||||
|
@ -84,7 +81,7 @@ class IndexerService :
|
||||||
// condition to cause us to load music before we were fully initialize.
|
// condition to cause us to load music before we were fully initialize.
|
||||||
indexerContentObserver = SystemContentObserver()
|
indexerContentObserver = SystemContentObserver()
|
||||||
settings = MusicSettings.from(this)
|
settings = MusicSettings.from(this)
|
||||||
settings.addListener(this)
|
settings.registerListener(this)
|
||||||
indexer.registerController(this)
|
indexer.registerController(this)
|
||||||
// An indeterminate indexer and a missing library implies we are extremely early
|
// An indeterminate indexer and a missing library implies we are extremely early
|
||||||
// in app initialization so start loading music.
|
// in app initialization so start loading music.
|
||||||
|
@ -108,7 +105,7 @@ class IndexerService :
|
||||||
// Then cancel the listener-dependent components to ensure that stray reloading
|
// Then cancel the listener-dependent components to ensure that stray reloading
|
||||||
// events will not occur.
|
// events will not occur.
|
||||||
indexerContentObserver.release()
|
indexerContentObserver.release()
|
||||||
settings.removeListener(this)
|
settings.unregisterListener(this)
|
||||||
indexer.unregisterController(this)
|
indexer.unregisterController(this)
|
||||||
// Then cancel any remaining music loading jobs.
|
// Then cancel any remaining music loading jobs.
|
||||||
serviceJob.cancel()
|
serviceJob.cancel()
|
||||||
|
@ -230,22 +227,18 @@ class IndexerService :
|
||||||
|
|
||||||
// --- SETTING CALLBACKS ---
|
// --- SETTING CALLBACKS ---
|
||||||
|
|
||||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
override fun onIndexingSettingChanged() {
|
||||||
when (key) {
|
// Music loading configuration changed, need to reload music.
|
||||||
// Hook changes in music settings to a new music loading event.
|
onStartIndexing(true)
|
||||||
getString(R.string.set_key_exclude_non_music),
|
}
|
||||||
getString(R.string.set_key_music_dirs),
|
|
||||||
getString(R.string.set_key_music_dirs_include),
|
override fun onObservingChanged() {
|
||||||
getString(R.string.set_key_separators) -> onStartIndexing(true)
|
// Make sure we don't override the service state with the observing
|
||||||
getString(R.string.set_key_observing) -> {
|
// notification if we were actively loading when the automatic rescanning
|
||||||
// Make sure we don't override the service state with the observing
|
// setting changed. In such a case, the state will still be updated when
|
||||||
// notification if we were actively loading when the automatic rescanning
|
// the music loading process ends.
|
||||||
// setting changed. In such a case, the state will still be updated when
|
if (!indexer.isIndexing) {
|
||||||
// the music loading process ends.
|
updateIdleSession()
|
||||||
if (!indexer.isIndexing) {
|
|
||||||
updateIdleSession()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ class PlaybackBarFragment : ViewBindingFragment<FragmentPlaybackBarBinding>() {
|
||||||
|
|
||||||
// Set up actions
|
// Set up actions
|
||||||
binding.playbackPlayPause.setOnClickListener { playbackModel.toggleIsPlaying() }
|
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
|
// Load the track color in manually as it's unclear whether the track actually supports
|
||||||
// using a ColorStateList in the resources.
|
// using a ColorStateList in the resources.
|
||||||
|
|
|
@ -31,11 +31,11 @@ import org.oxycblt.auxio.util.logD
|
||||||
* User configuration specific to the playback system.
|
* User configuration specific to the playback system.
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
interface PlaybackSettings : Settings {
|
interface PlaybackSettings : Settings<PlaybackSettings.Listener> {
|
||||||
/** The action to display on the playback bar. */
|
/** The action to display on the playback bar. */
|
||||||
val playbackBarAction: ActionMode
|
val barAction: ActionMode
|
||||||
/** The action to display in the playback notification. */
|
/** The action to display in the playback notification. */
|
||||||
val playbackNotificationAction: ActionMode
|
val notificationAction: ActionMode
|
||||||
/** Whether to start playback when a headset is plugged in. */
|
/** Whether to start playback when a headset is plugged in. */
|
||||||
val headsetAutoplay: Boolean
|
val headsetAutoplay: Boolean
|
||||||
/** The current ReplayGain configuration. */
|
/** The current ReplayGain configuration. */
|
||||||
|
@ -59,75 +59,72 @@ interface PlaybackSettings : Settings {
|
||||||
/** Whether a song should pause after every repeat. */
|
/** Whether a song should pause after every repeat. */
|
||||||
val pauseOnRepeat: Boolean
|
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
|
override val inListPlaybackMode: MusicMode
|
||||||
get() =
|
get() =
|
||||||
MusicMode.fromIntCode(
|
MusicMode.fromIntCode(
|
||||||
sharedPreferences.getInt(
|
sharedPreferences.getInt(
|
||||||
context.getString(R.string.set_key_library_song_playback_mode),
|
getString(R.string.set_key_in_list_playback_mode), Int.MIN_VALUE))
|
||||||
Int.MIN_VALUE))
|
|
||||||
?: MusicMode.SONGS
|
?: MusicMode.SONGS
|
||||||
|
|
||||||
override val inParentPlaybackMode: MusicMode?
|
override val inParentPlaybackMode: MusicMode?
|
||||||
get() =
|
get() =
|
||||||
MusicMode.fromIntCode(
|
MusicMode.fromIntCode(
|
||||||
sharedPreferences.getInt(
|
sharedPreferences.getInt(
|
||||||
context.getString(R.string.set_key_detail_song_playback_mode),
|
getString(R.string.set_key_in_parent_playback_mode), Int.MIN_VALUE))
|
||||||
Int.MIN_VALUE))
|
|
||||||
|
|
||||||
override val playbackBarAction: ActionMode
|
override val barAction: ActionMode
|
||||||
get() =
|
get() =
|
||||||
ActionMode.fromIntCode(
|
ActionMode.fromIntCode(
|
||||||
sharedPreferences.getInt(
|
sharedPreferences.getInt(getString(R.string.set_key_bar_action), Int.MIN_VALUE))
|
||||||
context.getString(R.string.set_key_bar_action), Int.MIN_VALUE))
|
|
||||||
?: ActionMode.NEXT
|
?: ActionMode.NEXT
|
||||||
|
|
||||||
override val playbackNotificationAction: ActionMode
|
override val notificationAction: ActionMode
|
||||||
get() =
|
get() =
|
||||||
ActionMode.fromIntCode(
|
ActionMode.fromIntCode(
|
||||||
sharedPreferences.getInt(
|
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
|
?: ActionMode.REPEAT
|
||||||
|
|
||||||
override val headsetAutoplay: Boolean
|
override val headsetAutoplay: Boolean
|
||||||
get() =
|
get() =
|
||||||
sharedPreferences.getBoolean(
|
sharedPreferences.getBoolean(getString(R.string.set_key_headset_autoplay), false)
|
||||||
context.getString(R.string.set_key_headset_autoplay), false)
|
|
||||||
|
|
||||||
override val replayGainMode: ReplayGainMode
|
override val replayGainMode: ReplayGainMode
|
||||||
get() =
|
get() =
|
||||||
ReplayGainMode.fromIntCode(
|
ReplayGainMode.fromIntCode(
|
||||||
sharedPreferences.getInt(
|
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
|
?: ReplayGainMode.DYNAMIC
|
||||||
|
|
||||||
override var replayGainPreAmp: ReplayGainPreAmp
|
override var replayGainPreAmp: ReplayGainPreAmp
|
||||||
get() =
|
get() =
|
||||||
ReplayGainPreAmp(
|
ReplayGainPreAmp(
|
||||||
sharedPreferences.getFloat(
|
sharedPreferences.getFloat(getString(R.string.set_key_pre_amp_with), 0f),
|
||||||
context.getString(R.string.set_key_pre_amp_with), 0f),
|
sharedPreferences.getFloat(getString(R.string.set_key_pre_amp_without), 0f))
|
||||||
sharedPreferences.getFloat(
|
|
||||||
context.getString(R.string.set_key_pre_amp_without), 0f))
|
|
||||||
set(value) {
|
set(value) {
|
||||||
sharedPreferences.edit {
|
sharedPreferences.edit {
|
||||||
putFloat(context.getString(R.string.set_key_pre_amp_with), value.with)
|
putFloat(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_without), value.without)
|
||||||
apply()
|
apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val keepShuffle: Boolean
|
override val keepShuffle: Boolean
|
||||||
get() =
|
get() = sharedPreferences.getBoolean(getString(R.string.set_key_keep_shuffle), true)
|
||||||
sharedPreferences.getBoolean(context.getString(R.string.set_key_keep_shuffle), true)
|
|
||||||
|
|
||||||
override val rewindWithPrev: Boolean
|
override val rewindWithPrev: Boolean
|
||||||
get() =
|
get() = sharedPreferences.getBoolean(getString(R.string.set_key_rewind_prev), true)
|
||||||
sharedPreferences.getBoolean(context.getString(R.string.set_key_rewind_prev), true)
|
|
||||||
|
|
||||||
override val pauseOnRepeat: Boolean
|
override val pauseOnRepeat: Boolean
|
||||||
get() =
|
get() = sharedPreferences.getBoolean(getString(R.string.set_key_repeat_pause), false)
|
||||||
sharedPreferences.getBoolean(
|
|
||||||
context.getString(R.string.set_key_repeat_pause), false)
|
|
||||||
|
|
||||||
override fun migrate() {
|
override fun migrate() {
|
||||||
// "Use alternate notification action" was converted to an ActionMode setting in 3.0.0.
|
// "Use alternate notification action" was converted to an ActionMode setting in 3.0.0.
|
||||||
|
@ -142,7 +139,7 @@ interface PlaybackSettings : Settings {
|
||||||
}
|
}
|
||||||
|
|
||||||
sharedPreferences.edit {
|
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)
|
remove(OLD_KEY_ALT_NOTIF_ACTION)
|
||||||
apply()
|
apply()
|
||||||
}
|
}
|
||||||
|
@ -170,9 +167,7 @@ interface PlaybackSettings : Settings {
|
||||||
?: MusicMode.SONGS
|
?: MusicMode.SONGS
|
||||||
|
|
||||||
sharedPreferences.edit {
|
sharedPreferences.edit {
|
||||||
putInt(
|
putInt(getString(R.string.set_key_in_list_playback_mode), mode.intCode)
|
||||||
context.getString(R.string.set_key_library_song_playback_mode),
|
|
||||||
mode.intCode)
|
|
||||||
remove(OLD_KEY_LIB_PLAYBACK_MODE)
|
remove(OLD_KEY_LIB_PLAYBACK_MODE)
|
||||||
apply()
|
apply()
|
||||||
}
|
}
|
||||||
|
@ -188,7 +183,7 @@ interface PlaybackSettings : Settings {
|
||||||
|
|
||||||
sharedPreferences.edit {
|
sharedPreferences.edit {
|
||||||
putInt(
|
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)
|
mode?.intCode ?: Int.MIN_VALUE)
|
||||||
remove(OLD_KEY_DETAIL_PLAYBACK_MODE)
|
remove(OLD_KEY_DETAIL_PLAYBACK_MODE)
|
||||||
apply()
|
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 {
|
companion object {
|
||||||
const val OLD_KEY_ALT_NOTIF_ACTION = "KEY_ALT_NOTIF_ACTION"
|
const val OLD_KEY_ALT_NOTIF_ACTION = "KEY_ALT_NOTIF_ACTION"
|
||||||
const val OLD_KEY_LIB_PLAYBACK_MODE = "KEY_SONG_PLAY_MODE2"
|
const val OLD_KEY_LIB_PLAYBACK_MODE = "KEY_SONG_PLAY_MODE2"
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
package org.oxycblt.auxio.playback.replaygain
|
package org.oxycblt.auxio.playback.replaygain
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
|
||||||
import com.google.android.exoplayer2.C
|
import com.google.android.exoplayer2.C
|
||||||
import com.google.android.exoplayer2.Format
|
import com.google.android.exoplayer2.Format
|
||||||
import com.google.android.exoplayer2.Player
|
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 com.google.android.exoplayer2.util.MimeTypes
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
import org.oxycblt.auxio.R
|
|
||||||
import org.oxycblt.auxio.music.Album
|
import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.music.extractor.TextTags
|
import org.oxycblt.auxio.music.extractor.TextTags
|
||||||
import org.oxycblt.auxio.playback.PlaybackSettings
|
import org.oxycblt.auxio.playback.PlaybackSettings
|
||||||
|
@ -45,10 +43,10 @@ import org.oxycblt.auxio.util.logD
|
||||||
*
|
*
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
class ReplayGainAudioProcessor(private val context: Context) :
|
class ReplayGainAudioProcessor(context: Context) :
|
||||||
BaseAudioProcessor(), Player.Listener, SharedPreferences.OnSharedPreferenceChangeListener {
|
BaseAudioProcessor(), Player.Listener, PlaybackSettings.Listener {
|
||||||
private val playbackManager = PlaybackStateManager.getInstance()
|
private val playbackManager = PlaybackStateManager.getInstance()
|
||||||
private val settings = PlaybackSettings.from(context)
|
private val playbackSettings = PlaybackSettings.from(context)
|
||||||
private var lastFormat: Format? = null
|
private var lastFormat: Format? = null
|
||||||
|
|
||||||
private var volume = 1f
|
private var volume = 1f
|
||||||
|
@ -65,7 +63,7 @@ class ReplayGainAudioProcessor(private val context: Context) :
|
||||||
*/
|
*/
|
||||||
fun addToListeners(player: Player) {
|
fun addToListeners(player: Player) {
|
||||||
player.addListener(this)
|
player.addListener(this)
|
||||||
settings.addListener(this)
|
playbackSettings.registerListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -75,7 +73,7 @@ class ReplayGainAudioProcessor(private val context: Context) :
|
||||||
*/
|
*/
|
||||||
fun releaseFromListeners(player: Player) {
|
fun releaseFromListeners(player: Player) {
|
||||||
player.removeListener(this)
|
player.removeListener(this)
|
||||||
settings.removeListener(this)
|
playbackSettings.unregisterListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- OVERRIDES ---
|
// --- OVERRIDES ---
|
||||||
|
@ -98,13 +96,9 @@ class ReplayGainAudioProcessor(private val context: Context) :
|
||||||
applyReplayGain(null)
|
applyReplayGain(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
|
override fun onReplayGainSettingsChanged() {
|
||||||
if (key == context.getString(R.string.set_key_replay_gain) ||
|
// ReplayGain config changed, we need to set it up again.
|
||||||
key == context.getString(R.string.set_key_pre_amp_with) ||
|
applyReplayGain(lastFormat)
|
||||||
key == context.getString(R.string.set_key_pre_amp_without)) {
|
|
||||||
// ReplayGain changed, we need to set it up again.
|
|
||||||
applyReplayGain(lastFormat)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- REPLAYGAIN PARSING ---
|
// --- REPLAYGAIN PARSING ---
|
||||||
|
@ -116,14 +110,14 @@ class ReplayGainAudioProcessor(private val context: Context) :
|
||||||
private fun applyReplayGain(format: Format?) {
|
private fun applyReplayGain(format: Format?) {
|
||||||
lastFormat = format
|
lastFormat = format
|
||||||
val gain = parseReplayGain(format ?: return)
|
val gain = parseReplayGain(format ?: return)
|
||||||
val preAmp = settings.replayGainPreAmp
|
val preAmp = playbackSettings.replayGainPreAmp
|
||||||
|
|
||||||
val adjust =
|
val adjust =
|
||||||
if (gain != null) {
|
if (gain != null) {
|
||||||
logD("Found ReplayGain adjustment $gain")
|
logD("Found ReplayGain adjustment $gain")
|
||||||
// ReplayGain is configurable, so determine what to do based off of the mode.
|
// ReplayGain is configurable, so determine what to do based off of the mode.
|
||||||
val useAlbumGain =
|
val useAlbumGain =
|
||||||
when (settings.replayGainMode) {
|
when (playbackSettings.replayGainMode) {
|
||||||
// User wants track gain to be preferred. Default to album gain only if
|
// User wants track gain to be preferred. Default to album gain only if
|
||||||
// there is no track gain.
|
// there is no track gain.
|
||||||
ReplayGainMode.TRACK -> gain.track == 0f
|
ReplayGainMode.TRACK -> gain.track == 0f
|
||||||
|
|
|
@ -116,7 +116,7 @@ class PlaybackStateManager private constructor() {
|
||||||
*/
|
*/
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun registerInternalPlayer(internalPlayer: InternalPlayer) {
|
fun registerInternalPlayer(internalPlayer: InternalPlayer) {
|
||||||
if (BuildConfig.DEBUG && this.internalPlayer != null) {
|
if (this.internalPlayer != null) {
|
||||||
logW("Internal player is already registered")
|
logW("Internal player is already registered")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -141,7 +141,7 @@ class PlaybackStateManager private constructor() {
|
||||||
*/
|
*/
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun unregisterInternalPlayer(internalPlayer: InternalPlayer) {
|
fun unregisterInternalPlayer(internalPlayer: InternalPlayer) {
|
||||||
if (BuildConfig.DEBUG && this.internalPlayer !== internalPlayer) {
|
if (this.internalPlayer !== internalPlayer) {
|
||||||
logW("Given internal player did not match current internal player")
|
logW("Given internal player did not match current internal player")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@ package org.oxycblt.auxio.playback.system
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.SharedPreferences
|
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
@ -31,6 +30,7 @@ import androidx.media.session.MediaButtonReceiver
|
||||||
import org.oxycblt.auxio.BuildConfig
|
import org.oxycblt.auxio.BuildConfig
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.image.BitmapProvider
|
import org.oxycblt.auxio.image.BitmapProvider
|
||||||
|
import org.oxycblt.auxio.image.ImageSettings
|
||||||
import org.oxycblt.auxio.music.MusicParent
|
import org.oxycblt.auxio.music.MusicParent
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.playback.ActionMode
|
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) :
|
class MediaSessionComponent(private val context: Context, private val listener: Listener) :
|
||||||
MediaSessionCompat.Callback(),
|
MediaSessionCompat.Callback(),
|
||||||
PlaybackStateManager.Listener,
|
PlaybackStateManager.Listener,
|
||||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
ImageSettings.Listener,
|
||||||
|
PlaybackSettings.Listener {
|
||||||
private val mediaSession =
|
private val mediaSession =
|
||||||
MediaSessionCompat(context, context.packageName).apply {
|
MediaSessionCompat(context, context.packageName).apply {
|
||||||
isActive = true
|
isActive = true
|
||||||
|
@ -59,13 +60,14 @@ class MediaSessionComponent(private val context: Context, private val listener:
|
||||||
}
|
}
|
||||||
|
|
||||||
private val playbackManager = PlaybackStateManager.getInstance()
|
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 notification = NotificationComponent(context, mediaSession.sessionToken)
|
||||||
private val provider = BitmapProvider(context)
|
private val provider = BitmapProvider(context)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
playbackManager.addListener(this)
|
playbackManager.addListener(this)
|
||||||
|
playbackSettings.registerListener(this)
|
||||||
mediaSession.setCallback(this)
|
mediaSession.setCallback(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +85,7 @@ class MediaSessionComponent(private val context: Context, private val listener:
|
||||||
*/
|
*/
|
||||||
fun release() {
|
fun release() {
|
||||||
provider.release()
|
provider.release()
|
||||||
settings.removeListener(this)
|
playbackSettings.unregisterListener(this)
|
||||||
playbackManager.removeListener(this)
|
playbackManager.removeListener(this)
|
||||||
mediaSession.apply {
|
mediaSession.apply {
|
||||||
isActive = false
|
isActive = false
|
||||||
|
@ -150,12 +152,14 @@ class MediaSessionComponent(private val context: Context, private val listener:
|
||||||
|
|
||||||
// --- SETTINGS OVERRIDES ---
|
// --- SETTINGS OVERRIDES ---
|
||||||
|
|
||||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
override fun onCoverModeChanged() {
|
||||||
when (key) {
|
// Need to reload the metadata cover.
|
||||||
context.getString(R.string.set_key_cover_mode) ->
|
updateMediaMetadata(playbackManager.queue.currentSong, playbackManager.parent)
|
||||||
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 ---
|
// --- 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)
|
// Add the secondary action (either repeat/shuffle depending on the configuration)
|
||||||
val secondaryAction =
|
val secondaryAction =
|
||||||
when (settings.playbackNotificationAction) {
|
when (playbackSettings.notificationAction) {
|
||||||
ActionMode.SHUFFLE ->
|
ActionMode.SHUFFLE ->
|
||||||
PlaybackStateCompat.CustomAction.Builder(
|
PlaybackStateCompat.CustomAction.Builder(
|
||||||
PlaybackService.ACTION_INVERT_SHUFFLE,
|
PlaybackService.ACTION_INVERT_SHUFFLE,
|
||||||
|
@ -393,7 +397,7 @@ class MediaSessionComponent(private val context: Context, private val listener:
|
||||||
private fun invalidateSecondaryAction() {
|
private fun invalidateSecondaryAction() {
|
||||||
invalidateSessionState()
|
invalidateSessionState()
|
||||||
|
|
||||||
when (settings.playbackNotificationAction) {
|
when (playbackSettings.notificationAction) {
|
||||||
ActionMode.SHUFFLE -> notification.updateShuffled(playbackManager.queue.isShuffled)
|
ActionMode.SHUFFLE -> notification.updateShuffled(playbackManager.queue.isShuffled)
|
||||||
else -> notification.updateRepeatMode(playbackManager.repeatMode)
|
else -> notification.updateRepeatMode(playbackManager.repeatMode)
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,21 +27,20 @@ import org.oxycblt.auxio.settings.Settings
|
||||||
* User configuration specific to the search UI.
|
* User configuration specific to the search UI.
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
interface SearchSettings : Settings {
|
interface SearchSettings : Settings<Nothing> {
|
||||||
/** The type of Music the search view is currently filtering to. */
|
/** The type of Music the search view is currently filtering to. */
|
||||||
var searchFilterMode: MusicMode?
|
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?
|
override var searchFilterMode: MusicMode?
|
||||||
get() =
|
get() =
|
||||||
MusicMode.fromIntCode(
|
MusicMode.fromIntCode(
|
||||||
sharedPreferences.getInt(
|
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) {
|
set(value) {
|
||||||
sharedPreferences.edit {
|
sharedPreferences.edit {
|
||||||
putInt(
|
putInt(
|
||||||
context.getString(R.string.set_key_search_filter),
|
getString(R.string.set_key_search_filter), value?.intCode ?: Int.MIN_VALUE)
|
||||||
value?.intCode ?: Int.MIN_VALUE)
|
|
||||||
apply()
|
apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,49 +19,75 @@ package org.oxycblt.auxio.settings
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
|
import androidx.annotation.StringRes
|
||||||
import androidx.preference.PreferenceManager
|
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
|
* Abstract user configuration information. This interface has no functionality whatsoever. Concrete
|
||||||
* implementations should be preferred instead.
|
* implementations should be preferred instead.
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
interface Settings {
|
interface Settings<L> {
|
||||||
/** Migrate any settings fields from older versions into their new counterparts. */
|
/**
|
||||||
|
* Migrate any settings fields from older versions into their new counterparts.
|
||||||
|
* @throws NotImplementedError If there is nothing to migrate.
|
||||||
|
*/
|
||||||
fun migrate() {
|
fun migrate() {
|
||||||
throw NotImplementedError()
|
throw NotImplementedError()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a [SharedPreferences.OnSharedPreferenceChangeListener] to monitor for settings updates.
|
* Add a listener to monitor for settings updates. Will do nothing if
|
||||||
* @param listener The [SharedPreferences.OnSharedPreferenceChangeListener] to add.
|
* @param listener The listener to add.
|
||||||
*/
|
*/
|
||||||
fun addListener(listener: SharedPreferences.OnSharedPreferenceChangeListener) {
|
fun registerListener(listener: L)
|
||||||
throw NotImplementedError()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unregister a [SharedPreferences.OnSharedPreferenceChangeListener], preventing any further
|
* Unregister a listener, preventing any further settings updates from being sent to it.
|
||||||
* settings updates from being sent to ti.t
|
* @param listener The listener to unregister, must be the same as the current listener.
|
||||||
*/
|
*/
|
||||||
fun removeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener) {
|
fun unregisterListener(listener: L)
|
||||||
throw NotImplementedError()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A framework-backed [Settings] implementation.
|
* A framework-backed [Settings] implementation.
|
||||||
* @param context [Context] required.
|
* @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 =
|
protected val sharedPreferences: SharedPreferences =
|
||||||
PreferenceManager.getDefaultSharedPreferences(context.applicationContext)
|
PreferenceManager.getDefaultSharedPreferences(context.applicationContext)
|
||||||
|
|
||||||
override fun addListener(listener: SharedPreferences.OnSharedPreferenceChangeListener) {
|
/** @see [Context.getString] */
|
||||||
sharedPreferences.registerOnSharedPreferenceChangeListener(listener)
|
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) {
|
override fun unregisterListener(listener: L) {
|
||||||
sharedPreferences.unregisterOnSharedPreferenceChangeListener(listener)
|
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) {
|
when (preference.key) {
|
||||||
getString(R.string.set_key_accent) ->
|
getString(R.string.set_key_accent) ->
|
||||||
SettingsFragmentDirections.goToAccentDialog()
|
SettingsFragmentDirections.goToAccentDialog()
|
||||||
getString(R.string.set_key_lib_tabs) ->
|
getString(R.string.set_key_home_tabs) ->
|
||||||
SettingsFragmentDirections.goToTabDialog()
|
SettingsFragmentDirections.goToTabDialog()
|
||||||
getString(R.string.set_key_pre_amp) ->
|
getString(R.string.set_key_pre_amp) ->
|
||||||
SettingsFragmentDirections.goToPreAmpDialog()
|
SettingsFragmentDirections.goToPreAmpDialog()
|
||||||
|
|
|
@ -26,7 +26,11 @@ import org.oxycblt.auxio.settings.Settings
|
||||||
import org.oxycblt.auxio.ui.accent.Accent
|
import org.oxycblt.auxio.ui.accent.Accent
|
||||||
import org.oxycblt.auxio.util.logD
|
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. */
|
/** The current theme. Represented by the AppCompatDelegate constants. */
|
||||||
val theme: Int
|
val theme: Int
|
||||||
/** Whether to use a black background when a dark theme is currently used. */
|
/** 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. */
|
/** Whether to round additional UI elements that require album covers to be rounded. */
|
||||||
val roundMode: Boolean
|
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
|
override val theme: Int
|
||||||
get() =
|
get() =
|
||||||
sharedPreferences.getInt(
|
sharedPreferences.getInt(
|
||||||
context.getString(R.string.set_key_theme),
|
getString(R.string.set_key_theme), AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||||
AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
|
||||||
|
|
||||||
override val useBlackTheme: Boolean
|
override val useBlackTheme: Boolean
|
||||||
get() =
|
get() = sharedPreferences.getBoolean(getString(R.string.set_key_black_theme), false)
|
||||||
sharedPreferences.getBoolean(context.getString(R.string.set_key_black_theme), false)
|
|
||||||
|
|
||||||
override var accent: Accent
|
override var accent: Accent
|
||||||
get() =
|
get() =
|
||||||
Accent.from(
|
Accent.from(
|
||||||
sharedPreferences.getInt(
|
sharedPreferences.getInt(getString(R.string.set_key_accent), Accent.DEFAULT))
|
||||||
context.getString(R.string.set_key_accent), Accent.DEFAULT))
|
|
||||||
set(value) {
|
set(value) {
|
||||||
sharedPreferences.edit {
|
sharedPreferences.edit {
|
||||||
putInt(context.getString(R.string.set_key_accent), value.index)
|
putInt(getString(R.string.set_key_accent), value.index)
|
||||||
apply()
|
apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val roundMode: Boolean
|
override val roundMode: Boolean
|
||||||
get() =
|
get() = sharedPreferences.getBoolean(getString(R.string.set_key_round_mode), false)
|
||||||
sharedPreferences.getBoolean(context.getString(R.string.set_key_round_mode), false)
|
|
||||||
|
|
||||||
override fun migrate() {
|
override fun migrate() {
|
||||||
if (sharedPreferences.contains(OLD_KEY_ACCENT3)) {
|
if (sharedPreferences.contains(OLD_KEY_ACCENT3)) {
|
||||||
|
@ -78,13 +83,19 @@ interface UISettings : Settings {
|
||||||
}
|
}
|
||||||
|
|
||||||
sharedPreferences.edit {
|
sharedPreferences.edit {
|
||||||
putInt(context.getString(R.string.set_key_accent), accent)
|
putInt(getString(R.string.set_key_accent), accent)
|
||||||
remove(OLD_KEY_ACCENT3)
|
remove(OLD_KEY_ACCENT3)
|
||||||
apply()
|
apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onSettingChanged(key: String, listener: Listener) {
|
||||||
|
if (key == getString(R.string.set_key_round_mode)) {
|
||||||
|
listener.onRoundModeChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val OLD_KEY_ACCENT3 = "auxio_accent"
|
const val OLD_KEY_ACCENT3 = "auxio_accent"
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,13 +18,13 @@
|
||||||
package org.oxycblt.auxio.widgets
|
package org.oxycblt.auxio.widgets
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
import coil.transform.RoundedCornersTransformation
|
import coil.transform.RoundedCornersTransformation
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.image.BitmapProvider
|
import org.oxycblt.auxio.image.BitmapProvider
|
||||||
|
import org.oxycblt.auxio.image.ImageSettings
|
||||||
import org.oxycblt.auxio.image.extractor.SquareFrameTransform
|
import org.oxycblt.auxio.image.extractor.SquareFrameTransform
|
||||||
import org.oxycblt.auxio.music.MusicParent
|
import org.oxycblt.auxio.music.MusicParent
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
|
@ -43,15 +43,17 @@ import org.oxycblt.auxio.util.logD
|
||||||
* @author Alexander Capehart (OxygenCobalt)
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
*/
|
*/
|
||||||
class WidgetComponent(private val context: Context) :
|
class WidgetComponent(private val context: Context) :
|
||||||
PlaybackStateManager.Listener, SharedPreferences.OnSharedPreferenceChangeListener {
|
PlaybackStateManager.Listener, UISettings.Listener, ImageSettings.Listener {
|
||||||
private val playbackManager = PlaybackStateManager.getInstance()
|
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 widgetProvider = WidgetProvider()
|
||||||
private val provider = BitmapProvider(context)
|
private val provider = BitmapProvider(context)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
playbackManager.addListener(this)
|
playbackManager.addListener(this)
|
||||||
settings.addListener(this)
|
uiSettings.registerListener(this)
|
||||||
|
imageSettings.registerListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Update [WidgetProvider] with the current playback state. */
|
/** 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) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
// Android 12, always round the cover with the widget's inner radius
|
// Android 12, always round the cover with the widget's inner radius
|
||||||
context.getDimenPixels(android.R.dimen.system_app_widget_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.
|
// < Android 12, but the user still enabled round mode.
|
||||||
context.getDimenPixels(R.dimen.size_corners_medium)
|
context.getDimenPixels(R.dimen.size_corners_medium)
|
||||||
} else {
|
} else {
|
||||||
|
@ -107,27 +109,23 @@ class WidgetComponent(private val context: Context) :
|
||||||
/** Release this instance, preventing any further events from updating the widget instances. */
|
/** Release this instance, preventing any further events from updating the widget instances. */
|
||||||
fun release() {
|
fun release() {
|
||||||
provider.release()
|
provider.release()
|
||||||
settings.removeListener(this)
|
uiSettings.unregisterListener(this)
|
||||||
widgetProvider.reset(context)
|
widgetProvider.reset(context)
|
||||||
playbackManager.removeListener(this)
|
playbackManager.removeListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- CALLBACKS ---
|
// --- CALLBACKS ---
|
||||||
|
|
||||||
// Hook all the major song-changing updates + the major player state updates
|
// Respond to all major song or player changes that will affect the widget
|
||||||
// to updating the "Now Playing" widget.
|
|
||||||
override fun onIndexMoved(queue: Queue) = update()
|
override fun onIndexMoved(queue: Queue) = update()
|
||||||
override fun onQueueReordered(queue: Queue) = update()
|
override fun onQueueReordered(queue: Queue) = update()
|
||||||
override fun onNewPlayback(queue: Queue, parent: MusicParent?) = update()
|
override fun onNewPlayback(queue: Queue, parent: MusicParent?) = update()
|
||||||
override fun onStateChanged(state: InternalPlayer.State) = update()
|
override fun onStateChanged(state: InternalPlayer.State) = update()
|
||||||
override fun onRepeatChanged(repeatMode: RepeatMode) = update()
|
override fun onRepeatChanged(repeatMode: RepeatMode) = update()
|
||||||
|
|
||||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
// Respond to settings changes that will affect the widget
|
||||||
if (key == context.getString(R.string.set_key_cover_mode) ||
|
override fun onRoundModeChanged() = update()
|
||||||
key == context.getString(R.string.set_key_round_mode)) {
|
override fun onCoverModeChanged() = update()
|
||||||
update()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A condensed form of the playback state that is safe to use in AppWidgets.
|
* 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_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_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_in_list_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_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_keep_shuffle" translatable="false">KEY_KEEP_SHUFFLE</string>
|
||||||
<string name="set_key_rewind_prev" translatable="false">KEY_PREV_REWIND</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>
|
<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_wipe_state" translatable="false">auxio_wipe_state</string>
|
||||||
<string name="set_key_restore_state" translatable="false">auxio_restore_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_hide_collaborators" translatable="false">auxio_hide_collaborators</string>
|
||||||
<string name="set_key_round_mode" translatable="false">auxio_round_covers</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>
|
<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_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_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_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_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_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_album_songs_sort" translatable="false">auxio_album_sort</string>
|
||||||
<string name="set_key_detail_artist_sort" translatable="false">auxio_artist_sort</string>
|
<string name="set_key_artist_songs_sort" translatable="false">auxio_artist_sort</string>
|
||||||
<string name="set_key_detail_genre_sort" translatable="false">auxio_genre_sort</string>
|
<string name="set_key_genre_songs_sort" translatable="false">auxio_genre_sort</string>
|
||||||
|
|
||||||
<string-array name="entries_theme">
|
<string-array name="entries_theme">
|
||||||
<item>@string/set_theme_auto</item>
|
<item>@string/set_theme_auto</item>
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
<PreferenceCategory app:title="@string/set_display">
|
<PreferenceCategory app:title="@string/set_display">
|
||||||
|
|
||||||
<org.oxycblt.auxio.settings.prefs.WrappedDialogPreference
|
<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:summary="@string/set_lib_tabs_desc"
|
||||||
app:title="@string/set_lib_tabs" />
|
app:title="@string/set_lib_tabs" />
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@
|
||||||
app:defaultValue="@integer/music_mode_songs"
|
app:defaultValue="@integer/music_mode_songs"
|
||||||
app:entries="@array/entries_library_song_playback_mode"
|
app:entries="@array/entries_library_song_playback_mode"
|
||||||
app:entryValues="@array/values_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:title="@string/set_library_song_playback_mode"
|
||||||
app:useSimpleSummaryProvider="true" />
|
app:useSimpleSummaryProvider="true" />
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@
|
||||||
app:defaultValue="@integer/music_mode_none"
|
app:defaultValue="@integer/music_mode_none"
|
||||||
app:entries="@array/entries_detail_song_playback_mode"
|
app:entries="@array/entries_detail_song_playback_mode"
|
||||||
app:entryValues="@array/values_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:title="@string/set_detail_song_playback_mode"
|
||||||
app:useSimpleSummaryProvider="true" />
|
app:useSimpleSummaryProvider="true" />
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,8 @@ package org.oxycblt.auxio.music
|
||||||
import org.oxycblt.auxio.music.storage.MusicDirectories
|
import org.oxycblt.auxio.music.storage.MusicDirectories
|
||||||
|
|
||||||
interface FakeMusicSettings : MusicSettings {
|
interface FakeMusicSettings : MusicSettings {
|
||||||
|
override fun registerListener(listener: MusicSettings.Listener) = throw NotImplementedError()
|
||||||
|
override fun unregisterListener(listener: MusicSettings.Listener) = throw NotImplementedError()
|
||||||
override var musicDirs: MusicDirectories
|
override var musicDirs: MusicDirectories
|
||||||
get() = throw NotImplementedError()
|
get() = throw NotImplementedError()
|
||||||
set(_) = throw NotImplementedError()
|
set(_) = throw NotImplementedError()
|
||||||
|
|
Loading…
Reference in a new issue