Refactor preferences to avoid a global state when it's not necessary
This commit is contained in:
parent
aa8e065412
commit
1e719b33ed
|
@ -1,10 +1,7 @@
|
||||||
package it.vfsfitvnm.vimusic
|
package it.vfsfitvnm.vimusic
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.ComponentName
|
import android.content.*
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.content.ServiceConnection
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
|
@ -27,9 +24,12 @@ import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
|
import androidx.compose.ui.text.ExperimentalTextApi
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
import com.valentinilk.shimmer.LocalShimmerTheme
|
import com.valentinilk.shimmer.LocalShimmerTheme
|
||||||
import com.valentinilk.shimmer.defaultShimmerTheme
|
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.service.PlayerService
|
||||||
import it.vfsfitvnm.vimusic.ui.components.BottomSheetMenu
|
import it.vfsfitvnm.vimusic.ui.components.BottomSheetMenu
|
||||||
import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
|
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.components.rememberMenuState
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.HomeScreen
|
import it.vfsfitvnm.vimusic.ui.screens.HomeScreen
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.IntentUriScreen
|
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.Dimensions
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
|
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.rememberTypography
|
|
||||||
import it.vfsfitvnm.vimusic.ui.views.PlayerView
|
import it.vfsfitvnm.vimusic.ui.views.PlayerView
|
||||||
import it.vfsfitvnm.vimusic.utils.LocalPreferences
|
import it.vfsfitvnm.vimusic.utils.*
|
||||||
import it.vfsfitvnm.vimusic.utils.intent
|
|
||||||
import it.vfsfitvnm.vimusic.utils.rememberHapticFeedback
|
|
||||||
import it.vfsfitvnm.vimusic.utils.rememberPreferences
|
|
||||||
|
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
|
@ -75,30 +71,77 @@ class MainActivity : ComponentActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("BatteryLife")
|
@SuppressLint("BatteryLife")
|
||||||
@OptIn(ExperimentalFoundationApi::class, ExperimentalAnimationApi::class)
|
@OptIn(ExperimentalFoundationApi::class, ExperimentalAnimationApi::class,
|
||||||
|
ExperimentalTextApi::class
|
||||||
|
)
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
uri = intent?.data
|
uri = intent?.data
|
||||||
|
|
||||||
setContent {
|
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 systemUiController = rememberSystemUiController()
|
||||||
|
|
||||||
val colorPalette = preferences.colorPaletteMode.palette(isSystemInDarkTheme())
|
val rippleTheme = remember(appearance.colorPalette.text, appearance.colorPalette.isDark) {
|
||||||
|
|
||||||
val rippleTheme = remember(colorPalette.text, colorPalette.isDark) {
|
|
||||||
object : RippleTheme {
|
object : RippleTheme {
|
||||||
@Composable
|
@Composable
|
||||||
override fun defaultColor(): Color = RippleTheme.defaultRippleColor(
|
override fun defaultColor(): Color = RippleTheme.defaultRippleColor(
|
||||||
contentColor = colorPalette.text,
|
contentColor = appearance.colorPalette.text,
|
||||||
lightTheme = !colorPalette.isDark
|
lightTheme = !appearance.colorPalette.isDark
|
||||||
)
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun rippleAlpha(): RippleAlpha = RippleTheme.defaultRippleAlpha(
|
override fun rippleAlpha(): RippleAlpha = RippleTheme.defaultRippleAlpha(
|
||||||
contentColor = colorPalette.text,
|
contentColor = appearance.colorPalette.text,
|
||||||
lightTheme = !colorPalette.isDark
|
lightTheme = !appearance.colorPalette.isDark
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,17 +165,15 @@ class MainActivity : ComponentActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
SideEffect {
|
SideEffect {
|
||||||
systemUiController.setSystemBarsColor(colorPalette.background, !colorPalette.isDark)
|
systemUiController.setSystemBarsColor(appearance.colorPalette.background, !appearance.colorPalette.isDark)
|
||||||
}
|
}
|
||||||
|
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
|
LocalAppearance provides appearance,
|
||||||
LocalOverscrollConfiguration provides null,
|
LocalOverscrollConfiguration provides null,
|
||||||
LocalIndication provides rememberRipple(bounded = false),
|
LocalIndication provides rememberRipple(bounded = false),
|
||||||
LocalRippleTheme provides rippleTheme,
|
LocalRippleTheme provides rippleTheme,
|
||||||
LocalPreferences provides preferences,
|
|
||||||
LocalColorPalette provides colorPalette,
|
|
||||||
LocalShimmerTheme provides shimmerTheme,
|
LocalShimmerTheme provides shimmerTheme,
|
||||||
LocalTypography provides rememberTypography(colorPalette.text),
|
|
||||||
LocalPlayerServiceBinder provides binder,
|
LocalPlayerServiceBinder provides binder,
|
||||||
LocalMenuState provides rememberMenuState(),
|
LocalMenuState provides rememberMenuState(),
|
||||||
LocalHapticFeedback provides rememberHapticFeedback()
|
LocalHapticFeedback provides rememberHapticFeedback()
|
||||||
|
@ -140,7 +181,7 @@ class MainActivity : ComponentActivity() {
|
||||||
BoxWithConstraints(
|
BoxWithConstraints(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.background(colorPalette.background)
|
.background(appearance.colorPalette.background)
|
||||||
) {
|
) {
|
||||||
when (val uri = uri) {
|
when (val uri = uri) {
|
||||||
null -> {
|
null -> {
|
||||||
|
|
|
@ -4,7 +4,10 @@ import android.app.Application
|
||||||
import coil.ImageLoader
|
import coil.ImageLoader
|
||||||
import coil.ImageLoaderFactory
|
import coil.ImageLoaderFactory
|
||||||
import coil.disk.DiskCache
|
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 {
|
class MainApplication : Application(), ImageLoaderFactory {
|
||||||
|
@ -19,7 +22,7 @@ class MainApplication : Application(), ImageLoaderFactory {
|
||||||
.diskCache(
|
.diskCache(
|
||||||
DiskCache.Builder()
|
DiskCache.Builder()
|
||||||
.directory(filesDir.resolve("coil"))
|
.directory(filesDir.resolve("coil"))
|
||||||
.maxSizeBytes(Preferences().coilDiskCacheMaxSize.bytes)
|
.maxSizeBytes(preferences.getEnum(coilDiskCacheMaxSizeKey, CoilDiskCacheMaxSize.`128MB`).bytes)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
|
|
|
@ -1,9 +1,20 @@
|
||||||
package it.vfsfitvnm.vimusic.enums
|
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.BlackColorPalette
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.ColorPalette
|
import it.vfsfitvnm.vimusic.ui.styling.ColorPalette
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.DarkColorPalette
|
import it.vfsfitvnm.vimusic.ui.styling.DarkColorPalette
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LightColorPalette
|
import it.vfsfitvnm.vimusic.ui.styling.LightColorPalette
|
||||||
|
import it.vfsfitvnm.vimusic.ui.styling.Typography
|
||||||
|
|
||||||
|
|
||||||
enum class ColorPaletteMode {
|
enum class ColorPaletteMode {
|
||||||
Light,
|
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),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import androidx.compose.runtime.ReadOnlyComposable
|
||||||
import androidx.compose.ui.graphics.RectangleShape
|
import androidx.compose.ui.graphics.RectangleShape
|
||||||
import androidx.compose.ui.graphics.Shape
|
import androidx.compose.ui.graphics.Shape
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import it.vfsfitvnm.vimusic.utils.LocalPreferences
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
|
|
||||||
enum class ThumbnailRoundness {
|
enum class ThumbnailRoundness {
|
||||||
None,
|
None,
|
||||||
|
@ -14,15 +14,19 @@ enum class ThumbnailRoundness {
|
||||||
Medium,
|
Medium,
|
||||||
Heavy;
|
Heavy;
|
||||||
|
|
||||||
companion object {
|
fun shape(): Shape {
|
||||||
val shape: Shape
|
return when (this) {
|
||||||
@Composable
|
|
||||||
@ReadOnlyComposable
|
|
||||||
get() = when (LocalPreferences.current.thumbnailRoundness) {
|
|
||||||
None -> RectangleShape
|
None -> RectangleShape
|
||||||
Light -> RoundedCornerShape(2.dp)
|
Light -> RoundedCornerShape(2.dp)
|
||||||
Medium -> RoundedCornerShape(4.dp)
|
Medium -> RoundedCornerShape(4.dp)
|
||||||
Heavy -> RoundedCornerShape(8.dp)
|
Heavy -> RoundedCornerShape(8.dp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val shape: Shape
|
||||||
|
@Composable
|
||||||
|
@ReadOnlyComposable
|
||||||
|
get() = LocalAppearance.current.thumbnailShape
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.content.ContextCompat.startForegroundService
|
import androidx.core.content.ContextCompat.startForegroundService
|
||||||
|
import androidx.core.content.edit
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.media3.common.*
|
import androidx.media3.common.*
|
||||||
|
@ -116,17 +117,14 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
|
||||||
|
|
||||||
createNotificationChannel()
|
createNotificationChannel()
|
||||||
|
|
||||||
getSharedPreferences(
|
preferences.registerOnSharedPreferenceChangeListener(this)
|
||||||
Preferences.fileName,
|
|
||||||
Context.MODE_PRIVATE
|
|
||||||
).registerOnSharedPreferenceChangeListener(this)
|
|
||||||
|
|
||||||
val preferences = Preferences()
|
val preferences = preferences
|
||||||
isPersistentQueueEnabled = preferences.persistentQueue
|
isPersistentQueueEnabled = preferences.getBoolean(persistentQueueKey, false)
|
||||||
isVolumeNormalizationEnabled = preferences.volumeNormalization
|
isVolumeNormalizationEnabled = preferences.getBoolean(volumeNormalizationKey, false)
|
||||||
isInvincibilityEnabled = preferences.isInvincibilityEnabled
|
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()
|
ExoPlayerDiskCacheMaxSize.Unlimited -> NoOpCacheEvictor()
|
||||||
else -> LeastRecentlyUsedCacheEvictor(size.bytes)
|
else -> LeastRecentlyUsedCacheEvictor(size.bytes)
|
||||||
}
|
}
|
||||||
|
@ -146,8 +144,8 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
|
||||||
.setUsePlatformDiagnostics(false)
|
.setUsePlatformDiagnostics(false)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
player.repeatMode = preferences.repeatMode
|
player.repeatMode = preferences.getInt(repeatModeKey, Player.REPEAT_MODE_OFF)
|
||||||
player.skipSilenceEnabled = preferences.skipSilence
|
player.skipSilenceEnabled = preferences.getBoolean(skipSilenceKey, false)
|
||||||
player.addListener(this)
|
player.addListener(this)
|
||||||
player.addAnalyticsListener(PlaybackStatsListener(false, this))
|
player.addAnalyticsListener(PlaybackStatsListener(false, this))
|
||||||
|
|
||||||
|
@ -184,10 +182,7 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
maybeSavePlayerQueue()
|
maybeSavePlayerQueue()
|
||||||
|
|
||||||
getSharedPreferences(
|
preferences.unregisterOnSharedPreferenceChangeListener(this)
|
||||||
Preferences.fileName,
|
|
||||||
Context.MODE_PRIVATE
|
|
||||||
).unregisterOnSharedPreferenceChangeListener(this)
|
|
||||||
|
|
||||||
player.removeListener(this)
|
player.removeListener(this)
|
||||||
player.stop()
|
player.stop()
|
||||||
|
@ -289,14 +284,16 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun normalizeVolume() {
|
private fun normalizeVolume() {
|
||||||
if (isVolumeNormalizationEnabled) {
|
player.volume = if (isVolumeNormalizationEnabled) {
|
||||||
player.volume = player.currentMediaItem?.let { mediaItem ->
|
player.currentMediaItem?.let { mediaItem ->
|
||||||
songPendingLoudnessDb.getOrElse(mediaItem.mediaId) {
|
songPendingLoudnessDb.getOrElse(mediaItem.mediaId) {
|
||||||
mediaItem.mediaMetadata.extras?.getFloatOrNull("loudnessDb")
|
mediaItem.mediaMetadata.extras?.getFloatOrNull("loudnessDb")
|
||||||
}?.takeIf { it > 0 }?.let { loudnessDb ->
|
}?.takeIf { it > 0 }?.let { loudnessDb ->
|
||||||
(1f - (0.01f + loudnessDb / 14)).coerceIn(0.1f, 1f)
|
(1f - (0.01f + loudnessDb / 14)).coerceIn(0.1f, 1f)
|
||||||
}
|
}
|
||||||
} ?: 1f
|
} ?: 1f
|
||||||
|
} else {
|
||||||
|
1f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,6 +306,10 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
|
||||||
else -> PlaybackState.STATE_NONE
|
else -> PlaybackState.STATE_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onRepeatModeChanged(repeatMode: Int) {
|
||||||
|
preferences.edit { putInt(repeatModeKey, repeatMode) }
|
||||||
|
}
|
||||||
|
|
||||||
override fun onEvents(player: Player, events: Player.Events) {
|
override fun onEvents(player: Player, events: Player.Events) {
|
||||||
if (player.duration != C.TIME_UNSET) {
|
if (player.duration != C.TIME_UNSET) {
|
||||||
metadataBuilder
|
metadataBuilder
|
||||||
|
@ -362,12 +363,16 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
|
||||||
|
|
||||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
||||||
when (key) {
|
when (key) {
|
||||||
Preferences.Keys.persistentQueue -> isPersistentQueueEnabled =
|
persistentQueueKey -> isPersistentQueueEnabled =
|
||||||
sharedPreferences.getBoolean(key, isPersistentQueueEnabled)
|
sharedPreferences.getBoolean(key, isPersistentQueueEnabled)
|
||||||
Preferences.Keys.volumeNormalization -> isVolumeNormalizationEnabled =
|
volumeNormalizationKey -> {
|
||||||
|
isVolumeNormalizationEnabled =
|
||||||
sharedPreferences.getBoolean(key, isVolumeNormalizationEnabled)
|
sharedPreferences.getBoolean(key, isVolumeNormalizationEnabled)
|
||||||
Preferences.Keys.isInvincibilityEnabled -> isInvincibilityEnabled =
|
normalizeVolume()
|
||||||
|
}
|
||||||
|
isInvincibilityEnabledKey -> isInvincibilityEnabled =
|
||||||
sharedPreferences.getBoolean(key, isInvincibilityEnabled)
|
sharedPreferences.getBoolean(key, isInvincibilityEnabled)
|
||||||
|
skipSilenceKey -> player.skipSilenceEnabled = sharedPreferences.getBoolean(key, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,8 +34,7 @@ import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.window.Dialog
|
import androidx.compose.ui.window.Dialog
|
||||||
import androidx.compose.ui.window.DialogProperties
|
import androidx.compose.ui.window.DialogProperties
|
||||||
import it.vfsfitvnm.vimusic.ui.components.ChunkyButton
|
import it.vfsfitvnm.vimusic.ui.components.ChunkyButton
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
|
|
||||||
import it.vfsfitvnm.vimusic.utils.*
|
import it.vfsfitvnm.vimusic.utils.*
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
|
||||||
|
@ -56,8 +55,7 @@ fun TextFieldDialog(
|
||||||
val focusRequester = remember {
|
val focusRequester = remember {
|
||||||
FocusRequester()
|
FocusRequester()
|
||||||
}
|
}
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val typography = LocalTypography.current
|
|
||||||
|
|
||||||
var textFieldValue by rememberSaveable(initialTextInput, stateSaver = TextFieldValue.Saver) {
|
var textFieldValue by rememberSaveable(initialTextInput, stateSaver = TextFieldValue.Saver) {
|
||||||
mutableStateOf(
|
mutableStateOf(
|
||||||
|
@ -162,8 +160,7 @@ fun ConfirmationDialog(
|
||||||
confirmText: String = "Confirm",
|
confirmText: String = "Confirm",
|
||||||
onCancel: () -> Unit = onDismiss
|
onCancel: () -> Unit = onDismiss
|
||||||
) {
|
) {
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val typography = LocalTypography.current
|
|
||||||
|
|
||||||
DefaultDialog(
|
DefaultDialog(
|
||||||
onDismiss = onDismiss,
|
onDismiss = onDismiss,
|
||||||
|
@ -211,6 +208,8 @@ inline fun DefaultDialog(
|
||||||
horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally,
|
horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally,
|
||||||
crossinline content: @Composable ColumnScope.() -> Unit
|
crossinline content: @Composable ColumnScope.() -> Unit
|
||||||
) {
|
) {
|
||||||
|
val (colorPalette) = LocalAppearance.current
|
||||||
|
|
||||||
Dialog(
|
Dialog(
|
||||||
onDismissRequest = onDismiss,
|
onDismissRequest = onDismiss,
|
||||||
properties = DialogProperties(usePlatformDefaultWidth = false)
|
properties = DialogProperties(usePlatformDefaultWidth = false)
|
||||||
|
@ -220,7 +219,7 @@ inline fun DefaultDialog(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.padding(all = 48.dp)
|
.padding(all = 48.dp)
|
||||||
.background(
|
.background(
|
||||||
color = LocalColorPalette.current.elevatedBackground,
|
color = colorPalette.elevatedBackground,
|
||||||
shape = RoundedCornerShape(8.dp)
|
shape = RoundedCornerShape(8.dp)
|
||||||
)
|
)
|
||||||
.padding(horizontal = 24.dp, vertical = 16.dp),
|
.padding(horizontal = 24.dp, vertical = 16.dp),
|
||||||
|
@ -240,15 +239,14 @@ inline fun <T> ValueSelectorDialog(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
crossinline valueText: (T) -> String = { it.toString() }
|
crossinline valueText: (T) -> String = { it.toString() }
|
||||||
) {
|
) {
|
||||||
val typography = LocalTypography.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val colorPalette = LocalColorPalette.current
|
|
||||||
|
|
||||||
Dialog(onDismissRequest = onDismiss) {
|
Dialog(onDismissRequest = onDismiss) {
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.padding(all = 48.dp)
|
.padding(all = 48.dp)
|
||||||
.background(
|
.background(
|
||||||
color = LocalColorPalette.current.elevatedBackground,
|
color = colorPalette.elevatedBackground,
|
||||||
shape = RoundedCornerShape(8.dp)
|
shape = RoundedCornerShape(8.dp)
|
||||||
)
|
)
|
||||||
.padding(vertical = 16.dp),
|
.padding(vertical = 16.dp),
|
||||||
|
|
|
@ -31,8 +31,7 @@ import it.vfsfitvnm.vimusic.ui.components.Pager
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.rememberAlbumRoute
|
import it.vfsfitvnm.vimusic.ui.screens.rememberAlbumRoute
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.rememberArtistRoute
|
import it.vfsfitvnm.vimusic.ui.screens.rememberArtistRoute
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.rememberCreatePlaylistRoute
|
import it.vfsfitvnm.vimusic.ui.screens.rememberCreatePlaylistRoute
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
|
|
||||||
import it.vfsfitvnm.vimusic.utils.*
|
import it.vfsfitvnm.vimusic.utils.*
|
||||||
import it.vfsfitvnm.youtubemusic.models.NavigationEndpoint
|
import it.vfsfitvnm.youtubemusic.models.NavigationEndpoint
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
@ -371,8 +370,7 @@ fun MediaItemMenu(
|
||||||
|
|
||||||
onSetSleepTimer?.let { onSetSleepTimer ->
|
onSetSleepTimer?.let { onSetSleepTimer ->
|
||||||
val binder = LocalPlayerServiceBinder.current
|
val binder = LocalPlayerServiceBinder.current
|
||||||
val typography = LocalTypography.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val colorPalette = LocalColorPalette.current
|
|
||||||
|
|
||||||
var isShowingSleepTimerDialog by remember {
|
var isShowingSleepTimerDialog by remember {
|
||||||
mutableStateOf(false)
|
mutableStateOf(false)
|
||||||
|
|
|
@ -16,8 +16,7 @@ import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import it.vfsfitvnm.vimusic.R
|
import it.vfsfitvnm.vimusic.R
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
|
|
||||||
import it.vfsfitvnm.vimusic.utils.medium
|
import it.vfsfitvnm.vimusic.utils.medium
|
||||||
import it.vfsfitvnm.vimusic.utils.secondary
|
import it.vfsfitvnm.vimusic.utils.secondary
|
||||||
|
|
||||||
|
@ -27,7 +26,7 @@ inline fun Menu(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
content: @Composable ColumnScope.() -> Unit
|
content: @Composable ColumnScope.() -> Unit
|
||||||
) {
|
) {
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette) = LocalAppearance.current
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
|
@ -52,8 +51,7 @@ fun MenuEntry(
|
||||||
secondaryText: String? = null,
|
secondaryText: String? = null,
|
||||||
isEnabled: Boolean = true,
|
isEnabled: Boolean = true,
|
||||||
) {
|
) {
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val typography = LocalTypography.current
|
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
@ -99,7 +97,7 @@ fun MenuIconButton(
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette) = LocalAppearance.current
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
|
|
|
@ -16,7 +16,7 @@ import androidx.compose.ui.geometry.center
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.Shadow
|
import androidx.compose.ui.graphics.Shadow
|
||||||
import androidx.compose.ui.unit.dp
|
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
|
import it.vfsfitvnm.vimusic.utils.drawCircle
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ fun Switch(
|
||||||
isChecked: Boolean,
|
isChecked: Boolean,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette) = LocalAppearance.current
|
||||||
|
|
||||||
val backgroundColor by animateColorAsState(if (isChecked) colorPalette.primaryContainer else colorPalette.lightBackground)
|
val backgroundColor by animateColorAsState(if (isChecked) colorPalette.primaryContainer else colorPalette.lightBackground)
|
||||||
val color by animateColorAsState(if (isChecked) colorPalette.onPrimaryContainer else colorPalette.textDisabled)
|
val color by animateColorAsState(if (isChecked) colorPalette.onPrimaryContainer else colorPalette.textDisabled)
|
||||||
|
|
|
@ -17,8 +17,7 @@ import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
|
|
||||||
import it.vfsfitvnm.vimusic.utils.align
|
import it.vfsfitvnm.vimusic.utils.align
|
||||||
import it.vfsfitvnm.vimusic.utils.secondary
|
import it.vfsfitvnm.vimusic.utils.secondary
|
||||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
import it.vfsfitvnm.vimusic.utils.semiBold
|
||||||
|
@ -32,7 +31,7 @@ fun TextCard(
|
||||||
onClick: (() -> Unit)? = null,
|
onClick: (() -> Unit)? = null,
|
||||||
content: @Composable TextCardScope.() -> Unit,
|
content: @Composable TextCardScope.() -> Unit,
|
||||||
) {
|
) {
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette) = LocalAppearance.current
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
|
@ -72,17 +71,19 @@ interface TextCardScope {
|
||||||
private object TextCardScopeImpl : TextCardScope {
|
private object TextCardScopeImpl : TextCardScope {
|
||||||
@Composable
|
@Composable
|
||||||
override fun Title(text: String) {
|
override fun Title(text: String) {
|
||||||
|
val (_, typography) = LocalAppearance.current
|
||||||
BasicText(
|
BasicText(
|
||||||
text = text,
|
text = text,
|
||||||
style = LocalTypography.current.xxs.semiBold,
|
style = typography.xxs.semiBold,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun Text(text: String) {
|
override fun Text(text: String) {
|
||||||
|
val (_, typography) = LocalAppearance.current
|
||||||
BasicText(
|
BasicText(
|
||||||
text = text,
|
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 {
|
private object IconTextCardScopeImpl : TextCardScope {
|
||||||
@Composable
|
@Composable
|
||||||
override fun Title(text: String) {
|
override fun Title(text: String) {
|
||||||
|
val (_, typography) = LocalAppearance.current
|
||||||
BasicText(
|
BasicText(
|
||||||
text = text,
|
text = text,
|
||||||
style = LocalTypography.current.xxs.semiBold,
|
style = typography.xxs.semiBold,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(horizontal = 16.dp)
|
.padding(horizontal = 16.dp)
|
||||||
)
|
)
|
||||||
|
@ -100,9 +102,10 @@ private object IconTextCardScopeImpl : TextCardScope {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun Text(text: String) {
|
override fun Text(text: String) {
|
||||||
|
val (_, typography) = LocalAppearance.current
|
||||||
BasicText(
|
BasicText(
|
||||||
text = text,
|
text = text,
|
||||||
style = LocalTypography.current.xxs.secondary,
|
style = typography.xxs.secondary,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(horizontal = 16.dp)
|
.padding(horizontal = 16.dp)
|
||||||
)
|
)
|
||||||
|
|
|
@ -10,20 +10,18 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TextPlaceholder(
|
fun TextPlaceholder(
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
|
val (colorPalette) = LocalAppearance.current
|
||||||
Spacer(
|
Spacer(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.padding(vertical = 4.dp)
|
.padding(vertical = 4.dp)
|
||||||
.background(
|
.background(color = colorPalette.darkGray, shape = RoundedCornerShape(0.dp))
|
||||||
color = LocalColorPalette.current.darkGray,
|
|
||||||
shape = RoundedCornerShape(0.dp)
|
|
||||||
)
|
|
||||||
.fillMaxWidth(remember { 0.25f + Random.nextFloat() * 0.5f })
|
.fillMaxWidth(remember { 0.25f + Random.nextFloat() * 0.5f })
|
||||||
.height(16.dp)
|
.height(16.dp)
|
||||||
)
|
)
|
||||||
|
|
|
@ -28,16 +28,17 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
import it.vfsfitvnm.route.RouteHandler
|
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.R
|
||||||
import it.vfsfitvnm.vimusic.enums.ThumbnailRoundness
|
import it.vfsfitvnm.vimusic.enums.ThumbnailRoundness
|
||||||
import it.vfsfitvnm.vimusic.models.*
|
import it.vfsfitvnm.vimusic.models.*
|
||||||
|
import it.vfsfitvnm.vimusic.query
|
||||||
import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
|
import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
|
||||||
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.*
|
import it.vfsfitvnm.vimusic.ui.components.themed.*
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
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.LocalTypography
|
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.px
|
import it.vfsfitvnm.vimusic.ui.styling.px
|
||||||
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
||||||
import it.vfsfitvnm.vimusic.utils.*
|
import it.vfsfitvnm.vimusic.utils.*
|
||||||
|
@ -90,8 +91,7 @@ fun AlbumScreen(
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val binder = LocalPlayerServiceBinder.current
|
val binder = LocalPlayerServiceBinder.current
|
||||||
|
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val typography = LocalTypography.current
|
|
||||||
val menuState = LocalMenuState.current
|
val menuState = LocalMenuState.current
|
||||||
|
|
||||||
|
|
||||||
|
@ -356,6 +356,8 @@ private fun LoadingOrError(
|
||||||
errorMessage: String? = null,
|
errorMessage: String? = null,
|
||||||
onRetry: (() -> Unit)? = null
|
onRetry: (() -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
|
val (colorPalette) = LocalAppearance.current
|
||||||
|
|
||||||
LoadingOrError(
|
LoadingOrError(
|
||||||
errorMessage = errorMessage,
|
errorMessage = errorMessage,
|
||||||
onRetry = onRetry
|
onRetry = onRetry
|
||||||
|
@ -369,7 +371,7 @@ private fun LoadingOrError(
|
||||||
) {
|
) {
|
||||||
Spacer(
|
Spacer(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(color = LocalColorPalette.current.darkGray, shape = ThumbnailRoundness.shape)
|
.background(color = colorPalette.darkGray, shape = ThumbnailRoundness.shape)
|
||||||
.size(Dimensions.thumbnails.album)
|
.size(Dimensions.thumbnails.album)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -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.LoadingOrError
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.TextCard
|
import it.vfsfitvnm.vimusic.ui.components.themed.TextCard
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.TextPlaceholder
|
import it.vfsfitvnm.vimusic.ui.components.themed.TextPlaceholder
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
import it.vfsfitvnm.vimusic.ui.styling.*
|
||||||
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.views.SongItem
|
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
||||||
import it.vfsfitvnm.vimusic.utils.*
|
import it.vfsfitvnm.vimusic.utils.*
|
||||||
import it.vfsfitvnm.youtubemusic.YouTube
|
import it.vfsfitvnm.youtubemusic.YouTube
|
||||||
|
@ -77,8 +74,7 @@ fun ArtistScreen(
|
||||||
host {
|
host {
|
||||||
val binder = LocalPlayerServiceBinder.current
|
val binder = LocalPlayerServiceBinder.current
|
||||||
|
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val typography = LocalTypography.current
|
|
||||||
|
|
||||||
val artistResult by remember(browseId) {
|
val artistResult by remember(browseId) {
|
||||||
Database.artist(browseId).map { artist ->
|
Database.artist(browseId).map { artist ->
|
||||||
|
@ -294,7 +290,7 @@ private fun LoadingOrError(
|
||||||
errorMessage: String? = null,
|
errorMessage: String? = null,
|
||||||
onRetry: (() -> Unit)? = null
|
onRetry: (() -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette) = LocalAppearance.current
|
||||||
|
|
||||||
LoadingOrError(
|
LoadingOrError(
|
||||||
errorMessage = errorMessage,
|
errorMessage = errorMessage,
|
||||||
|
|
|
@ -29,10 +29,7 @@ import it.vfsfitvnm.vimusic.models.DetailedSong
|
||||||
import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
|
import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
|
||||||
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.*
|
import it.vfsfitvnm.vimusic.ui.components.themed.*
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
import it.vfsfitvnm.vimusic.ui.styling.*
|
||||||
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.views.SongItem
|
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
||||||
import it.vfsfitvnm.vimusic.utils.*
|
import it.vfsfitvnm.vimusic.utils.*
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
@ -66,8 +63,7 @@ fun BuiltInPlaylistScreen(
|
||||||
val menuState = LocalMenuState.current
|
val menuState = LocalMenuState.current
|
||||||
|
|
||||||
val binder = LocalPlayerServiceBinder.current
|
val binder = LocalPlayerServiceBinder.current
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val typography = LocalTypography.current
|
|
||||||
|
|
||||||
val thumbnailSize = Dimensions.thumbnails.song.px
|
val thumbnailSize = Dimensions.thumbnails.song.px
|
||||||
|
|
||||||
|
|
|
@ -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.DropdownMenu
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.InHistoryMediaItemMenu
|
import it.vfsfitvnm.vimusic.ui.components.themed.InHistoryMediaItemMenu
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.TextFieldDialog
|
import it.vfsfitvnm.vimusic.ui.components.themed.TextFieldDialog
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
import it.vfsfitvnm.vimusic.ui.styling.*
|
||||||
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.views.PlaylistPreviewItem
|
import it.vfsfitvnm.vimusic.ui.views.PlaylistPreviewItem
|
||||||
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
||||||
import it.vfsfitvnm.vimusic.utils.*
|
import it.vfsfitvnm.vimusic.utils.*
|
||||||
|
@ -64,8 +61,7 @@ import kotlinx.coroutines.Dispatchers
|
||||||
@ExperimentalAnimationApi
|
@ExperimentalAnimationApi
|
||||||
@Composable
|
@Composable
|
||||||
fun HomeScreen() {
|
fun HomeScreen() {
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val typography = LocalTypography.current
|
|
||||||
|
|
||||||
val lazyListState = rememberLazyListState()
|
val lazyListState = rememberLazyListState()
|
||||||
|
|
||||||
|
@ -82,10 +78,11 @@ fun HomeScreen() {
|
||||||
Database.playlistPreviews()
|
Database.playlistPreviews()
|
||||||
}.collectAsState(initial = emptyList(), context = Dispatchers.IO)
|
}.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) {
|
val songCollection by remember(songSortBy, songSortOrder) {
|
||||||
Database.songs(preferences.songSortBy, preferences.songSortOrder)
|
Database.songs(songSortBy, songSortOrder)
|
||||||
}.collectAsState(initial = emptyList(), context = Dispatchers.IO)
|
}.collectAsState(initial = emptyList(), context = Dispatchers.IO)
|
||||||
|
|
||||||
RouteHandler(listenToGlobalEmitter = true) {
|
RouteHandler(listenToGlobalEmitter = true) {
|
||||||
|
@ -153,6 +150,9 @@ fun HomeScreen() {
|
||||||
|
|
||||||
val binder = LocalPlayerServiceBinder.current
|
val binder = LocalPlayerServiceBinder.current
|
||||||
|
|
||||||
|
val isFirstLaunch by rememberPreference(isFirstLaunchKey, true)
|
||||||
|
val isCachedPlaylistShown by rememberPreference(isCachedPlaylistShownKey, false)
|
||||||
|
|
||||||
val thumbnailSize = Dimensions.thumbnails.song.px
|
val thumbnailSize = Dimensions.thumbnails.song.px
|
||||||
|
|
||||||
var isGridExpanded by remember {
|
var isGridExpanded by remember {
|
||||||
|
@ -199,7 +199,7 @@ fun HomeScreen() {
|
||||||
}
|
}
|
||||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||||
.run {
|
.run {
|
||||||
if (preferences.isFirstLaunch) {
|
if (isFirstLaunch) {
|
||||||
drawBehind {
|
drawBehind {
|
||||||
drawCircle(
|
drawCircle(
|
||||||
color = colorPalette.red,
|
color = colorPalette.red,
|
||||||
|
@ -321,7 +321,7 @@ fun HomeScreen() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (preferences.isCachedPlaylistShown) {
|
if (isCachedPlaylistShown) {
|
||||||
item {
|
item {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
@ -492,16 +492,16 @@ fun HomeScreen() {
|
||||||
) {
|
) {
|
||||||
Item(
|
Item(
|
||||||
text = "PLAY TIME",
|
text = "PLAY TIME",
|
||||||
isSelected = preferences.songSortBy == SongSortBy.PlayTime,
|
isSelected = songSortBy == SongSortBy.PlayTime,
|
||||||
onClick = {
|
onClick = {
|
||||||
preferences.songSortBy = SongSortBy.PlayTime
|
songSortBy = SongSortBy.PlayTime
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
Item(
|
Item(
|
||||||
text = "DATE ADDED",
|
text = "DATE ADDED",
|
||||||
isSelected = preferences.songSortBy == SongSortBy.DateAdded,
|
isSelected = songSortBy == SongSortBy.DateAdded,
|
||||||
onClick = {
|
onClick = {
|
||||||
preferences.songSortBy = SongSortBy.DateAdded
|
songSortBy = SongSortBy.DateAdded
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -518,14 +518,14 @@ fun HomeScreen() {
|
||||||
.width(IntrinsicSize.Max),
|
.width(IntrinsicSize.Max),
|
||||||
) {
|
) {
|
||||||
Item(
|
Item(
|
||||||
text = when (preferences.songSortOrder) {
|
text = when (songSortOrder) {
|
||||||
SortOrder.Ascending -> "ASCENDING"
|
SortOrder.Ascending -> "ASCENDING"
|
||||||
SortOrder.Descending -> "DESCENDING"
|
SortOrder.Descending -> "DESCENDING"
|
||||||
},
|
},
|
||||||
textColor = colorPalette.text,
|
textColor = colorPalette.text,
|
||||||
backgroundColor = colorPalette.elevatedBackground,
|
backgroundColor = colorPalette.elevatedBackground,
|
||||||
onClick = {
|
onClick = {
|
||||||
preferences.songSortOrder = !preferences.songSortOrder
|
songSortOrder = !songSortOrder
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -556,7 +556,7 @@ fun HomeScreen() {
|
||||||
},
|
},
|
||||||
onThumbnailContent = {
|
onThumbnailContent = {
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
visible = preferences.songSortBy == SongSortBy.PlayTime,
|
visible = songSortBy == SongSortBy.PlayTime,
|
||||||
enter = fadeIn(),
|
enter = fadeIn(),
|
||||||
exit = fadeOut(),
|
exit = fadeOut(),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
|
@ -27,7 +27,7 @@ import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
|
||||||
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.*
|
import it.vfsfitvnm.vimusic.ui.components.themed.*
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
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.ui.styling.px
|
||||||
import it.vfsfitvnm.vimusic.utils.asMediaItem
|
import it.vfsfitvnm.vimusic.utils.asMediaItem
|
||||||
import it.vfsfitvnm.vimusic.utils.enqueue
|
import it.vfsfitvnm.vimusic.utils.enqueue
|
||||||
|
@ -61,7 +61,7 @@ fun IntentUriScreen(uri: Uri) {
|
||||||
|
|
||||||
host {
|
host {
|
||||||
val menuState = LocalMenuState.current
|
val menuState = LocalMenuState.current
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette) = LocalAppearance.current
|
||||||
val binder = LocalPlayerServiceBinder.current
|
val binder = LocalPlayerServiceBinder.current
|
||||||
|
|
||||||
val thumbnailSizePx = Dimensions.thumbnails.song.px
|
val thumbnailSizePx = Dimensions.thumbnails.song.px
|
||||||
|
|
|
@ -32,8 +32,7 @@ import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
|
||||||
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.*
|
import it.vfsfitvnm.vimusic.ui.components.themed.*
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
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.LocalTypography
|
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.px
|
import it.vfsfitvnm.vimusic.ui.styling.px
|
||||||
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
||||||
import it.vfsfitvnm.vimusic.utils.*
|
import it.vfsfitvnm.vimusic.utils.*
|
||||||
|
@ -73,8 +72,7 @@ fun LocalPlaylistScreen(
|
||||||
val menuState = LocalMenuState.current
|
val menuState = LocalMenuState.current
|
||||||
|
|
||||||
val binder = LocalPlayerServiceBinder.current
|
val binder = LocalPlayerServiceBinder.current
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val typography = LocalTypography.current
|
|
||||||
|
|
||||||
val thumbnailSize = Dimensions.thumbnails.song.px
|
val thumbnailSize = Dimensions.thumbnails.song.px
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,7 @@ import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
|
||||||
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.*
|
import it.vfsfitvnm.vimusic.ui.components.themed.*
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
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.LocalTypography
|
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.px
|
import it.vfsfitvnm.vimusic.ui.styling.px
|
||||||
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
||||||
import it.vfsfitvnm.vimusic.utils.*
|
import it.vfsfitvnm.vimusic.utils.*
|
||||||
|
@ -73,8 +72,7 @@ fun PlaylistScreen(
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val binder = LocalPlayerServiceBinder.current
|
val binder = LocalPlayerServiceBinder.current
|
||||||
|
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val typography = LocalTypography.current
|
|
||||||
val menuState = LocalMenuState.current
|
val menuState = LocalMenuState.current
|
||||||
|
|
||||||
val thumbnailSizePx = Dimensions.thumbnails.playlist.px
|
val thumbnailSizePx = Dimensions.thumbnails.playlist.px
|
||||||
|
@ -387,7 +385,7 @@ private fun LoadingOrError(
|
||||||
errorMessage: String? = null,
|
errorMessage: String? = null,
|
||||||
onRetry: (() -> Unit)? = null
|
onRetry: (() -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette) = LocalAppearance.current
|
||||||
|
|
||||||
LoadingOrError(
|
LoadingOrError(
|
||||||
errorMessage = errorMessage,
|
errorMessage = errorMessage,
|
||||||
|
|
|
@ -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.TextCard
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.TextPlaceholder
|
import it.vfsfitvnm.vimusic.ui.components.themed.TextPlaceholder
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
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.LocalTypography
|
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.px
|
import it.vfsfitvnm.vimusic.ui.styling.px
|
||||||
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
||||||
import it.vfsfitvnm.vimusic.utils.*
|
import it.vfsfitvnm.vimusic.utils.*
|
||||||
|
@ -53,29 +52,29 @@ fun SearchResultScreen(
|
||||||
query: String,
|
query: String,
|
||||||
onSearchAgain: () -> Unit,
|
onSearchAgain: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val typography = LocalTypography.current
|
|
||||||
val preferences = LocalPreferences.current
|
|
||||||
val binder = LocalPlayerServiceBinder.current
|
val binder = LocalPlayerServiceBinder.current
|
||||||
|
|
||||||
|
var searchFilter by rememberPreference(searchFilterKey, YouTube.Item.Song.Filter.value)
|
||||||
|
|
||||||
val lazyListState = rememberLazyListState()
|
val lazyListState = rememberLazyListState()
|
||||||
|
|
||||||
val items = remember(preferences.searchFilter) {
|
val items = remember(searchFilter) {
|
||||||
mutableStateListOf<YouTube.Item>()
|
mutableStateListOf<YouTube.Item>()
|
||||||
}
|
}
|
||||||
|
|
||||||
var continuationResult by remember(preferences.searchFilter) {
|
var continuationResult by remember(searchFilter) {
|
||||||
mutableStateOf<Result<String?>?>(null)
|
mutableStateOf<Result<String?>?>(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
val onLoad = relaunchableEffect(preferences.searchFilter) {
|
val onLoad = relaunchableEffect(searchFilter) {
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
val token = continuationResult?.getOrNull()
|
val token = continuationResult?.getOrNull()
|
||||||
|
|
||||||
continuationResult = null
|
continuationResult = null
|
||||||
|
|
||||||
continuationResult = withContext(Dispatchers.IO) {
|
continuationResult = withContext(Dispatchers.IO) {
|
||||||
YouTube.search(query, preferences.searchFilter, token)
|
YouTube.search(query, searchFilter, token)
|
||||||
}?.map { searchResult ->
|
}?.map { searchResult ->
|
||||||
items.addAll(searchResult.items)
|
items.addAll(searchResult.items)
|
||||||
searchResult.continuation
|
searchResult.continuation
|
||||||
|
@ -186,14 +185,14 @@ fun SearchResultScreen(
|
||||||
value = YouTube.Item.FeaturedPlaylist.Filter.value
|
value = YouTube.Item.FeaturedPlaylist.Filter.value
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
value = preferences.searchFilter,
|
value = searchFilter,
|
||||||
selectedBackgroundColor = colorPalette.primaryContainer,
|
selectedBackgroundColor = colorPalette.primaryContainer,
|
||||||
unselectedBackgroundColor = colorPalette.lightBackground,
|
unselectedBackgroundColor = colorPalette.lightBackground,
|
||||||
selectedTextStyle = typography.xs.medium.color(colorPalette.onPrimaryContainer),
|
selectedTextStyle = typography.xs.medium.color(colorPalette.onPrimaryContainer),
|
||||||
unselectedTextStyle = typography.xs.medium,
|
unselectedTextStyle = typography.xs.medium,
|
||||||
shape = RoundedCornerShape(36.dp),
|
shape = RoundedCornerShape(36.dp),
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
preferences.searchFilter = it
|
searchFilter = it
|
||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(vertical = 8.dp)
|
.padding(vertical = 8.dp)
|
||||||
|
@ -255,7 +254,7 @@ fun SearchResultScreen(
|
||||||
} ?: item(key = "loading") {
|
} ?: item(key = "loading") {
|
||||||
LoadingOrError(
|
LoadingOrError(
|
||||||
itemCount = if (items.isEmpty()) 8 else 3,
|
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,
|
thumbnailSizeDp: Dp,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette) = LocalAppearance.current
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
@ -293,7 +292,7 @@ fun SmallArtistItemShimmer(
|
||||||
thumbnailSizeDp: Dp,
|
thumbnailSizeDp: Dp,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette) = LocalAppearance.current
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
@ -422,7 +421,7 @@ fun SmallPlaylistItem(
|
||||||
thumbnailSizePx: Int,
|
thumbnailSizePx: Int,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val typography = LocalTypography.current
|
val (_, typography) = LocalAppearance.current
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
@ -474,7 +473,7 @@ fun SmallAlbumItem(
|
||||||
thumbnailSizePx: Int,
|
thumbnailSizePx: Int,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val typography = LocalTypography.current
|
val (_, typography) = LocalAppearance.current
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
@ -526,7 +525,7 @@ fun SmallArtistItem(
|
||||||
thumbnailSizePx: Int,
|
thumbnailSizePx: Int,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val typography = LocalTypography.current
|
val (_, typography) = LocalAppearance.current
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
|
|
@ -37,8 +37,7 @@ import it.vfsfitvnm.vimusic.query
|
||||||
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.LoadingOrError
|
import it.vfsfitvnm.vimusic.ui.components.themed.LoadingOrError
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
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.LocalTypography
|
|
||||||
import it.vfsfitvnm.vimusic.utils.medium
|
import it.vfsfitvnm.vimusic.utils.medium
|
||||||
import it.vfsfitvnm.vimusic.utils.secondary
|
import it.vfsfitvnm.vimusic.utils.secondary
|
||||||
import it.vfsfitvnm.youtubemusic.YouTube
|
import it.vfsfitvnm.youtubemusic.YouTube
|
||||||
|
@ -104,8 +103,7 @@ fun SearchScreen(
|
||||||
}
|
}
|
||||||
|
|
||||||
host {
|
host {
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val typography = LocalTypography.current
|
|
||||||
|
|
||||||
val isOpenableUrl = remember(textFieldValue.text) {
|
val isOpenableUrl = remember(textFieldValue.text) {
|
||||||
listOf(
|
listOf(
|
||||||
|
|
|
@ -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.Switch
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.ValueSelectorDialog
|
import it.vfsfitvnm.vimusic.ui.components.themed.ValueSelectorDialog
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.settings.*
|
import it.vfsfitvnm.vimusic.ui.screens.settings.*
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
|
|
||||||
import it.vfsfitvnm.vimusic.utils.*
|
import it.vfsfitvnm.vimusic.utils.*
|
||||||
|
|
||||||
|
|
||||||
|
@ -92,9 +91,9 @@ fun SettingsScreen() {
|
||||||
}
|
}
|
||||||
|
|
||||||
host {
|
host {
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val typography = LocalTypography.current
|
|
||||||
val preferences = LocalPreferences.current
|
var isFirstLaunch by rememberPreference(isFirstLaunchKey, true)
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
@ -242,9 +241,9 @@ fun SettingsScreen() {
|
||||||
title = "Other",
|
title = "Other",
|
||||||
description = "Advanced settings",
|
description = "Advanced settings",
|
||||||
route = otherSettingsRoute,
|
route = otherSettingsRoute,
|
||||||
withAlert = LocalPreferences.current.isFirstLaunch,
|
withAlert = isFirstLaunch,
|
||||||
onClick = {
|
onClick = {
|
||||||
preferences.isFirstLaunch = false
|
isFirstLaunch = false
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -324,8 +323,7 @@ fun SwitchSettingEntry(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
isEnabled: Boolean = true
|
isEnabled: Boolean = true
|
||||||
) {
|
) {
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val typography = LocalTypography.current
|
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
|
@ -370,8 +368,8 @@ fun SettingsEntry(
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
isEnabled: Boolean = true
|
isEnabled: Boolean = true
|
||||||
) {
|
) {
|
||||||
val typography = LocalTypography.current
|
val (_, typography) = LocalAppearance.current
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette) = LocalAppearance.current
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
|
@ -422,7 +420,7 @@ fun BaseSettingsEntry(
|
||||||
titleTextStyle: @Composable TextStyle.() -> TextStyle = { this },
|
titleTextStyle: @Composable TextStyle.() -> TextStyle = { this },
|
||||||
textStyle: @Composable TextStyle.() -> TextStyle = { this },
|
textStyle: @Composable TextStyle.() -> TextStyle = { this },
|
||||||
) {
|
) {
|
||||||
val typography = LocalTypography.current
|
val (_, typography) = LocalAppearance.current
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
|
@ -447,11 +445,11 @@ fun SettingsEntryGroupText(
|
||||||
title: String,
|
title: String,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val typography = LocalTypography.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
|
|
||||||
BasicText(
|
BasicText(
|
||||||
text = title.uppercase(),
|
text = title.uppercase(),
|
||||||
style = typography.xxs.semiBold.copy(LocalColorPalette.current.blue),
|
style = typography.xxs.semiBold.copy(colorPalette.blue),
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.padding(start = 24.dp, top = 24.dp)
|
.padding(start = 24.dp, top = 24.dp)
|
||||||
.padding(horizontal = 32.dp)
|
.padding(horizontal = 32.dp)
|
||||||
|
|
|
@ -16,12 +16,11 @@ import it.vfsfitvnm.route.RouteHandler
|
||||||
import it.vfsfitvnm.vimusic.BuildConfig
|
import it.vfsfitvnm.vimusic.BuildConfig
|
||||||
import it.vfsfitvnm.vimusic.R
|
import it.vfsfitvnm.vimusic.R
|
||||||
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
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.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.screens.rememberAlbumRoute
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
|
import it.vfsfitvnm.vimusic.ui.screens.rememberArtistRoute
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.utils.bold
|
import it.vfsfitvnm.vimusic.utils.bold
|
||||||
import it.vfsfitvnm.vimusic.utils.secondary
|
import it.vfsfitvnm.vimusic.utils.secondary
|
||||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
import it.vfsfitvnm.vimusic.utils.semiBold
|
||||||
|
@ -48,8 +47,7 @@ fun AboutScreen() {
|
||||||
}
|
}
|
||||||
|
|
||||||
host {
|
host {
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val typography = LocalTypography.current
|
|
||||||
val uriHandler = LocalUriHandler.current
|
val uriHandler = LocalUriHandler.current
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
|
|
|
@ -5,18 +5,20 @@ import androidx.compose.foundation.*
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.text.BasicText
|
import androidx.compose.foundation.text.BasicText
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import it.vfsfitvnm.route.RouteHandler
|
import it.vfsfitvnm.route.RouteHandler
|
||||||
import it.vfsfitvnm.vimusic.R
|
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.components.TopAppBar
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.*
|
import it.vfsfitvnm.vimusic.ui.screens.*
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
|
import it.vfsfitvnm.vimusic.utils.*
|
||||||
import it.vfsfitvnm.vimusic.utils.LocalPreferences
|
|
||||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
|
||||||
|
|
||||||
@ExperimentalAnimationApi
|
@ExperimentalAnimationApi
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -40,9 +42,11 @@ fun AppearanceSettingsScreen() {
|
||||||
}
|
}
|
||||||
|
|
||||||
host {
|
host {
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val typography = LocalTypography.current
|
|
||||||
val preferences = LocalPreferences.current
|
var colorPaletteMode by rememberPreference(colorPaletteModeKey, ColorPaletteMode.System)
|
||||||
|
var thumbnailRoundness by rememberPreference(thumbnailRoundnessKey, ThumbnailRoundness.Light)
|
||||||
|
var isCachedPlaylistShown by rememberPreference(isCachedPlaylistShownKey, false)
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
@ -81,9 +85,9 @@ fun AppearanceSettingsScreen() {
|
||||||
|
|
||||||
EnumValueSelectorSettingsEntry(
|
EnumValueSelectorSettingsEntry(
|
||||||
title = "Theme mode",
|
title = "Theme mode",
|
||||||
selectedValue = preferences.colorPaletteMode,
|
selectedValue = colorPaletteMode,
|
||||||
onValueSelected = {
|
onValueSelected = {
|
||||||
preferences.colorPaletteMode = it
|
colorPaletteMode = it
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -91,9 +95,9 @@ fun AppearanceSettingsScreen() {
|
||||||
|
|
||||||
EnumValueSelectorSettingsEntry(
|
EnumValueSelectorSettingsEntry(
|
||||||
title = "Thumbnail roundness",
|
title = "Thumbnail roundness",
|
||||||
selectedValue = preferences.thumbnailRoundness,
|
selectedValue = thumbnailRoundness,
|
||||||
onValueSelected = {
|
onValueSelected = {
|
||||||
preferences.thumbnailRoundness = it
|
thumbnailRoundness = it
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -102,9 +106,9 @@ fun AppearanceSettingsScreen() {
|
||||||
SwitchSettingEntry(
|
SwitchSettingEntry(
|
||||||
title = "Cached playlist",
|
title = "Cached playlist",
|
||||||
text = "Display a playlist whose songs can be played offline",
|
text = "Display a playlist whose songs can be played offline",
|
||||||
isChecked = preferences.isCachedPlaylistShown,
|
isChecked = isCachedPlaylistShown,
|
||||||
onCheckedChange = {
|
onCheckedChange = {
|
||||||
preferences.isCachedPlaylistShown = it
|
isCachedPlaylistShown = it
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,8 +31,7 @@ import it.vfsfitvnm.vimusic.ui.screens.AlbumScreen
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.ArtistScreen
|
import it.vfsfitvnm.vimusic.ui.screens.ArtistScreen
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.rememberAlbumRoute
|
import it.vfsfitvnm.vimusic.ui.screens.rememberAlbumRoute
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.rememberArtistRoute
|
import it.vfsfitvnm.vimusic.ui.screens.rememberArtistRoute
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
|
|
||||||
import it.vfsfitvnm.vimusic.utils.intent
|
import it.vfsfitvnm.vimusic.utils.intent
|
||||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
import it.vfsfitvnm.vimusic.utils.semiBold
|
||||||
import java.io.FileInputStream
|
import java.io.FileInputStream
|
||||||
|
@ -64,8 +63,7 @@ fun BackupAndRestoreScreen() {
|
||||||
}
|
}
|
||||||
|
|
||||||
host {
|
host {
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val typography = LocalTypography.current
|
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
val backupLauncher =
|
val backupLauncher =
|
||||||
|
|
|
@ -16,13 +16,15 @@ import coil.annotation.ExperimentalCoilApi
|
||||||
import it.vfsfitvnm.route.RouteHandler
|
import it.vfsfitvnm.route.RouteHandler
|
||||||
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
||||||
import it.vfsfitvnm.vimusic.R
|
import it.vfsfitvnm.vimusic.R
|
||||||
|
import it.vfsfitvnm.vimusic.enums.CoilDiskCacheMaxSize
|
||||||
import it.vfsfitvnm.vimusic.enums.ExoPlayerDiskCacheMaxSize
|
import it.vfsfitvnm.vimusic.enums.ExoPlayerDiskCacheMaxSize
|
||||||
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.TextCard
|
import it.vfsfitvnm.vimusic.ui.components.themed.TextCard
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.*
|
import it.vfsfitvnm.vimusic.ui.screens.*
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
|
import it.vfsfitvnm.vimusic.utils.coilDiskCacheMaxSizeKey
|
||||||
import it.vfsfitvnm.vimusic.utils.LocalPreferences
|
import it.vfsfitvnm.vimusic.utils.exoPlayerDiskCacheMaxSizeKey
|
||||||
|
import it.vfsfitvnm.vimusic.utils.rememberPreference
|
||||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
import it.vfsfitvnm.vimusic.utils.semiBold
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
@ -51,11 +53,12 @@ fun CacheSettingsScreen() {
|
||||||
|
|
||||||
host {
|
host {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val typography = LocalTypography.current
|
|
||||||
val preferences = LocalPreferences.current
|
|
||||||
val binder = LocalPlayerServiceBinder.current
|
val binder = LocalPlayerServiceBinder.current
|
||||||
|
|
||||||
|
var coilDiskCacheMaxSize by rememberPreference(coilDiskCacheMaxSizeKey, CoilDiskCacheMaxSize.`128MB`)
|
||||||
|
var exoPlayerDiskCacheMaxSize by rememberPreference(exoPlayerDiskCacheMaxSizeKey, ExoPlayerDiskCacheMaxSize.`2GB`)
|
||||||
|
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
|
@ -100,9 +103,9 @@ fun CacheSettingsScreen() {
|
||||||
|
|
||||||
EnumValueSelectorSettingsEntry(
|
EnumValueSelectorSettingsEntry(
|
||||||
title = "Max size",
|
title = "Max size",
|
||||||
selectedValue = preferences.coilDiskCacheMaxSize,
|
selectedValue = coilDiskCacheMaxSize,
|
||||||
onValueSelected = {
|
onValueSelected = {
|
||||||
preferences.coilDiskCacheMaxSize = it
|
coilDiskCacheMaxSize = it
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -114,9 +117,7 @@ fun CacheSettingsScreen() {
|
||||||
diskCacheSize
|
diskCacheSize
|
||||||
)
|
)
|
||||||
} (${
|
} (${
|
||||||
diskCacheSize * 100 / preferences.coilDiskCacheMaxSize.bytes.coerceAtLeast(
|
diskCacheSize * 100 / coilDiskCacheMaxSize.bytes.coerceAtLeast(1)
|
||||||
1
|
|
||||||
)
|
|
||||||
}%)",
|
}%)",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -143,9 +144,9 @@ fun CacheSettingsScreen() {
|
||||||
|
|
||||||
EnumValueSelectorSettingsEntry(
|
EnumValueSelectorSettingsEntry(
|
||||||
title = "Max size",
|
title = "Max size",
|
||||||
selectedValue = preferences.exoPlayerDiskCacheMaxSize,
|
selectedValue = exoPlayerDiskCacheMaxSize,
|
||||||
onValueSelected = {
|
onValueSelected = {
|
||||||
preferences.exoPlayerDiskCacheMaxSize = it
|
exoPlayerDiskCacheMaxSize = it
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -154,7 +155,7 @@ fun CacheSettingsScreen() {
|
||||||
text = buildString {
|
text = buildString {
|
||||||
append(Formatter.formatShortFileSize(context, diskCacheSize))
|
append(Formatter.formatShortFileSize(context, diskCacheSize))
|
||||||
|
|
||||||
when (val size = preferences.exoPlayerDiskCacheMaxSize) {
|
when (val size = exoPlayerDiskCacheMaxSize) {
|
||||||
ExoPlayerDiskCacheMaxSize.Unlimited -> {}
|
ExoPlayerDiskCacheMaxSize.Unlimited -> {}
|
||||||
else -> append("(${diskCacheSize * 100 / size.bytes}%)")
|
else -> append("(${diskCacheSize * 100 / size.bytes}%)")
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,10 +23,10 @@ import it.vfsfitvnm.vimusic.R
|
||||||
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.TextCard
|
import it.vfsfitvnm.vimusic.ui.components.themed.TextCard
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.*
|
import it.vfsfitvnm.vimusic.ui.screens.*
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
|
|
||||||
import it.vfsfitvnm.vimusic.utils.LocalPreferences
|
|
||||||
import it.vfsfitvnm.vimusic.utils.isIgnoringBatteryOptimizations
|
import it.vfsfitvnm.vimusic.utils.isIgnoringBatteryOptimizations
|
||||||
|
import it.vfsfitvnm.vimusic.utils.isInvincibilityEnabledKey
|
||||||
|
import it.vfsfitvnm.vimusic.utils.rememberPreference
|
||||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
import it.vfsfitvnm.vimusic.utils.semiBold
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,9 +53,9 @@ fun OtherSettingsScreen() {
|
||||||
|
|
||||||
host {
|
host {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val typography = LocalTypography.current
|
|
||||||
val preferences = LocalPreferences.current
|
var isInvincibilityEnabled by rememberPreference(isInvincibilityEnabledKey, false)
|
||||||
|
|
||||||
var isIgnoringBatteryOptimizations by remember {
|
var isIgnoringBatteryOptimizations by remember {
|
||||||
mutableStateOf(context.isIgnoringBatteryOptimizations)
|
mutableStateOf(context.isIgnoringBatteryOptimizations)
|
||||||
|
@ -140,9 +140,9 @@ fun OtherSettingsScreen() {
|
||||||
SwitchSettingEntry(
|
SwitchSettingEntry(
|
||||||
title = "Invincible service",
|
title = "Invincible service",
|
||||||
text = "When turning off battery optimizations is not enough",
|
text = "When turning off battery optimizations is not enough",
|
||||||
isChecked = preferences.isInvincibilityEnabled,
|
isChecked = isInvincibilityEnabled,
|
||||||
onCheckedChange = {
|
onCheckedChange = {
|
||||||
preferences.isInvincibilityEnabled = it
|
isInvincibilityEnabled = it
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@ import androidx.compose.foundation.*
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.text.BasicText
|
import androidx.compose.foundation.text.BasicText
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
@ -20,10 +22,8 @@ import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
||||||
import it.vfsfitvnm.vimusic.R
|
import it.vfsfitvnm.vimusic.R
|
||||||
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.*
|
import it.vfsfitvnm.vimusic.ui.screens.*
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
|
import it.vfsfitvnm.vimusic.utils.*
|
||||||
import it.vfsfitvnm.vimusic.utils.LocalPreferences
|
|
||||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
|
||||||
|
|
||||||
|
|
||||||
@ExperimentalAnimationApi
|
@ExperimentalAnimationApi
|
||||||
|
@ -49,11 +49,13 @@ fun PlayerSettingsScreen() {
|
||||||
|
|
||||||
host {
|
host {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val typography = LocalTypography.current
|
|
||||||
val preferences = LocalPreferences.current
|
|
||||||
val binder = LocalPlayerServiceBinder.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 =
|
val activityResultLauncher =
|
||||||
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||||
}
|
}
|
||||||
|
@ -96,9 +98,9 @@ fun PlayerSettingsScreen() {
|
||||||
SwitchSettingEntry(
|
SwitchSettingEntry(
|
||||||
title = "Persistent queue",
|
title = "Persistent queue",
|
||||||
text = "Save and restore playing songs",
|
text = "Save and restore playing songs",
|
||||||
isChecked = preferences.persistentQueue,
|
isChecked = persistentQueue,
|
||||||
onCheckedChange = {
|
onCheckedChange = {
|
||||||
preferences.persistentQueue = it
|
persistentQueue = it
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -107,19 +109,18 @@ fun PlayerSettingsScreen() {
|
||||||
SwitchSettingEntry(
|
SwitchSettingEntry(
|
||||||
title = "Skip silence",
|
title = "Skip silence",
|
||||||
text = "Skip silent parts during playback",
|
text = "Skip silent parts during playback",
|
||||||
isChecked = preferences.skipSilence,
|
isChecked = skipSilence,
|
||||||
onCheckedChange = {
|
onCheckedChange = {
|
||||||
binder?.player?.skipSilenceEnabled = it
|
skipSilence = it
|
||||||
preferences.skipSilence = it
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
SwitchSettingEntry(
|
SwitchSettingEntry(
|
||||||
title = "Loudness normalization",
|
title = "Loudness normalization",
|
||||||
text = "Lower the volume to a standard level",
|
text = "Lower the volume to a standard level",
|
||||||
isChecked = preferences.volumeNormalization,
|
isChecked = volumeNormalization,
|
||||||
onCheckedChange = {
|
onCheckedChange = {
|
||||||
preferences.volumeNormalization = it
|
volumeNormalization = it
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -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() }
|
|
@ -82,5 +82,3 @@ val LightColorPalette = ColorPalette(
|
||||||
// iconOnPrimaryContainer = Color(0xff2e30b8),
|
// iconOnPrimaryContainer = Color(0xff2e30b8),
|
||||||
isDark = false
|
isDark = false
|
||||||
)
|
)
|
||||||
|
|
||||||
val LocalColorPalette = staticCompositionLocalOf { LightColorPalette }
|
|
||||||
|
|
|
@ -23,53 +23,3 @@ data class Typography(
|
||||||
val m: TextStyle,
|
val m: TextStyle,
|
||||||
val l: 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),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -36,10 +36,7 @@ import it.vfsfitvnm.vimusic.ui.components.BottomSheetState
|
||||||
import it.vfsfitvnm.vimusic.ui.components.MusicBars
|
import it.vfsfitvnm.vimusic.ui.components.MusicBars
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.QueuedMediaItemMenu
|
import it.vfsfitvnm.vimusic.ui.components.themed.QueuedMediaItemMenu
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.SmallSongItemShimmer
|
import it.vfsfitvnm.vimusic.ui.screens.SmallSongItemShimmer
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
import it.vfsfitvnm.vimusic.ui.styling.*
|
||||||
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.utils.PlayerState
|
import it.vfsfitvnm.vimusic.utils.PlayerState
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,7 +50,7 @@ fun CurrentPlaylistView(
|
||||||
) {
|
) {
|
||||||
val binder = LocalPlayerServiceBinder.current
|
val binder = LocalPlayerServiceBinder.current
|
||||||
val hapticFeedback = LocalHapticFeedback.current
|
val hapticFeedback = LocalHapticFeedback.current
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette) = LocalAppearance.current
|
||||||
|
|
||||||
val thumbnailSize = Dimensions.thumbnails.song.px
|
val thumbnailSize = Dimensions.thumbnails.song.px
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ import it.vfsfitvnm.vimusic.R
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.TextCard
|
import it.vfsfitvnm.vimusic.ui.components.themed.TextCard
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.TextFieldDialog
|
import it.vfsfitvnm.vimusic.ui.components.themed.TextFieldDialog
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.TextPlaceholder
|
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.center
|
||||||
import it.vfsfitvnm.vimusic.utils.secondary
|
import it.vfsfitvnm.vimusic.utils.secondary
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ fun LyricsView(
|
||||||
onLyricsUpdate: (String) -> Unit,
|
onLyricsUpdate: (String) -> Unit,
|
||||||
nestedScrollConnectionProvider: () -> NestedScrollConnection,
|
nestedScrollConnectionProvider: () -> NestedScrollConnection,
|
||||||
) {
|
) {
|
||||||
val typography = LocalTypography.current
|
val (_, typography) = LocalAppearance.current
|
||||||
|
|
||||||
var isEditingLyrics by remember {
|
var isEditingLyrics by remember {
|
||||||
mutableStateOf(false)
|
mutableStateOf(false)
|
||||||
|
|
|
@ -28,8 +28,7 @@ import it.vfsfitvnm.vimusic.ui.components.BottomSheet
|
||||||
import it.vfsfitvnm.vimusic.ui.components.BottomSheetState
|
import it.vfsfitvnm.vimusic.ui.components.BottomSheetState
|
||||||
import it.vfsfitvnm.vimusic.ui.components.HorizontalTabPager
|
import it.vfsfitvnm.vimusic.ui.components.HorizontalTabPager
|
||||||
import it.vfsfitvnm.vimusic.ui.components.rememberTabPagerState
|
import it.vfsfitvnm.vimusic.ui.components.rememberTabPagerState
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
|
|
||||||
import it.vfsfitvnm.vimusic.utils.PlayerState
|
import it.vfsfitvnm.vimusic.utils.PlayerState
|
||||||
import it.vfsfitvnm.vimusic.utils.center
|
import it.vfsfitvnm.vimusic.utils.center
|
||||||
import it.vfsfitvnm.vimusic.utils.color
|
import it.vfsfitvnm.vimusic.utils.color
|
||||||
|
@ -50,8 +49,7 @@ fun PlayerBottomSheet(
|
||||||
onGlobalRouteEmitted: () -> Unit,
|
onGlobalRouteEmitted: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val typography = LocalTypography.current
|
|
||||||
|
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
|
|
@ -63,8 +63,7 @@ fun PlayerView(
|
||||||
) {
|
) {
|
||||||
val menuState = LocalMenuState.current
|
val menuState = LocalMenuState.current
|
||||||
|
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val typography = LocalTypography.current
|
|
||||||
val binder = LocalPlayerServiceBinder.current
|
val binder = LocalPlayerServiceBinder.current
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val configuration = LocalConfiguration.current
|
val configuration = LocalConfiguration.current
|
||||||
|
@ -318,7 +317,7 @@ private fun Thumbnail(
|
||||||
song: Song?,
|
song: Song?,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val typography = LocalTypography.current
|
val (_, typography) = LocalAppearance.current
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val binder = LocalPlayerServiceBinder.current
|
val binder = LocalPlayerServiceBinder.current
|
||||||
val player = binder?.player ?: return
|
val player = binder?.player ?: return
|
||||||
|
@ -527,9 +526,7 @@ private fun Controls(
|
||||||
song: Song?,
|
song: Song?,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val typography = LocalTypography.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val colorPalette = LocalColorPalette.current
|
|
||||||
val preferences = LocalPreferences.current
|
|
||||||
|
|
||||||
val binder = LocalPlayerServiceBinder.current
|
val binder = LocalPlayerServiceBinder.current
|
||||||
val player = binder?.player ?: return
|
val player = binder?.player ?: return
|
||||||
|
@ -730,9 +727,8 @@ private fun Controls(
|
||||||
player.repeatMode
|
player.repeatMode
|
||||||
.plus(2)
|
.plus(2)
|
||||||
.mod(3)
|
.mod(3)
|
||||||
.let { repeatMode ->
|
.let {
|
||||||
player.repeatMode = repeatMode
|
player.repeatMode = it
|
||||||
preferences.repeatMode = repeatMode
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
|
|
|
@ -23,8 +23,7 @@ import coil.compose.AsyncImage
|
||||||
import it.vfsfitvnm.vimusic.Database
|
import it.vfsfitvnm.vimusic.Database
|
||||||
import it.vfsfitvnm.vimusic.models.PlaylistPreview
|
import it.vfsfitvnm.vimusic.models.PlaylistPreview
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
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.LocalTypography
|
|
||||||
import it.vfsfitvnm.vimusic.utils.color
|
import it.vfsfitvnm.vimusic.utils.color
|
||||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
import it.vfsfitvnm.vimusic.utils.semiBold
|
||||||
import it.vfsfitvnm.vimusic.utils.thumbnail
|
import it.vfsfitvnm.vimusic.utils.thumbnail
|
||||||
|
@ -38,8 +37,7 @@ fun PlaylistPreviewItem(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
thumbnailSize: Dp = Dimensions.thumbnails.song,
|
thumbnailSize: Dp = Dimensions.thumbnails.song,
|
||||||
) {
|
) {
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val typography = LocalTypography.current
|
|
||||||
val density = LocalDensity.current
|
val density = LocalDensity.current
|
||||||
|
|
||||||
val thumbnailSizePx = density.run {
|
val thumbnailSizePx = density.run {
|
||||||
|
|
|
@ -26,8 +26,7 @@ import it.vfsfitvnm.vimusic.enums.ThumbnailRoundness
|
||||||
import it.vfsfitvnm.vimusic.models.DetailedSong
|
import it.vfsfitvnm.vimusic.models.DetailedSong
|
||||||
import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
|
import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
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.LocalTypography
|
|
||||||
import it.vfsfitvnm.vimusic.utils.secondary
|
import it.vfsfitvnm.vimusic.utils.secondary
|
||||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
import it.vfsfitvnm.vimusic.utils.semiBold
|
||||||
import it.vfsfitvnm.vimusic.utils.thumbnail
|
import it.vfsfitvnm.vimusic.utils.thumbnail
|
||||||
|
@ -150,8 +149,7 @@ fun SongItem(
|
||||||
trailingContent: (@Composable () -> Unit)? = null
|
trailingContent: (@Composable () -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
val menuState = LocalMenuState.current
|
val menuState = LocalMenuState.current
|
||||||
val colorPalette = LocalColorPalette.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val typography = LocalTypography.current
|
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
|
|
@ -5,145 +5,24 @@ import android.content.SharedPreferences
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import androidx.media3.common.Player
|
|
||||||
import it.vfsfitvnm.vimusic.enums.*
|
|
||||||
import it.vfsfitvnm.youtubemusic.YouTube
|
|
||||||
|
|
||||||
|
|
||||||
@Stable
|
const val colorPaletteModeKey = "colorPaletteMode"
|
||||||
class Preferences(
|
const val thumbnailRoundnessKey = "thumbnailRoundness"
|
||||||
private val edit: (action: SharedPreferences.Editor.() -> Unit) -> Unit,
|
const val isCachedPlaylistShownKey = "isCachedPlaylistShown"
|
||||||
initialIsFirstLaunch: Boolean,
|
const val coilDiskCacheMaxSizeKey = "coilDiskCacheMaxSize"
|
||||||
initialSongSortBy: SongSortBy,
|
const val exoPlayerDiskCacheMaxSizeKey = "exoPlayerDiskCacheMaxSize"
|
||||||
initialSongSortOrder: SortOrder,
|
const val isInvincibilityEnabledKey = "isInvincibilityEnabled"
|
||||||
initialColorPaletteMode: ColorPaletteMode,
|
const val isFirstLaunchKey = "isFirstLaunch"
|
||||||
initialSearchFilter: String,
|
const val songSortOrderKey = "songSortOrder"
|
||||||
initialRepeatMode: Int,
|
const val songSortByKey = "songSortBy"
|
||||||
initialThumbnailRoundness: ThumbnailRoundness,
|
const val searchFilterKey = "searchFilter"
|
||||||
initialCoilDiskCacheMaxSize: CoilDiskCacheMaxSize,
|
const val repeatModeKey = "repeatMode"
|
||||||
initialExoPlayerDiskCacheMaxSize: ExoPlayerDiskCacheMaxSize,
|
const val skipSilenceKey = "skipSilence"
|
||||||
initialSkipSilence: Boolean,
|
const val volumeNormalizationKey = "volumeNormalization"
|
||||||
initialVolumeNormalization: Boolean,
|
const val persistentQueueKey = "persistentQueue"
|
||||||
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),
|
|
||||||
)
|
|
||||||
|
|
||||||
var isFirstLaunch = initialIsFirstLaunch
|
inline fun <reified T : Enum<T>> SharedPreferences.getEnum(
|
||||||
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(
|
|
||||||
key: String,
|
key: String,
|
||||||
defaultValue: T
|
defaultValue: T
|
||||||
): T =
|
): T =
|
||||||
|
@ -155,6 +34,51 @@ private inline fun <reified T : Enum<T>> SharedPreferences.getEnum(
|
||||||
}
|
}
|
||||||
} ?: defaultValue
|
} ?: 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)
|
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
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
|
@ -7,7 +7,7 @@ import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.font.FontStyle
|
import androidx.compose.ui.text.font.FontStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
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)
|
fun TextStyle.style(style: FontStyle) = copy(fontStyle = style)
|
||||||
|
|
||||||
|
@ -35,9 +35,9 @@ inline val TextStyle.center: TextStyle
|
||||||
inline val TextStyle.secondary: TextStyle
|
inline val TextStyle.secondary: TextStyle
|
||||||
@Composable
|
@Composable
|
||||||
@ReadOnlyComposable
|
@ReadOnlyComposable
|
||||||
get() = color(LocalColorPalette.current.textSecondary)
|
get() = color(LocalAppearance.current.colorPalette.textSecondary)
|
||||||
|
|
||||||
inline val TextStyle.disabled: TextStyle
|
inline val TextStyle.disabled: TextStyle
|
||||||
@Composable
|
@Composable
|
||||||
@ReadOnlyComposable
|
@ReadOnlyComposable
|
||||||
get() = color(LocalColorPalette.current.textDisabled)
|
get() = color(LocalAppearance.current.colorPalette.textDisabled)
|
||||||
|
|
Loading…
Reference in a new issue