Add dynamic theme (#159)

This commit is contained in:
vfsfitvnm 2022-08-10 13:09:35 +02:00
parent a26eebd806
commit 2716319339
42 changed files with 458 additions and 399 deletions

View file

@ -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)

View file

@ -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 -> {

View file

@ -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),
)
}
} }

View file

@ -0,0 +1,7 @@
package it.vfsfitvnm.vimusic.enums
enum class ColorPaletteName {
Default,
Dynamic,
PureBlack
}

View file

@ -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()

View file

@ -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()

View file

@ -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(

View file

@ -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(

View file

@ -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 = {

View file

@ -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)

View file

@ -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(

View file

@ -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)

View file

@ -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)
) )

View file

@ -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)
) )

View file

@ -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)
) )

View file

@ -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 {

View file

@ -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
) )

View file

@ -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 {

View file

@ -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 {

View file

@ -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)
) )
} }

View file

@ -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)
) )

View file

@ -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(

View file

@ -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)

View file

@ -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)

View file

@ -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
} }

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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),
)
}

View file

@ -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)

View file

@ -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()
) )
} }

View file

@ -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)
) )

View file

@ -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(

View file

@ -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()

View file

@ -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(

View file

@ -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 {

View file

@ -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)

View file

@ -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),

View file

@ -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"

View file

@ -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")
} }