Add dynamic theme (#159)
This commit is contained in:
parent
a26eebd806
commit
2716319339
|
@ -86,6 +86,7 @@ dependencies {
|
||||||
implementation(libs.compose.coil)
|
implementation(libs.compose.coil)
|
||||||
|
|
||||||
implementation(libs.accompanist.systemuicontroller)
|
implementation(libs.accompanist.systemuicontroller)
|
||||||
|
implementation(libs.palette)
|
||||||
|
|
||||||
implementation(libs.exoplayer)
|
implementation(libs.exoplayer)
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.ServiceConnection
|
import android.content.ServiceConnection
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
|
import android.graphics.Bitmap
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
|
@ -34,6 +35,7 @@ import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.neverEqualPolicy
|
import androidx.compose.runtime.neverEqualPolicy
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.runtime.staticCompositionLocalOf
|
import androidx.compose.runtime.staticCompositionLocalOf
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
|
@ -47,6 +49,7 @@ 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.ColorPaletteMode
|
||||||
|
import it.vfsfitvnm.vimusic.enums.ColorPaletteName
|
||||||
import it.vfsfitvnm.vimusic.enums.ThumbnailRoundness
|
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
|
||||||
|
@ -58,14 +61,21 @@ import it.vfsfitvnm.vimusic.ui.screens.IntentUriScreen
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.Appearance
|
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.LocalAppearance
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
|
import it.vfsfitvnm.vimusic.ui.styling.colorPaletteOf
|
||||||
|
import it.vfsfitvnm.vimusic.ui.styling.dynamicColorPaletteOf
|
||||||
|
import it.vfsfitvnm.vimusic.ui.styling.typographyOf
|
||||||
import it.vfsfitvnm.vimusic.ui.views.PlayerView
|
import it.vfsfitvnm.vimusic.ui.views.PlayerView
|
||||||
import it.vfsfitvnm.vimusic.utils.colorPaletteModeKey
|
import it.vfsfitvnm.vimusic.utils.colorPaletteModeKey
|
||||||
|
import it.vfsfitvnm.vimusic.utils.colorPaletteNameKey
|
||||||
import it.vfsfitvnm.vimusic.utils.getEnum
|
import it.vfsfitvnm.vimusic.utils.getEnum
|
||||||
import it.vfsfitvnm.vimusic.utils.intent
|
import it.vfsfitvnm.vimusic.utils.intent
|
||||||
import it.vfsfitvnm.vimusic.utils.listener
|
import it.vfsfitvnm.vimusic.utils.listener
|
||||||
import it.vfsfitvnm.vimusic.utils.preferences
|
import it.vfsfitvnm.vimusic.utils.preferences
|
||||||
import it.vfsfitvnm.vimusic.utils.rememberHapticFeedback
|
import it.vfsfitvnm.vimusic.utils.rememberHapticFeedback
|
||||||
import it.vfsfitvnm.vimusic.utils.thumbnailRoundnessKey
|
import it.vfsfitvnm.vimusic.utils.thumbnailRoundnessKey
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
private val serviceConnection = object : ServiceConnection {
|
private val serviceConnection = object : ServiceConnection {
|
||||||
|
@ -103,36 +113,84 @@ class MainActivity : ComponentActivity() {
|
||||||
uri = intent?.data
|
uri = intent?.data
|
||||||
|
|
||||||
setContent {
|
setContent {
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
val isSystemInDarkTheme = isSystemInDarkTheme()
|
val isSystemInDarkTheme = isSystemInDarkTheme()
|
||||||
|
|
||||||
var appearance by remember(isSystemInDarkTheme) {
|
var appearance by remember(isSystemInDarkTheme) {
|
||||||
with(preferences) {
|
with(preferences) {
|
||||||
|
val colorPaletteName = getEnum(colorPaletteNameKey, ColorPaletteName.Dynamic)
|
||||||
val colorPaletteMode = getEnum(colorPaletteModeKey, ColorPaletteMode.System)
|
val colorPaletteMode = getEnum(colorPaletteModeKey, ColorPaletteMode.System)
|
||||||
val thumbnailRoundness =
|
val thumbnailRoundness =
|
||||||
getEnum(thumbnailRoundnessKey, ThumbnailRoundness.Light)
|
getEnum(thumbnailRoundnessKey, ThumbnailRoundness.Light)
|
||||||
|
|
||||||
|
val colorPalette =
|
||||||
|
colorPaletteOf(colorPaletteName, colorPaletteMode, isSystemInDarkTheme)
|
||||||
|
|
||||||
mutableStateOf(
|
mutableStateOf(
|
||||||
Appearance(
|
Appearance(
|
||||||
colorPalette = colorPaletteMode.palette(isSystemInDarkTheme),
|
colorPalette = colorPalette,
|
||||||
typography = colorPaletteMode.typography(isSystemInDarkTheme),
|
typography = typographyOf(colorPalette.text),
|
||||||
thumbnailShape = thumbnailRoundness.shape()
|
thumbnailShape = thumbnailRoundness.shape()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DisposableEffect(isSystemInDarkTheme) {
|
DisposableEffect(binder, isSystemInDarkTheme) {
|
||||||
|
var bitmapListenerJob: Job? = null
|
||||||
|
|
||||||
|
fun setDynamicPalette(colorPaletteMode: ColorPaletteMode) {
|
||||||
|
val isDark =
|
||||||
|
colorPaletteMode == ColorPaletteMode.Dark || (colorPaletteMode == ColorPaletteMode.System && isSystemInDarkTheme)
|
||||||
|
|
||||||
|
binder?.setBitmapListener { bitmap: Bitmap? ->
|
||||||
|
if (bitmap == null) {
|
||||||
|
val colorPalette =
|
||||||
|
colorPaletteOf(ColorPaletteName.Dynamic, colorPaletteMode, isSystemInDarkTheme)
|
||||||
|
|
||||||
|
appearance = appearance.copy(
|
||||||
|
colorPalette = colorPalette,
|
||||||
|
typography = typographyOf(colorPalette.text)
|
||||||
|
)
|
||||||
|
|
||||||
|
return@setBitmapListener
|
||||||
|
}
|
||||||
|
|
||||||
|
bitmapListenerJob = coroutineScope.launch(Dispatchers.IO) {
|
||||||
|
dynamicColorPaletteOf(bitmap, isDark)?.let {
|
||||||
|
appearance = appearance.copy(colorPalette = it, typography = typographyOf(it.text))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val listener =
|
val listener =
|
||||||
SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, key ->
|
SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, key ->
|
||||||
when (key) {
|
when (key) {
|
||||||
colorPaletteModeKey -> {
|
colorPaletteNameKey, colorPaletteModeKey -> {
|
||||||
val colorPaletteMode =
|
val colorPaletteName =
|
||||||
sharedPreferences.getEnum(key, ColorPaletteMode.System)
|
sharedPreferences.getEnum(colorPaletteNameKey, ColorPaletteName.Dynamic)
|
||||||
|
|
||||||
appearance = appearance.copy(
|
val colorPaletteMode =
|
||||||
colorPalette = colorPaletteMode.palette(isSystemInDarkTheme),
|
sharedPreferences.getEnum(colorPaletteModeKey, ColorPaletteMode.System)
|
||||||
typography = colorPaletteMode.typography(isSystemInDarkTheme),
|
|
||||||
)
|
if (colorPaletteName == ColorPaletteName.Dynamic) {
|
||||||
|
setDynamicPalette(colorPaletteMode)
|
||||||
|
} else {
|
||||||
|
bitmapListenerJob?.cancel()
|
||||||
|
binder?.setBitmapListener(null)
|
||||||
|
|
||||||
|
val colorPalette = colorPaletteOf(
|
||||||
|
colorPaletteName,
|
||||||
|
colorPaletteMode,
|
||||||
|
isSystemInDarkTheme
|
||||||
|
)
|
||||||
|
|
||||||
|
appearance = appearance.copy(
|
||||||
|
colorPalette = colorPalette,
|
||||||
|
typography = typographyOf(colorPalette.text),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
thumbnailRoundnessKey -> {
|
thumbnailRoundnessKey -> {
|
||||||
val thumbnailRoundness =
|
val thumbnailRoundness =
|
||||||
|
@ -148,7 +206,14 @@ class MainActivity : ComponentActivity() {
|
||||||
with(preferences) {
|
with(preferences) {
|
||||||
registerOnSharedPreferenceChangeListener(listener)
|
registerOnSharedPreferenceChangeListener(listener)
|
||||||
|
|
||||||
|
val colorPaletteName = getEnum(colorPaletteNameKey, ColorPaletteName.Dynamic)
|
||||||
|
if (colorPaletteName == ColorPaletteName.Dynamic) {
|
||||||
|
setDynamicPalette(getEnum(colorPaletteModeKey, ColorPaletteMode.System))
|
||||||
|
}
|
||||||
|
|
||||||
onDispose {
|
onDispose {
|
||||||
|
bitmapListenerJob?.cancel()
|
||||||
|
binder?.setBitmapListener(null)
|
||||||
unregisterOnSharedPreferenceChangeListener(listener)
|
unregisterOnSharedPreferenceChangeListener(listener)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,7 +258,7 @@ class MainActivity : ComponentActivity() {
|
||||||
|
|
||||||
SideEffect {
|
SideEffect {
|
||||||
systemUiController.setSystemBarsColor(
|
systemUiController.setSystemBarsColor(
|
||||||
appearance.colorPalette.background,
|
appearance.colorPalette.background1,
|
||||||
!appearance.colorPalette.isDark
|
!appearance.colorPalette.isDark
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -211,7 +276,7 @@ class MainActivity : ComponentActivity() {
|
||||||
BoxWithConstraints(
|
BoxWithConstraints(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.background(appearance.colorPalette.background)
|
.background(appearance.colorPalette.background0)
|
||||||
) {
|
) {
|
||||||
when (val uri = uri) {
|
when (val uri = uri) {
|
||||||
null -> {
|
null -> {
|
||||||
|
|
|
@ -1,81 +1,7 @@
|
||||||
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.ColorPalette
|
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.DarkColorPalette
|
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LightColorPalette
|
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.Typography
|
|
||||||
|
|
||||||
enum class ColorPaletteMode {
|
enum class ColorPaletteMode {
|
||||||
Light,
|
Light,
|
||||||
Dark,
|
Dark,
|
||||||
Black,
|
System
|
||||||
System;
|
|
||||||
|
|
||||||
fun palette(isSystemInDarkMode: Boolean): ColorPalette {
|
|
||||||
return when (this) {
|
|
||||||
Light -> LightColorPalette
|
|
||||||
Dark -> DarkColorPalette
|
|
||||||
Black -> BlackColorPalette
|
|
||||||
System -> when (isSystemInDarkMode) {
|
|
||||||
true -> DarkColorPalette
|
|
||||||
false -> LightColorPalette
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@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),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package it.vfsfitvnm.vimusic.enums
|
||||||
|
|
||||||
|
enum class ColorPaletteName {
|
||||||
|
Default,
|
||||||
|
Dynamic,
|
||||||
|
PureBlack
|
||||||
|
}
|
|
@ -17,7 +17,7 @@ class BitmapProvider(
|
||||||
private val colorProvider: (isSystemInDarkMode: Boolean) -> Int
|
private val colorProvider: (isSystemInDarkMode: Boolean) -> Int
|
||||||
) {
|
) {
|
||||||
private var lastUri: Uri? = null
|
private var lastUri: Uri? = null
|
||||||
private var lastBitmap: Bitmap? = null
|
var lastBitmap: Bitmap? = null
|
||||||
private var lastIsSystemInDarkMode = false
|
private var lastIsSystemInDarkMode = false
|
||||||
|
|
||||||
private var lastEnqueued: Disposable? = null
|
private var lastEnqueued: Disposable? = null
|
||||||
|
@ -27,6 +27,12 @@ class BitmapProvider(
|
||||||
val bitmap: Bitmap
|
val bitmap: Bitmap
|
||||||
get() = lastBitmap ?: defaultBitmap
|
get() = lastBitmap ?: defaultBitmap
|
||||||
|
|
||||||
|
var listener: ((Bitmap?) -> Unit)? = null
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
value?.invoke(lastBitmap)
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
setDefaultBitmap()
|
setDefaultBitmap()
|
||||||
}
|
}
|
||||||
|
@ -56,14 +62,18 @@ class BitmapProvider(
|
||||||
lastEnqueued = applicationContext.imageLoader.enqueue(
|
lastEnqueued = applicationContext.imageLoader.enqueue(
|
||||||
ImageRequest.Builder(applicationContext)
|
ImageRequest.Builder(applicationContext)
|
||||||
.data(uri.thumbnail(bitmapSize))
|
.data(uri.thumbnail(bitmapSize))
|
||||||
|
.allowHardware(false)
|
||||||
.listener(
|
.listener(
|
||||||
onError = { _, _ ->
|
onError = { _, _ ->
|
||||||
lastBitmap = null
|
lastBitmap = null
|
||||||
onDone(bitmap)
|
onDone(bitmap)
|
||||||
|
listener?.invoke(lastBitmap)
|
||||||
},
|
},
|
||||||
onSuccess = { _, result ->
|
onSuccess = { _, result ->
|
||||||
lastBitmap = (result.drawable as BitmapDrawable).bitmap
|
lastBitmap = (result.drawable as BitmapDrawable).bitmap
|
||||||
onDone(bitmap)
|
onDone(bitmap)
|
||||||
|
println("invoking listener")
|
||||||
|
listener?.invoke(lastBitmap)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
|
|
|
@ -11,6 +11,7 @@ import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
|
import android.graphics.Bitmap
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.media.MediaMetadata
|
import android.media.MediaMetadata
|
||||||
import android.media.session.MediaSession
|
import android.media.session.MediaSession
|
||||||
|
@ -680,6 +681,13 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
|
||||||
var isLoadingRadio by mutableStateOf(false)
|
var isLoadingRadio by mutableStateOf(false)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
val lastBitmap: Bitmap?
|
||||||
|
get() = bitmapProvider.lastBitmap
|
||||||
|
|
||||||
|
fun setBitmapListener(listener: ((Bitmap?) -> Unit)?) {
|
||||||
|
bitmapProvider.listener = listener
|
||||||
|
}
|
||||||
|
|
||||||
fun startSleepTimer(delayMillis: Long) {
|
fun startSleepTimer(delayMillis: Long) {
|
||||||
timerJob?.cancel()
|
timerJob?.cancel()
|
||||||
|
|
||||||
|
|
|
@ -153,9 +153,9 @@ fun TextFieldDialog(
|
||||||
)
|
)
|
||||||
|
|
||||||
ChunkyButton(
|
ChunkyButton(
|
||||||
backgroundColor = colorPalette.primaryContainer,
|
backgroundColor = colorPalette.accent,
|
||||||
text = doneText,
|
text = doneText,
|
||||||
textStyle = typography.xs.semiBold.color(colorPalette.onPrimaryContainer),
|
textStyle = typography.xs.semiBold.color(colorPalette.onAccent),
|
||||||
shape = RoundedCornerShape(36.dp),
|
shape = RoundedCornerShape(36.dp),
|
||||||
onClick = {
|
onClick = {
|
||||||
if (isTextInputValid(textFieldValue.text)) {
|
if (isTextInputValid(textFieldValue.text)) {
|
||||||
|
@ -210,9 +210,9 @@ fun ConfirmationDialog(
|
||||||
)
|
)
|
||||||
|
|
||||||
ChunkyButton(
|
ChunkyButton(
|
||||||
backgroundColor = colorPalette.primaryContainer,
|
backgroundColor = colorPalette.accent,
|
||||||
text = confirmText,
|
text = confirmText,
|
||||||
textStyle = typography.xs.semiBold.color(colorPalette.onPrimaryContainer),
|
textStyle = typography.xs.semiBold.color(colorPalette.onAccent),
|
||||||
shape = RoundedCornerShape(36.dp),
|
shape = RoundedCornerShape(36.dp),
|
||||||
onClick = {
|
onClick = {
|
||||||
onConfirm()
|
onConfirm()
|
||||||
|
@ -242,7 +242,7 @@ inline fun DefaultDialog(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.padding(all = 48.dp)
|
.padding(all = 48.dp)
|
||||||
.background(
|
.background(
|
||||||
color = colorPalette.elevatedBackground,
|
color = colorPalette.background1,
|
||||||
shape = RoundedCornerShape(8.dp)
|
shape = RoundedCornerShape(8.dp)
|
||||||
)
|
)
|
||||||
.padding(horizontal = 24.dp, vertical = 16.dp),
|
.padding(horizontal = 24.dp, vertical = 16.dp),
|
||||||
|
@ -268,7 +268,7 @@ inline fun <T> ValueSelectorDialog(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.padding(all = 48.dp)
|
.padding(all = 48.dp)
|
||||||
.background(
|
.background(
|
||||||
color = colorPalette.elevatedBackground,
|
color = colorPalette.background1,
|
||||||
shape = RoundedCornerShape(8.dp)
|
shape = RoundedCornerShape(8.dp)
|
||||||
)
|
)
|
||||||
.padding(vertical = 16.dp),
|
.padding(vertical = 16.dp),
|
||||||
|
@ -305,12 +305,12 @@ inline fun <T> ValueSelectorDialog(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(18.dp)
|
.size(18.dp)
|
||||||
.background(
|
.background(
|
||||||
color = colorPalette.primaryContainer,
|
color = colorPalette.accent,
|
||||||
shape = CircleShape
|
shape = CircleShape
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
drawCircle(
|
drawCircle(
|
||||||
color = colorPalette.onPrimaryContainer,
|
color = colorPalette.onAccent,
|
||||||
radius = 4.dp.toPx(),
|
radius = 4.dp.toPx(),
|
||||||
center = size.center,
|
center = size.center,
|
||||||
shadow = Shadow(
|
shadow = Shadow(
|
||||||
|
|
|
@ -35,7 +35,7 @@ fun DropDownSection(content: @Composable ColumnScope.() -> Unit) {
|
||||||
elevation = 2.dp,
|
elevation = 2.dp,
|
||||||
shape = RoundedCornerShape(16.dp)
|
shape = RoundedCornerShape(16.dp)
|
||||||
)
|
)
|
||||||
.background(colorPalette.elevatedBackground)
|
.background(colorPalette.background1)
|
||||||
.width(IntrinsicSize.Max),
|
.width(IntrinsicSize.Max),
|
||||||
content = content
|
content = content
|
||||||
)
|
)
|
||||||
|
@ -60,14 +60,14 @@ fun DropDownTextItem(
|
||||||
DropDownTextItem(
|
DropDownTextItem(
|
||||||
text = text,
|
text = text,
|
||||||
textColor = if (isSelected) {
|
textColor = if (isSelected) {
|
||||||
colorPalette.onPrimaryContainer
|
colorPalette.onAccent
|
||||||
} else {
|
} else {
|
||||||
colorPalette.textSecondary
|
colorPalette.textSecondary
|
||||||
},
|
},
|
||||||
backgroundColor = if (isSelected) {
|
backgroundColor = if (isSelected) {
|
||||||
colorPalette.primaryContainer
|
colorPalette.accent
|
||||||
} else {
|
} else {
|
||||||
colorPalette.elevatedBackground
|
colorPalette.background1
|
||||||
},
|
},
|
||||||
onClick = onClick
|
onClick = onClick
|
||||||
)
|
)
|
||||||
|
@ -95,7 +95,7 @@ fun DropDownTextItem(
|
||||||
interactionSource = remember { MutableInteractionSource() },
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
onClick = onClick
|
onClick = onClick
|
||||||
)
|
)
|
||||||
.background(backgroundColor ?: colorPalette.elevatedBackground)
|
.background(backgroundColor ?: colorPalette.background1)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.widthIn(min = 124.dp, max = 248.dp)
|
.widthIn(min = 124.dp, max = 248.dp)
|
||||||
.padding(
|
.padding(
|
||||||
|
|
|
@ -536,9 +536,9 @@ fun MediaItemMenu(
|
||||||
)
|
)
|
||||||
|
|
||||||
ChunkyButton(
|
ChunkyButton(
|
||||||
backgroundColor = colorPalette.primaryContainer,
|
backgroundColor = colorPalette.accent,
|
||||||
text = "Set",
|
text = "Set",
|
||||||
textStyle = typography.xs.semiBold.color(colorPalette.onPrimaryContainer),
|
textStyle = typography.xs.semiBold.color(colorPalette.onAccent),
|
||||||
shape = RoundedCornerShape(36.dp),
|
shape = RoundedCornerShape(36.dp),
|
||||||
isEnabled = hours > 0 || minutes > 0,
|
isEnabled = hours > 0 || minutes > 0,
|
||||||
onClick = {
|
onClick = {
|
||||||
|
|
|
@ -44,7 +44,7 @@ inline fun Menu(
|
||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.background(
|
.background(
|
||||||
color = colorPalette.elevatedBackground,
|
color = colorPalette.background1,
|
||||||
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)
|
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)
|
||||||
)
|
)
|
||||||
.padding(top = 8.dp)
|
.padding(top = 8.dp)
|
||||||
|
|
|
@ -26,8 +26,8 @@ fun Switch(
|
||||||
) {
|
) {
|
||||||
val (colorPalette) = LocalAppearance.current
|
val (colorPalette) = LocalAppearance.current
|
||||||
|
|
||||||
val backgroundColor by animateColorAsState(if (isChecked) colorPalette.primaryContainer else colorPalette.lightBackground)
|
val backgroundColor by animateColorAsState(if (isChecked) colorPalette.accent else colorPalette.background1)
|
||||||
val color by animateColorAsState(if (isChecked) colorPalette.onPrimaryContainer else colorPalette.textDisabled)
|
val color by animateColorAsState(if (isChecked) colorPalette.onAccent else colorPalette.textDisabled)
|
||||||
val offset by animateDpAsState(if (isChecked) 36.dp else 12.dp)
|
val offset by animateDpAsState(if (isChecked) 36.dp else 12.dp)
|
||||||
|
|
||||||
Spacer(
|
Spacer(
|
||||||
|
|
|
@ -13,6 +13,7 @@ import androidx.compose.material.ripple.rememberRipple
|
||||||
import androidx.compose.runtime.Composable
|
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.graphics.Color
|
||||||
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.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
@ -41,14 +42,14 @@ fun TextCard(
|
||||||
enabled = onClick != null,
|
enabled = onClick != null,
|
||||||
onClick = onClick ?: {}
|
onClick = onClick ?: {}
|
||||||
)
|
)
|
||||||
.background(colorPalette.lightBackground)
|
.background(colorPalette.background1)
|
||||||
.padding(horizontal = 16.dp, vertical = 16.dp)
|
.padding(horizontal = 16.dp, vertical = 16.dp)
|
||||||
) {
|
) {
|
||||||
icon?.let {
|
icon?.let {
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(icon),
|
painter = painterResource(icon),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
colorFilter = iconColor ?: ColorFilter.tint(colorPalette.red),
|
colorFilter = iconColor ?: ColorFilter.tint(Color.Red),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(bottom = 16.dp)
|
.padding(bottom = 16.dp)
|
||||||
.size(24.dp)
|
.size(24.dp)
|
||||||
|
|
|
@ -5,23 +5,24 @@ import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.runtime.Composable
|
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.graphics.Color
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
|
import it.vfsfitvnm.vimusic.ui.styling.shimmer
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TextPlaceholder(
|
fun TextPlaceholder(
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier,
|
||||||
|
color: Color = LocalAppearance.current.colorPalette.shimmer
|
||||||
) {
|
) {
|
||||||
val (colorPalette) = LocalAppearance.current
|
|
||||||
Spacer(
|
Spacer(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.padding(vertical = 4.dp)
|
.padding(vertical = 4.dp)
|
||||||
.background(color = colorPalette.darkGray, shape = RoundedCornerShape(0.dp))
|
.background(color)
|
||||||
.fillMaxWidth(remember { 0.25f + Random.nextFloat() * 0.5f })
|
.fillMaxWidth(remember { 0.25f + Random.nextFloat() * 0.5f })
|
||||||
.height(16.dp)
|
.height(16.dp)
|
||||||
)
|
)
|
||||||
|
|
|
@ -59,6 +59,7 @@ 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.LocalAppearance
|
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.ui.styling.shimmer
|
||||||
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
||||||
import it.vfsfitvnm.vimusic.utils.asMediaItem
|
import it.vfsfitvnm.vimusic.utils.asMediaItem
|
||||||
import it.vfsfitvnm.vimusic.utils.bold
|
import it.vfsfitvnm.vimusic.utils.bold
|
||||||
|
@ -110,7 +111,7 @@ fun AlbumScreen(browseId: String) {
|
||||||
state = lazyListState,
|
state = lazyListState,
|
||||||
contentPadding = PaddingValues(bottom = 72.dp),
|
contentPadding = PaddingValues(bottom = 72.dp),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(colorPalette.background)
|
.background(colorPalette.background0)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
item {
|
item {
|
||||||
|
@ -377,7 +378,7 @@ private fun LoadingOrError(
|
||||||
) {
|
) {
|
||||||
Spacer(
|
Spacer(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(color = colorPalette.darkGray, shape = ThumbnailRoundness.shape)
|
.background(color = colorPalette.shimmer, shape = ThumbnailRoundness.shape)
|
||||||
.size(Dimensions.thumbnails.album)
|
.size(Dimensions.thumbnails.album)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
import androidx.compose.ui.draw.alpha
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.geometry.center
|
import androidx.compose.ui.geometry.center
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
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.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
@ -53,6 +54,7 @@ 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.LocalAppearance
|
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.ui.styling.shimmer
|
||||||
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
||||||
import it.vfsfitvnm.vimusic.utils.asMediaItem
|
import it.vfsfitvnm.vimusic.utils.asMediaItem
|
||||||
import it.vfsfitvnm.vimusic.utils.forcePlayAtIndex
|
import it.vfsfitvnm.vimusic.utils.forcePlayAtIndex
|
||||||
|
@ -102,7 +104,7 @@ fun ArtistScreen(browseId: String) {
|
||||||
contentPadding = PaddingValues(bottom = 72.dp),
|
contentPadding = PaddingValues(bottom = 72.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(colorPalette.background)
|
.background(colorPalette.background0)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
item {
|
item {
|
||||||
|
@ -213,7 +215,7 @@ fun ArtistScreen(browseId: String) {
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(colorPalette.background)
|
.background(colorPalette.background0)
|
||||||
.zIndex(1f)
|
.zIndex(1f)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 8.dp)
|
.padding(horizontal = 8.dp)
|
||||||
|
@ -271,7 +273,7 @@ fun ArtistScreen(browseId: String) {
|
||||||
Column(
|
Column(
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(colorPalette.background)
|
.background(colorPalette.background0)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 8.dp)
|
.padding(horizontal = 8.dp)
|
||||||
.padding(top = 32.dp)
|
.padding(top = 32.dp)
|
||||||
|
@ -295,14 +297,14 @@ fun ArtistScreen(browseId: String) {
|
||||||
.width(48.dp)
|
.width(48.dp)
|
||||||
) {
|
) {
|
||||||
drawLine(
|
drawLine(
|
||||||
color = colorPalette.backgroundContainer,
|
color = colorPalette.background2,
|
||||||
start = size.center.copy(y = 0f),
|
start = size.center.copy(y = 0f),
|
||||||
end = size.center.copy(y = size.height),
|
end = size.center.copy(y = size.height),
|
||||||
strokeWidth = 2.dp.toPx()
|
strokeWidth = 2.dp.toPx()
|
||||||
)
|
)
|
||||||
|
|
||||||
drawCircle(
|
drawCircle(
|
||||||
color = colorPalette.backgroundContainer,
|
color = colorPalette.background2,
|
||||||
center = size.center.copy(y = size.height),
|
center = size.center.copy(y = size.height),
|
||||||
radius = 4.dp.toPx()
|
radius = 4.dp.toPx()
|
||||||
)
|
)
|
||||||
|
@ -340,7 +342,7 @@ private fun LoadingOrError(
|
||||||
) {
|
) {
|
||||||
Spacer(
|
Spacer(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(color = colorPalette.darkGray, shape = CircleShape)
|
.background(color = colorPalette.shimmer, shape = CircleShape)
|
||||||
.size(Dimensions.thumbnails.artist)
|
.size(Dimensions.thumbnails.artist)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,7 @@ fun BuiltInPlaylistScreen(builtInPlaylist: BuiltInPlaylist) {
|
||||||
state = lazyListState,
|
state = lazyListState,
|
||||||
contentPadding = PaddingValues(bottom = Dimensions.collapsedPlayer),
|
contentPadding = PaddingValues(bottom = Dimensions.collapsedPlayer),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(colorPalette.background)
|
.background(colorPalette.background0)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
item {
|
item {
|
||||||
|
|
|
@ -38,25 +38,15 @@ import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.drawBehind
|
import androidx.compose.ui.draw.drawBehind
|
||||||
import androidx.compose.ui.draw.drawWithCache
|
|
||||||
import androidx.compose.ui.geometry.Offset
|
import androidx.compose.ui.geometry.Offset
|
||||||
import androidx.compose.ui.geometry.center
|
|
||||||
import androidx.compose.ui.graphics.Brush
|
import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.compose.ui.graphics.ClipOp
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.graphics.Paint
|
|
||||||
import androidx.compose.ui.graphics.Path
|
|
||||||
import androidx.compose.ui.graphics.Shadow
|
import androidx.compose.ui.graphics.Shadow
|
||||||
import androidx.compose.ui.graphics.asAndroidPath
|
|
||||||
import androidx.compose.ui.graphics.drawscope.clipPath
|
|
||||||
import androidx.compose.ui.graphics.toArgb
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.zIndex
|
import androidx.compose.ui.zIndex
|
||||||
import androidx.core.content.res.ResourcesCompat
|
|
||||||
import it.vfsfitvnm.route.RouteHandler
|
import it.vfsfitvnm.route.RouteHandler
|
||||||
import it.vfsfitvnm.vimusic.Database
|
import it.vfsfitvnm.vimusic.Database
|
||||||
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
||||||
|
@ -79,6 +69,8 @@ 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.Dimensions
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
|
import it.vfsfitvnm.vimusic.ui.styling.onOverlay
|
||||||
|
import it.vfsfitvnm.vimusic.ui.styling.overlay
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.px
|
import it.vfsfitvnm.vimusic.ui.styling.px
|
||||||
import it.vfsfitvnm.vimusic.ui.views.BuiltInPlaylistItem
|
import it.vfsfitvnm.vimusic.ui.views.BuiltInPlaylistItem
|
||||||
import it.vfsfitvnm.vimusic.ui.views.PlaylistPreviewItem
|
import it.vfsfitvnm.vimusic.ui.views.PlaylistPreviewItem
|
||||||
|
@ -186,7 +178,6 @@ fun HomeScreen() {
|
||||||
@Suppress("UNUSED_EXPRESSION") playlistPreviews
|
@Suppress("UNUSED_EXPRESSION") playlistPreviews
|
||||||
@Suppress("UNUSED_EXPRESSION") songCollection
|
@Suppress("UNUSED_EXPRESSION") songCollection
|
||||||
|
|
||||||
val context = LocalContext.current
|
|
||||||
val binder = LocalPlayerServiceBinder.current
|
val binder = LocalPlayerServiceBinder.current
|
||||||
|
|
||||||
val isFirstLaunch by rememberPreference(isFirstLaunchKey, true)
|
val isFirstLaunch by rememberPreference(isFirstLaunchKey, true)
|
||||||
|
@ -215,7 +206,7 @@ fun HomeScreen() {
|
||||||
state = lazyListState,
|
state = lazyListState,
|
||||||
contentPadding = PaddingValues(bottom = 72.dp),
|
contentPadding = PaddingValues(bottom = 72.dp),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(colorPalette.background)
|
.background(colorPalette.background0)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
item("topAppBar") {
|
item("topAppBar") {
|
||||||
|
@ -228,22 +219,20 @@ fun HomeScreen() {
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
colorFilter = ColorFilter.tint(colorPalette.text),
|
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clickable {
|
.clickable { settingsRoute() }
|
||||||
settingsRoute()
|
|
||||||
}
|
|
||||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||||
.run {
|
.run {
|
||||||
if (isFirstLaunch) {
|
if (isFirstLaunch) {
|
||||||
drawBehind {
|
drawBehind {
|
||||||
drawCircle(
|
drawCircle(
|
||||||
color = colorPalette.red,
|
color = colorPalette.accent,
|
||||||
center = Offset(
|
center = Offset(
|
||||||
x = size.width,
|
x = size.width,
|
||||||
y = 0.dp.toPx()
|
y = 0.dp.toPx()
|
||||||
),
|
),
|
||||||
radius = 4.dp.toPx(),
|
radius = 4.dp.toPx(),
|
||||||
shadow = Shadow(
|
shadow = Shadow(
|
||||||
color = colorPalette.red,
|
color = colorPalette.accent,
|
||||||
blurRadius = 4.dp.toPx()
|
blurRadius = 4.dp.toPx()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -255,88 +244,12 @@ fun HomeScreen() {
|
||||||
.size(24.dp)
|
.size(24.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
BasicText(
|
|
||||||
text = "ViMusic",
|
|
||||||
style = typography.l.semiBold,
|
|
||||||
modifier = Modifier
|
|
||||||
.drawWithCache {
|
|
||||||
val decorationPath = Path().apply {
|
|
||||||
with(asAndroidPath()) {
|
|
||||||
addCircle(
|
|
||||||
8.dp.toPx(),
|
|
||||||
size.center.y,
|
|
||||||
16.dp.toPx(),
|
|
||||||
android.graphics.Path.Direction.CCW
|
|
||||||
)
|
|
||||||
addCircle(
|
|
||||||
32.dp.toPx(),
|
|
||||||
-2.dp.toPx(),
|
|
||||||
8.dp.toPx(),
|
|
||||||
android.graphics.Path.Direction.CCW
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (colorPalette.isDark) {
|
|
||||||
return@drawWithCache onDrawBehind {
|
|
||||||
drawPath(
|
|
||||||
path = decorationPath,
|
|
||||||
color = colorPalette.primaryContainer
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val textPaint = Paint()
|
|
||||||
.asFrameworkPaint()
|
|
||||||
.apply {
|
|
||||||
isAntiAlias = true
|
|
||||||
textSize = typography.l.fontSize.toPx()
|
|
||||||
color = colorPalette.text.toArgb()
|
|
||||||
typeface = ResourcesCompat.getFont(
|
|
||||||
context,
|
|
||||||
R.font.poppins_w500
|
|
||||||
)
|
|
||||||
textAlign = android.graphics.Paint.Align.CENTER
|
|
||||||
}
|
|
||||||
|
|
||||||
val textY =
|
|
||||||
((textPaint.fontMetrics.descent - textPaint.fontMetrics.ascent) / 2) - textPaint.fontMetrics.descent
|
|
||||||
|
|
||||||
val textPath = Path().apply {
|
|
||||||
textPaint.getTextPath(
|
|
||||||
"ViMusic",
|
|
||||||
0,
|
|
||||||
7,
|
|
||||||
size.width / 2,
|
|
||||||
size.height / 2 + textY,
|
|
||||||
asAndroidPath()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
onDrawWithContent {
|
|
||||||
clipPath(textPath, ClipOp.Difference) {
|
|
||||||
drawPath(
|
|
||||||
path = decorationPath,
|
|
||||||
color = colorPalette.primaryContainer
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
clipPath(decorationPath, ClipOp.Difference) {
|
|
||||||
this@onDrawWithContent.drawContent()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.padding(horizontal = 8.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(R.drawable.search),
|
painter = painterResource(R.drawable.search),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
colorFilter = ColorFilter.tint(colorPalette.text),
|
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clickable {
|
.clickable { searchRoute("") }
|
||||||
searchRoute("")
|
|
||||||
}
|
|
||||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||||
.size(24.dp)
|
.size(24.dp)
|
||||||
)
|
)
|
||||||
|
@ -364,9 +277,7 @@ fun HomeScreen() {
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
colorFilter = ColorFilter.tint(colorPalette.text),
|
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clickable {
|
.clickable { isCreatingANewPlaylist = true }
|
||||||
isCreatingANewPlaylist = true
|
|
||||||
}
|
|
||||||
.padding(all = 8.dp)
|
.padding(all = 8.dp)
|
||||||
.size(20.dp)
|
.size(20.dp)
|
||||||
)
|
)
|
||||||
|
@ -381,18 +292,14 @@ fun HomeScreen() {
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
colorFilter = ColorFilter.tint(colorPalette.text),
|
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clickable {
|
.clickable { isSortMenuDisplayed = true }
|
||||||
isSortMenuDisplayed = true
|
|
||||||
}
|
|
||||||
.padding(horizontal = 8.dp, vertical = 8.dp)
|
.padding(horizontal = 8.dp, vertical = 8.dp)
|
||||||
.size(20.dp)
|
.size(20.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
DropdownMenu(
|
DropdownMenu(
|
||||||
isDisplayed = isSortMenuDisplayed,
|
isDisplayed = isSortMenuDisplayed,
|
||||||
onDismissRequest = {
|
onDismissRequest = { isSortMenuDisplayed = false }
|
||||||
isSortMenuDisplayed = false
|
|
||||||
}
|
|
||||||
) {
|
) {
|
||||||
DropDownSection {
|
DropDownSection {
|
||||||
DropDownTextItem(
|
DropDownTextItem(
|
||||||
|
@ -520,7 +427,7 @@ fun HomeScreen() {
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(colorPalette.background)
|
.background(colorPalette.background0)
|
||||||
.zIndex(1f)
|
.zIndex(1f)
|
||||||
.padding(horizontal = 8.dp)
|
.padding(horizontal = 8.dp)
|
||||||
.padding(top = 32.dp)
|
.padding(top = 32.dp)
|
||||||
|
@ -649,17 +556,14 @@ fun HomeScreen() {
|
||||||
) {
|
) {
|
||||||
BasicText(
|
BasicText(
|
||||||
text = song.formattedTotalPlayTime,
|
text = song.formattedTotalPlayTime,
|
||||||
style = typography.xxs.semiBold.center.color(Color.White),
|
style = typography.xxs.semiBold.center.color(colorPalette.onOverlay),
|
||||||
maxLines = 2,
|
maxLines = 2,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.background(
|
.background(
|
||||||
brush = Brush.verticalGradient(
|
brush = Brush.verticalGradient(
|
||||||
colors = listOf(
|
colors = listOf(Color.Transparent, colorPalette.overlay)
|
||||||
Color.Transparent,
|
|
||||||
Color.Black.copy(alpha = 0.75f)
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
shape = ThumbnailRoundness.shape
|
shape = ThumbnailRoundness.shape
|
||||||
)
|
)
|
||||||
|
|
|
@ -146,7 +146,7 @@ fun IntentUriScreen(uri: Uri) {
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
contentPadding = PaddingValues(bottom = Dimensions.collapsedPlayer),
|
contentPadding = PaddingValues(bottom = Dimensions.collapsedPlayer),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(colorPalette.background)
|
.background(colorPalette.background0)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
item {
|
item {
|
||||||
|
|
|
@ -128,7 +128,7 @@ fun LocalPlaylistScreen(playlistId: Long) {
|
||||||
state = lazyListState,
|
state = lazyListState,
|
||||||
contentPadding = PaddingValues(bottom = Dimensions.collapsedPlayer),
|
contentPadding = PaddingValues(bottom = Dimensions.collapsedPlayer),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(colorPalette.background)
|
.background(colorPalette.background0)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
item {
|
item {
|
||||||
|
|
|
@ -33,6 +33,7 @@ import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
import androidx.compose.ui.draw.alpha
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
@ -59,6 +60,7 @@ 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.LocalAppearance
|
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.ui.styling.shimmer
|
||||||
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
||||||
import it.vfsfitvnm.vimusic.utils.bold
|
import it.vfsfitvnm.vimusic.utils.bold
|
||||||
import it.vfsfitvnm.vimusic.utils.center
|
import it.vfsfitvnm.vimusic.utils.center
|
||||||
|
@ -109,7 +111,7 @@ fun PlaylistScreen(browseId: String) {
|
||||||
state = lazyListState,
|
state = lazyListState,
|
||||||
contentPadding = PaddingValues(bottom = 72.dp),
|
contentPadding = PaddingValues(bottom = 72.dp),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(colorPalette.background)
|
.background(colorPalette.background0)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
item {
|
item {
|
||||||
|
@ -396,7 +398,7 @@ private fun LoadingOrError(
|
||||||
) {
|
) {
|
||||||
Spacer(
|
Spacer(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(color = colorPalette.darkGray, shape = ThumbnailRoundness.shape)
|
.background(color = colorPalette.shimmer, shape = ThumbnailRoundness.shape)
|
||||||
.size(Dimensions.thumbnails.playlist)
|
.size(Dimensions.thumbnails.playlist)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -434,7 +436,7 @@ private fun LoadingOrError(
|
||||||
Spacer(
|
Spacer(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(8.dp)
|
.size(8.dp)
|
||||||
.background(color = colorPalette.darkGray, shape = CircleShape)
|
.background(color = Color.Black, shape = CircleShape)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ 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.LocalAppearance
|
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.ui.styling.shimmer
|
||||||
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
import it.vfsfitvnm.vimusic.ui.views.SongItem
|
||||||
import it.vfsfitvnm.vimusic.utils.asMediaItem
|
import it.vfsfitvnm.vimusic.utils.asMediaItem
|
||||||
import it.vfsfitvnm.vimusic.utils.center
|
import it.vfsfitvnm.vimusic.utils.center
|
||||||
|
@ -129,7 +130,7 @@ fun SearchResultScreen(query: String, onSearchAgain: () -> Unit) {
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
contentPadding = PaddingValues(bottom = Dimensions.collapsedPlayer),
|
contentPadding = PaddingValues(bottom = Dimensions.collapsedPlayer),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(colorPalette.background)
|
.background(colorPalette.background0)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
item {
|
item {
|
||||||
|
@ -200,9 +201,9 @@ fun SearchResultScreen(query: String, onSearchAgain: () -> Unit) {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
value = searchFilter,
|
value = searchFilter,
|
||||||
selectedBackgroundColor = colorPalette.primaryContainer,
|
selectedBackgroundColor = colorPalette.accent,
|
||||||
unselectedBackgroundColor = colorPalette.lightBackground,
|
unselectedBackgroundColor = colorPalette.background1,
|
||||||
selectedTextStyle = typography.xs.medium.color(colorPalette.onPrimaryContainer),
|
selectedTextStyle = typography.xs.medium.color(colorPalette.onAccent),
|
||||||
unselectedTextStyle = typography.xs.medium,
|
unselectedTextStyle = typography.xs.medium,
|
||||||
shape = RoundedCornerShape(36.dp),
|
shape = RoundedCornerShape(36.dp),
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
|
@ -281,7 +282,7 @@ fun SmallSongItemShimmer(
|
||||||
thumbnailSizeDp: Dp,
|
thumbnailSizeDp: Dp,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val (colorPalette) = LocalAppearance.current
|
val (colorPalette, _, thumbnailShape) = LocalAppearance.current
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
@ -290,7 +291,7 @@ fun SmallSongItemShimmer(
|
||||||
) {
|
) {
|
||||||
Spacer(
|
Spacer(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(color = colorPalette.darkGray, shape = ThumbnailRoundness.shape)
|
.background(color = colorPalette.shimmer, shape = thumbnailShape)
|
||||||
.size(thumbnailSizeDp)
|
.size(thumbnailSizeDp)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -315,7 +316,7 @@ fun SmallArtistItemShimmer(
|
||||||
) {
|
) {
|
||||||
Spacer(
|
Spacer(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(color = colorPalette.darkGray, shape = CircleShape)
|
.background(color = colorPalette.shimmer, shape = CircleShape)
|
||||||
.size(thumbnailSizeDp)
|
.size(thumbnailSizeDp)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.rotate
|
import androidx.compose.ui.draw.rotate
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.graphics.SolidColor
|
import androidx.compose.ui.graphics.SolidColor
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
|
@ -194,7 +195,7 @@ fun SearchScreen(initialTextInput: String, onSearch: (String) -> Unit, onUri: (U
|
||||||
}
|
}
|
||||||
.padding(horizontal = 14.dp, vertical = 6.dp)
|
.padding(horizontal = 14.dp, vertical = 6.dp)
|
||||||
.background(
|
.background(
|
||||||
color = colorPalette.lightBackground,
|
color = colorPalette.background1,
|
||||||
shape = CircleShape
|
shape = CircleShape
|
||||||
)
|
)
|
||||||
.size(28.dp)
|
.size(28.dp)
|
||||||
|
@ -228,13 +229,13 @@ fun SearchScreen(initialTextInput: String, onSearch: (String) -> Unit, onUri: (U
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.background(colorPalette.lightBackground)
|
.background(colorPalette.background1)
|
||||||
.padding(vertical = 16.dp, horizontal = 8.dp)
|
.padding(vertical = 16.dp, horizontal = 8.dp)
|
||||||
) {
|
) {
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(R.drawable.link),
|
painter = painterResource(R.drawable.link),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
colorFilter = ColorFilter.tint(colorPalette.darkGray),
|
colorFilter = ColorFilter.tint( Color.Black),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(horizontal = 8.dp)
|
.padding(horizontal = 8.dp)
|
||||||
.size(20.dp)
|
.size(20.dp)
|
||||||
|
@ -262,17 +263,16 @@ fun SearchScreen(initialTextInput: String, onSearch: (String) -> Unit, onUri: (U
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clickable(
|
.clickable(
|
||||||
indication = rememberRipple(bounded = true),
|
indication = rememberRipple(bounded = true),
|
||||||
interactionSource = remember { MutableInteractionSource() }
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
) {
|
onClick = { onSearch(searchQuery.query) }
|
||||||
onSearch(searchQuery.query)
|
)
|
||||||
}
|
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(vertical = 16.dp, horizontal = 8.dp)
|
.padding(vertical = 16.dp, horizontal = 8.dp)
|
||||||
) {
|
) {
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(R.drawable.time),
|
painter = painterResource(R.drawable.time),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
colorFilter = ColorFilter.tint(colorPalette.darkGray),
|
colorFilter = ColorFilter.tint(colorPalette.textDisabled),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(horizontal = 8.dp)
|
.padding(horizontal = 8.dp)
|
||||||
.size(20.dp)
|
.size(20.dp)
|
||||||
|
@ -289,7 +289,7 @@ fun SearchScreen(initialTextInput: String, onSearch: (String) -> Unit, onUri: (U
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(R.drawable.close),
|
painter = painterResource(R.drawable.close),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
colorFilter = ColorFilter.tint(colorPalette.darkGray),
|
colorFilter = ColorFilter.tint(colorPalette.textDisabled),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clickable {
|
.clickable {
|
||||||
query {
|
query {
|
||||||
|
@ -303,7 +303,7 @@ fun SearchScreen(initialTextInput: String, onSearch: (String) -> Unit, onUri: (U
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(R.drawable.arrow_forward),
|
painter = painterResource(R.drawable.arrow_forward),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
colorFilter = ColorFilter.tint(colorPalette.darkGray),
|
colorFilter = ColorFilter.tint(colorPalette.textDisabled),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clickable {
|
.clickable {
|
||||||
textFieldValue = TextFieldValue(
|
textFieldValue = TextFieldValue(
|
||||||
|
@ -325,10 +325,9 @@ fun SearchScreen(initialTextInput: String, onSearch: (String) -> Unit, onUri: (U
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clickable(
|
.clickable(
|
||||||
indication = rememberRipple(bounded = true),
|
indication = rememberRipple(bounded = true),
|
||||||
interactionSource = remember { MutableInteractionSource() }
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
) {
|
onClick = { onSearch(suggestion) }
|
||||||
onSearch(suggestion)
|
)
|
||||||
}
|
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(vertical = 16.dp, horizontal = 8.dp)
|
.padding(vertical = 16.dp, horizontal = 8.dp)
|
||||||
) {
|
) {
|
||||||
|
@ -346,11 +345,10 @@ fun SearchScreen(initialTextInput: String, onSearch: (String) -> Unit, onUri: (U
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(R.drawable.arrow_forward),
|
painter = painterResource(R.drawable.arrow_forward),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
colorFilter = ColorFilter.tint(colorPalette.darkGray),
|
colorFilter = ColorFilter.tint(Color.Black),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clickable {
|
.clickable {
|
||||||
textFieldValue = TextFieldValue(
|
textFieldValue = TextFieldValue(
|
||||||
|
|
|
@ -76,7 +76,7 @@ fun SettingsScreen() {
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(colorPalette.background)
|
.background(colorPalette.background0)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.verticalScroll(scrollState)
|
.verticalScroll(scrollState)
|
||||||
.padding(bottom = 72.dp)
|
.padding(bottom = 72.dp)
|
||||||
|
@ -137,10 +137,10 @@ fun SettingsScreen() {
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(icon),
|
painter = painterResource(icon),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
colorFilter = ColorFilter.tint(colorPalette.background),
|
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.Center)
|
.align(Alignment.Center)
|
||||||
.size(18.dp)
|
.size(16.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,11 +166,11 @@ fun SettingsScreen() {
|
||||||
.size(8.dp)
|
.size(8.dp)
|
||||||
) {
|
) {
|
||||||
drawCircle(
|
drawCircle(
|
||||||
color = colorPalette.red,
|
color = colorPalette.accent,
|
||||||
center = size.center.copy(x = size.width),
|
center = size.center.copy(x = size.width),
|
||||||
radius = 4.dp.toPx(),
|
radius = 4.dp.toPx(),
|
||||||
shadow = Shadow(
|
shadow = Shadow(
|
||||||
color = colorPalette.red,
|
color = colorPalette.accent,
|
||||||
blurRadius = 4.dp.toPx()
|
blurRadius = 4.dp.toPx()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -180,7 +180,7 @@ fun SettingsScreen() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Entry(
|
Entry(
|
||||||
color = colorPalette.magenta,
|
color = colorPalette.background2,
|
||||||
icon = R.drawable.color_palette,
|
icon = R.drawable.color_palette,
|
||||||
title = "Appearance",
|
title = "Appearance",
|
||||||
description = "Change the colors and shapes",
|
description = "Change the colors and shapes",
|
||||||
|
@ -188,7 +188,7 @@ fun SettingsScreen() {
|
||||||
)
|
)
|
||||||
|
|
||||||
Entry(
|
Entry(
|
||||||
color = colorPalette.blue,
|
color = colorPalette.background2,
|
||||||
icon = R.drawable.play,
|
icon = R.drawable.play,
|
||||||
title = "Player & Audio",
|
title = "Player & Audio",
|
||||||
description = "Player and audio settings",
|
description = "Player and audio settings",
|
||||||
|
@ -196,7 +196,7 @@ fun SettingsScreen() {
|
||||||
)
|
)
|
||||||
|
|
||||||
Entry(
|
Entry(
|
||||||
color = colorPalette.cyan,
|
color = colorPalette.background2,
|
||||||
icon = R.drawable.server,
|
icon = R.drawable.server,
|
||||||
title = "Cache",
|
title = "Cache",
|
||||||
description = "Manage the used space",
|
description = "Manage the used space",
|
||||||
|
@ -204,7 +204,7 @@ fun SettingsScreen() {
|
||||||
)
|
)
|
||||||
|
|
||||||
Entry(
|
Entry(
|
||||||
color = colorPalette.orange,
|
color = colorPalette.background2,
|
||||||
icon = R.drawable.save,
|
icon = R.drawable.save,
|
||||||
title = "Backup & Restore",
|
title = "Backup & Restore",
|
||||||
description = "Backup and restore the database",
|
description = "Backup and restore the database",
|
||||||
|
@ -212,7 +212,7 @@ fun SettingsScreen() {
|
||||||
)
|
)
|
||||||
|
|
||||||
Entry(
|
Entry(
|
||||||
color = colorPalette.green,
|
color = colorPalette.background2,
|
||||||
icon = R.drawable.shapes,
|
icon = R.drawable.shapes,
|
||||||
title = "Other",
|
title = "Other",
|
||||||
description = "Advanced settings",
|
description = "Advanced settings",
|
||||||
|
@ -224,7 +224,7 @@ fun SettingsScreen() {
|
||||||
)
|
)
|
||||||
|
|
||||||
Entry(
|
Entry(
|
||||||
color = colorPalette.magenta,
|
color = colorPalette.background2,
|
||||||
icon = R.drawable.information,
|
icon = R.drawable.information,
|
||||||
title = "About",
|
title = "About",
|
||||||
description = "App version and social links",
|
description = "App version and social links",
|
||||||
|
@ -241,6 +241,7 @@ inline fun <reified T : Enum<T>> EnumValueSelectorSettingsEntry(
|
||||||
selectedValue: T,
|
selectedValue: T,
|
||||||
crossinline onValueSelected: (T) -> Unit,
|
crossinline onValueSelected: (T) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
isEnabled: Boolean = true,
|
||||||
crossinline valueText: (T) -> String = Enum<T>::name
|
crossinline valueText: (T) -> String = Enum<T>::name
|
||||||
) {
|
) {
|
||||||
ValueSelectorSettingsEntry(
|
ValueSelectorSettingsEntry(
|
||||||
|
@ -249,6 +250,7 @@ inline fun <reified T : Enum<T>> EnumValueSelectorSettingsEntry(
|
||||||
values = enumValues<T>().toList(),
|
values = enumValues<T>().toList(),
|
||||||
onValueSelected = onValueSelected,
|
onValueSelected = onValueSelected,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
|
isEnabled = isEnabled,
|
||||||
valueText = valueText
|
valueText = valueText
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -260,6 +262,7 @@ inline fun <T> ValueSelectorSettingsEntry(
|
||||||
values: List<T>,
|
values: List<T>,
|
||||||
crossinline onValueSelected: (T) -> Unit,
|
crossinline onValueSelected: (T) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
isEnabled: Boolean = true,
|
||||||
crossinline valueText: (T) -> String = { it.toString() }
|
crossinline valueText: (T) -> String = { it.toString() }
|
||||||
) {
|
) {
|
||||||
var isShowingDialog by remember {
|
var isShowingDialog by remember {
|
||||||
|
@ -283,6 +286,7 @@ inline fun <T> ValueSelectorSettingsEntry(
|
||||||
title = title,
|
title = title,
|
||||||
text = valueText(selectedValue),
|
text = valueText(selectedValue),
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
|
isEnabled = isEnabled,
|
||||||
onClick = {
|
onClick = {
|
||||||
isShowingDialog = true
|
isShowingDialog = true
|
||||||
}
|
}
|
||||||
|
@ -428,7 +432,7 @@ fun SettingsEntryGroupText(
|
||||||
|
|
||||||
BasicText(
|
BasicText(
|
||||||
text = title.uppercase(),
|
text = title.uppercase(),
|
||||||
style = typography.xxs.semiBold.copy(colorPalette.blue),
|
style = typography.xxs.semiBold.copy(colorPalette.accent),
|
||||||
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)
|
||||||
|
|
|
@ -42,7 +42,7 @@ fun AboutScreen() {
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(colorPalette.background)
|
.background(colorPalette.background0)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.verticalScroll(scrollState)
|
.verticalScroll(scrollState)
|
||||||
.padding(bottom = 72.dp)
|
.padding(bottom = 72.dp)
|
||||||
|
|
|
@ -21,6 +21,7 @@ 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.ColorPaletteMode
|
||||||
|
import it.vfsfitvnm.vimusic.enums.ColorPaletteName
|
||||||
import it.vfsfitvnm.vimusic.enums.ThumbnailRoundness
|
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.EnumValueSelectorSettingsEntry
|
import it.vfsfitvnm.vimusic.ui.screens.EnumValueSelectorSettingsEntry
|
||||||
|
@ -30,6 +31,7 @@ import it.vfsfitvnm.vimusic.ui.screens.SwitchSettingEntry
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.globalRoutes
|
import it.vfsfitvnm.vimusic.ui.screens.globalRoutes
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.utils.colorPaletteModeKey
|
import it.vfsfitvnm.vimusic.utils.colorPaletteModeKey
|
||||||
|
import it.vfsfitvnm.vimusic.utils.colorPaletteNameKey
|
||||||
import it.vfsfitvnm.vimusic.utils.isShowingThumbnailInLockscreenKey
|
import it.vfsfitvnm.vimusic.utils.isShowingThumbnailInLockscreenKey
|
||||||
import it.vfsfitvnm.vimusic.utils.rememberPreference
|
import it.vfsfitvnm.vimusic.utils.rememberPreference
|
||||||
import it.vfsfitvnm.vimusic.utils.thumbnailRoundnessKey
|
import it.vfsfitvnm.vimusic.utils.thumbnailRoundnessKey
|
||||||
|
@ -45,6 +47,7 @@ fun AppearanceSettingsScreen() {
|
||||||
host {
|
host {
|
||||||
val (colorPalette) = LocalAppearance.current
|
val (colorPalette) = LocalAppearance.current
|
||||||
|
|
||||||
|
var colorPaletteName by rememberPreference(colorPaletteNameKey, ColorPaletteName.Dynamic)
|
||||||
var colorPaletteMode by rememberPreference(colorPaletteModeKey, ColorPaletteMode.System)
|
var colorPaletteMode by rememberPreference(colorPaletteModeKey, ColorPaletteMode.System)
|
||||||
var thumbnailRoundness by rememberPreference(
|
var thumbnailRoundness by rememberPreference(
|
||||||
thumbnailRoundnessKey,
|
thumbnailRoundnessKey,
|
||||||
|
@ -57,7 +60,7 @@ fun AppearanceSettingsScreen() {
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(colorPalette.background)
|
.background(colorPalette.background0)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.verticalScroll(scrollState)
|
.verticalScroll(scrollState)
|
||||||
.padding(bottom = 72.dp)
|
.padding(bottom = 72.dp)
|
||||||
|
@ -81,9 +84,18 @@ fun AppearanceSettingsScreen() {
|
||||||
|
|
||||||
SettingsEntryGroupText(title = "COLORS")
|
SettingsEntryGroupText(title = "COLORS")
|
||||||
|
|
||||||
|
EnumValueSelectorSettingsEntry(
|
||||||
|
title = "Theme",
|
||||||
|
selectedValue = colorPaletteName,
|
||||||
|
onValueSelected = {
|
||||||
|
colorPaletteName = it
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
EnumValueSelectorSettingsEntry(
|
EnumValueSelectorSettingsEntry(
|
||||||
title = "Theme mode",
|
title = "Theme mode",
|
||||||
selectedValue = colorPaletteMode,
|
selectedValue = colorPaletteMode,
|
||||||
|
isEnabled = colorPaletteName != ColorPaletteName.PureBlack,
|
||||||
onValueSelected = {
|
onValueSelected = {
|
||||||
colorPaletteMode = it
|
colorPaletteMode = it
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,7 +119,7 @@ fun BackupAndRestoreScreen() {
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(colorPalette.background)
|
.background(colorPalette.background0)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.verticalScroll(scrollState)
|
.verticalScroll(scrollState)
|
||||||
.padding(bottom = 72.dp)
|
.padding(bottom = 72.dp)
|
||||||
|
|
|
@ -67,7 +67,7 @@ fun CacheSettingsScreen() {
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(colorPalette.background)
|
.background(colorPalette.background0)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.verticalScroll(scrollState)
|
.verticalScroll(scrollState)
|
||||||
.padding(bottom = 72.dp)
|
.padding(bottom = 72.dp)
|
||||||
|
|
|
@ -71,7 +71,7 @@ fun OtherSettingsScreen() {
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(colorPalette.background)
|
.background(colorPalette.background0)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.verticalScroll(scrollState)
|
.verticalScroll(scrollState)
|
||||||
.padding(bottom = 72.dp)
|
.padding(bottom = 72.dp)
|
||||||
|
|
|
@ -63,7 +63,7 @@ fun PlayerSettingsScreen() {
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(colorPalette.background)
|
.background(colorPalette.background0)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.verticalScroll(scrollState)
|
.verticalScroll(scrollState)
|
||||||
.padding(bottom = 72.dp)
|
.padding(bottom = 72.dp)
|
||||||
|
|
|
@ -1,83 +1,142 @@
|
||||||
package it.vfsfitvnm.vimusic.ui.styling
|
package it.vfsfitvnm.vimusic.ui.styling
|
||||||
|
|
||||||
|
import android.graphics.Bitmap
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.palette.graphics.Palette
|
||||||
|
import it.vfsfitvnm.vimusic.enums.ColorPaletteMode
|
||||||
|
import it.vfsfitvnm.vimusic.enums.ColorPaletteName
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class ColorPalette(
|
data class ColorPalette(
|
||||||
val background: Color,
|
val background0: Color,
|
||||||
val elevatedBackground: Color,
|
val background1: Color,
|
||||||
val lightBackground: Color,
|
val background2: Color,
|
||||||
val backgroundContainer: Color,
|
val accent: Color,
|
||||||
|
val onAccent: Color,
|
||||||
|
val red: Color = Color(0xffbf4040),
|
||||||
|
val blue: Color = Color(0xFF4472CF),
|
||||||
val text: Color,
|
val text: Color,
|
||||||
val textSecondary: Color,
|
val textSecondary: Color,
|
||||||
val textDisabled: Color,
|
val textDisabled: Color,
|
||||||
val lightGray: Color,
|
|
||||||
val gray: Color,
|
|
||||||
val darkGray: Color,
|
|
||||||
val blue: Color,
|
|
||||||
val red: Color,
|
|
||||||
val green: Color,
|
|
||||||
val orange: Color,
|
|
||||||
val magenta: Color,
|
|
||||||
val cyan: Color,
|
|
||||||
|
|
||||||
val primaryContainer: Color,
|
|
||||||
val onPrimaryContainer: Color,
|
|
||||||
val iconOnPrimaryContainer: Color,
|
|
||||||
|
|
||||||
val isDark: Boolean
|
val isDark: Boolean
|
||||||
)
|
)
|
||||||
|
|
||||||
val DarkColorPalette = ColorPalette(
|
val DefaultDarkColorPalette = ColorPalette(
|
||||||
background = Color(0xff16171d),
|
background0 = Color(0xff16171d),
|
||||||
lightBackground = Color(0xff1f2029),
|
background1 = Color(0xff1f2029),
|
||||||
elevatedBackground = Color(0xff1f2029),
|
background2 = Color(0xff2b2d3b),
|
||||||
backgroundContainer = Color(0xff2b2d3b),
|
|
||||||
text = Color(0xffe1e1e2),
|
text = Color(0xffe1e1e2),
|
||||||
textSecondary = Color(0xffa3a4a6),
|
textSecondary = Color(0xffa3a4a6),
|
||||||
textDisabled = Color(0xff6f6f73),
|
textDisabled = Color(0xff6f6f73),
|
||||||
lightGray = Color(0xfff8f8f8),
|
accent = Color(0xff4046bf),
|
||||||
gray = Color(0xFFE5E5E5),
|
onAccent = Color.White,
|
||||||
darkGray = Color(0xFF838383),
|
|
||||||
blue = Color(0xff507fdd),
|
|
||||||
red = Color(0xffbf4040),
|
|
||||||
green = Color(0xff82b154),
|
|
||||||
orange = Color(0xffe9a033),
|
|
||||||
magenta = Color(0xffbb4da4),
|
|
||||||
cyan = Color(0xFF4DA5BB),
|
|
||||||
primaryContainer = Color(0xff4046bf),
|
|
||||||
onPrimaryContainer = Color.White,
|
|
||||||
iconOnPrimaryContainer = Color.White,
|
|
||||||
isDark = true
|
isDark = true
|
||||||
)
|
)
|
||||||
|
|
||||||
val BlackColorPalette = DarkColorPalette.copy(
|
val DefaultLightColorPalette = ColorPalette(
|
||||||
background = Color.Black,
|
background0 = Color(0xfffdfdfe),
|
||||||
lightBackground = Color(0xff0d0d12),
|
background1 = Color(0xfff8f8fc),
|
||||||
elevatedBackground = Color(0xff0d0d12),
|
background2 = Color(0xffeaeaf5),
|
||||||
backgroundContainer = Color(0xff0d0d12)
|
|
||||||
)
|
|
||||||
|
|
||||||
val LightColorPalette = ColorPalette(
|
|
||||||
background = Color(0xfffdfdfe),
|
|
||||||
lightBackground = Color(0xfff8f8fc),
|
|
||||||
elevatedBackground = Color(0xfff8f8fc),
|
|
||||||
backgroundContainer = Color(0xffeaeaf5),
|
|
||||||
lightGray = Color(0xfff8f8f8),
|
|
||||||
gray = Color(0xFFE5E5E5),
|
|
||||||
darkGray = Color(0xFF838383),
|
|
||||||
text = Color(0xff212121),
|
text = Color(0xff212121),
|
||||||
textSecondary = Color(0xFF656566),
|
textSecondary = Color(0xFF656566),
|
||||||
textDisabled = Color(0xFF9d9d9d),
|
textDisabled = Color(0xFF9d9d9d),
|
||||||
blue = Color(0xff4059bf),
|
accent = Color(0xff4046bf),
|
||||||
red = Color(0xffbf4040),
|
onAccent = Color.White,
|
||||||
green = Color(0xff7fbf40),
|
|
||||||
orange = Color(0xffe8730e),
|
|
||||||
magenta = Color(0xffbb4da4),
|
|
||||||
cyan = Color(0xFF4DBBB2),
|
|
||||||
primaryContainer = Color(0xff4046bf),
|
|
||||||
onPrimaryContainer = Color.White,
|
|
||||||
iconOnPrimaryContainer = Color.White,
|
|
||||||
isDark = false
|
isDark = false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val PureBlackColorPalette = DefaultDarkColorPalette.copy(
|
||||||
|
background0 = Color.Black,
|
||||||
|
background1 = Color.Black,
|
||||||
|
background2 = Color.Black
|
||||||
|
)
|
||||||
|
|
||||||
|
fun colorPaletteOf(
|
||||||
|
colorPaletteName: ColorPaletteName,
|
||||||
|
colorPaletteMode: ColorPaletteMode,
|
||||||
|
isSystemInDarkMode: Boolean
|
||||||
|
): ColorPalette {
|
||||||
|
return when (colorPaletteName) {
|
||||||
|
ColorPaletteName.Default, ColorPaletteName.Dynamic -> when (colorPaletteMode) {
|
||||||
|
ColorPaletteMode.Light -> DefaultLightColorPalette
|
||||||
|
ColorPaletteMode.Dark -> DefaultDarkColorPalette
|
||||||
|
ColorPaletteMode.System -> when (isSystemInDarkMode) {
|
||||||
|
true -> DefaultDarkColorPalette
|
||||||
|
false -> DefaultLightColorPalette
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ColorPaletteName.PureBlack -> PureBlackColorPalette
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun dynamicColorPaletteOf(bitmap: Bitmap, isDark: Boolean): ColorPalette? {
|
||||||
|
val palette = Palette
|
||||||
|
.from(bitmap)
|
||||||
|
.maximumColorCount(8)
|
||||||
|
.addFilter(if (isDark) ({ _, hsl -> hsl[0] !in 36f..100f }) else null)
|
||||||
|
.generate()
|
||||||
|
|
||||||
|
val hsl = if (isDark) {
|
||||||
|
palette.dominantSwatch ?: Palette
|
||||||
|
.from(bitmap)
|
||||||
|
.maximumColorCount(8)
|
||||||
|
.generate()
|
||||||
|
.dominantSwatch
|
||||||
|
} else {
|
||||||
|
palette.dominantSwatch
|
||||||
|
}?.hsl ?: return null
|
||||||
|
|
||||||
|
return if (hsl[1] < 0.08) {
|
||||||
|
val newHsl = palette.swatches
|
||||||
|
.map(Palette.Swatch::getHsl)
|
||||||
|
.sortedByDescending(FloatArray::component2)
|
||||||
|
.find { it[1] != 0f }
|
||||||
|
?: hsl
|
||||||
|
|
||||||
|
dynamicColorPaletteOf(newHsl, isDark)
|
||||||
|
} else {
|
||||||
|
dynamicColorPaletteOf(hsl, isDark)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun dynamicColorPaletteOf(hsl: FloatArray, isDark: Boolean): ColorPalette {
|
||||||
|
return colorPaletteOf(ColorPaletteName.Dynamic, if (isDark) ColorPaletteMode.Dark else ColorPaletteMode.Light, false).copy(
|
||||||
|
background0 = Color.hsl(hsl[0], hsl[1].coerceAtMost(0.1f), if (isDark) 0.10f else 0.925f),
|
||||||
|
background1 = Color.hsl(hsl[0], hsl[1].coerceAtMost(0.3f), if (isDark) 0.15f else 0.90f),
|
||||||
|
background2 = Color.hsl(hsl[0], hsl[1].coerceAtMost(0.4f), if (isDark) 0.2f else 0.85f),
|
||||||
|
accent = Color.hsl(hsl[0], hsl[1].coerceAtMost(0.5f), 0.5f),
|
||||||
|
// background3 = Color.hsl(hue, saturation, if (isDark) 0.20f else 0.85f),
|
||||||
|
// background4 = Color.hsl(hue, saturation, if (isDark) 0.25f else 0.75f),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline val ColorPalette.collapsedPlayerProgressBar: Color
|
||||||
|
get() = if (this === DefaultDarkColorPalette || this === DefaultLightColorPalette || this == PureBlackColorPalette) {
|
||||||
|
text
|
||||||
|
} else {
|
||||||
|
accent
|
||||||
|
}
|
||||||
|
|
||||||
|
inline val ColorPalette.favoritesIcon: Color
|
||||||
|
get() = if (this === DefaultDarkColorPalette || this === DefaultLightColorPalette || this == PureBlackColorPalette) {
|
||||||
|
red
|
||||||
|
} else {
|
||||||
|
accent
|
||||||
|
}
|
||||||
|
|
||||||
|
inline val ColorPalette.shimmer: Color
|
||||||
|
get() = if (this === DefaultDarkColorPalette || this === DefaultLightColorPalette || this == PureBlackColorPalette) {
|
||||||
|
Color(0xff838383)
|
||||||
|
} else {
|
||||||
|
accent
|
||||||
|
}
|
||||||
|
|
||||||
|
inline val ColorPalette.overlay: Color
|
||||||
|
get() = PureBlackColorPalette.background0.copy(alpha = 0.75f)
|
||||||
|
|
||||||
|
inline val ColorPalette.onOverlay: Color
|
||||||
|
get() = PureBlackColorPalette.text
|
||||||
|
|
||||||
|
inline val ColorPalette.onOverlayShimmer: Color
|
||||||
|
get() = PureBlackColorPalette.shimmer
|
||||||
|
|
|
@ -1,7 +1,16 @@
|
||||||
package it.vfsfitvnm.vimusic.ui.styling
|
package it.vfsfitvnm.vimusic.ui.styling
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.text.ExperimentalTextApi
|
||||||
|
import androidx.compose.ui.text.PlatformTextStyle
|
||||||
import androidx.compose.ui.text.TextStyle
|
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
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class Typography(
|
data class Typography(
|
||||||
|
@ -11,3 +20,47 @@ data class Typography(
|
||||||
val m: TextStyle,
|
val m: TextStyle,
|
||||||
val l: TextStyle,
|
val l: TextStyle,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@OptIn(ExperimentalTextApi::class)
|
||||||
|
fun typographyOf(color: Color): Typography {
|
||||||
|
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),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -47,8 +47,8 @@ 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.Dimensions
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LightColorPalette
|
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
|
import it.vfsfitvnm.vimusic.ui.styling.onOverlay
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.px
|
import it.vfsfitvnm.vimusic.ui.styling.px
|
||||||
import it.vfsfitvnm.vimusic.utils.medium
|
import it.vfsfitvnm.vimusic.utils.medium
|
||||||
import it.vfsfitvnm.vimusic.utils.rememberMediaItemIndex
|
import it.vfsfitvnm.vimusic.utils.rememberMediaItemIndex
|
||||||
|
@ -91,6 +91,7 @@ fun CurrentPlaylistView(
|
||||||
.nestedScroll(remember {
|
.nestedScroll(remember {
|
||||||
layoutState.nestedScrollConnection(lazyListState.firstVisibleItemIndex == 0 && lazyListState.firstVisibleItemScrollOffset == 0)
|
layoutState.nestedScrollConnection(lazyListState.firstVisibleItemIndex == 0 && lazyListState.firstVisibleItemScrollOffset == 0)
|
||||||
})
|
})
|
||||||
|
.background(colorPalette.background1)
|
||||||
) {
|
) {
|
||||||
items(
|
items(
|
||||||
items = windows,
|
items = windows,
|
||||||
|
@ -137,7 +138,7 @@ fun CurrentPlaylistView(
|
||||||
) {
|
) {
|
||||||
if (shouldBePlaying) {
|
if (shouldBePlaying) {
|
||||||
MusicBars(
|
MusicBars(
|
||||||
color = LightColorPalette.background,
|
color = colorPalette.onOverlay,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.height(24.dp)
|
.height(24.dp)
|
||||||
)
|
)
|
||||||
|
@ -145,7 +146,7 @@ fun CurrentPlaylistView(
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(R.drawable.play),
|
painter = painterResource(R.drawable.play),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
colorFilter = ColorFilter.tint(LightColorPalette.background),
|
colorFilter = ColorFilter.tint(colorPalette.onOverlay),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(24.dp)
|
.size(24.dp)
|
||||||
)
|
)
|
||||||
|
@ -164,7 +165,6 @@ fun CurrentPlaylistView(
|
||||||
.size(20.dp)
|
.size(20.dp)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
backgroundColor = colorPalette.background,
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
// .animateItemPlacement()
|
// .animateItemPlacement()
|
||||||
.verticalDragAfterLongPressToReorder(
|
.verticalDragAfterLongPressToReorder(
|
||||||
|
@ -211,7 +211,7 @@ fun CurrentPlaylistView(
|
||||||
onClick = layoutState::collapseSoft
|
onClick = layoutState::collapseSoft
|
||||||
)
|
)
|
||||||
.height(64.dp)
|
.height(64.dp)
|
||||||
.background(colorPalette.elevatedBackground)
|
.background(colorPalette.background2)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 8.dp)
|
.padding(horizontal = 8.dp)
|
||||||
.align(Alignment.BottomCenter)
|
.align(Alignment.BottomCenter)
|
||||||
|
|
|
@ -7,6 +7,8 @@ import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.drawBehind
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
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
|
||||||
|
@ -18,6 +20,7 @@ import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
@ExperimentalAnimationApi
|
@ExperimentalAnimationApi
|
||||||
@Composable
|
@Composable
|
||||||
fun PlayerBottomSheet(
|
fun PlayerBottomSheet(
|
||||||
|
backgroundColorProvider: () -> Color,
|
||||||
layoutState: BottomSheetState,
|
layoutState: BottomSheetState,
|
||||||
onGlobalRouteEmitted: () -> Unit,
|
onGlobalRouteEmitted: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
@ -31,7 +34,7 @@ fun PlayerBottomSheet(
|
||||||
collapsedContent = {
|
collapsedContent = {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(colorPalette.background)
|
.drawBehind { drawRect(backgroundColorProvider()) }
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
Image(
|
Image(
|
||||||
|
@ -40,7 +43,6 @@ fun PlayerBottomSheet(
|
||||||
colorFilter = ColorFilter.tint(colorPalette.text),
|
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.Center)
|
.align(Alignment.Center)
|
||||||
.padding(all = 8.dp)
|
|
||||||
.size(18.dp)
|
.size(18.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -52,7 +54,7 @@ fun PlayerBottomSheet(
|
||||||
layoutState = layoutState,
|
layoutState = layoutState,
|
||||||
onGlobalRouteEmitted = onGlobalRouteEmitted,
|
onGlobalRouteEmitted = onGlobalRouteEmitted,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(colorPalette.background)
|
.background(colorPalette.background0)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.draw.drawBehind
|
import androidx.compose.ui.draw.drawBehind
|
||||||
import androidx.compose.ui.geometry.Offset
|
import androidx.compose.ui.geometry.Offset
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
|
@ -49,6 +50,7 @@ import it.vfsfitvnm.vimusic.ui.components.rememberBottomSheetState
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.BaseMediaItemMenu
|
import it.vfsfitvnm.vimusic.ui.components.themed.BaseMediaItemMenu
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
|
import it.vfsfitvnm.vimusic.ui.styling.collapsedPlayerProgressBar
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.px
|
import it.vfsfitvnm.vimusic.ui.styling.px
|
||||||
import it.vfsfitvnm.vimusic.ui.views.player.Controls
|
import it.vfsfitvnm.vimusic.ui.views.player.Controls
|
||||||
import it.vfsfitvnm.vimusic.ui.views.player.Thumbnail
|
import it.vfsfitvnm.vimusic.ui.views.player.Thumbnail
|
||||||
|
@ -70,7 +72,7 @@ fun PlayerView(
|
||||||
) {
|
) {
|
||||||
val menuState = LocalMenuState.current
|
val menuState = LocalMenuState.current
|
||||||
|
|
||||||
val (colorPalette, typography) = LocalAppearance.current
|
val (colorPalette, typography, thumbnailShape) = LocalAppearance.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
|
||||||
|
@ -96,30 +98,32 @@ fun PlayerView(
|
||||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(colorPalette.elevatedBackground)
|
.background(colorPalette.background1)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.drawBehind {
|
.drawBehind {
|
||||||
val progress =
|
val progress =
|
||||||
positionAndDuration.first.toFloat() / positionAndDuration.second.absoluteValue
|
positionAndDuration.first.toFloat() / positionAndDuration.second.absoluteValue
|
||||||
val offset = Dimensions.thumbnails.player.songPreview.toPx()
|
|
||||||
|
|
||||||
drawLine(
|
drawLine(
|
||||||
color = colorPalette.text,
|
color = colorPalette.collapsedPlayerProgressBar,
|
||||||
start = Offset(x = offset, y = 1.dp.toPx()),
|
start = Offset(x = 0f, y = 1.dp.toPx()),
|
||||||
end = Offset(
|
end = Offset(x = size.width * progress, y = 1.dp.toPx()),
|
||||||
x = ((size.width - offset) * progress) + offset,
|
|
||||||
y = 1.dp.toPx()
|
|
||||||
),
|
|
||||||
strokeWidth = 2.dp.toPx()
|
strokeWidth = 2.dp.toPx()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
|
Spacer(
|
||||||
|
modifier = Modifier
|
||||||
|
.width(2.dp)
|
||||||
|
)
|
||||||
|
|
||||||
AsyncImage(
|
AsyncImage(
|
||||||
model = mediaItem.mediaMetadata.artworkUri.thumbnail(Dimensions.thumbnails.player.songPreview.px),
|
model = mediaItem.mediaMetadata.artworkUri.thumbnail(Dimensions.thumbnails.player.songPreview.px),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
contentScale = ContentScale.Crop,
|
contentScale = ContentScale.Crop,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(Dimensions.thumbnails.player.songPreview)
|
.clip(thumbnailShape)
|
||||||
|
.size(48.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
|
@ -206,7 +210,7 @@ fun PlayerView(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(bottom = 64.dp)
|
.padding(bottom = 64.dp)
|
||||||
.background(colorPalette.background)
|
.background(colorPalette.background1)
|
||||||
.padding(top = 16.dp)
|
.padding(top = 16.dp)
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
|
@ -242,7 +246,7 @@ fun PlayerView(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(bottom = 64.dp)
|
.padding(bottom = 64.dp)
|
||||||
.background(colorPalette.background)
|
.background(colorPalette.background1)
|
||||||
.padding(top = 32.dp)
|
.padding(top = 32.dp)
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
|
@ -355,6 +359,7 @@ fun PlayerView(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
backgroundColorProvider = { colorPalette.background2 },
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.BottomCenter)
|
.align(Alignment.BottomCenter)
|
||||||
)
|
)
|
||||||
|
|
|
@ -91,7 +91,7 @@ fun PlaylistPreviewItem(
|
||||||
contentScale = ContentScale.Crop,
|
contentScale = ContentScale.Crop,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clip(thumbnailShape)
|
.clip(thumbnailShape)
|
||||||
.border(width = 1.dp, color = colorPalette.lightBackground)
|
.border(width = 1.dp, color = colorPalette.background1)
|
||||||
.align(alignment)
|
.align(alignment)
|
||||||
.size(thumbnailSize)
|
.size(thumbnailSize)
|
||||||
)
|
)
|
||||||
|
@ -143,7 +143,7 @@ fun PlaylistItem(
|
||||||
Box(
|
Box(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.clip(thumbnailShape)
|
.clip(thumbnailShape)
|
||||||
.background(colorPalette.lightBackground)
|
.background(colorPalette.background1)
|
||||||
.size(thumbnailSize * 2)
|
.size(thumbnailSize * 2)
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
|
|
|
@ -2,7 +2,6 @@ package it.vfsfitvnm.vimusic.ui.views
|
||||||
|
|
||||||
import androidx.compose.animation.ExperimentalAnimationApi
|
import androidx.compose.animation.ExperimentalAnimationApi
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.combinedClickable
|
import androidx.compose.foundation.combinedClickable
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
@ -22,7 +21,6 @@ import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
@ -48,7 +46,6 @@ fun SongItem(
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
menuContent: @Composable () -> Unit,
|
menuContent: @Composable () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
backgroundColor: Color? = null,
|
|
||||||
onThumbnailContent: (@Composable BoxScope.() -> Unit)? = null,
|
onThumbnailContent: (@Composable BoxScope.() -> Unit)? = null,
|
||||||
trailingContent: (@Composable () -> Unit)? = null
|
trailingContent: (@Composable () -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
|
@ -64,7 +61,6 @@ fun SongItem(
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
onThumbnailContent = onThumbnailContent,
|
onThumbnailContent = onThumbnailContent,
|
||||||
trailingContent = trailingContent,
|
trailingContent = trailingContent,
|
||||||
backgroundColor = backgroundColor,
|
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -78,7 +74,6 @@ fun SongItem(
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
menuContent: @Composable () -> Unit,
|
menuContent: @Composable () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
backgroundColor: Color? = null,
|
|
||||||
onThumbnailContent: (@Composable BoxScope.() -> Unit)? = null,
|
onThumbnailContent: (@Composable BoxScope.() -> Unit)? = null,
|
||||||
trailingContent: (@Composable () -> Unit)? = null
|
trailingContent: (@Composable () -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
|
@ -90,7 +85,6 @@ fun SongItem(
|
||||||
menuContent = menuContent,
|
menuContent = menuContent,
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
onThumbnailContent = onThumbnailContent,
|
onThumbnailContent = onThumbnailContent,
|
||||||
backgroundColor = backgroundColor,
|
|
||||||
trailingContent = trailingContent,
|
trailingContent = trailingContent,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
)
|
)
|
||||||
|
@ -107,7 +101,6 @@ fun SongItem(
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
menuContent: @Composable () -> Unit,
|
menuContent: @Composable () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
backgroundColor: Color? = null,
|
|
||||||
onThumbnailContent: (@Composable BoxScope.() -> Unit)? = null,
|
onThumbnailContent: (@Composable BoxScope.() -> Unit)? = null,
|
||||||
trailingContent: (@Composable () -> Unit)? = null
|
trailingContent: (@Composable () -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
|
@ -134,7 +127,6 @@ fun SongItem(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
menuContent = menuContent,
|
menuContent = menuContent,
|
||||||
backgroundColor = backgroundColor,
|
|
||||||
trailingContent = trailingContent,
|
trailingContent = trailingContent,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
)
|
)
|
||||||
|
@ -151,11 +143,10 @@ fun SongItem(
|
||||||
startContent: @Composable () -> Unit,
|
startContent: @Composable () -> Unit,
|
||||||
menuContent: @Composable () -> Unit,
|
menuContent: @Composable () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
backgroundColor: Color? = null,
|
|
||||||
trailingContent: (@Composable () -> Unit)? = null
|
trailingContent: (@Composable () -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
val menuState = LocalMenuState.current
|
val menuState = LocalMenuState.current
|
||||||
val (colorPalette, typography) = LocalAppearance.current
|
val (_, typography) = LocalAppearance.current
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
@ -171,7 +162,6 @@ fun SongItem(
|
||||||
)
|
)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(vertical = Dimensions.itemsVerticalPadding)
|
.padding(vertical = Dimensions.itemsVerticalPadding)
|
||||||
.background(backgroundColor ?: colorPalette.background)
|
|
||||||
.padding(start = 16.dp, end = if (trailingContent == null) 16.dp else 8.dp)
|
.padding(start = 16.dp, end = if (trailingContent == null) 16.dp else 8.dp)
|
||||||
) {
|
) {
|
||||||
startContent()
|
startContent()
|
||||||
|
|
|
@ -2,6 +2,7 @@ package it.vfsfitvnm.vimusic.ui.views.player
|
||||||
|
|
||||||
import android.text.format.DateUtils
|
import android.text.format.DateUtils
|
||||||
import androidx.compose.animation.core.animateDpAsState
|
import androidx.compose.animation.core.animateDpAsState
|
||||||
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
@ -40,6 +41,7 @@ import it.vfsfitvnm.vimusic.models.Song
|
||||||
import it.vfsfitvnm.vimusic.query
|
import it.vfsfitvnm.vimusic.query
|
||||||
import it.vfsfitvnm.vimusic.ui.components.SeekBar
|
import it.vfsfitvnm.vimusic.ui.components.SeekBar
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
|
import it.vfsfitvnm.vimusic.ui.styling.favoritesIcon
|
||||||
import it.vfsfitvnm.vimusic.utils.bold
|
import it.vfsfitvnm.vimusic.utils.bold
|
||||||
import it.vfsfitvnm.vimusic.utils.rememberRepeatMode
|
import it.vfsfitvnm.vimusic.utils.rememberRepeatMode
|
||||||
import it.vfsfitvnm.vimusic.utils.secondary
|
import it.vfsfitvnm.vimusic.utils.secondary
|
||||||
|
@ -70,7 +72,7 @@ fun Controls(
|
||||||
Database.likedAt(mediaItem.mediaId).distinctUntilChanged()
|
Database.likedAt(mediaItem.mediaId).distinctUntilChanged()
|
||||||
}.collectAsState(initial = null, context = Dispatchers.IO)
|
}.collectAsState(initial = null, context = Dispatchers.IO)
|
||||||
|
|
||||||
val playPauseRoundness by animateDpAsState(if (shouldBePlaying) 32.dp else 16.dp)
|
val playPauseRoundness by animateDpAsState(if (shouldBePlaying) 32.dp else 16.dp, tween())
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
@ -121,7 +123,7 @@ fun Controls(
|
||||||
scrubbingPosition = null
|
scrubbingPosition = null
|
||||||
},
|
},
|
||||||
color = colorPalette.text,
|
color = colorPalette.text,
|
||||||
backgroundColor = colorPalette.backgroundContainer,
|
backgroundColor = colorPalette.background2,
|
||||||
shape = RoundedCornerShape(8.dp)
|
shape = RoundedCornerShape(8.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -166,7 +168,7 @@ fun Controls(
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(R.drawable.heart),
|
painter = painterResource(R.drawable.heart),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
colorFilter = ColorFilter.tint(if (likedAt != null) colorPalette.red else colorPalette.textDisabled),
|
colorFilter = ColorFilter.tint(if (likedAt == null) colorPalette.background2 else colorPalette.favoritesIcon),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clickable {
|
.clickable {
|
||||||
query {
|
query {
|
||||||
|
@ -211,7 +213,7 @@ fun Controls(
|
||||||
binder.player.play()
|
binder.player.play()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.background(color = colorPalette.backgroundContainer)
|
.background(colorPalette.background2)
|
||||||
.size(64.dp)
|
.size(64.dp)
|
||||||
) {
|
) {
|
||||||
Image(
|
Image(
|
||||||
|
|
|
@ -57,9 +57,10 @@ import it.vfsfitvnm.vimusic.ui.components.themed.Menu
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.MenuEntry
|
import it.vfsfitvnm.vimusic.ui.components.themed.MenuEntry
|
||||||
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.BlackColorPalette
|
import it.vfsfitvnm.vimusic.ui.styling.PureBlackColorPalette
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.DarkColorPalette
|
import it.vfsfitvnm.vimusic.ui.styling.DefaultDarkColorPalette
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
|
import it.vfsfitvnm.vimusic.ui.styling.onOverlayShimmer
|
||||||
import it.vfsfitvnm.vimusic.utils.SynchronizedLyrics
|
import it.vfsfitvnm.vimusic.utils.SynchronizedLyrics
|
||||||
import it.vfsfitvnm.vimusic.utils.center
|
import it.vfsfitvnm.vimusic.utils.center
|
||||||
import it.vfsfitvnm.vimusic.utils.color
|
import it.vfsfitvnm.vimusic.utils.color
|
||||||
|
@ -88,7 +89,7 @@ fun Lyrics(
|
||||||
nestedScrollConnectionProvider: () -> NestedScrollConnection,
|
nestedScrollConnectionProvider: () -> NestedScrollConnection,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val (_, typography) = LocalAppearance.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
|
@ -194,7 +195,7 @@ fun Lyrics(
|
||||||
) {
|
) {
|
||||||
BasicText(
|
BasicText(
|
||||||
text = "An error has occurred while fetching the ${if (isShowingSynchronizedLyrics) "synchronized " else ""}lyrics",
|
text = "An error has occurred while fetching the ${if (isShowingSynchronizedLyrics) "synchronized " else ""}lyrics",
|
||||||
style = typography.xs.center.medium.color(BlackColorPalette.text),
|
style = typography.xs.center.medium.color(PureBlackColorPalette.text),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(Color.Black.copy(0.4f))
|
.background(Color.Black.copy(0.4f))
|
||||||
.padding(all = 8.dp)
|
.padding(all = 8.dp)
|
||||||
|
@ -211,7 +212,7 @@ fun Lyrics(
|
||||||
) {
|
) {
|
||||||
BasicText(
|
BasicText(
|
||||||
text = "${if (isShowingSynchronizedLyrics) "Synchronized l" else "L"}yrics are not available for this song",
|
text = "${if (isShowingSynchronizedLyrics) "Synchronized l" else "L"}yrics are not available for this song",
|
||||||
style = typography.xs.center.medium.color(BlackColorPalette.text),
|
style = typography.xs.center.medium.color(PureBlackColorPalette.text),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(Color.Black.copy(0.4f))
|
.background(Color.Black.copy(0.4f))
|
||||||
.padding(all = 8.dp)
|
.padding(all = 8.dp)
|
||||||
|
@ -227,6 +228,7 @@ fun Lyrics(
|
||||||
) {
|
) {
|
||||||
repeat(4) { index ->
|
repeat(4) { index ->
|
||||||
TextPlaceholder(
|
TextPlaceholder(
|
||||||
|
color = colorPalette.onOverlayShimmer,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.alpha(1f - index * 0.05f)
|
.alpha(1f - index * 0.05f)
|
||||||
)
|
)
|
||||||
|
@ -269,7 +271,7 @@ fun Lyrics(
|
||||||
itemsIndexed(items = synchronizedLyrics.sentences) { index, sentence ->
|
itemsIndexed(items = synchronizedLyrics.sentences) { index, sentence ->
|
||||||
BasicText(
|
BasicText(
|
||||||
text = sentence.second,
|
text = sentence.second,
|
||||||
style = typography.xs.center.medium.color(if (index == synchronizedLyrics.index) BlackColorPalette.text else BlackColorPalette.textDisabled),
|
style = typography.xs.center.medium.color(if (index == synchronizedLyrics.index) PureBlackColorPalette.text else PureBlackColorPalette.textDisabled),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(vertical = 4.dp, horizontal = 32.dp)
|
.padding(vertical = 4.dp, horizontal = 32.dp)
|
||||||
)
|
)
|
||||||
|
@ -278,7 +280,7 @@ fun Lyrics(
|
||||||
} else {
|
} else {
|
||||||
BasicText(
|
BasicText(
|
||||||
text = lyrics,
|
text = lyrics,
|
||||||
style = typography.xs.center.medium.color(BlackColorPalette.text),
|
style = typography.xs.center.medium.color(PureBlackColorPalette.text),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.nestedScroll(remember { nestedScrollConnectionProvider() })
|
.nestedScroll(remember { nestedScrollConnectionProvider() })
|
||||||
.verticalFadingEdge()
|
.verticalFadingEdge()
|
||||||
|
@ -293,7 +295,7 @@ fun Lyrics(
|
||||||
Image(
|
Image(
|
||||||
painter = painterResource(R.drawable.ellipsis_horizontal),
|
painter = painterResource(R.drawable.ellipsis_horizontal),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
colorFilter = ColorFilter.tint(DarkColorPalette.text),
|
colorFilter = ColorFilter.tint(DefaultDarkColorPalette.text),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(all = 4.dp)
|
.padding(all = 4.dp)
|
||||||
.clickable {
|
.clickable {
|
||||||
|
|
|
@ -20,7 +20,7 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.input.pointer.pointerInput
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.BlackColorPalette
|
import it.vfsfitvnm.vimusic.ui.styling.PureBlackColorPalette
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.utils.center
|
import it.vfsfitvnm.vimusic.utils.center
|
||||||
import it.vfsfitvnm.vimusic.utils.color
|
import it.vfsfitvnm.vimusic.utils.color
|
||||||
|
@ -64,7 +64,7 @@ fun PlaybackError(
|
||||||
) {
|
) {
|
||||||
BasicText(
|
BasicText(
|
||||||
text = remember { messageProvider() },
|
text = remember { messageProvider() },
|
||||||
style = typography.xs.center.medium.color(BlackColorPalette.text),
|
style = typography.xs.center.medium.color(PureBlackColorPalette.text),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(Color.Black.copy(0.4f))
|
.background(Color.Black.copy(0.4f))
|
||||||
.padding(all = 8.dp)
|
.padding(all = 8.dp)
|
||||||
|
|
|
@ -25,7 +25,6 @@ import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
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.input.pointer.pointerInput
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
@ -35,8 +34,9 @@ import it.vfsfitvnm.vimusic.Database
|
||||||
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
||||||
import it.vfsfitvnm.vimusic.models.Format
|
import it.vfsfitvnm.vimusic.models.Format
|
||||||
import it.vfsfitvnm.vimusic.query
|
import it.vfsfitvnm.vimusic.query
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.BlackColorPalette
|
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
|
import it.vfsfitvnm.vimusic.ui.styling.onOverlay
|
||||||
|
import it.vfsfitvnm.vimusic.ui.styling.overlay
|
||||||
import it.vfsfitvnm.vimusic.utils.color
|
import it.vfsfitvnm.vimusic.utils.color
|
||||||
import it.vfsfitvnm.vimusic.utils.medium
|
import it.vfsfitvnm.vimusic.utils.medium
|
||||||
import it.vfsfitvnm.vimusic.utils.rememberVolume
|
import it.vfsfitvnm.vimusic.utils.rememberVolume
|
||||||
|
@ -53,7 +53,7 @@ fun StatsForNerds(
|
||||||
onDismiss: () -> Unit,
|
onDismiss: () -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val (_, typography) = LocalAppearance.current
|
val (colorPalette, typography) = LocalAppearance.current
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val binder = LocalPlayerServiceBinder.current ?: return
|
val binder = LocalPlayerServiceBinder.current ?: return
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ fun StatsForNerds(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.background(Color.Black.copy(alpha = 0.8f))
|
.background(colorPalette.overlay)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
|
@ -117,50 +117,50 @@ fun StatsForNerds(
|
||||||
Column(horizontalAlignment = Alignment.End) {
|
Column(horizontalAlignment = Alignment.End) {
|
||||||
BasicText(
|
BasicText(
|
||||||
text = "Id",
|
text = "Id",
|
||||||
style = typography.xs.medium.color(BlackColorPalette.text)
|
style = typography.xs.medium.color(colorPalette.onOverlay)
|
||||||
)
|
)
|
||||||
BasicText(
|
BasicText(
|
||||||
text = "Volume",
|
text = "Volume",
|
||||||
style = typography.xs.medium.color(BlackColorPalette.text)
|
style = typography.xs.medium.color(colorPalette.onOverlay)
|
||||||
)
|
)
|
||||||
BasicText(
|
BasicText(
|
||||||
text = "Loudness",
|
text = "Loudness",
|
||||||
style = typography.xs.medium.color(BlackColorPalette.text)
|
style = typography.xs.medium.color(colorPalette.onOverlay)
|
||||||
)
|
)
|
||||||
BasicText(
|
BasicText(
|
||||||
text = "Bitrate",
|
text = "Bitrate",
|
||||||
style = typography.xs.medium.color(BlackColorPalette.text)
|
style = typography.xs.medium.color(colorPalette.onOverlay)
|
||||||
)
|
)
|
||||||
BasicText(
|
BasicText(
|
||||||
text = "Size",
|
text = "Size",
|
||||||
style = typography.xs.medium.color(BlackColorPalette.text)
|
style = typography.xs.medium.color(colorPalette.onOverlay)
|
||||||
)
|
)
|
||||||
BasicText(
|
BasicText(
|
||||||
text = "Cached",
|
text = "Cached",
|
||||||
style = typography.xs.medium.color(BlackColorPalette.text)
|
style = typography.xs.medium.color(colorPalette.onOverlay)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
BasicText(
|
BasicText(
|
||||||
text = mediaId,
|
text = mediaId,
|
||||||
style = typography.xs.medium.color(BlackColorPalette.text)
|
style = typography.xs.medium.color(colorPalette.onOverlay)
|
||||||
)
|
)
|
||||||
BasicText(
|
BasicText(
|
||||||
text = "${volume.times(100).roundToInt()}%",
|
text = "${volume.times(100).roundToInt()}%",
|
||||||
style = typography.xs.medium.color(BlackColorPalette.text)
|
style = typography.xs.medium.color(colorPalette.onOverlay)
|
||||||
)
|
)
|
||||||
BasicText(
|
BasicText(
|
||||||
text = format?.loudnessDb?.let { loudnessDb ->
|
text = format?.loudnessDb?.let { loudnessDb ->
|
||||||
"%.2f dB".format(loudnessDb)
|
"%.2f dB".format(loudnessDb)
|
||||||
} ?: "Unknown",
|
} ?: "Unknown",
|
||||||
style = typography.xs.medium.color(BlackColorPalette.text)
|
style = typography.xs.medium.color(colorPalette.onOverlay)
|
||||||
)
|
)
|
||||||
BasicText(
|
BasicText(
|
||||||
text = format?.bitrate?.let { bitrate ->
|
text = format?.bitrate?.let { bitrate ->
|
||||||
"${bitrate / 1000} kbps"
|
"${bitrate / 1000} kbps"
|
||||||
} ?: "Unknown",
|
} ?: "Unknown",
|
||||||
style = typography.xs.medium.color(BlackColorPalette.text)
|
style = typography.xs.medium.color(colorPalette.onOverlay)
|
||||||
)
|
)
|
||||||
BasicText(
|
BasicText(
|
||||||
text = format?.contentLength?.let { contentLength ->
|
text = format?.contentLength?.let { contentLength ->
|
||||||
|
@ -169,7 +169,7 @@ fun StatsForNerds(
|
||||||
contentLength
|
contentLength
|
||||||
)
|
)
|
||||||
} ?: "Unknown",
|
} ?: "Unknown",
|
||||||
style = typography.xs.medium.color(BlackColorPalette.text)
|
style = typography.xs.medium.color(colorPalette.onOverlay)
|
||||||
)
|
)
|
||||||
BasicText(
|
BasicText(
|
||||||
text = buildString {
|
text = buildString {
|
||||||
|
@ -179,7 +179,7 @@ fun StatsForNerds(
|
||||||
append(" (${(cachedBytes.toFloat() / contentLength * 100).roundToInt()}%)")
|
append(" (${(cachedBytes.toFloat() / contentLength * 100).roundToInt()}%)")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
style = typography.xs.medium.color(BlackColorPalette.text)
|
style = typography.xs.medium.color(colorPalette.onOverlay)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,7 +187,7 @@ fun StatsForNerds(
|
||||||
if (format != null && format?.itag == null) {
|
if (format != null && format?.itag == null) {
|
||||||
BasicText(
|
BasicText(
|
||||||
text = "FETCH MISSING DATA",
|
text = "FETCH MISSING DATA",
|
||||||
style = typography.xxs.medium.color(BlackColorPalette.text),
|
style = typography.xxs.medium.color(colorPalette.onOverlay),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clickable(
|
.clickable(
|
||||||
indication = rememberRipple(bounded = true),
|
indication = rememberRipple(bounded = true),
|
||||||
|
|
|
@ -10,6 +10,7 @@ import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
|
|
||||||
|
const val colorPaletteNameKey = "colorPaletteName"
|
||||||
const val colorPaletteModeKey = "colorPaletteMode"
|
const val colorPaletteModeKey = "colorPaletteMode"
|
||||||
const val thumbnailRoundnessKey = "thumbnailRoundness"
|
const val thumbnailRoundnessKey = "thumbnailRoundness"
|
||||||
const val coilDiskCacheMaxSizeKey = "coilDiskCacheMaxSize"
|
const val coilDiskCacheMaxSizeKey = "coilDiskCacheMaxSize"
|
||||||
|
|
|
@ -49,6 +49,8 @@ dependencyResolutionManagement {
|
||||||
|
|
||||||
library("brotli", "org.brotli", "dec").version("0.1.2")
|
library("brotli", "org.brotli", "dec").version("0.1.2")
|
||||||
|
|
||||||
|
library("palette", "androidx.palette", "palette").version("1.0.0")
|
||||||
|
|
||||||
library("desugaring", "com.android.tools", "desugar_jdk_libs").version("1.1.5")
|
library("desugaring", "com.android.tools", "desugar_jdk_libs").version("1.1.5")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue