Migrate to DataStore

This commit is contained in:
vfsfitvnm 2022-06-05 17:35:07 +02:00
parent c808b2a482
commit b9489e5274

View file

@ -1,112 +1,123 @@
package it.vfsfitvnm.vimusic.utils
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.datastore.core.DataStore
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.media3.common.Player
import it.vfsfitvnm.vimusic.enums.ColorPaletteMode
import it.vfsfitvnm.vimusic.enums.SongCollection
import it.vfsfitvnm.vimusic.enums.ThumbnailRoundness
import it.vfsfitvnm.youtubemusic.YouTube
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import androidx.datastore.preferences.core.Preferences as DataStorePreferences
@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)
@Immutable
data class Preferences(
val isReady: Boolean,
val colorPaletteMode: ColorPaletteMode,
val onColorPaletteModeChange: (ColorPaletteMode) -> Unit,
val searchFilter: String,
val onSearchFilterChange: (String) -> Unit,
val repeatMode: Int,
val onRepeatModeChange: (Int) -> Unit,
val homePageSongCollection: SongCollection,
val onHomePageSongCollectionChange: (SongCollection) -> Unit,
val thumbnailRoundness: ThumbnailRoundness,
val onThumbnailRoundnessChange: (ThumbnailRoundness) -> Unit,
) {
constructor(
isReady: Boolean,
colorPaletteMode: ColorPaletteMode? = null,
onColorPaletteModeChange: (ColorPaletteMode) -> Unit = {},
searchFilter: String? = null,
onSearchFilterChange: (String) -> Unit = {},
repeatMode: Int? = null,
onRepeatModeChange: (Int) -> Unit = {},
homePageSongCollection: SongCollection? = null,
onHomePageSongCollectionChange: (SongCollection) -> Unit = {},
thumbnailRoundness: ThumbnailRoundness? = null,
onThumbnailRoundnessChange: (ThumbnailRoundness) -> Unit = {},
) : this(
isReady = isReady,
colorPaletteMode = colorPaletteMode ?: ColorPaletteMode.System,
onColorPaletteModeChange = onColorPaletteModeChange,
searchFilter = searchFilter ?: YouTube.Item.Song.Filter.value,
onSearchFilterChange = onSearchFilterChange,
repeatMode = repeatMode ?: Player.REPEAT_MODE_OFF,
onRepeatModeChange = onRepeatModeChange,
homePageSongCollection = homePageSongCollection ?: SongCollection.MostPlayed,
onHomePageSongCollectionChange = onHomePageSongCollectionChange,
thumbnailRoundness = thumbnailRoundness ?: ThumbnailRoundness.Light,
onThumbnailRoundnessChange = onThumbnailRoundnessChange
)
companion object {
val Default = Preferences(isReady = false)
}
}
val LocalPreferences = staticCompositionLocalOf<Preferences> { TODO() }
val LocalPreferences = staticCompositionLocalOf { Preferences.Default }
private val colorPaletteModeKey = stringPreferencesKey("colorPaletteMode")
private val searchFilterKey = stringPreferencesKey("searchFilter")
private val repeatModeKey = intPreferencesKey("repeatMode")
private val homePageSongCollectionKey = stringPreferencesKey("homePageSongCollection")
private val thumbnailRoundnessKey = stringPreferencesKey("thumbnailRoundness")
@Composable
fun rememberPreferences(): Preferences {
val context = LocalContext.current
return remember {
Preferences(context.getSharedPreferences("preferences", Context.MODE_PRIVATE))
}
fun rememberPreferences(dataStore: DataStore<DataStorePreferences>): State<Preferences> {
val coroutineScope = rememberCoroutineScope()
return remember(dataStore, coroutineScope) {
dataStore.data.map { preferences ->
Preferences(
isReady = true,
colorPaletteMode = preferences[colorPaletteModeKey]?.let { enumValueOf<ColorPaletteMode>(it) },
onColorPaletteModeChange = { colorPaletteMode ->
coroutineScope.launch(Dispatchers.IO) {
dataStore.edit { mutablePreferences ->
mutablePreferences[colorPaletteModeKey] = colorPaletteMode.name
}
}
},
searchFilter = preferences[searchFilterKey],
onSearchFilterChange = { searchFilter ->
coroutineScope.launch(Dispatchers.IO) {
dataStore.edit { mutablePreferences ->
mutablePreferences[searchFilterKey] = searchFilter
}
}
},
repeatMode = preferences[repeatModeKey],
onRepeatModeChange = { repeatMode ->
coroutineScope.launch(Dispatchers.IO) {
dataStore.edit { mutablePreferences ->
mutablePreferences[repeatModeKey] = repeatMode
}
}
},
homePageSongCollection = preferences[homePageSongCollectionKey]?.let { enumValueOf<SongCollection>(it) },
onHomePageSongCollectionChange = { homePageSongCollection ->
coroutineScope.launch(Dispatchers.IO) {
dataStore.edit { mutablePreferences ->
mutablePreferences[homePageSongCollectionKey] = homePageSongCollection.name
}
}
},
thumbnailRoundness = preferences[thumbnailRoundnessKey]?.let { enumValueOf<ThumbnailRoundness>(it) },
onThumbnailRoundnessChange = { thumbnailRoundness ->
coroutineScope.launch(Dispatchers.IO) {
dataStore.edit { mutablePreferences ->
mutablePreferences[thumbnailRoundnessKey] = thumbnailRoundness.name
}
}
},
)
}
}.collectAsState(initial = Preferences.Default, context = Dispatchers.IO)
}
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(
key: String,
defaultValue: T
) =
mutableStateOf(value = enumValueOf<T>(getString(key, defaultValue.name)!!)) {
edit {
putString(key, it.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
}
})