Refactor preferences to avoid a global state when it's not necessary

This commit is contained in:
vfsfitvnm 2022-07-16 13:51:38 +02:00
parent aa8e065412
commit 1e719b33ed
38 changed files with 415 additions and 452 deletions

View file

@ -1,10 +1,7 @@
package it.vfsfitvnm.vimusic
import android.annotation.SuppressLint
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.content.*
import android.net.Uri
import android.os.Bundle
import android.os.IBinder
@ -27,9 +24,12 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.text.ExperimentalTextApi
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.valentinilk.shimmer.LocalShimmerTheme
import com.valentinilk.shimmer.defaultShimmerTheme
import it.vfsfitvnm.vimusic.enums.ColorPaletteMode
import it.vfsfitvnm.vimusic.enums.ThumbnailRoundness
import it.vfsfitvnm.vimusic.service.PlayerService
import it.vfsfitvnm.vimusic.ui.components.BottomSheetMenu
import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
@ -37,15 +37,11 @@ import it.vfsfitvnm.vimusic.ui.components.rememberBottomSheetState
import it.vfsfitvnm.vimusic.ui.components.rememberMenuState
import it.vfsfitvnm.vimusic.ui.screens.HomeScreen
import it.vfsfitvnm.vimusic.ui.screens.IntentUriScreen
import it.vfsfitvnm.vimusic.ui.styling.Appearance
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
import it.vfsfitvnm.vimusic.ui.styling.rememberTypography
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.ui.views.PlayerView
import it.vfsfitvnm.vimusic.utils.LocalPreferences
import it.vfsfitvnm.vimusic.utils.intent
import it.vfsfitvnm.vimusic.utils.rememberHapticFeedback
import it.vfsfitvnm.vimusic.utils.rememberPreferences
import it.vfsfitvnm.vimusic.utils.*
class MainActivity : ComponentActivity() {
@ -75,30 +71,77 @@ class MainActivity : ComponentActivity() {
}
@SuppressLint("BatteryLife")
@OptIn(ExperimentalFoundationApi::class, ExperimentalAnimationApi::class)
@OptIn(ExperimentalFoundationApi::class, ExperimentalAnimationApi::class,
ExperimentalTextApi::class
)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
uri = intent?.data
setContent {
val preferences = rememberPreferences()
val isSystemInDarkTheme = isSystemInDarkTheme()
var appearance by remember(isSystemInDarkTheme) {
with(preferences) {
val colorPaletteMode = getEnum(colorPaletteModeKey, ColorPaletteMode.System)
val thumbnailRoundness = getEnum(thumbnailRoundnessKey, ThumbnailRoundness.Light)
mutableStateOf(
Appearance(
colorPalette = colorPaletteMode.palette(isSystemInDarkTheme),
typography = colorPaletteMode.typography(isSystemInDarkTheme),
thumbnailShape = thumbnailRoundness.shape()
)
)
}
}
DisposableEffect(isSystemInDarkTheme) {
val listener =
SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, key ->
when (key) {
colorPaletteModeKey -> {
val colorPaletteMode = sharedPreferences.getEnum(key, ColorPaletteMode.System)
appearance = appearance.copy(
colorPalette = colorPaletteMode.palette(isSystemInDarkTheme),
typography = colorPaletteMode.typography(isSystemInDarkTheme),
)
}
thumbnailRoundnessKey -> {
val thumbnailRoundness = sharedPreferences.getEnum(key, ThumbnailRoundness.Light)
appearance = appearance.copy(
thumbnailShape = thumbnailRoundness.shape()
)
}
}
}
with(preferences) {
registerOnSharedPreferenceChangeListener(listener)
onDispose {
unregisterOnSharedPreferenceChangeListener(listener)
}
}
}
val systemUiController = rememberSystemUiController()
val colorPalette = preferences.colorPaletteMode.palette(isSystemInDarkTheme())
val rippleTheme = remember(colorPalette.text, colorPalette.isDark) {
val rippleTheme = remember(appearance.colorPalette.text, appearance.colorPalette.isDark) {
object : RippleTheme {
@Composable
override fun defaultColor(): Color = RippleTheme.defaultRippleColor(
contentColor = colorPalette.text,
lightTheme = !colorPalette.isDark
contentColor = appearance.colorPalette.text,
lightTheme = !appearance.colorPalette.isDark
)
@Composable
override fun rippleAlpha(): RippleAlpha = RippleTheme.defaultRippleAlpha(
contentColor = colorPalette.text,
lightTheme = !colorPalette.isDark
contentColor = appearance.colorPalette.text,
lightTheme = !appearance.colorPalette.isDark
)
}
}
@ -122,17 +165,15 @@ class MainActivity : ComponentActivity() {
}
SideEffect {
systemUiController.setSystemBarsColor(colorPalette.background, !colorPalette.isDark)
systemUiController.setSystemBarsColor(appearance.colorPalette.background, !appearance.colorPalette.isDark)
}
CompositionLocalProvider(
LocalAppearance provides appearance,
LocalOverscrollConfiguration provides null,
LocalIndication provides rememberRipple(bounded = false),
LocalRippleTheme provides rippleTheme,
LocalPreferences provides preferences,
LocalColorPalette provides colorPalette,
LocalShimmerTheme provides shimmerTheme,
LocalTypography provides rememberTypography(colorPalette.text),
LocalPlayerServiceBinder provides binder,
LocalMenuState provides rememberMenuState(),
LocalHapticFeedback provides rememberHapticFeedback()
@ -140,7 +181,7 @@ class MainActivity : ComponentActivity() {
BoxWithConstraints(
modifier = Modifier
.fillMaxSize()
.background(colorPalette.background)
.background(appearance.colorPalette.background)
) {
when (val uri = uri) {
null -> {
@ -173,4 +214,4 @@ class MainActivity : ComponentActivity() {
}
}
val LocalPlayerServiceBinder = staticCompositionLocalOf<PlayerService.Binder?> { null }
val LocalPlayerServiceBinder = staticCompositionLocalOf<PlayerService.Binder?> { null }

View file

@ -4,7 +4,10 @@ import android.app.Application
import coil.ImageLoader
import coil.ImageLoaderFactory
import coil.disk.DiskCache
import it.vfsfitvnm.vimusic.utils.Preferences
import it.vfsfitvnm.vimusic.enums.CoilDiskCacheMaxSize
import it.vfsfitvnm.vimusic.utils.coilDiskCacheMaxSizeKey
import it.vfsfitvnm.vimusic.utils.getEnum
import it.vfsfitvnm.vimusic.utils.preferences
class MainApplication : Application(), ImageLoaderFactory {
@ -19,7 +22,7 @@ class MainApplication : Application(), ImageLoaderFactory {
.diskCache(
DiskCache.Builder()
.directory(filesDir.resolve("coil"))
.maxSizeBytes(Preferences().coilDiskCacheMaxSize.bytes)
.maxSizeBytes(preferences.getEnum(coilDiskCacheMaxSizeKey, CoilDiskCacheMaxSize.`128MB`).bytes)
.build()
)
.build()

View file

@ -1,9 +1,20 @@
package it.vfsfitvnm.vimusic.enums
import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.PlatformTextStyle
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import it.vfsfitvnm.vimusic.R
import it.vfsfitvnm.vimusic.ui.styling.BlackColorPalette
import it.vfsfitvnm.vimusic.ui.styling.ColorPalette
import it.vfsfitvnm.vimusic.ui.styling.DarkColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LightColorPalette
import it.vfsfitvnm.vimusic.ui.styling.Typography
enum class ColorPaletteMode {
Light,
@ -22,4 +33,50 @@ enum class ColorPaletteMode {
}
}
}
@OptIn(ExperimentalTextApi::class)
fun typography(isSystemInDarkMode: Boolean): Typography {
val color = palette(isSystemInDarkMode).text
val textStyle = TextStyle(
fontFamily = FontFamily(
Font(
resId = R.font.poppins_w300,
weight = FontWeight.Light
),
Font(
resId = R.font.poppins_w400,
weight = FontWeight.Normal
),
Font(
resId = R.font.poppins_w400_italic,
weight = FontWeight.Normal,
style = FontStyle.Italic
),
Font(
resId = R.font.poppins_w500,
weight = FontWeight.Medium
),
Font(
resId = R.font.poppins_w600,
weight = FontWeight.SemiBold
),
Font(
resId = R.font.poppins_w700,
weight = FontWeight.Bold
),
),
fontWeight = FontWeight.Normal,
color = color,
platformStyle = @Suppress("DEPRECATION") PlatformTextStyle(includeFontPadding = false)
)
return Typography(
xxs = textStyle.copy(fontSize = 12.sp),
xs = textStyle.copy(fontSize = 14.sp),
s = textStyle.copy(fontSize = 16.sp),
m = textStyle.copy(fontSize = 18.sp),
l = textStyle.copy(fontSize = 20.sp),
)
}
}

View file

@ -6,7 +6,7 @@ import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.unit.dp
import it.vfsfitvnm.vimusic.utils.LocalPreferences
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
enum class ThumbnailRoundness {
None,
@ -14,15 +14,19 @@ enum class ThumbnailRoundness {
Medium,
Heavy;
fun shape(): Shape {
return when (this) {
None -> RectangleShape
Light -> RoundedCornerShape(2.dp)
Medium -> RoundedCornerShape(4.dp)
Heavy -> RoundedCornerShape(8.dp)
}
}
companion object {
val shape: Shape
@Composable
@ReadOnlyComposable
get() = when (LocalPreferences.current.thumbnailRoundness) {
None -> RectangleShape
Light -> RoundedCornerShape(2.dp)
Medium -> RoundedCornerShape(4.dp)
Heavy -> RoundedCornerShape(8.dp)
}
get() = LocalAppearance.current.thumbnailShape
}
}

View file

@ -18,6 +18,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat.startForegroundService
import androidx.core.content.edit
import androidx.core.content.getSystemService
import androidx.core.net.toUri
import androidx.media3.common.*
@ -116,17 +117,14 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
createNotificationChannel()
getSharedPreferences(
Preferences.fileName,
Context.MODE_PRIVATE
).registerOnSharedPreferenceChangeListener(this)
preferences.registerOnSharedPreferenceChangeListener(this)
val preferences = Preferences()
isPersistentQueueEnabled = preferences.persistentQueue
isVolumeNormalizationEnabled = preferences.volumeNormalization
isInvincibilityEnabled = preferences.isInvincibilityEnabled
val preferences = preferences
isPersistentQueueEnabled = preferences.getBoolean(persistentQueueKey, false)
isVolumeNormalizationEnabled = preferences.getBoolean(volumeNormalizationKey, false)
isInvincibilityEnabled = preferences.getBoolean(isInvincibilityEnabledKey, false)
val cacheEvictor = when (val size = preferences.exoPlayerDiskCacheMaxSize) {
val cacheEvictor = when (val size = preferences.getEnum(exoPlayerDiskCacheMaxSizeKey, ExoPlayerDiskCacheMaxSize.`2GB`)) {
ExoPlayerDiskCacheMaxSize.Unlimited -> NoOpCacheEvictor()
else -> LeastRecentlyUsedCacheEvictor(size.bytes)
}
@ -146,8 +144,8 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
.setUsePlatformDiagnostics(false)
.build()
player.repeatMode = preferences.repeatMode
player.skipSilenceEnabled = preferences.skipSilence
player.repeatMode = preferences.getInt(repeatModeKey, Player.REPEAT_MODE_OFF)
player.skipSilenceEnabled = preferences.getBoolean(skipSilenceKey, false)
player.addListener(this)
player.addAnalyticsListener(PlaybackStatsListener(false, this))
@ -184,10 +182,7 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
override fun onDestroy() {
maybeSavePlayerQueue()
getSharedPreferences(
Preferences.fileName,
Context.MODE_PRIVATE
).unregisterOnSharedPreferenceChangeListener(this)
preferences.unregisterOnSharedPreferenceChangeListener(this)
player.removeListener(this)
player.stop()
@ -289,14 +284,16 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
}
private fun normalizeVolume() {
if (isVolumeNormalizationEnabled) {
player.volume = player.currentMediaItem?.let { mediaItem ->
player.volume = if (isVolumeNormalizationEnabled) {
player.currentMediaItem?.let { mediaItem ->
songPendingLoudnessDb.getOrElse(mediaItem.mediaId) {
mediaItem.mediaMetadata.extras?.getFloatOrNull("loudnessDb")
}?.takeIf { it > 0 }?.let { loudnessDb ->
(1f - (0.01f + loudnessDb / 14)).coerceIn(0.1f, 1f)
}
} ?: 1f
} else {
1f
}
}
@ -309,6 +306,10 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
else -> PlaybackState.STATE_NONE
}
override fun onRepeatModeChanged(repeatMode: Int) {
preferences.edit { putInt(repeatModeKey, repeatMode) }
}
override fun onEvents(player: Player, events: Player.Events) {
if (player.duration != C.TIME_UNSET) {
metadataBuilder
@ -362,12 +363,16 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
when (key) {
Preferences.Keys.persistentQueue -> isPersistentQueueEnabled =
persistentQueueKey -> isPersistentQueueEnabled =
sharedPreferences.getBoolean(key, isPersistentQueueEnabled)
Preferences.Keys.volumeNormalization -> isVolumeNormalizationEnabled =
sharedPreferences.getBoolean(key, isVolumeNormalizationEnabled)
Preferences.Keys.isInvincibilityEnabled -> isInvincibilityEnabled =
volumeNormalizationKey -> {
isVolumeNormalizationEnabled =
sharedPreferences.getBoolean(key, isVolumeNormalizationEnabled)
normalizeVolume()
}
isInvincibilityEnabledKey -> isInvincibilityEnabled =
sharedPreferences.getBoolean(key, isInvincibilityEnabled)
skipSilenceKey -> player.skipSilenceEnabled = sharedPreferences.getBoolean(key, false)
}
}

View file

@ -34,8 +34,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import it.vfsfitvnm.vimusic.ui.components.ChunkyButton
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.*
import kotlinx.coroutines.delay
@ -56,8 +55,7 @@ fun TextFieldDialog(
val focusRequester = remember {
FocusRequester()
}
val colorPalette = LocalColorPalette.current
val typography = LocalTypography.current
val (colorPalette, typography) = LocalAppearance.current
var textFieldValue by rememberSaveable(initialTextInput, stateSaver = TextFieldValue.Saver) {
mutableStateOf(
@ -162,8 +160,7 @@ fun ConfirmationDialog(
confirmText: String = "Confirm",
onCancel: () -> Unit = onDismiss
) {
val colorPalette = LocalColorPalette.current
val typography = LocalTypography.current
val (colorPalette, typography) = LocalAppearance.current
DefaultDialog(
onDismiss = onDismiss,
@ -211,6 +208,8 @@ inline fun DefaultDialog(
horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally,
crossinline content: @Composable ColumnScope.() -> Unit
) {
val (colorPalette) = LocalAppearance.current
Dialog(
onDismissRequest = onDismiss,
properties = DialogProperties(usePlatformDefaultWidth = false)
@ -220,7 +219,7 @@ inline fun DefaultDialog(
modifier = modifier
.padding(all = 48.dp)
.background(
color = LocalColorPalette.current.elevatedBackground,
color = colorPalette.elevatedBackground,
shape = RoundedCornerShape(8.dp)
)
.padding(horizontal = 24.dp, vertical = 16.dp),
@ -240,15 +239,14 @@ inline fun <T> ValueSelectorDialog(
modifier: Modifier = Modifier,
crossinline valueText: (T) -> String = { it.toString() }
) {
val typography = LocalTypography.current
val colorPalette = LocalColorPalette.current
val (colorPalette, typography) = LocalAppearance.current
Dialog(onDismissRequest = onDismiss) {
Column(
modifier = modifier
.padding(all = 48.dp)
.background(
color = LocalColorPalette.current.elevatedBackground,
color = colorPalette.elevatedBackground,
shape = RoundedCornerShape(8.dp)
)
.padding(vertical = 16.dp),

View file

@ -31,8 +31,7 @@ import it.vfsfitvnm.vimusic.ui.components.Pager
import it.vfsfitvnm.vimusic.ui.screens.rememberAlbumRoute
import it.vfsfitvnm.vimusic.ui.screens.rememberArtistRoute
import it.vfsfitvnm.vimusic.ui.screens.rememberCreatePlaylistRoute
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.*
import it.vfsfitvnm.youtubemusic.models.NavigationEndpoint
import kotlinx.coroutines.Dispatchers
@ -371,8 +370,7 @@ fun MediaItemMenu(
onSetSleepTimer?.let { onSetSleepTimer ->
val binder = LocalPlayerServiceBinder.current
val typography = LocalTypography.current
val colorPalette = LocalColorPalette.current
val (colorPalette, typography) = LocalAppearance.current
var isShowingSleepTimerDialog by remember {
mutableStateOf(false)

View file

@ -16,8 +16,7 @@ import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import it.vfsfitvnm.vimusic.R
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.medium
import it.vfsfitvnm.vimusic.utils.secondary
@ -27,7 +26,7 @@ inline fun Menu(
modifier: Modifier = Modifier,
content: @Composable ColumnScope.() -> Unit
) {
val colorPalette = LocalColorPalette.current
val (colorPalette) = LocalAppearance.current
Column(
modifier = modifier
@ -52,8 +51,7 @@ fun MenuEntry(
secondaryText: String? = null,
isEnabled: Boolean = true,
) {
val colorPalette = LocalColorPalette.current
val typography = LocalTypography.current
val (colorPalette, typography) = LocalAppearance.current
Row(
verticalAlignment = Alignment.CenterVertically,
@ -99,7 +97,7 @@ fun MenuIconButton(
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
val colorPalette = LocalColorPalette.current
val (colorPalette) = LocalAppearance.current
Box(
modifier = modifier

View file

@ -16,7 +16,7 @@ import androidx.compose.ui.geometry.center
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shadow
import androidx.compose.ui.unit.dp
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.drawCircle
@ -25,7 +25,7 @@ fun Switch(
isChecked: Boolean,
modifier: Modifier = Modifier,
) {
val colorPalette = LocalColorPalette.current
val (colorPalette) = LocalAppearance.current
val backgroundColor by animateColorAsState(if (isChecked) colorPalette.primaryContainer else colorPalette.lightBackground)
val color by animateColorAsState(if (isChecked) colorPalette.onPrimaryContainer else colorPalette.textDisabled)

View file

@ -17,8 +17,7 @@ import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.align
import it.vfsfitvnm.vimusic.utils.secondary
import it.vfsfitvnm.vimusic.utils.semiBold
@ -32,7 +31,7 @@ fun TextCard(
onClick: (() -> Unit)? = null,
content: @Composable TextCardScope.() -> Unit,
) {
val colorPalette = LocalColorPalette.current
val (colorPalette) = LocalAppearance.current
Column(
modifier = modifier
@ -72,17 +71,19 @@ interface TextCardScope {
private object TextCardScopeImpl : TextCardScope {
@Composable
override fun Title(text: String) {
val (_, typography) = LocalAppearance.current
BasicText(
text = text,
style = LocalTypography.current.xxs.semiBold,
style = typography.xxs.semiBold,
)
}
@Composable
override fun Text(text: String) {
val (_, typography) = LocalAppearance.current
BasicText(
text = text,
style = LocalTypography.current.xxs.secondary.align(TextAlign.Justify),
style = typography.xxs.secondary.align(TextAlign.Justify),
)
}
}
@ -90,9 +91,10 @@ private object TextCardScopeImpl : TextCardScope {
private object IconTextCardScopeImpl : TextCardScope {
@Composable
override fun Title(text: String) {
val (_, typography) = LocalAppearance.current
BasicText(
text = text,
style = LocalTypography.current.xxs.semiBold,
style = typography.xxs.semiBold,
modifier = Modifier
.padding(horizontal = 16.dp)
)
@ -100,9 +102,10 @@ private object IconTextCardScopeImpl : TextCardScope {
@Composable
override fun Text(text: String) {
val (_, typography) = LocalAppearance.current
BasicText(
text = text,
style = LocalTypography.current.xxs.secondary,
style = typography.xxs.secondary,
modifier = Modifier
.padding(horizontal = 16.dp)
)

View file

@ -10,20 +10,18 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import kotlin.random.Random
@Composable
fun TextPlaceholder(
modifier: Modifier = Modifier
) {
val (colorPalette) = LocalAppearance.current
Spacer(
modifier = modifier
.padding(vertical = 4.dp)
.background(
color = LocalColorPalette.current.darkGray,
shape = RoundedCornerShape(0.dp)
)
.background(color = colorPalette.darkGray, shape = RoundedCornerShape(0.dp))
.fillMaxWidth(remember { 0.25f + Random.nextFloat() * 0.5f })
.height(16.dp)
)

View file

@ -28,16 +28,17 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage
import it.vfsfitvnm.route.RouteHandler
import it.vfsfitvnm.vimusic.*
import it.vfsfitvnm.vimusic.Database
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
import it.vfsfitvnm.vimusic.R
import it.vfsfitvnm.vimusic.enums.ThumbnailRoundness
import it.vfsfitvnm.vimusic.models.*
import it.vfsfitvnm.vimusic.query
import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
import it.vfsfitvnm.vimusic.ui.components.themed.*
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.ui.styling.px
import it.vfsfitvnm.vimusic.ui.views.SongItem
import it.vfsfitvnm.vimusic.utils.*
@ -90,8 +91,7 @@ fun AlbumScreen(
val context = LocalContext.current
val binder = LocalPlayerServiceBinder.current
val colorPalette = LocalColorPalette.current
val typography = LocalTypography.current
val (colorPalette, typography) = LocalAppearance.current
val menuState = LocalMenuState.current
@ -356,6 +356,8 @@ private fun LoadingOrError(
errorMessage: String? = null,
onRetry: (() -> Unit)? = null
) {
val (colorPalette) = LocalAppearance.current
LoadingOrError(
errorMessage = errorMessage,
onRetry = onRetry
@ -369,7 +371,7 @@ private fun LoadingOrError(
) {
Spacer(
modifier = Modifier
.background(color = LocalColorPalette.current.darkGray, shape = ThumbnailRoundness.shape)
.background(color = colorPalette.darkGray, shape = ThumbnailRoundness.shape)
.size(Dimensions.thumbnails.album)
)

View file

@ -36,10 +36,7 @@ import it.vfsfitvnm.vimusic.ui.components.themed.InHistoryMediaItemMenu
import it.vfsfitvnm.vimusic.ui.components.themed.LoadingOrError
import it.vfsfitvnm.vimusic.ui.components.themed.TextCard
import it.vfsfitvnm.vimusic.ui.components.themed.TextPlaceholder
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
import it.vfsfitvnm.vimusic.ui.styling.px
import it.vfsfitvnm.vimusic.ui.styling.*
import it.vfsfitvnm.vimusic.ui.views.SongItem
import it.vfsfitvnm.vimusic.utils.*
import it.vfsfitvnm.youtubemusic.YouTube
@ -77,8 +74,7 @@ fun ArtistScreen(
host {
val binder = LocalPlayerServiceBinder.current
val colorPalette = LocalColorPalette.current
val typography = LocalTypography.current
val (colorPalette, typography) = LocalAppearance.current
val artistResult by remember(browseId) {
Database.artist(browseId).map { artist ->
@ -294,7 +290,7 @@ private fun LoadingOrError(
errorMessage: String? = null,
onRetry: (() -> Unit)? = null
) {
val colorPalette = LocalColorPalette.current
val (colorPalette) = LocalAppearance.current
LoadingOrError(
errorMessage = errorMessage,

View file

@ -29,10 +29,7 @@ import it.vfsfitvnm.vimusic.models.DetailedSong
import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
import it.vfsfitvnm.vimusic.ui.components.themed.*
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
import it.vfsfitvnm.vimusic.ui.styling.px
import it.vfsfitvnm.vimusic.ui.styling.*
import it.vfsfitvnm.vimusic.ui.views.SongItem
import it.vfsfitvnm.vimusic.utils.*
import kotlinx.coroutines.Dispatchers
@ -66,8 +63,7 @@ fun BuiltInPlaylistScreen(
val menuState = LocalMenuState.current
val binder = LocalPlayerServiceBinder.current
val colorPalette = LocalColorPalette.current
val typography = LocalTypography.current
val (colorPalette, typography) = LocalAppearance.current
val thumbnailSize = Dimensions.thumbnails.song.px

View file

@ -50,10 +50,7 @@ import it.vfsfitvnm.vimusic.ui.components.TopAppBar
import it.vfsfitvnm.vimusic.ui.components.themed.DropdownMenu
import it.vfsfitvnm.vimusic.ui.components.themed.InHistoryMediaItemMenu
import it.vfsfitvnm.vimusic.ui.components.themed.TextFieldDialog
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
import it.vfsfitvnm.vimusic.ui.styling.px
import it.vfsfitvnm.vimusic.ui.styling.*
import it.vfsfitvnm.vimusic.ui.views.PlaylistPreviewItem
import it.vfsfitvnm.vimusic.ui.views.SongItem
import it.vfsfitvnm.vimusic.utils.*
@ -64,8 +61,7 @@ import kotlinx.coroutines.Dispatchers
@ExperimentalAnimationApi
@Composable
fun HomeScreen() {
val colorPalette = LocalColorPalette.current
val typography = LocalTypography.current
val (colorPalette, typography) = LocalAppearance.current
val lazyListState = rememberLazyListState()
@ -82,10 +78,11 @@ fun HomeScreen() {
Database.playlistPreviews()
}.collectAsState(initial = emptyList(), context = Dispatchers.IO)
val preferences = LocalPreferences.current
var songSortBy by rememberPreference(songSortByKey, SongSortBy.DateAdded)
var songSortOrder by rememberPreference(songSortOrderKey, SortOrder.Descending)
val songCollection by remember(preferences.songSortBy, preferences.songSortOrder) {
Database.songs(preferences.songSortBy, preferences.songSortOrder)
val songCollection by remember(songSortBy, songSortOrder) {
Database.songs(songSortBy, songSortOrder)
}.collectAsState(initial = emptyList(), context = Dispatchers.IO)
RouteHandler(listenToGlobalEmitter = true) {
@ -153,6 +150,9 @@ fun HomeScreen() {
val binder = LocalPlayerServiceBinder.current
val isFirstLaunch by rememberPreference(isFirstLaunchKey, true)
val isCachedPlaylistShown by rememberPreference(isCachedPlaylistShownKey, false)
val thumbnailSize = Dimensions.thumbnails.song.px
var isGridExpanded by remember {
@ -199,7 +199,7 @@ fun HomeScreen() {
}
.padding(horizontal = 16.dp, vertical = 8.dp)
.run {
if (preferences.isFirstLaunch) {
if (isFirstLaunch) {
drawBehind {
drawCircle(
color = colorPalette.red,
@ -321,7 +321,7 @@ fun HomeScreen() {
}
}
if (preferences.isCachedPlaylistShown) {
if (isCachedPlaylistShown) {
item {
Box(
modifier = Modifier
@ -492,16 +492,16 @@ fun HomeScreen() {
) {
Item(
text = "PLAY TIME",
isSelected = preferences.songSortBy == SongSortBy.PlayTime,
isSelected = songSortBy == SongSortBy.PlayTime,
onClick = {
preferences.songSortBy = SongSortBy.PlayTime
songSortBy = SongSortBy.PlayTime
}
)
Item(
text = "DATE ADDED",
isSelected = preferences.songSortBy == SongSortBy.DateAdded,
isSelected = songSortBy == SongSortBy.DateAdded,
onClick = {
preferences.songSortBy = SongSortBy.DateAdded
songSortBy = SongSortBy.DateAdded
}
)
}
@ -518,14 +518,14 @@ fun HomeScreen() {
.width(IntrinsicSize.Max),
) {
Item(
text = when (preferences.songSortOrder) {
text = when (songSortOrder) {
SortOrder.Ascending -> "ASCENDING"
SortOrder.Descending -> "DESCENDING"
},
textColor = colorPalette.text,
backgroundColor = colorPalette.elevatedBackground,
onClick = {
preferences.songSortOrder = !preferences.songSortOrder
songSortOrder = !songSortOrder
}
)
}
@ -556,7 +556,7 @@ fun HomeScreen() {
},
onThumbnailContent = {
AnimatedVisibility(
visible = preferences.songSortBy == SongSortBy.PlayTime,
visible = songSortBy == SongSortBy.PlayTime,
enter = fadeIn(),
exit = fadeOut(),
modifier = Modifier

View file

@ -27,7 +27,7 @@ import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
import it.vfsfitvnm.vimusic.ui.components.themed.*
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.ui.styling.px
import it.vfsfitvnm.vimusic.utils.asMediaItem
import it.vfsfitvnm.vimusic.utils.enqueue
@ -61,7 +61,7 @@ fun IntentUriScreen(uri: Uri) {
host {
val menuState = LocalMenuState.current
val colorPalette = LocalColorPalette.current
val (colorPalette) = LocalAppearance.current
val binder = LocalPlayerServiceBinder.current
val thumbnailSizePx = Dimensions.thumbnails.song.px

View file

@ -32,8 +32,7 @@ import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
import it.vfsfitvnm.vimusic.ui.components.themed.*
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.ui.styling.px
import it.vfsfitvnm.vimusic.ui.views.SongItem
import it.vfsfitvnm.vimusic.utils.*
@ -73,8 +72,7 @@ fun LocalPlaylistScreen(
val menuState = LocalMenuState.current
val binder = LocalPlayerServiceBinder.current
val colorPalette = LocalColorPalette.current
val typography = LocalTypography.current
val (colorPalette, typography) = LocalAppearance.current
val thumbnailSize = Dimensions.thumbnails.song.px

View file

@ -36,8 +36,7 @@ import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
import it.vfsfitvnm.vimusic.ui.components.themed.*
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.ui.styling.px
import it.vfsfitvnm.vimusic.ui.views.SongItem
import it.vfsfitvnm.vimusic.utils.*
@ -73,8 +72,7 @@ fun PlaylistScreen(
val context = LocalContext.current
val binder = LocalPlayerServiceBinder.current
val colorPalette = LocalColorPalette.current
val typography = LocalTypography.current
val (colorPalette, typography) = LocalAppearance.current
val menuState = LocalMenuState.current
val thumbnailSizePx = Dimensions.thumbnails.playlist.px
@ -387,7 +385,7 @@ private fun LoadingOrError(
errorMessage: String? = null,
onRetry: (() -> Unit)? = null
) {
val colorPalette = LocalColorPalette.current
val (colorPalette) = LocalAppearance.current
LoadingOrError(
errorMessage = errorMessage,

View file

@ -37,8 +37,7 @@ import it.vfsfitvnm.vimusic.ui.components.themed.NonQueuedMediaItemMenu
import it.vfsfitvnm.vimusic.ui.components.themed.TextCard
import it.vfsfitvnm.vimusic.ui.components.themed.TextPlaceholder
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.ui.styling.px
import it.vfsfitvnm.vimusic.ui.views.SongItem
import it.vfsfitvnm.vimusic.utils.*
@ -53,29 +52,29 @@ fun SearchResultScreen(
query: String,
onSearchAgain: () -> Unit,
) {
val colorPalette = LocalColorPalette.current
val typography = LocalTypography.current
val preferences = LocalPreferences.current
val (colorPalette, typography) = LocalAppearance.current
val binder = LocalPlayerServiceBinder.current
var searchFilter by rememberPreference(searchFilterKey, YouTube.Item.Song.Filter.value)
val lazyListState = rememberLazyListState()
val items = remember(preferences.searchFilter) {
val items = remember(searchFilter) {
mutableStateListOf<YouTube.Item>()
}
var continuationResult by remember(preferences.searchFilter) {
var continuationResult by remember(searchFilter) {
mutableStateOf<Result<String?>?>(null)
}
val onLoad = relaunchableEffect(preferences.searchFilter) {
val onLoad = relaunchableEffect(searchFilter) {
withContext(Dispatchers.Main) {
val token = continuationResult?.getOrNull()
continuationResult = null
continuationResult = withContext(Dispatchers.IO) {
YouTube.search(query, preferences.searchFilter, token)
YouTube.search(query, searchFilter, token)
}?.map { searchResult ->
items.addAll(searchResult.items)
searchResult.continuation
@ -186,14 +185,14 @@ fun SearchResultScreen(
value = YouTube.Item.FeaturedPlaylist.Filter.value
),
),
value = preferences.searchFilter,
value = searchFilter,
selectedBackgroundColor = colorPalette.primaryContainer,
unselectedBackgroundColor = colorPalette.lightBackground,
selectedTextStyle = typography.xs.medium.color(colorPalette.onPrimaryContainer),
unselectedTextStyle = typography.xs.medium,
shape = RoundedCornerShape(36.dp),
onValueChanged = {
preferences.searchFilter = it
searchFilter = it
},
modifier = Modifier
.padding(vertical = 8.dp)
@ -255,7 +254,7 @@ fun SearchResultScreen(
} ?: item(key = "loading") {
LoadingOrError(
itemCount = if (items.isEmpty()) 8 else 3,
isLoadingArtists = preferences.searchFilter == YouTube.Item.Artist.Filter.value
isLoadingArtists = searchFilter == YouTube.Item.Artist.Filter.value
)
}
}
@ -268,7 +267,7 @@ fun SmallSongItemShimmer(
thumbnailSizeDp: Dp,
modifier: Modifier = Modifier
) {
val colorPalette = LocalColorPalette.current
val (colorPalette) = LocalAppearance.current
Row(
verticalAlignment = Alignment.CenterVertically,
@ -293,7 +292,7 @@ fun SmallArtistItemShimmer(
thumbnailSizeDp: Dp,
modifier: Modifier = Modifier
) {
val colorPalette = LocalColorPalette.current
val (colorPalette) = LocalAppearance.current
Row(
verticalAlignment = Alignment.CenterVertically,
@ -422,7 +421,7 @@ fun SmallPlaylistItem(
thumbnailSizePx: Int,
modifier: Modifier = Modifier
) {
val typography = LocalTypography.current
val (_, typography) = LocalAppearance.current
Row(
verticalAlignment = Alignment.CenterVertically,
@ -474,7 +473,7 @@ fun SmallAlbumItem(
thumbnailSizePx: Int,
modifier: Modifier = Modifier,
) {
val typography = LocalTypography.current
val (_, typography) = LocalAppearance.current
Row(
verticalAlignment = Alignment.CenterVertically,
@ -526,7 +525,7 @@ fun SmallArtistItem(
thumbnailSizePx: Int,
modifier: Modifier = Modifier,
) {
val typography = LocalTypography.current
val (_, typography) = LocalAppearance.current
Row(
verticalAlignment = Alignment.CenterVertically,

View file

@ -37,8 +37,7 @@ import it.vfsfitvnm.vimusic.query
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
import it.vfsfitvnm.vimusic.ui.components.themed.LoadingOrError
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.medium
import it.vfsfitvnm.vimusic.utils.secondary
import it.vfsfitvnm.youtubemusic.YouTube
@ -104,8 +103,7 @@ fun SearchScreen(
}
host {
val colorPalette = LocalColorPalette.current
val typography = LocalTypography.current
val (colorPalette, typography) = LocalAppearance.current
val isOpenableUrl = remember(textFieldValue.text) {
listOf(

View file

@ -23,8 +23,7 @@ import it.vfsfitvnm.vimusic.ui.components.TopAppBar
import it.vfsfitvnm.vimusic.ui.components.themed.Switch
import it.vfsfitvnm.vimusic.ui.components.themed.ValueSelectorDialog
import it.vfsfitvnm.vimusic.ui.screens.settings.*
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.*
@ -92,9 +91,9 @@ fun SettingsScreen() {
}
host {
val colorPalette = LocalColorPalette.current
val typography = LocalTypography.current
val preferences = LocalPreferences.current
val (colorPalette, typography) = LocalAppearance.current
var isFirstLaunch by rememberPreference(isFirstLaunchKey, true)
Column(
modifier = Modifier
@ -242,9 +241,9 @@ fun SettingsScreen() {
title = "Other",
description = "Advanced settings",
route = otherSettingsRoute,
withAlert = LocalPreferences.current.isFirstLaunch,
withAlert = isFirstLaunch,
onClick = {
preferences.isFirstLaunch = false
isFirstLaunch = false
}
)
@ -324,8 +323,7 @@ fun SwitchSettingEntry(
modifier: Modifier = Modifier,
isEnabled: Boolean = true
) {
val colorPalette = LocalColorPalette.current
val typography = LocalTypography.current
val (colorPalette, typography) = LocalAppearance.current
Row(
horizontalArrangement = Arrangement.spacedBy(16.dp),
@ -370,8 +368,8 @@ fun SettingsEntry(
onClick: () -> Unit,
isEnabled: Boolean = true
) {
val typography = LocalTypography.current
val colorPalette = LocalColorPalette.current
val (_, typography) = LocalAppearance.current
val (colorPalette) = LocalAppearance.current
Column(
modifier = modifier
@ -422,7 +420,7 @@ fun BaseSettingsEntry(
titleTextStyle: @Composable TextStyle.() -> TextStyle = { this },
textStyle: @Composable TextStyle.() -> TextStyle = { this },
) {
val typography = LocalTypography.current
val (_, typography) = LocalAppearance.current
Column(
modifier = modifier
@ -447,11 +445,11 @@ fun SettingsEntryGroupText(
title: String,
modifier: Modifier = Modifier,
) {
val typography = LocalTypography.current
val (colorPalette, typography) = LocalAppearance.current
BasicText(
text = title.uppercase(),
style = typography.xxs.semiBold.copy(LocalColorPalette.current.blue),
style = typography.xxs.semiBold.copy(colorPalette.blue),
modifier = modifier
.padding(start = 24.dp, top = 24.dp)
.padding(horizontal = 32.dp)

View file

@ -16,12 +16,11 @@ import it.vfsfitvnm.route.RouteHandler
import it.vfsfitvnm.vimusic.BuildConfig
import it.vfsfitvnm.vimusic.R
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
import it.vfsfitvnm.vimusic.ui.screens.ArtistScreen
import it.vfsfitvnm.vimusic.ui.screens.AlbumScreen
import it.vfsfitvnm.vimusic.ui.screens.rememberArtistRoute
import it.vfsfitvnm.vimusic.ui.screens.ArtistScreen
import it.vfsfitvnm.vimusic.ui.screens.rememberAlbumRoute
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
import it.vfsfitvnm.vimusic.ui.screens.rememberArtistRoute
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.bold
import it.vfsfitvnm.vimusic.utils.secondary
import it.vfsfitvnm.vimusic.utils.semiBold
@ -48,8 +47,7 @@ fun AboutScreen() {
}
host {
val colorPalette = LocalColorPalette.current
val typography = LocalTypography.current
val (colorPalette, typography) = LocalAppearance.current
val uriHandler = LocalUriHandler.current
Column(

View file

@ -5,18 +5,20 @@ import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.BasicText
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import it.vfsfitvnm.route.RouteHandler
import it.vfsfitvnm.vimusic.R
import it.vfsfitvnm.vimusic.enums.ColorPaletteMode
import it.vfsfitvnm.vimusic.enums.ThumbnailRoundness
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
import it.vfsfitvnm.vimusic.ui.screens.*
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
import it.vfsfitvnm.vimusic.utils.LocalPreferences
import it.vfsfitvnm.vimusic.utils.semiBold
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.*
@ExperimentalAnimationApi
@Composable
@ -40,9 +42,11 @@ fun AppearanceSettingsScreen() {
}
host {
val colorPalette = LocalColorPalette.current
val typography = LocalTypography.current
val preferences = LocalPreferences.current
val (colorPalette, typography) = LocalAppearance.current
var colorPaletteMode by rememberPreference(colorPaletteModeKey, ColorPaletteMode.System)
var thumbnailRoundness by rememberPreference(thumbnailRoundnessKey, ThumbnailRoundness.Light)
var isCachedPlaylistShown by rememberPreference(isCachedPlaylistShownKey, false)
Column(
modifier = Modifier
@ -81,9 +85,9 @@ fun AppearanceSettingsScreen() {
EnumValueSelectorSettingsEntry(
title = "Theme mode",
selectedValue = preferences.colorPaletteMode,
selectedValue = colorPaletteMode,
onValueSelected = {
preferences.colorPaletteMode = it
colorPaletteMode = it
}
)
@ -91,9 +95,9 @@ fun AppearanceSettingsScreen() {
EnumValueSelectorSettingsEntry(
title = "Thumbnail roundness",
selectedValue = preferences.thumbnailRoundness,
selectedValue = thumbnailRoundness,
onValueSelected = {
preferences.thumbnailRoundness = it
thumbnailRoundness = it
}
)
@ -102,9 +106,9 @@ fun AppearanceSettingsScreen() {
SwitchSettingEntry(
title = "Cached playlist",
text = "Display a playlist whose songs can be played offline",
isChecked = preferences.isCachedPlaylistShown,
isChecked = isCachedPlaylistShown,
onCheckedChange = {
preferences.isCachedPlaylistShown = it
isCachedPlaylistShown = it
}
)
}

View file

@ -31,8 +31,7 @@ import it.vfsfitvnm.vimusic.ui.screens.AlbumScreen
import it.vfsfitvnm.vimusic.ui.screens.ArtistScreen
import it.vfsfitvnm.vimusic.ui.screens.rememberAlbumRoute
import it.vfsfitvnm.vimusic.ui.screens.rememberArtistRoute
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.intent
import it.vfsfitvnm.vimusic.utils.semiBold
import java.io.FileInputStream
@ -64,8 +63,7 @@ fun BackupAndRestoreScreen() {
}
host {
val colorPalette = LocalColorPalette.current
val typography = LocalTypography.current
val (colorPalette, typography) = LocalAppearance.current
val context = LocalContext.current
val backupLauncher =

View file

@ -16,13 +16,15 @@ import coil.annotation.ExperimentalCoilApi
import it.vfsfitvnm.route.RouteHandler
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
import it.vfsfitvnm.vimusic.R
import it.vfsfitvnm.vimusic.enums.CoilDiskCacheMaxSize
import it.vfsfitvnm.vimusic.enums.ExoPlayerDiskCacheMaxSize
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
import it.vfsfitvnm.vimusic.ui.components.themed.TextCard
import it.vfsfitvnm.vimusic.ui.screens.*
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
import it.vfsfitvnm.vimusic.utils.LocalPreferences
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.coilDiskCacheMaxSizeKey
import it.vfsfitvnm.vimusic.utils.exoPlayerDiskCacheMaxSizeKey
import it.vfsfitvnm.vimusic.utils.rememberPreference
import it.vfsfitvnm.vimusic.utils.semiBold
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@ -51,11 +53,12 @@ fun CacheSettingsScreen() {
host {
val context = LocalContext.current
val colorPalette = LocalColorPalette.current
val typography = LocalTypography.current
val preferences = LocalPreferences.current
val (colorPalette, typography) = LocalAppearance.current
val binder = LocalPlayerServiceBinder.current
var coilDiskCacheMaxSize by rememberPreference(coilDiskCacheMaxSizeKey, CoilDiskCacheMaxSize.`128MB`)
var exoPlayerDiskCacheMaxSize by rememberPreference(exoPlayerDiskCacheMaxSizeKey, ExoPlayerDiskCacheMaxSize.`2GB`)
val coroutineScope = rememberCoroutineScope()
Column(
@ -100,9 +103,9 @@ fun CacheSettingsScreen() {
EnumValueSelectorSettingsEntry(
title = "Max size",
selectedValue = preferences.coilDiskCacheMaxSize,
selectedValue = coilDiskCacheMaxSize,
onValueSelected = {
preferences.coilDiskCacheMaxSize = it
coilDiskCacheMaxSize = it
}
)
@ -114,9 +117,7 @@ fun CacheSettingsScreen() {
diskCacheSize
)
} (${
diskCacheSize * 100 / preferences.coilDiskCacheMaxSize.bytes.coerceAtLeast(
1
)
diskCacheSize * 100 / coilDiskCacheMaxSize.bytes.coerceAtLeast(1)
}%)",
)
@ -143,9 +144,9 @@ fun CacheSettingsScreen() {
EnumValueSelectorSettingsEntry(
title = "Max size",
selectedValue = preferences.exoPlayerDiskCacheMaxSize,
selectedValue = exoPlayerDiskCacheMaxSize,
onValueSelected = {
preferences.exoPlayerDiskCacheMaxSize = it
exoPlayerDiskCacheMaxSize = it
}
)
@ -154,7 +155,7 @@ fun CacheSettingsScreen() {
text = buildString {
append(Formatter.formatShortFileSize(context, diskCacheSize))
when (val size = preferences.exoPlayerDiskCacheMaxSize) {
when (val size = exoPlayerDiskCacheMaxSize) {
ExoPlayerDiskCacheMaxSize.Unlimited -> {}
else -> append("(${diskCacheSize * 100 / size.bytes}%)")
}

View file

@ -23,10 +23,10 @@ import it.vfsfitvnm.vimusic.R
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
import it.vfsfitvnm.vimusic.ui.components.themed.TextCard
import it.vfsfitvnm.vimusic.ui.screens.*
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
import it.vfsfitvnm.vimusic.utils.LocalPreferences
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.isIgnoringBatteryOptimizations
import it.vfsfitvnm.vimusic.utils.isInvincibilityEnabledKey
import it.vfsfitvnm.vimusic.utils.rememberPreference
import it.vfsfitvnm.vimusic.utils.semiBold
@ -53,9 +53,9 @@ fun OtherSettingsScreen() {
host {
val context = LocalContext.current
val colorPalette = LocalColorPalette.current
val typography = LocalTypography.current
val preferences = LocalPreferences.current
val (colorPalette, typography) = LocalAppearance.current
var isInvincibilityEnabled by rememberPreference(isInvincibilityEnabledKey, false)
var isIgnoringBatteryOptimizations by remember {
mutableStateOf(context.isIgnoringBatteryOptimizations)
@ -140,9 +140,9 @@ fun OtherSettingsScreen() {
SwitchSettingEntry(
title = "Invincible service",
text = "When turning off battery optimizations is not enough",
isChecked = preferences.isInvincibilityEnabled,
isChecked = isInvincibilityEnabled,
onCheckedChange = {
preferences.isInvincibilityEnabled = it
isInvincibilityEnabled = it
}
)

View file

@ -10,6 +10,8 @@ import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.BasicText
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.platform.LocalContext
@ -20,10 +22,8 @@ import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
import it.vfsfitvnm.vimusic.R
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
import it.vfsfitvnm.vimusic.ui.screens.*
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
import it.vfsfitvnm.vimusic.utils.LocalPreferences
import it.vfsfitvnm.vimusic.utils.semiBold
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.*
@ExperimentalAnimationApi
@ -49,11 +49,13 @@ fun PlayerSettingsScreen() {
host {
val context = LocalContext.current
val colorPalette = LocalColorPalette.current
val typography = LocalTypography.current
val preferences = LocalPreferences.current
val (colorPalette, typography) = LocalAppearance.current
val binder = LocalPlayerServiceBinder.current
var persistentQueue by rememberPreference(persistentQueueKey, false)
var skipSilence by rememberPreference(skipSilenceKey, false)
var volumeNormalization by rememberPreference(volumeNormalizationKey, false)
val activityResultLauncher =
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
}
@ -96,9 +98,9 @@ fun PlayerSettingsScreen() {
SwitchSettingEntry(
title = "Persistent queue",
text = "Save and restore playing songs",
isChecked = preferences.persistentQueue,
isChecked = persistentQueue,
onCheckedChange = {
preferences.persistentQueue = it
persistentQueue = it
}
)
@ -107,19 +109,18 @@ fun PlayerSettingsScreen() {
SwitchSettingEntry(
title = "Skip silence",
text = "Skip silent parts during playback",
isChecked = preferences.skipSilence,
isChecked = skipSilence,
onCheckedChange = {
binder?.player?.skipSilenceEnabled = it
preferences.skipSilence = it
skipSilence = it
}
)
SwitchSettingEntry(
title = "Loudness normalization",
text = "Lower the volume to a standard level",
isChecked = preferences.volumeNormalization,
isChecked = volumeNormalization,
onCheckedChange = {
preferences.volumeNormalization = it
volumeNormalization = it
}
)

View file

@ -0,0 +1,12 @@
package it.vfsfitvnm.vimusic.ui.styling
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.graphics.Shape
data class Appearance(
val colorPalette: ColorPalette,
val typography: Typography,
val thumbnailShape: Shape
)
val LocalAppearance = staticCompositionLocalOf<Appearance> { TODO() }

View file

@ -82,5 +82,3 @@ val LightColorPalette = ColorPalette(
// iconOnPrimaryContainer = Color(0xff2e30b8),
isDark = false
)
val LocalColorPalette = staticCompositionLocalOf { LightColorPalette }

View file

@ -23,53 +23,3 @@ data class Typography(
val m: TextStyle,
val l: TextStyle,
)
val LocalTypography = staticCompositionLocalOf<Typography> { TODO() }
@Suppress("DEPRECATION")
@OptIn(ExperimentalTextApi::class)
@Composable
fun rememberTypography(color: Color): Typography {
return remember(color) {
TextStyle(
fontFamily = FontFamily(
Font(
resId = R.font.poppins_w300,
weight = FontWeight.Light
),
Font(
resId = R.font.poppins_w400,
weight = FontWeight.Normal
),
Font(
resId = R.font.poppins_w400_italic,
weight = FontWeight.Normal,
style = FontStyle.Italic
),
Font(
resId = R.font.poppins_w500,
weight = FontWeight.Medium
),
Font(
resId = R.font.poppins_w600,
weight = FontWeight.SemiBold
),
Font(
resId = R.font.poppins_w700,
weight = FontWeight.Bold
),
),
fontWeight = FontWeight.Normal,
color = color,
platformStyle = PlatformTextStyle(includeFontPadding = false)
).run {
Typography(
xxs = copy(fontSize = 12.sp),
xs = copy(fontSize = 14.sp),
s = copy(fontSize = 16.sp),
m = copy(fontSize = 18.sp),
l = copy(fontSize = 20.sp),
)
}
}
}

View file

@ -36,10 +36,7 @@ import it.vfsfitvnm.vimusic.ui.components.BottomSheetState
import it.vfsfitvnm.vimusic.ui.components.MusicBars
import it.vfsfitvnm.vimusic.ui.components.themed.QueuedMediaItemMenu
import it.vfsfitvnm.vimusic.ui.screens.SmallSongItemShimmer
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
import it.vfsfitvnm.vimusic.ui.styling.LightColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.px
import it.vfsfitvnm.vimusic.ui.styling.*
import it.vfsfitvnm.vimusic.utils.PlayerState
@ -53,7 +50,7 @@ fun CurrentPlaylistView(
) {
val binder = LocalPlayerServiceBinder.current
val hapticFeedback = LocalHapticFeedback.current
val colorPalette = LocalColorPalette.current
val (colorPalette) = LocalAppearance.current
val thumbnailSize = Dimensions.thumbnails.song.px

View file

@ -19,7 +19,7 @@ import it.vfsfitvnm.vimusic.R
import it.vfsfitvnm.vimusic.ui.components.themed.TextCard
import it.vfsfitvnm.vimusic.ui.components.themed.TextFieldDialog
import it.vfsfitvnm.vimusic.ui.components.themed.TextPlaceholder
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.center
import it.vfsfitvnm.vimusic.utils.secondary
@ -32,7 +32,7 @@ fun LyricsView(
onLyricsUpdate: (String) -> Unit,
nestedScrollConnectionProvider: () -> NestedScrollConnection,
) {
val typography = LocalTypography.current
val (_, typography) = LocalAppearance.current
var isEditingLyrics by remember {
mutableStateOf(false)

View file

@ -28,8 +28,7 @@ import it.vfsfitvnm.vimusic.ui.components.BottomSheet
import it.vfsfitvnm.vimusic.ui.components.BottomSheetState
import it.vfsfitvnm.vimusic.ui.components.HorizontalTabPager
import it.vfsfitvnm.vimusic.ui.components.rememberTabPagerState
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.PlayerState
import it.vfsfitvnm.vimusic.utils.center
import it.vfsfitvnm.vimusic.utils.color
@ -50,8 +49,7 @@ fun PlayerBottomSheet(
onGlobalRouteEmitted: () -> Unit,
modifier: Modifier = Modifier,
) {
val colorPalette = LocalColorPalette.current
val typography = LocalTypography.current
val (colorPalette, typography) = LocalAppearance.current
val coroutineScope = rememberCoroutineScope()

View file

@ -63,8 +63,7 @@ fun PlayerView(
) {
val menuState = LocalMenuState.current
val colorPalette = LocalColorPalette.current
val typography = LocalTypography.current
val (colorPalette, typography) = LocalAppearance.current
val binder = LocalPlayerServiceBinder.current
val context = LocalContext.current
val configuration = LocalConfiguration.current
@ -318,7 +317,7 @@ private fun Thumbnail(
song: Song?,
modifier: Modifier = Modifier
) {
val typography = LocalTypography.current
val (_, typography) = LocalAppearance.current
val context = LocalContext.current
val binder = LocalPlayerServiceBinder.current
val player = binder?.player ?: return
@ -527,9 +526,7 @@ private fun Controls(
song: Song?,
modifier: Modifier = Modifier
) {
val typography = LocalTypography.current
val colorPalette = LocalColorPalette.current
val preferences = LocalPreferences.current
val (colorPalette, typography) = LocalAppearance.current
val binder = LocalPlayerServiceBinder.current
val player = binder?.player ?: return
@ -730,9 +727,8 @@ private fun Controls(
player.repeatMode
.plus(2)
.mod(3)
.let { repeatMode ->
player.repeatMode = repeatMode
preferences.repeatMode = repeatMode
.let {
player.repeatMode = it
}
}
.weight(1f)

View file

@ -23,8 +23,7 @@ import coil.compose.AsyncImage
import it.vfsfitvnm.vimusic.Database
import it.vfsfitvnm.vimusic.models.PlaylistPreview
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.color
import it.vfsfitvnm.vimusic.utils.semiBold
import it.vfsfitvnm.vimusic.utils.thumbnail
@ -38,8 +37,7 @@ fun PlaylistPreviewItem(
modifier: Modifier = Modifier,
thumbnailSize: Dp = Dimensions.thumbnails.song,
) {
val colorPalette = LocalColorPalette.current
val typography = LocalTypography.current
val (colorPalette, typography) = LocalAppearance.current
val density = LocalDensity.current
val thumbnailSizePx = density.run {

View file

@ -26,8 +26,7 @@ import it.vfsfitvnm.vimusic.enums.ThumbnailRoundness
import it.vfsfitvnm.vimusic.models.DetailedSong
import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.secondary
import it.vfsfitvnm.vimusic.utils.semiBold
import it.vfsfitvnm.vimusic.utils.thumbnail
@ -150,8 +149,7 @@ fun SongItem(
trailingContent: (@Composable () -> Unit)? = null
) {
val menuState = LocalMenuState.current
val colorPalette = LocalColorPalette.current
val typography = LocalTypography.current
val (colorPalette, typography) = LocalAppearance.current
Row(
verticalAlignment = Alignment.CenterVertically,

View file

@ -5,145 +5,24 @@ import android.content.SharedPreferences
import androidx.compose.runtime.*
import androidx.compose.ui.platform.LocalContext
import androidx.core.content.edit
import androidx.media3.common.Player
import it.vfsfitvnm.vimusic.enums.*
import it.vfsfitvnm.youtubemusic.YouTube
@Stable
class Preferences(
private val edit: (action: SharedPreferences.Editor.() -> Unit) -> Unit,
initialIsFirstLaunch: Boolean,
initialSongSortBy: SongSortBy,
initialSongSortOrder: SortOrder,
initialColorPaletteMode: ColorPaletteMode,
initialSearchFilter: String,
initialRepeatMode: Int,
initialThumbnailRoundness: ThumbnailRoundness,
initialCoilDiskCacheMaxSize: CoilDiskCacheMaxSize,
initialExoPlayerDiskCacheMaxSize: ExoPlayerDiskCacheMaxSize,
initialSkipSilence: Boolean,
initialVolumeNormalization: Boolean,
initialPersistentQueue: Boolean,
initialIsInvincibilityEnabled: Boolean,
initialIsCachedPlaylistShown: Boolean,
) {
constructor(preferences: SharedPreferences) : this(
edit = { action: SharedPreferences.Editor.() -> Unit ->
preferences.edit(action = action)
},
initialIsFirstLaunch = preferences.getBoolean(Keys.isFirstLaunch, true),
initialSongSortBy = preferences.getEnum(Keys.songSortBy, SongSortBy.DateAdded),
initialSongSortOrder = preferences.getEnum(Keys.songSortOrder, SortOrder.Descending),
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),
initialThumbnailRoundness = preferences.getEnum(Keys.thumbnailRoundness, ThumbnailRoundness.Light),
initialCoilDiskCacheMaxSize = preferences.getEnum(Keys.coilDiskCacheMaxSize, CoilDiskCacheMaxSize.`128MB`),
initialExoPlayerDiskCacheMaxSize = preferences.getEnum(Keys.exoPlayerDiskCacheMaxSize, ExoPlayerDiskCacheMaxSize.`2GB`),
initialSkipSilence = preferences.getBoolean(Keys.skipSilence, false),
initialVolumeNormalization = preferences.getBoolean(Keys.volumeNormalization, false),
initialPersistentQueue = preferences.getBoolean(Keys.persistentQueue, false),
initialIsInvincibilityEnabled = preferences.getBoolean(Keys.isInvincibilityEnabled, false),
initialIsCachedPlaylistShown = preferences.getBoolean(Keys.isCachedPlaylistShown, false),
)
const val colorPaletteModeKey = "colorPaletteMode"
const val thumbnailRoundnessKey = "thumbnailRoundness"
const val isCachedPlaylistShownKey = "isCachedPlaylistShown"
const val coilDiskCacheMaxSizeKey = "coilDiskCacheMaxSize"
const val exoPlayerDiskCacheMaxSizeKey = "exoPlayerDiskCacheMaxSize"
const val isInvincibilityEnabledKey = "isInvincibilityEnabled"
const val isFirstLaunchKey = "isFirstLaunch"
const val songSortOrderKey = "songSortOrder"
const val songSortByKey = "songSortBy"
const val searchFilterKey = "searchFilter"
const val repeatModeKey = "repeatMode"
const val skipSilenceKey = "skipSilence"
const val volumeNormalizationKey = "volumeNormalization"
const val persistentQueueKey = "persistentQueue"
var isFirstLaunch = initialIsFirstLaunch
set(value) = edit { putBoolean(Keys.isFirstLaunch, value) }
var songSortBy = initialSongSortBy
set(value) = edit { putEnum(Keys.songSortBy, value) }
var songSortOrder = initialSongSortOrder
set(value) = edit { putEnum(Keys.songSortOrder, value) }
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 thumbnailRoundness = initialThumbnailRoundness
set(value) = edit { putEnum(Keys.thumbnailRoundness, value) }
var coilDiskCacheMaxSize = initialCoilDiskCacheMaxSize
set(value) = edit { putEnum(Keys.coilDiskCacheMaxSize, value) }
var exoPlayerDiskCacheMaxSize = initialExoPlayerDiskCacheMaxSize
set(value) = edit { putEnum(Keys.exoPlayerDiskCacheMaxSize, 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) }
var isInvincibilityEnabled = initialIsInvincibilityEnabled
set(value) = edit { putBoolean(Keys.isInvincibilityEnabled, value) }
var isCachedPlaylistShown = initialIsCachedPlaylistShown
set(value) = edit { putBoolean(Keys.isCachedPlaylistShown, value) }
object Keys {
const val isFirstLaunch = "isFirstLaunch"
const val songSortOrder = "songSortOrder"
const val songSortBy = "songSortBy"
const val colorPaletteMode = "colorPaletteMode"
const val searchFilter = "searchFilter"
const val repeatMode = "repeatMode"
const val thumbnailRoundness = "thumbnailRoundness"
const val coilDiskCacheMaxSize = "coilDiskCacheMaxSize"
const val exoPlayerDiskCacheMaxSize = "exoPlayerDiskCacheMaxSize"
const val skipSilence = "skipSilence"
const val volumeNormalization = "volumeNormalization"
const val persistentQueue = "persistentQueue"
const val isInvincibilityEnabled = "isInvincibilityEnabled"
const val isCachedPlaylistShown = "isCachedPlaylistShown"
}
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
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 inline fun <reified T : Enum<T>> SharedPreferences.getEnum(
inline fun <reified T : Enum<T>> SharedPreferences.getEnum(
key: String,
defaultValue: T
): T =
@ -155,6 +34,51 @@ private inline fun <reified T : Enum<T>> SharedPreferences.getEnum(
}
} ?: defaultValue
private inline fun <reified T : Enum<T>> SharedPreferences.Editor.putEnum(key: String, value: T) =
inline fun <reified T : Enum<T>> SharedPreferences.Editor.putEnum(key: String, value: T) =
putString(key, value.name)
val Context.preferences: SharedPreferences
get() = getSharedPreferences("preferences", Context.MODE_PRIVATE)
@Composable
fun rememberPreference(key: String, defaultValue: Boolean): MutableState<Boolean> {
val context = LocalContext.current
return remember {
mutableStatePreferenceOf(context.preferences.getBoolean(key, defaultValue)) {
context.preferences.edit { putBoolean(key, it) }
}
}
}
@Composable
fun rememberPreference(key: String, defaultValue: String): MutableState<String> {
val context = LocalContext.current
return remember {
mutableStatePreferenceOf(context.preferences.getString(key, null) ?: defaultValue) {
context.preferences.edit { putString(key, it) }
}
}
}
@Composable
inline fun <reified T: Enum<T>> rememberPreference(key: String, defaultValue: T): MutableState<T> {
val context = LocalContext.current
return remember {
mutableStatePreferenceOf(context.preferences.getEnum(key, defaultValue)) {
context.preferences.edit { putEnum(key, it) }
}
}
}
inline fun <T> mutableStatePreferenceOf(value: T, crossinline 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
}
})

View file

@ -7,7 +7,7 @@ import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
fun TextStyle.style(style: FontStyle) = copy(fontStyle = style)
@ -35,9 +35,9 @@ inline val TextStyle.center: TextStyle
inline val TextStyle.secondary: TextStyle
@Composable
@ReadOnlyComposable
get() = color(LocalColorPalette.current.textSecondary)
get() = color(LocalAppearance.current.colorPalette.textSecondary)
inline val TextStyle.disabled: TextStyle
@Composable
@ReadOnlyComposable
get() = color(LocalColorPalette.current.textDisabled)
get() = color(LocalAppearance.current.colorPalette.textDisabled)