New Preferences class
This commit is contained in:
parent
9139609cf3
commit
b738910d63
|
@ -4,7 +4,7 @@ import android.app.Application
|
|||
import coil.ImageLoader
|
||||
import coil.ImageLoaderFactory
|
||||
import coil.disk.DiskCache
|
||||
import it.vfsfitvnm.vimusic.utils.preferences
|
||||
import it.vfsfitvnm.vimusic.utils.Preferences
|
||||
|
||||
|
||||
class MainApplication : Application(), ImageLoaderFactory {
|
||||
|
@ -19,7 +19,7 @@ class MainApplication : Application(), ImageLoaderFactory {
|
|||
.diskCache(
|
||||
DiskCache.Builder()
|
||||
.directory(filesDir.resolve("coil"))
|
||||
.maxSizeBytes(preferences.coilDiskCacheMaxSizeBytes)
|
||||
.maxSizeBytes(Preferences().coilDiskCacheMaxSizeBytes)
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
|
|
|
@ -127,6 +127,8 @@ class PlayerService : Service(), Player.Listener, PlaybackStatsListener.Callback
|
|||
|
||||
createNotificationChannel()
|
||||
|
||||
val preferences = Preferences()
|
||||
|
||||
val cacheEvictor = LeastRecentlyUsedCacheEvictor(preferences.exoPlayerDiskCacheMaxSizeBytes)
|
||||
cache = SimpleCache(cacheDir, cacheEvictor, StandaloneDatabaseProvider(this))
|
||||
|
||||
|
@ -201,7 +203,7 @@ class PlayerService : Service(), Player.Listener, PlaybackStatsListener.Callback
|
|||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
if (preferences.persistentQueue) {
|
||||
if (Preferences().persistentQueue) {
|
||||
val mediaItems = player.currentTimeline.mediaItems
|
||||
val mediaItemIndex = player.currentMediaItemIndex
|
||||
val mediaItemPosition = player.currentPosition
|
||||
|
@ -262,7 +264,7 @@ class PlayerService : Service(), Player.Listener, PlaybackStatsListener.Callback
|
|||
}
|
||||
|
||||
private fun normalizeVolume() {
|
||||
if (preferences.volumeNormalization) {
|
||||
if (Preferences().volumeNormalization) {
|
||||
player.volume = player.currentMediaItem?.let { mediaItem ->
|
||||
songPendingLoudnessDb.getOrElse(mediaItem.mediaId) {
|
||||
mediaItem.mediaMetadata.extras?.getFloatOrNull("loudnessDb")
|
||||
|
|
|
@ -4,10 +4,6 @@ import android.content.Context
|
|||
import android.content.SharedPreferences
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.TextUnit
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.core.content.edit
|
||||
import androidx.media3.common.Player
|
||||
import it.vfsfitvnm.vimusic.enums.ColorPaletteMode
|
||||
|
@ -15,105 +11,128 @@ import it.vfsfitvnm.vimusic.enums.SongCollection
|
|||
import it.vfsfitvnm.vimusic.enums.ThumbnailRoundness
|
||||
import it.vfsfitvnm.youtubemusic.YouTube
|
||||
|
||||
@Stable
|
||||
class Preferences(holder: SharedPreferences) : SharedPreferences by holder {
|
||||
var colorPaletteMode by preference("colorPaletteMode", ColorPaletteMode.System)
|
||||
var searchFilter by preference("searchFilter", YouTube.Item.Song.Filter.value)
|
||||
var repeatMode by preference("repeatMode", Player.REPEAT_MODE_OFF)
|
||||
var homePageSongCollection by preference("homePageSongCollection", SongCollection.MostPlayed)
|
||||
var thumbnailRoundness by preference("thumbnailRoundness", ThumbnailRoundness.Light)
|
||||
var coilDiskCacheMaxSizeBytes by preference("coilDiskCacheMaxSizeBytes", 512L * 1024 * 1024)
|
||||
var exoPlayerDiskCacheMaxSizeBytes by preference("exoPlayerDiskCacheMaxSizeBytes", 512L * 1024 * 1024)
|
||||
var skipSilence by preference("skipSilence", false)
|
||||
var volumeNormalization by preference("volumeNormalization", true)
|
||||
var persistentQueue by preference("persistentQueue", false)
|
||||
}
|
||||
|
||||
val Context.preferences: Preferences
|
||||
get() = Preferences(getSharedPreferences("preferences", Context.MODE_PRIVATE))
|
||||
@Stable
|
||||
class Preferences(
|
||||
private val edit: (action: SharedPreferences.Editor.() -> Unit) -> Unit,
|
||||
initialColorPaletteMode: ColorPaletteMode,
|
||||
initialSearchFilter: String,
|
||||
initialRepeatMode: Int,
|
||||
initialHomePageSongCollection: SongCollection,
|
||||
initialThumbnailRoundness: ThumbnailRoundness,
|
||||
initialCoilDiskCacheMaxSizeBytes: Long,
|
||||
initialExoPlayerDiskCacheMaxSizeBytes: Long,
|
||||
initialSkipSilence: Boolean,
|
||||
initialVolumeNormalization: Boolean,
|
||||
initialPersistentQueue: Boolean,
|
||||
) {
|
||||
constructor(preferences: SharedPreferences) : this(
|
||||
edit = { action: SharedPreferences.Editor.() -> Unit ->
|
||||
preferences.edit(action = action)
|
||||
},
|
||||
initialColorPaletteMode = preferences.getEnum(Keys.colorPaletteMode, ColorPaletteMode.System),
|
||||
initialSearchFilter = preferences.getString(Keys.searchFilter, YouTube.Item.Song.Filter.value)!!,
|
||||
initialRepeatMode = preferences.getInt(Keys.repeatMode, Player.REPEAT_MODE_OFF),
|
||||
initialHomePageSongCollection = preferences.getEnum(Keys.homePageSongCollection, SongCollection.History),
|
||||
initialThumbnailRoundness = preferences.getEnum(Keys.thumbnailRoundness, ThumbnailRoundness.Light),
|
||||
initialCoilDiskCacheMaxSizeBytes = preferences.getLong(Keys.coilDiskCacheMaxSizeBytes, 512L * 1024 * 1024),
|
||||
initialExoPlayerDiskCacheMaxSizeBytes = preferences.getLong(Keys.exoPlayerDiskCacheMaxSizeBytes, 512L * 1024 * 1024),
|
||||
initialSkipSilence = preferences.getBoolean(Keys.skipSilence, false),
|
||||
initialVolumeNormalization = preferences.getBoolean(Keys.volumeNormalization, false),
|
||||
initialPersistentQueue = preferences.getBoolean(Keys.persistentQueue, false)
|
||||
)
|
||||
|
||||
var colorPaletteMode = initialColorPaletteMode
|
||||
set(value) = edit { putEnum(Keys.colorPaletteMode, value) }
|
||||
|
||||
var searchFilter = initialSearchFilter
|
||||
set(value) = edit { putString(Keys.searchFilter, value) }
|
||||
|
||||
var repeatMode = initialRepeatMode
|
||||
set(value) = edit { putInt(Keys.repeatMode, value) }
|
||||
|
||||
var homePageSongCollection = initialHomePageSongCollection
|
||||
set(value) = edit { putEnum(Keys.homePageSongCollection, value) }
|
||||
|
||||
var thumbnailRoundness = initialThumbnailRoundness
|
||||
set(value) = edit { putEnum(Keys.thumbnailRoundness, value) }
|
||||
|
||||
var coilDiskCacheMaxSizeBytes = initialCoilDiskCacheMaxSizeBytes
|
||||
set(value) = edit { putLong(Keys.coilDiskCacheMaxSizeBytes, value) }
|
||||
|
||||
var exoPlayerDiskCacheMaxSizeBytes = initialExoPlayerDiskCacheMaxSizeBytes
|
||||
set(value) = edit { putLong(Keys.exoPlayerDiskCacheMaxSizeBytes, value) }
|
||||
|
||||
var skipSilence = initialSkipSilence
|
||||
set(value) = edit { putBoolean(Keys.skipSilence, value) }
|
||||
|
||||
var volumeNormalization = initialVolumeNormalization
|
||||
set(value) = edit { putBoolean(Keys.volumeNormalization, value) }
|
||||
|
||||
var persistentQueue = initialPersistentQueue
|
||||
set(value) = edit { putBoolean(Keys.persistentQueue, value) }
|
||||
|
||||
private object Keys {
|
||||
const val colorPaletteMode = "colorPaletteMode"
|
||||
const val searchFilter = "searchFilter"
|
||||
const val repeatMode = "repeatMode"
|
||||
const val homePageSongCollection = "homePageSongCollection"
|
||||
const val thumbnailRoundness = "thumbnailRoundness"
|
||||
const val coilDiskCacheMaxSizeBytes = "coilDiskCacheMaxSizeBytes"
|
||||
const val exoPlayerDiskCacheMaxSizeBytes = "exoPlayerDiskCacheMaxSizeBytes"
|
||||
const val skipSilence = "skipSilence"
|
||||
const val volumeNormalization = "volumeNormalization"
|
||||
const val persistentQueue = "persistentQueue"
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val fileName = "preferences"
|
||||
|
||||
context(Context)
|
||||
operator fun invoke() =
|
||||
Preferences(getSharedPreferences(fileName, Context.MODE_PRIVATE))
|
||||
}
|
||||
}
|
||||
|
||||
val LocalPreferences = staticCompositionLocalOf<Preferences> { TODO() }
|
||||
|
||||
@Composable
|
||||
fun rememberPreferences(): Preferences {
|
||||
val context = LocalContext.current
|
||||
return remember {
|
||||
context.preferences
|
||||
var preferences by remember {
|
||||
mutableStateOf(context.run { Preferences() })
|
||||
}
|
||||
|
||||
DisposableEffect(Unit) {
|
||||
val holder = context.getSharedPreferences(Preferences.fileName, Context.MODE_PRIVATE)
|
||||
|
||||
val listener =
|
||||
SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, _ ->
|
||||
preferences = Preferences(sharedPreferences)
|
||||
}
|
||||
|
||||
holder.registerOnSharedPreferenceChangeListener(listener)
|
||||
|
||||
onDispose {
|
||||
holder.unregisterOnSharedPreferenceChangeListener(listener)
|
||||
}
|
||||
}
|
||||
|
||||
return preferences
|
||||
}
|
||||
|
||||
private fun SharedPreferences.preference(key: String, defaultValue: Boolean) =
|
||||
mutableStateOf(value = getBoolean(key, defaultValue)) {
|
||||
edit {
|
||||
putBoolean(key, it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SharedPreferences.preference(key: String, defaultValue: Int) =
|
||||
mutableStateOf(value = getInt(key, defaultValue)) {
|
||||
edit {
|
||||
putInt(key, it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SharedPreferences.preference(key: String, defaultValue: Long) =
|
||||
mutableStateOf(value = getLong(key, defaultValue)) {
|
||||
edit {
|
||||
putLong(key, it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SharedPreferences.preference(key: String, defaultValue: Float) =
|
||||
mutableStateOf(value = getFloat(key, defaultValue)) {
|
||||
edit {
|
||||
putFloat(key, it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SharedPreferences.preference(key: String, defaultValue: String) =
|
||||
mutableStateOf(value = getString(key, defaultValue)!!) {
|
||||
edit {
|
||||
putString(key, it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SharedPreferences.preference(key: String, defaultValue: Set<String>) =
|
||||
mutableStateOf(value = getStringSet(key, defaultValue)!!) {
|
||||
edit {
|
||||
putStringSet(key, it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SharedPreferences.preference(key: String, defaultValue: Dp) =
|
||||
mutableStateOf(value = getFloat(key, defaultValue.value).dp) {
|
||||
edit {
|
||||
putFloat(key, it.value)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SharedPreferences.preference(key: String, defaultValue: TextUnit) =
|
||||
mutableStateOf(value = getFloat(key, defaultValue.value).sp) {
|
||||
edit {
|
||||
putFloat(key, it.value)
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <reified T : Enum<T>> SharedPreferences.preference(
|
||||
private inline fun <reified T : Enum<T>> SharedPreferences.getEnum(
|
||||
key: String,
|
||||
defaultValue: T
|
||||
) = mutableStateOf(value = enumValueOf<T>(getString(key, defaultValue.name)!!)) {
|
||||
edit {
|
||||
putString(key, it.name)
|
||||
): T =
|
||||
getString(key, null)?.let {
|
||||
try {
|
||||
enumValueOf<T>(it)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
} ?: defaultValue
|
||||
|
||||
private inline fun <reified T : Enum<T>> SharedPreferences.Editor.putEnum(key: String, value: T) =
|
||||
putString(key, value.name)
|
||||
|
||||
private fun <T> mutableStateOf(value: T, onStructuralInequality: (newValue: T) -> Unit) =
|
||||
mutableStateOf(
|
||||
value = value,
|
||||
policy = object : SnapshotMutationPolicy<T> {
|
||||
override fun equivalent(a: T, b: T): Boolean {
|
||||
val areEquals = a == b
|
||||
if (!areEquals) onStructuralInequality(b)
|
||||
return areEquals
|
||||
}
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue