diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c4ee7ea..fd1baf0 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -88,8 +88,6 @@ dependencies { implementation(libs.media3.session) implementation(libs.media3.exoplayer) - implementation(libs.datastore) - implementation(libs.room) kapt(libs.room.compiler) diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/MainActivity.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/MainActivity.kt index 66cfab8..5f78c56 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/MainActivity.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/MainActivity.kt @@ -58,7 +58,7 @@ class MainActivity : ComponentActivity() { mediaControllerFuture = MediaController.Builder(this, sessionToken).buildAsync() setContent { - val preferences by rememberPreferences(dataStore) + val preferences = rememberPreferences() val systemUiController = rememberSystemUiController() val (isDarkTheme, colorPalette) = when (preferences.colorPaletteMode) { @@ -118,9 +118,7 @@ class MainActivity : ComponentActivity() { LocalShimmerTheme provides shimmerTheme, LocalTypography provides rememberTypography(colorPalette.text), LocalYoutubePlayer provides rememberYoutubePlayer(mediaControllerFuture) { - if (preferences.isReady) { - it.repeatMode = preferences.repeatMode - } + it.repeatMode = preferences.repeatMode }, LocalMenuState provides rememberMenuState(), LocalHapticFeedback provides rememberHapticFeedback() diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/MainApplication.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/MainApplication.kt index 46e8b70..4e9050f 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/MainApplication.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/MainApplication.kt @@ -1,6 +1,7 @@ package it.vfsfitvnm.vimusic import android.app.Application +import android.content.Context import coil.ImageLoader import coil.ImageLoaderFactory import coil.disk.DiskCache @@ -13,14 +14,18 @@ class MainApplication : Application(), ImageLoaderFactory { } override fun newImageLoader(): ImageLoader { - return ImageLoader.Builder(this) - .crossfade(true) - .diskCache( - DiskCache.Builder() - .directory(filesDir.resolve("coil")) - .maxSizeBytes(1024 * 1024 * 1024) - .build() - ) - .build() + return defaultCoilImageLoader(1024 * 1024 * 1024) } } + +fun Context.defaultCoilImageLoader(diskCacheMaxSize: Long): ImageLoader { + return ImageLoader.Builder(this) + .crossfade(true) + .diskCache( + DiskCache.Builder() + .directory(filesDir.resolve("coil")) + .maxSizeBytes(diskCacheMaxSize) + .build() + ) + .build() +} \ No newline at end of file diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/HomeScreen.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/HomeScreen.kt index d299e08..261db34 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/HomeScreen.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/HomeScreen.kt @@ -80,11 +80,7 @@ fun HomeScreen( val preferences = LocalPreferences.current - val songCollection by remember(preferences.isReady, preferences.homePageSongCollection) { - if (!preferences.isReady) { - return@remember flowOf(emptyList()) - } - + val songCollection by remember(preferences.homePageSongCollection) { when (preferences.homePageSongCollection) { SongCollection.MostPlayed -> Database.mostPlayed() SongCollection.Favorites -> Database.favorites() @@ -311,21 +307,19 @@ fun HomeScreen( val songCollections = enumValues() val nextSongCollection = songCollections[(preferences.homePageSongCollection.ordinal + 1) % songCollections.size] - BasicText( - text = when (nextSongCollection) { - SongCollection.MostPlayed -> "Most played" - SongCollection.Favorites -> "Favorites" - SongCollection.History -> "History" - }, - style = typography.xxs.secondary.bold, - modifier = Modifier - .clickable( - indication = rememberRipple(bounded = true), - interactionSource = remember { MutableInteractionSource() } - ) { - preferences.onHomePageSongCollectionChange( - nextSongCollection - ) + BasicText( + text = when (nextSongCollection) { + SongCollection.MostPlayed -> "Most played" + SongCollection.Favorites -> "Favorites" + SongCollection.History -> "History" + }, + style = typography.xxs.secondary.bold, + modifier = Modifier + .clickable( + indication = rememberRipple(bounded = true), + interactionSource = remember { MutableInteractionSource() }, + onClick = { + preferences.homePageSongCollection = nextSongCollection } // .alignByBaseline() .padding(horizontal = 16.dp) diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/settings/AppearanceScreen.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/settings/AppearanceScreen.kt index efab4f9..82c24d9 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/settings/AppearanceScreen.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/settings/AppearanceScreen.kt @@ -80,13 +80,17 @@ fun AppearanceScreen() { EnumValueSelectorEntry( title = "Theme mode", selectedValue = preferences.colorPaletteMode, - onValueSelected = preferences.onColorPaletteModeChange + onValueSelected = { + preferences.colorPaletteMode = it + } ) EnumValueSelectorEntry( title = "Thumbnail roundness", selectedValue = preferences.thumbnailRoundness, - onValueSelected = preferences.onThumbnailRoundnessChange + onValueSelected = { + preferences.thumbnailRoundness = it + } ) } } diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerView.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerView.kt index 3c7f802..54656ef 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerView.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/PlayerView.kt @@ -429,7 +429,7 @@ fun PlayerView( player.mediaController.repeatMode = (player.mediaController.repeatMode + 2) % 3 - preferences.onRepeatModeChange(player.mediaController.repeatMode) + preferences.repeatMode = player.mediaController.repeatMode } .padding(horizontal = 16.dp) .size(28.dp) diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/Preferences.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/Preferences.kt index e3dd17f..c74d8d8 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/Preferences.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/Preferences.kt @@ -1,123 +1,114 @@ package it.vfsfitvnm.vimusic.utils +import android.content.Context +import android.content.SharedPreferences import androidx.compose.runtime.* -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.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 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 - ) +val Context.preferences: Preferences + get() = Preferences(getSharedPreferences("preferences", Context.MODE_PRIVATE)) - companion object { - val Default = Preferences(isReady = false) +val LocalPreferences = staticCompositionLocalOf { TODO() } + +@Composable +fun rememberPreferences(): Preferences { + val context = LocalContext.current + return remember { + context.preferences } } -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(dataStore: DataStore): State { - val coroutineScope = rememberCoroutineScope() - - return remember(dataStore, coroutineScope) { - dataStore.data.map { preferences -> - Preferences( - isReady = true, - colorPaletteMode = preferences[colorPaletteModeKey]?.let { enumValueOf(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(it) }, - onHomePageSongCollectionChange = { homePageSongCollection -> - coroutineScope.launch(Dispatchers.IO) { - dataStore.edit { mutablePreferences -> - mutablePreferences[homePageSongCollectionKey] = homePageSongCollection.name - } - } - }, - thumbnailRoundness = preferences[thumbnailRoundnessKey]?.let { enumValueOf(it) }, - onThumbnailRoundnessChange = { thumbnailRoundness -> - coroutineScope.launch(Dispatchers.IO) { - dataStore.edit { mutablePreferences -> - mutablePreferences[thumbnailRoundnessKey] = thumbnailRoundness.name - } - } - }, - ) +private fun SharedPreferences.preference(key: String, defaultValue: Boolean) = + mutableStateOf(value = getBoolean(key, defaultValue)) { + edit { + putBoolean(key, it) } - }.collectAsState(initial = Preferences.Default, context = Dispatchers.IO) -} + } + +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) = + 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 > SharedPreferences.preference( + key: String, + defaultValue: T +) = mutableStateOf(value = enumValueOf(getString(key, defaultValue.name)!!)) { + edit { + putString(key, it.name) + } + } + +private fun mutableStateOf(value: T, onStructuralInequality: (newValue: T) -> Unit) = + mutableStateOf( + value = value, + policy = object : SnapshotMutationPolicy { + override fun equivalent(a: T, b: T): Boolean { + val areEquals = a == b + if (!areEquals) onStructuralInequality(b) + return areEquals + } + }) diff --git a/settings.gradle.kts b/settings.gradle.kts index a5537a7..b33eb36 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -31,8 +31,6 @@ dependencyResolutionManagement { version("accompanist", "0.24.10-beta") alias("accompanist-systemuicontroller").to("com.google.accompanist", "accompanist-systemuicontroller").versionRef("accompanist") - alias("datastore").to("androidx.datastore", "datastore-preferences").version("1.0.0") - version("room", "2.5.0-alpha01") alias("room").to("androidx.room", "room-ktx").versionRef("room") alias("room-compiler").to("androidx.room", "room-compiler").versionRef("room")