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.accompanist.systemuicontroller)
implementation(libs.palette)
implementation(libs.exoplayer)

View file

@ -5,6 +5,7 @@ import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.content.SharedPreferences
import android.graphics.Bitmap
import android.net.Uri
import android.os.Bundle
import android.os.IBinder
@ -34,6 +35,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.neverEqualPolicy
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.Alignment
@ -47,6 +49,7 @@ import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.valentinilk.shimmer.LocalShimmerTheme
import com.valentinilk.shimmer.defaultShimmerTheme
import it.vfsfitvnm.vimusic.enums.ColorPaletteMode
import it.vfsfitvnm.vimusic.enums.ColorPaletteName
import it.vfsfitvnm.vimusic.enums.ThumbnailRoundness
import it.vfsfitvnm.vimusic.service.PlayerService
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.Dimensions
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.utils.colorPaletteModeKey
import it.vfsfitvnm.vimusic.utils.colorPaletteNameKey
import it.vfsfitvnm.vimusic.utils.getEnum
import it.vfsfitvnm.vimusic.utils.intent
import it.vfsfitvnm.vimusic.utils.listener
import it.vfsfitvnm.vimusic.utils.preferences
import it.vfsfitvnm.vimusic.utils.rememberHapticFeedback
import it.vfsfitvnm.vimusic.utils.thumbnailRoundnessKey
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
class MainActivity : ComponentActivity() {
private val serviceConnection = object : ServiceConnection {
@ -103,36 +113,84 @@ class MainActivity : ComponentActivity() {
uri = intent?.data
setContent {
val coroutineScope = rememberCoroutineScope()
val isSystemInDarkTheme = isSystemInDarkTheme()
var appearance by remember(isSystemInDarkTheme) {
with(preferences) {
val colorPaletteName = getEnum(colorPaletteNameKey, ColorPaletteName.Dynamic)
val colorPaletteMode = getEnum(colorPaletteModeKey, ColorPaletteMode.System)
val thumbnailRoundness =
getEnum(thumbnailRoundnessKey, ThumbnailRoundness.Light)
val colorPalette =
colorPaletteOf(colorPaletteName, colorPaletteMode, isSystemInDarkTheme)
mutableStateOf(
Appearance(
colorPalette = colorPaletteMode.palette(isSystemInDarkTheme),
typography = colorPaletteMode.typography(isSystemInDarkTheme),
colorPalette = colorPalette,
typography = typographyOf(colorPalette.text),
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 =
SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, key ->
when (key) {
colorPaletteModeKey -> {
val colorPaletteMode =
sharedPreferences.getEnum(key, ColorPaletteMode.System)
colorPaletteNameKey, colorPaletteModeKey -> {
val colorPaletteName =
sharedPreferences.getEnum(colorPaletteNameKey, ColorPaletteName.Dynamic)
appearance = appearance.copy(
colorPalette = colorPaletteMode.palette(isSystemInDarkTheme),
typography = colorPaletteMode.typography(isSystemInDarkTheme),
)
val colorPaletteMode =
sharedPreferences.getEnum(colorPaletteModeKey, ColorPaletteMode.System)
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 -> {
val thumbnailRoundness =
@ -148,7 +206,14 @@ class MainActivity : ComponentActivity() {
with(preferences) {
registerOnSharedPreferenceChangeListener(listener)
val colorPaletteName = getEnum(colorPaletteNameKey, ColorPaletteName.Dynamic)
if (colorPaletteName == ColorPaletteName.Dynamic) {
setDynamicPalette(getEnum(colorPaletteModeKey, ColorPaletteMode.System))
}
onDispose {
bitmapListenerJob?.cancel()
binder?.setBitmapListener(null)
unregisterOnSharedPreferenceChangeListener(listener)
}
}
@ -193,7 +258,7 @@ class MainActivity : ComponentActivity() {
SideEffect {
systemUiController.setSystemBarsColor(
appearance.colorPalette.background,
appearance.colorPalette.background1,
!appearance.colorPalette.isDark
)
}
@ -211,7 +276,7 @@ class MainActivity : ComponentActivity() {
BoxWithConstraints(
modifier = Modifier
.fillMaxSize()
.background(appearance.colorPalette.background)
.background(appearance.colorPalette.background0)
) {
when (val uri = uri) {
null -> {

View file

@ -1,81 +1,7 @@
package it.vfsfitvnm.vimusic.enums
import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.PlatformTextStyle
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import it.vfsfitvnm.vimusic.R
import it.vfsfitvnm.vimusic.ui.styling.BlackColorPalette
import it.vfsfitvnm.vimusic.ui.styling.ColorPalette
import it.vfsfitvnm.vimusic.ui.styling.DarkColorPalette
import it.vfsfitvnm.vimusic.ui.styling.LightColorPalette
import it.vfsfitvnm.vimusic.ui.styling.Typography
enum class ColorPaletteMode {
Light,
Dark,
Black,
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),
)
}
System
}

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 var lastUri: Uri? = null
private var lastBitmap: Bitmap? = null
var lastBitmap: Bitmap? = null
private var lastIsSystemInDarkMode = false
private var lastEnqueued: Disposable? = null
@ -27,6 +27,12 @@ class BitmapProvider(
val bitmap: Bitmap
get() = lastBitmap ?: defaultBitmap
var listener: ((Bitmap?) -> Unit)? = null
set(value) {
field = value
value?.invoke(lastBitmap)
}
init {
setDefaultBitmap()
}
@ -56,14 +62,18 @@ class BitmapProvider(
lastEnqueued = applicationContext.imageLoader.enqueue(
ImageRequest.Builder(applicationContext)
.data(uri.thumbnail(bitmapSize))
.allowHardware(false)
.listener(
onError = { _, _ ->
lastBitmap = null
onDone(bitmap)
listener?.invoke(lastBitmap)
},
onSuccess = { _, result ->
lastBitmap = (result.drawable as BitmapDrawable).bitmap
onDone(bitmap)
println("invoking listener")
listener?.invoke(lastBitmap)
}
)
.build()

View file

@ -11,6 +11,7 @@ import android.content.Intent
import android.content.IntentFilter
import android.content.SharedPreferences
import android.content.res.Configuration
import android.graphics.Bitmap
import android.graphics.Color
import android.media.MediaMetadata
import android.media.session.MediaSession
@ -680,6 +681,13 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
var isLoadingRadio by mutableStateOf(false)
private set
val lastBitmap: Bitmap?
get() = bitmapProvider.lastBitmap
fun setBitmapListener(listener: ((Bitmap?) -> Unit)?) {
bitmapProvider.listener = listener
}
fun startSleepTimer(delayMillis: Long) {
timerJob?.cancel()

View file

@ -153,9 +153,9 @@ fun TextFieldDialog(
)
ChunkyButton(
backgroundColor = colorPalette.primaryContainer,
backgroundColor = colorPalette.accent,
text = doneText,
textStyle = typography.xs.semiBold.color(colorPalette.onPrimaryContainer),
textStyle = typography.xs.semiBold.color(colorPalette.onAccent),
shape = RoundedCornerShape(36.dp),
onClick = {
if (isTextInputValid(textFieldValue.text)) {
@ -210,9 +210,9 @@ fun ConfirmationDialog(
)
ChunkyButton(
backgroundColor = colorPalette.primaryContainer,
backgroundColor = colorPalette.accent,
text = confirmText,
textStyle = typography.xs.semiBold.color(colorPalette.onPrimaryContainer),
textStyle = typography.xs.semiBold.color(colorPalette.onAccent),
shape = RoundedCornerShape(36.dp),
onClick = {
onConfirm()
@ -242,7 +242,7 @@ inline fun DefaultDialog(
modifier = modifier
.padding(all = 48.dp)
.background(
color = colorPalette.elevatedBackground,
color = colorPalette.background1,
shape = RoundedCornerShape(8.dp)
)
.padding(horizontal = 24.dp, vertical = 16.dp),
@ -268,7 +268,7 @@ inline fun <T> ValueSelectorDialog(
modifier = modifier
.padding(all = 48.dp)
.background(
color = colorPalette.elevatedBackground,
color = colorPalette.background1,
shape = RoundedCornerShape(8.dp)
)
.padding(vertical = 16.dp),
@ -305,12 +305,12 @@ inline fun <T> ValueSelectorDialog(
modifier = Modifier
.size(18.dp)
.background(
color = colorPalette.primaryContainer,
color = colorPalette.accent,
shape = CircleShape
)
) {
drawCircle(
color = colorPalette.onPrimaryContainer,
color = colorPalette.onAccent,
radius = 4.dp.toPx(),
center = size.center,
shadow = Shadow(

View file

@ -35,7 +35,7 @@ fun DropDownSection(content: @Composable ColumnScope.() -> Unit) {
elevation = 2.dp,
shape = RoundedCornerShape(16.dp)
)
.background(colorPalette.elevatedBackground)
.background(colorPalette.background1)
.width(IntrinsicSize.Max),
content = content
)
@ -60,14 +60,14 @@ fun DropDownTextItem(
DropDownTextItem(
text = text,
textColor = if (isSelected) {
colorPalette.onPrimaryContainer
colorPalette.onAccent
} else {
colorPalette.textSecondary
},
backgroundColor = if (isSelected) {
colorPalette.primaryContainer
colorPalette.accent
} else {
colorPalette.elevatedBackground
colorPalette.background1
},
onClick = onClick
)
@ -95,7 +95,7 @@ fun DropDownTextItem(
interactionSource = remember { MutableInteractionSource() },
onClick = onClick
)
.background(backgroundColor ?: colorPalette.elevatedBackground)
.background(backgroundColor ?: colorPalette.background1)
.fillMaxWidth()
.widthIn(min = 124.dp, max = 248.dp)
.padding(

View file

@ -536,9 +536,9 @@ fun MediaItemMenu(
)
ChunkyButton(
backgroundColor = colorPalette.primaryContainer,
backgroundColor = colorPalette.accent,
text = "Set",
textStyle = typography.xs.semiBold.color(colorPalette.onPrimaryContainer),
textStyle = typography.xs.semiBold.color(colorPalette.onAccent),
shape = RoundedCornerShape(36.dp),
isEnabled = hours > 0 || minutes > 0,
onClick = {

View file

@ -44,7 +44,7 @@ inline fun Menu(
.verticalScroll(rememberScrollState())
.fillMaxWidth()
.background(
color = colorPalette.elevatedBackground,
color = colorPalette.background1,
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)
)
.padding(top = 8.dp)

View file

@ -26,8 +26,8 @@ fun Switch(
) {
val (colorPalette) = LocalAppearance.current
val backgroundColor by animateColorAsState(if (isChecked) colorPalette.primaryContainer else colorPalette.lightBackground)
val color by animateColorAsState(if (isChecked) colorPalette.onPrimaryContainer else colorPalette.textDisabled)
val backgroundColor by animateColorAsState(if (isChecked) colorPalette.accent else colorPalette.background1)
val color by animateColorAsState(if (isChecked) colorPalette.onAccent else colorPalette.textDisabled)
val offset by animateDpAsState(if (isChecked) 36.dp else 12.dp)
Spacer(

View file

@ -13,6 +13,7 @@ import androidx.compose.material.ripple.rememberRipple
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
@ -41,14 +42,14 @@ fun TextCard(
enabled = onClick != null,
onClick = onClick ?: {}
)
.background(colorPalette.lightBackground)
.background(colorPalette.background1)
.padding(horizontal = 16.dp, vertical = 16.dp)
) {
icon?.let {
Image(
painter = painterResource(icon),
contentDescription = null,
colorFilter = iconColor ?: ColorFilter.tint(colorPalette.red),
colorFilter = iconColor ?: ColorFilter.tint(Color.Red),
modifier = Modifier
.padding(bottom = 16.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.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
import it.vfsfitvnm.vimusic.ui.styling.shimmer
import kotlin.random.Random
@Composable
fun TextPlaceholder(
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
color: Color = LocalAppearance.current.colorPalette.shimmer
) {
val (colorPalette) = LocalAppearance.current
Spacer(
modifier = modifier
.padding(vertical = 4.dp)
.background(color = colorPalette.darkGray, shape = RoundedCornerShape(0.dp))
.background(color)
.fillMaxWidth(remember { 0.25f + Random.nextFloat() * 0.5f })
.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.LocalAppearance
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.utils.asMediaItem
import it.vfsfitvnm.vimusic.utils.bold
@ -110,7 +111,7 @@ fun AlbumScreen(browseId: String) {
state = lazyListState,
contentPadding = PaddingValues(bottom = 72.dp),
modifier = Modifier
.background(colorPalette.background)
.background(colorPalette.background0)
.fillMaxSize()
) {
item {
@ -377,7 +378,7 @@ private fun LoadingOrError(
) {
Spacer(
modifier = Modifier
.background(color = colorPalette.darkGray, shape = ThumbnailRoundness.shape)
.background(color = colorPalette.shimmer, shape = ThumbnailRoundness.shape)
.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.clip
import androidx.compose.ui.geometry.center
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource
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.LocalAppearance
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.utils.asMediaItem
import it.vfsfitvnm.vimusic.utils.forcePlayAtIndex
@ -102,7 +104,7 @@ fun ArtistScreen(browseId: String) {
contentPadding = PaddingValues(bottom = 72.dp),
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.background(colorPalette.background)
.background(colorPalette.background0)
.fillMaxSize()
) {
item {
@ -213,7 +215,7 @@ fun ArtistScreen(browseId: String) {
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier
.background(colorPalette.background)
.background(colorPalette.background0)
.zIndex(1f)
.fillMaxWidth()
.padding(horizontal = 8.dp)
@ -271,7 +273,7 @@ fun ArtistScreen(browseId: String) {
Column(
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier
.background(colorPalette.background)
.background(colorPalette.background0)
.fillMaxWidth()
.padding(horizontal = 8.dp)
.padding(top = 32.dp)
@ -295,14 +297,14 @@ fun ArtistScreen(browseId: String) {
.width(48.dp)
) {
drawLine(
color = colorPalette.backgroundContainer,
color = colorPalette.background2,
start = size.center.copy(y = 0f),
end = size.center.copy(y = size.height),
strokeWidth = 2.dp.toPx()
)
drawCircle(
color = colorPalette.backgroundContainer,
color = colorPalette.background2,
center = size.center.copy(y = size.height),
radius = 4.dp.toPx()
)
@ -340,7 +342,7 @@ private fun LoadingOrError(
) {
Spacer(
modifier = Modifier
.background(color = colorPalette.darkGray, shape = CircleShape)
.background(color = colorPalette.shimmer, shape = CircleShape)
.size(Dimensions.thumbnails.artist)
)

View file

@ -85,7 +85,7 @@ fun BuiltInPlaylistScreen(builtInPlaylist: BuiltInPlaylist) {
state = lazyListState,
contentPadding = PaddingValues(bottom = Dimensions.collapsedPlayer),
modifier = Modifier
.background(colorPalette.background)
.background(colorPalette.background0)
.fillMaxSize()
) {
item {

View file

@ -38,25 +38,15 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.center
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.ClipOp
import androidx.compose.ui.graphics.Color
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.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.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import androidx.core.content.res.ResourcesCompat
import it.vfsfitvnm.route.RouteHandler
import it.vfsfitvnm.vimusic.Database
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.styling.Dimensions
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.views.BuiltInPlaylistItem
import it.vfsfitvnm.vimusic.ui.views.PlaylistPreviewItem
@ -186,7 +178,6 @@ fun HomeScreen() {
@Suppress("UNUSED_EXPRESSION") playlistPreviews
@Suppress("UNUSED_EXPRESSION") songCollection
val context = LocalContext.current
val binder = LocalPlayerServiceBinder.current
val isFirstLaunch by rememberPreference(isFirstLaunchKey, true)
@ -215,7 +206,7 @@ fun HomeScreen() {
state = lazyListState,
contentPadding = PaddingValues(bottom = 72.dp),
modifier = Modifier
.background(colorPalette.background)
.background(colorPalette.background0)
.fillMaxSize()
) {
item("topAppBar") {
@ -228,22 +219,20 @@ fun HomeScreen() {
contentDescription = null,
colorFilter = ColorFilter.tint(colorPalette.text),
modifier = Modifier
.clickable {
settingsRoute()
}
.clickable { settingsRoute() }
.padding(horizontal = 16.dp, vertical = 8.dp)
.run {
if (isFirstLaunch) {
drawBehind {
drawCircle(
color = colorPalette.red,
color = colorPalette.accent,
center = Offset(
x = size.width,
y = 0.dp.toPx()
),
radius = 4.dp.toPx(),
shadow = Shadow(
color = colorPalette.red,
color = colorPalette.accent,
blurRadius = 4.dp.toPx()
)
)
@ -255,88 +244,12 @@ fun HomeScreen() {
.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(
painter = painterResource(R.drawable.search),
contentDescription = null,
colorFilter = ColorFilter.tint(colorPalette.text),
modifier = Modifier
.clickable {
searchRoute("")
}
.clickable { searchRoute("") }
.padding(horizontal = 16.dp, vertical = 8.dp)
.size(24.dp)
)
@ -364,9 +277,7 @@ fun HomeScreen() {
contentDescription = null,
colorFilter = ColorFilter.tint(colorPalette.text),
modifier = Modifier
.clickable {
isCreatingANewPlaylist = true
}
.clickable { isCreatingANewPlaylist = true }
.padding(all = 8.dp)
.size(20.dp)
)
@ -381,18 +292,14 @@ fun HomeScreen() {
contentDescription = null,
colorFilter = ColorFilter.tint(colorPalette.text),
modifier = Modifier
.clickable {
isSortMenuDisplayed = true
}
.clickable { isSortMenuDisplayed = true }
.padding(horizontal = 8.dp, vertical = 8.dp)
.size(20.dp)
)
DropdownMenu(
isDisplayed = isSortMenuDisplayed,
onDismissRequest = {
isSortMenuDisplayed = false
}
onDismissRequest = { isSortMenuDisplayed = false }
) {
DropDownSection {
DropDownTextItem(
@ -520,7 +427,7 @@ fun HomeScreen() {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.background(colorPalette.background)
.background(colorPalette.background0)
.zIndex(1f)
.padding(horizontal = 8.dp)
.padding(top = 32.dp)
@ -649,17 +556,14 @@ fun HomeScreen() {
) {
BasicText(
text = song.formattedTotalPlayTime,
style = typography.xxs.semiBold.center.color(Color.White),
style = typography.xxs.semiBold.center.color(colorPalette.onOverlay),
maxLines = 2,
overflow = TextOverflow.Ellipsis,
modifier = Modifier
.fillMaxWidth()
.background(
brush = Brush.verticalGradient(
colors = listOf(
Color.Transparent,
Color.Black.copy(alpha = 0.75f)
)
colors = listOf(Color.Transparent, colorPalette.overlay)
),
shape = ThumbnailRoundness.shape
)

View file

@ -146,7 +146,7 @@ fun IntentUriScreen(uri: Uri) {
horizontalAlignment = Alignment.CenterHorizontally,
contentPadding = PaddingValues(bottom = Dimensions.collapsedPlayer),
modifier = Modifier
.background(colorPalette.background)
.background(colorPalette.background0)
.fillMaxSize()
) {
item {

View file

@ -128,7 +128,7 @@ fun LocalPlaylistScreen(playlistId: Long) {
state = lazyListState,
contentPadding = PaddingValues(bottom = Dimensions.collapsedPlayer),
modifier = Modifier
.background(colorPalette.background)
.background(colorPalette.background0)
.fillMaxSize()
) {
item {

View file

@ -33,6 +33,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.layout.ContentScale
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.LocalAppearance
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.utils.bold
import it.vfsfitvnm.vimusic.utils.center
@ -109,7 +111,7 @@ fun PlaylistScreen(browseId: String) {
state = lazyListState,
contentPadding = PaddingValues(bottom = 72.dp),
modifier = Modifier
.background(colorPalette.background)
.background(colorPalette.background0)
.fillMaxSize()
) {
item {
@ -396,7 +398,7 @@ private fun LoadingOrError(
) {
Spacer(
modifier = Modifier
.background(color = colorPalette.darkGray, shape = ThumbnailRoundness.shape)
.background(color = colorPalette.shimmer, shape = ThumbnailRoundness.shape)
.size(Dimensions.thumbnails.playlist)
)
@ -434,7 +436,7 @@ private fun LoadingOrError(
Spacer(
modifier = Modifier
.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.LocalAppearance
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.utils.asMediaItem
import it.vfsfitvnm.vimusic.utils.center
@ -129,7 +130,7 @@ fun SearchResultScreen(query: String, onSearchAgain: () -> Unit) {
horizontalAlignment = Alignment.CenterHorizontally,
contentPadding = PaddingValues(bottom = Dimensions.collapsedPlayer),
modifier = Modifier
.background(colorPalette.background)
.background(colorPalette.background0)
.fillMaxSize()
) {
item {
@ -200,9 +201,9 @@ fun SearchResultScreen(query: String, onSearchAgain: () -> Unit) {
),
),
value = searchFilter,
selectedBackgroundColor = colorPalette.primaryContainer,
unselectedBackgroundColor = colorPalette.lightBackground,
selectedTextStyle = typography.xs.medium.color(colorPalette.onPrimaryContainer),
selectedBackgroundColor = colorPalette.accent,
unselectedBackgroundColor = colorPalette.background1,
selectedTextStyle = typography.xs.medium.color(colorPalette.onAccent),
unselectedTextStyle = typography.xs.medium,
shape = RoundedCornerShape(36.dp),
onValueChanged = {
@ -281,7 +282,7 @@ fun SmallSongItemShimmer(
thumbnailSizeDp: Dp,
modifier: Modifier = Modifier
) {
val (colorPalette) = LocalAppearance.current
val (colorPalette, _, thumbnailShape) = LocalAppearance.current
Row(
verticalAlignment = Alignment.CenterVertically,
@ -290,7 +291,7 @@ fun SmallSongItemShimmer(
) {
Spacer(
modifier = Modifier
.background(color = colorPalette.darkGray, shape = ThumbnailRoundness.shape)
.background(color = colorPalette.shimmer, shape = thumbnailShape)
.size(thumbnailSizeDp)
)
@ -315,7 +316,7 @@ fun SmallArtistItemShimmer(
) {
Spacer(
modifier = Modifier
.background(color = colorPalette.darkGray, shape = CircleShape)
.background(color = colorPalette.shimmer, shape = CircleShape)
.size(thumbnailSizeDp)
)

View file

@ -41,6 +41,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
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.SolidColor
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)
.background(
color = colorPalette.lightBackground,
color = colorPalette.background1,
shape = CircleShape
)
.size(28.dp)
@ -228,13 +229,13 @@ fun SearchScreen(initialTextInput: String, onSearch: (String) -> Unit, onUri: (U
}
)
.fillMaxWidth()
.background(colorPalette.lightBackground)
.background(colorPalette.background1)
.padding(vertical = 16.dp, horizontal = 8.dp)
) {
Image(
painter = painterResource(R.drawable.link),
contentDescription = null,
colorFilter = ColorFilter.tint(colorPalette.darkGray),
colorFilter = ColorFilter.tint( Color.Black),
modifier = Modifier
.padding(horizontal = 8.dp)
.size(20.dp)
@ -262,17 +263,16 @@ fun SearchScreen(initialTextInput: String, onSearch: (String) -> Unit, onUri: (U
modifier = Modifier
.clickable(
indication = rememberRipple(bounded = true),
interactionSource = remember { MutableInteractionSource() }
) {
onSearch(searchQuery.query)
}
interactionSource = remember { MutableInteractionSource() },
onClick = { onSearch(searchQuery.query) }
)
.fillMaxWidth()
.padding(vertical = 16.dp, horizontal = 8.dp)
) {
Image(
painter = painterResource(R.drawable.time),
contentDescription = null,
colorFilter = ColorFilter.tint(colorPalette.darkGray),
colorFilter = ColorFilter.tint(colorPalette.textDisabled),
modifier = Modifier
.padding(horizontal = 8.dp)
.size(20.dp)
@ -289,7 +289,7 @@ fun SearchScreen(initialTextInput: String, onSearch: (String) -> Unit, onUri: (U
Image(
painter = painterResource(R.drawable.close),
contentDescription = null,
colorFilter = ColorFilter.tint(colorPalette.darkGray),
colorFilter = ColorFilter.tint(colorPalette.textDisabled),
modifier = Modifier
.clickable {
query {
@ -303,7 +303,7 @@ fun SearchScreen(initialTextInput: String, onSearch: (String) -> Unit, onUri: (U
Image(
painter = painterResource(R.drawable.arrow_forward),
contentDescription = null,
colorFilter = ColorFilter.tint(colorPalette.darkGray),
colorFilter = ColorFilter.tint(colorPalette.textDisabled),
modifier = Modifier
.clickable {
textFieldValue = TextFieldValue(
@ -325,10 +325,9 @@ fun SearchScreen(initialTextInput: String, onSearch: (String) -> Unit, onUri: (U
modifier = Modifier
.clickable(
indication = rememberRipple(bounded = true),
interactionSource = remember { MutableInteractionSource() }
) {
onSearch(suggestion)
}
interactionSource = remember { MutableInteractionSource() },
onClick = { onSearch(suggestion) }
)
.fillMaxWidth()
.padding(vertical = 16.dp, horizontal = 8.dp)
) {
@ -346,11 +345,10 @@ fun SearchScreen(initialTextInput: String, onSearch: (String) -> Unit, onUri: (U
.weight(1f)
)
Image(
painter = painterResource(R.drawable.arrow_forward),
contentDescription = null,
colorFilter = ColorFilter.tint(colorPalette.darkGray),
colorFilter = ColorFilter.tint(Color.Black),
modifier = Modifier
.clickable {
textFieldValue = TextFieldValue(

View file

@ -76,7 +76,7 @@ fun SettingsScreen() {
Column(
modifier = Modifier
.background(colorPalette.background)
.background(colorPalette.background0)
.fillMaxSize()
.verticalScroll(scrollState)
.padding(bottom = 72.dp)
@ -137,10 +137,10 @@ fun SettingsScreen() {
Image(
painter = painterResource(icon),
contentDescription = null,
colorFilter = ColorFilter.tint(colorPalette.background),
colorFilter = ColorFilter.tint(colorPalette.text),
modifier = Modifier
.align(Alignment.Center)
.size(18.dp)
.size(16.dp)
)
}
@ -166,11 +166,11 @@ fun SettingsScreen() {
.size(8.dp)
) {
drawCircle(
color = colorPalette.red,
color = colorPalette.accent,
center = size.center.copy(x = size.width),
radius = 4.dp.toPx(),
shadow = Shadow(
color = colorPalette.red,
color = colorPalette.accent,
blurRadius = 4.dp.toPx()
)
)
@ -180,7 +180,7 @@ fun SettingsScreen() {
}
Entry(
color = colorPalette.magenta,
color = colorPalette.background2,
icon = R.drawable.color_palette,
title = "Appearance",
description = "Change the colors and shapes",
@ -188,7 +188,7 @@ fun SettingsScreen() {
)
Entry(
color = colorPalette.blue,
color = colorPalette.background2,
icon = R.drawable.play,
title = "Player & Audio",
description = "Player and audio settings",
@ -196,7 +196,7 @@ fun SettingsScreen() {
)
Entry(
color = colorPalette.cyan,
color = colorPalette.background2,
icon = R.drawable.server,
title = "Cache",
description = "Manage the used space",
@ -204,7 +204,7 @@ fun SettingsScreen() {
)
Entry(
color = colorPalette.orange,
color = colorPalette.background2,
icon = R.drawable.save,
title = "Backup & Restore",
description = "Backup and restore the database",
@ -212,7 +212,7 @@ fun SettingsScreen() {
)
Entry(
color = colorPalette.green,
color = colorPalette.background2,
icon = R.drawable.shapes,
title = "Other",
description = "Advanced settings",
@ -224,7 +224,7 @@ fun SettingsScreen() {
)
Entry(
color = colorPalette.magenta,
color = colorPalette.background2,
icon = R.drawable.information,
title = "About",
description = "App version and social links",
@ -241,6 +241,7 @@ inline fun <reified T : Enum<T>> EnumValueSelectorSettingsEntry(
selectedValue: T,
crossinline onValueSelected: (T) -> Unit,
modifier: Modifier = Modifier,
isEnabled: Boolean = true,
crossinline valueText: (T) -> String = Enum<T>::name
) {
ValueSelectorSettingsEntry(
@ -249,6 +250,7 @@ inline fun <reified T : Enum<T>> EnumValueSelectorSettingsEntry(
values = enumValues<T>().toList(),
onValueSelected = onValueSelected,
modifier = modifier,
isEnabled = isEnabled,
valueText = valueText
)
}
@ -260,6 +262,7 @@ inline fun <T> ValueSelectorSettingsEntry(
values: List<T>,
crossinline onValueSelected: (T) -> Unit,
modifier: Modifier = Modifier,
isEnabled: Boolean = true,
crossinline valueText: (T) -> String = { it.toString() }
) {
var isShowingDialog by remember {
@ -283,6 +286,7 @@ inline fun <T> ValueSelectorSettingsEntry(
title = title,
text = valueText(selectedValue),
modifier = modifier,
isEnabled = isEnabled,
onClick = {
isShowingDialog = true
}
@ -428,7 +432,7 @@ fun SettingsEntryGroupText(
BasicText(
text = title.uppercase(),
style = typography.xxs.semiBold.copy(colorPalette.blue),
style = typography.xxs.semiBold.copy(colorPalette.accent),
modifier = modifier
.padding(start = 24.dp, top = 24.dp)
.padding(horizontal = 32.dp)

View file

@ -42,7 +42,7 @@ fun AboutScreen() {
Column(
modifier = Modifier
.background(colorPalette.background)
.background(colorPalette.background0)
.fillMaxSize()
.verticalScroll(scrollState)
.padding(bottom = 72.dp)

View file

@ -21,6 +21,7 @@ import androidx.compose.ui.unit.dp
import it.vfsfitvnm.route.RouteHandler
import it.vfsfitvnm.vimusic.R
import it.vfsfitvnm.vimusic.enums.ColorPaletteMode
import it.vfsfitvnm.vimusic.enums.ColorPaletteName
import it.vfsfitvnm.vimusic.enums.ThumbnailRoundness
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
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.styling.LocalAppearance
import it.vfsfitvnm.vimusic.utils.colorPaletteModeKey
import it.vfsfitvnm.vimusic.utils.colorPaletteNameKey
import it.vfsfitvnm.vimusic.utils.isShowingThumbnailInLockscreenKey
import it.vfsfitvnm.vimusic.utils.rememberPreference
import it.vfsfitvnm.vimusic.utils.thumbnailRoundnessKey
@ -45,6 +47,7 @@ fun AppearanceSettingsScreen() {
host {
val (colorPalette) = LocalAppearance.current
var colorPaletteName by rememberPreference(colorPaletteNameKey, ColorPaletteName.Dynamic)
var colorPaletteMode by rememberPreference(colorPaletteModeKey, ColorPaletteMode.System)
var thumbnailRoundness by rememberPreference(
thumbnailRoundnessKey,
@ -57,7 +60,7 @@ fun AppearanceSettingsScreen() {
Column(
modifier = Modifier
.background(colorPalette.background)
.background(colorPalette.background0)
.fillMaxSize()
.verticalScroll(scrollState)
.padding(bottom = 72.dp)
@ -81,9 +84,18 @@ fun AppearanceSettingsScreen() {
SettingsEntryGroupText(title = "COLORS")
EnumValueSelectorSettingsEntry(
title = "Theme",
selectedValue = colorPaletteName,
onValueSelected = {
colorPaletteName = it
}
)
EnumValueSelectorSettingsEntry(
title = "Theme mode",
selectedValue = colorPaletteMode,
isEnabled = colorPaletteName != ColorPaletteName.PureBlack,
onValueSelected = {
colorPaletteMode = it
}

View file

@ -119,7 +119,7 @@ fun BackupAndRestoreScreen() {
Column(
modifier = Modifier
.background(colorPalette.background)
.background(colorPalette.background0)
.fillMaxSize()
.verticalScroll(scrollState)
.padding(bottom = 72.dp)

View file

@ -67,7 +67,7 @@ fun CacheSettingsScreen() {
Column(
modifier = Modifier
.background(colorPalette.background)
.background(colorPalette.background0)
.fillMaxSize()
.verticalScroll(scrollState)
.padding(bottom = 72.dp)

View file

@ -71,7 +71,7 @@ fun OtherSettingsScreen() {
Column(
modifier = Modifier
.background(colorPalette.background)
.background(colorPalette.background0)
.fillMaxSize()
.verticalScroll(scrollState)
.padding(bottom = 72.dp)

View file

@ -63,7 +63,7 @@ fun PlayerSettingsScreen() {
Column(
modifier = Modifier
.background(colorPalette.background)
.background(colorPalette.background0)
.fillMaxSize()
.verticalScroll(scrollState)
.padding(bottom = 72.dp)

View file

@ -1,83 +1,142 @@
package it.vfsfitvnm.vimusic.ui.styling
import android.graphics.Bitmap
import androidx.compose.runtime.Immutable
import androidx.compose.ui.graphics.Color
import androidx.palette.graphics.Palette
import it.vfsfitvnm.vimusic.enums.ColorPaletteMode
import it.vfsfitvnm.vimusic.enums.ColorPaletteName
@Immutable
data class ColorPalette(
val background: Color,
val elevatedBackground: Color,
val lightBackground: Color,
val backgroundContainer: Color,
val background0: Color,
val background1: Color,
val background2: Color,
val accent: Color,
val onAccent: Color,
val red: Color = Color(0xffbf4040),
val blue: Color = Color(0xFF4472CF),
val text: Color,
val textSecondary: 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 DarkColorPalette = ColorPalette(
background = Color(0xff16171d),
lightBackground = Color(0xff1f2029),
elevatedBackground = Color(0xff1f2029),
backgroundContainer = Color(0xff2b2d3b),
val DefaultDarkColorPalette = ColorPalette(
background0 = Color(0xff16171d),
background1 = Color(0xff1f2029),
background2 = Color(0xff2b2d3b),
text = Color(0xffe1e1e2),
textSecondary = Color(0xffa3a4a6),
textDisabled = Color(0xff6f6f73),
lightGray = Color(0xfff8f8f8),
gray = Color(0xFFE5E5E5),
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,
accent = Color(0xff4046bf),
onAccent = Color.White,
isDark = true
)
val BlackColorPalette = DarkColorPalette.copy(
background = Color.Black,
lightBackground = Color(0xff0d0d12),
elevatedBackground = Color(0xff0d0d12),
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),
val DefaultLightColorPalette = ColorPalette(
background0 = Color(0xfffdfdfe),
background1 = Color(0xfff8f8fc),
background2 = Color(0xffeaeaf5),
text = Color(0xff212121),
textSecondary = Color(0xFF656566),
textDisabled = Color(0xFF9d9d9d),
blue = Color(0xff4059bf),
red = Color(0xffbf4040),
green = Color(0xff7fbf40),
orange = Color(0xffe8730e),
magenta = Color(0xffbb4da4),
cyan = Color(0xFF4DBBB2),
primaryContainer = Color(0xff4046bf),
onPrimaryContainer = Color.White,
iconOnPrimaryContainer = Color.White,
accent = Color(0xff4046bf),
onAccent = Color.White,
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
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.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
data class Typography(
@ -11,3 +20,47 @@ data class Typography(
val m: 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.screens.SmallSongItemShimmer
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.onOverlay
import it.vfsfitvnm.vimusic.ui.styling.px
import it.vfsfitvnm.vimusic.utils.medium
import it.vfsfitvnm.vimusic.utils.rememberMediaItemIndex
@ -91,6 +91,7 @@ fun CurrentPlaylistView(
.nestedScroll(remember {
layoutState.nestedScrollConnection(lazyListState.firstVisibleItemIndex == 0 && lazyListState.firstVisibleItemScrollOffset == 0)
})
.background(colorPalette.background1)
) {
items(
items = windows,
@ -137,7 +138,7 @@ fun CurrentPlaylistView(
) {
if (shouldBePlaying) {
MusicBars(
color = LightColorPalette.background,
color = colorPalette.onOverlay,
modifier = Modifier
.height(24.dp)
)
@ -145,7 +146,7 @@ fun CurrentPlaylistView(
Image(
painter = painterResource(R.drawable.play),
contentDescription = null,
colorFilter = ColorFilter.tint(LightColorPalette.background),
colorFilter = ColorFilter.tint(colorPalette.onOverlay),
modifier = Modifier
.size(24.dp)
)
@ -164,7 +165,6 @@ fun CurrentPlaylistView(
.size(20.dp)
)
},
backgroundColor = colorPalette.background,
modifier = Modifier
// .animateItemPlacement()
.verticalDragAfterLongPressToReorder(
@ -211,7 +211,7 @@ fun CurrentPlaylistView(
onClick = layoutState::collapseSoft
)
.height(64.dp)
.background(colorPalette.elevatedBackground)
.background(colorPalette.background2)
.fillMaxWidth()
.padding(horizontal = 8.dp)
.align(Alignment.BottomCenter)

View file

@ -7,6 +7,8 @@ import androidx.compose.foundation.layout.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
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.res.painterResource
import androidx.compose.ui.unit.dp
@ -18,6 +20,7 @@ import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
@ExperimentalAnimationApi
@Composable
fun PlayerBottomSheet(
backgroundColorProvider: () -> Color,
layoutState: BottomSheetState,
onGlobalRouteEmitted: () -> Unit,
modifier: Modifier = Modifier,
@ -31,7 +34,7 @@ fun PlayerBottomSheet(
collapsedContent = {
Box(
modifier = Modifier
.background(colorPalette.background)
.drawBehind { drawRect(backgroundColorProvider()) }
.fillMaxSize()
) {
Image(
@ -40,7 +43,6 @@ fun PlayerBottomSheet(
colorFilter = ColorFilter.tint(colorPalette.text),
modifier = Modifier
.align(Alignment.Center)
.padding(all = 8.dp)
.size(18.dp)
)
@ -52,7 +54,7 @@ fun PlayerBottomSheet(
layoutState = layoutState,
onGlobalRouteEmitted = onGlobalRouteEmitted,
modifier = Modifier
.background(colorPalette.background)
.background(colorPalette.background0)
.fillMaxSize()
)
}

View file

@ -29,6 +29,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Offset
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.styling.Dimensions
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.views.player.Controls
import it.vfsfitvnm.vimusic.ui.views.player.Thumbnail
@ -70,7 +72,7 @@ fun PlayerView(
) {
val menuState = LocalMenuState.current
val (colorPalette, typography) = LocalAppearance.current
val (colorPalette, typography, thumbnailShape) = LocalAppearance.current
val binder = LocalPlayerServiceBinder.current
val context = LocalContext.current
val configuration = LocalConfiguration.current
@ -96,30 +98,32 @@ fun PlayerView(
horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.background(colorPalette.elevatedBackground)
.background(colorPalette.background1)
.fillMaxSize()
.drawBehind {
val progress =
positionAndDuration.first.toFloat() / positionAndDuration.second.absoluteValue
val offset = Dimensions.thumbnails.player.songPreview.toPx()
drawLine(
color = colorPalette.text,
start = Offset(x = offset, y = 1.dp.toPx()),
end = Offset(
x = ((size.width - offset) * progress) + offset,
y = 1.dp.toPx()
),
color = colorPalette.collapsedPlayerProgressBar,
start = Offset(x = 0f, y = 1.dp.toPx()),
end = Offset(x = size.width * progress, y = 1.dp.toPx()),
strokeWidth = 2.dp.toPx()
)
}
) {
Spacer(
modifier = Modifier
.width(2.dp)
)
AsyncImage(
model = mediaItem.mediaMetadata.artworkUri.thumbnail(Dimensions.thumbnails.player.songPreview.px),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier
.size(Dimensions.thumbnails.player.songPreview)
.clip(thumbnailShape)
.size(48.dp)
)
Column(
@ -206,7 +210,7 @@ fun PlayerView(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.padding(bottom = 64.dp)
.background(colorPalette.background)
.background(colorPalette.background1)
.padding(top = 16.dp)
) {
Box(
@ -242,7 +246,7 @@ fun PlayerView(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.padding(bottom = 64.dp)
.background(colorPalette.background)
.background(colorPalette.background1)
.padding(top = 32.dp)
) {
Box(
@ -355,6 +359,7 @@ fun PlayerView(
)
}
},
backgroundColorProvider = { colorPalette.background2 },
modifier = Modifier
.align(Alignment.BottomCenter)
)

View file

@ -91,7 +91,7 @@ fun PlaylistPreviewItem(
contentScale = ContentScale.Crop,
modifier = Modifier
.clip(thumbnailShape)
.border(width = 1.dp, color = colorPalette.lightBackground)
.border(width = 1.dp, color = colorPalette.background1)
.align(alignment)
.size(thumbnailSize)
)
@ -143,7 +143,7 @@ fun PlaylistItem(
Box(
modifier = modifier
.clip(thumbnailShape)
.background(colorPalette.lightBackground)
.background(colorPalette.background1)
.size(thumbnailSize * 2)
) {
Box(

View file

@ -2,7 +2,6 @@ package it.vfsfitvnm.vimusic.ui.views
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
@ -22,7 +21,6 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextOverflow
@ -48,7 +46,6 @@ fun SongItem(
onClick: () -> Unit,
menuContent: @Composable () -> Unit,
modifier: Modifier = Modifier,
backgroundColor: Color? = null,
onThumbnailContent: (@Composable BoxScope.() -> Unit)? = null,
trailingContent: (@Composable () -> Unit)? = null
) {
@ -64,7 +61,6 @@ fun SongItem(
onClick = onClick,
onThumbnailContent = onThumbnailContent,
trailingContent = trailingContent,
backgroundColor = backgroundColor,
modifier = modifier,
)
}
@ -78,7 +74,6 @@ fun SongItem(
onClick: () -> Unit,
menuContent: @Composable () -> Unit,
modifier: Modifier = Modifier,
backgroundColor: Color? = null,
onThumbnailContent: (@Composable BoxScope.() -> Unit)? = null,
trailingContent: (@Composable () -> Unit)? = null
) {
@ -90,7 +85,6 @@ fun SongItem(
menuContent = menuContent,
onClick = onClick,
onThumbnailContent = onThumbnailContent,
backgroundColor = backgroundColor,
trailingContent = trailingContent,
modifier = modifier,
)
@ -107,7 +101,6 @@ fun SongItem(
onClick: () -> Unit,
menuContent: @Composable () -> Unit,
modifier: Modifier = Modifier,
backgroundColor: Color? = null,
onThumbnailContent: (@Composable BoxScope.() -> Unit)? = null,
trailingContent: (@Composable () -> Unit)? = null
) {
@ -134,7 +127,6 @@ fun SongItem(
}
},
menuContent = menuContent,
backgroundColor = backgroundColor,
trailingContent = trailingContent,
modifier = modifier,
)
@ -151,11 +143,10 @@ fun SongItem(
startContent: @Composable () -> Unit,
menuContent: @Composable () -> Unit,
modifier: Modifier = Modifier,
backgroundColor: Color? = null,
trailingContent: (@Composable () -> Unit)? = null
) {
val menuState = LocalMenuState.current
val (colorPalette, typography) = LocalAppearance.current
val (_, typography) = LocalAppearance.current
Row(
verticalAlignment = Alignment.CenterVertically,
@ -171,7 +162,6 @@ fun SongItem(
)
.fillMaxWidth()
.padding(vertical = Dimensions.itemsVerticalPadding)
.background(backgroundColor ?: colorPalette.background)
.padding(start = 16.dp, end = if (trailingContent == null) 16.dp else 8.dp)
) {
startContent()

View file

@ -2,6 +2,7 @@ package it.vfsfitvnm.vimusic.ui.views.player
import android.text.format.DateUtils
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
@ -40,6 +41,7 @@ import it.vfsfitvnm.vimusic.models.Song
import it.vfsfitvnm.vimusic.query
import it.vfsfitvnm.vimusic.ui.components.SeekBar
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.rememberRepeatMode
import it.vfsfitvnm.vimusic.utils.secondary
@ -70,7 +72,7 @@ fun Controls(
Database.likedAt(mediaItem.mediaId).distinctUntilChanged()
}.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(
horizontalAlignment = Alignment.CenterHorizontally,
@ -121,7 +123,7 @@ fun Controls(
scrubbingPosition = null
},
color = colorPalette.text,
backgroundColor = colorPalette.backgroundContainer,
backgroundColor = colorPalette.background2,
shape = RoundedCornerShape(8.dp)
)
@ -166,7 +168,7 @@ fun Controls(
Image(
painter = painterResource(R.drawable.heart),
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
.clickable {
query {
@ -211,7 +213,7 @@ fun Controls(
binder.player.play()
}
}
.background(color = colorPalette.backgroundContainer)
.background(colorPalette.background2)
.size(64.dp)
) {
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.TextFieldDialog
import it.vfsfitvnm.vimusic.ui.components.themed.TextPlaceholder
import it.vfsfitvnm.vimusic.ui.styling.BlackColorPalette
import it.vfsfitvnm.vimusic.ui.styling.DarkColorPalette
import it.vfsfitvnm.vimusic.ui.styling.PureBlackColorPalette
import it.vfsfitvnm.vimusic.ui.styling.DefaultDarkColorPalette
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.center
import it.vfsfitvnm.vimusic.utils.color
@ -88,7 +89,7 @@ fun Lyrics(
nestedScrollConnectionProvider: () -> NestedScrollConnection,
modifier: Modifier = Modifier
) {
val (_, typography) = LocalAppearance.current
val (colorPalette, typography) = LocalAppearance.current
val context = LocalContext.current
AnimatedVisibility(
@ -194,7 +195,7 @@ fun Lyrics(
) {
BasicText(
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
.background(Color.Black.copy(0.4f))
.padding(all = 8.dp)
@ -211,7 +212,7 @@ fun Lyrics(
) {
BasicText(
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
.background(Color.Black.copy(0.4f))
.padding(all = 8.dp)
@ -227,6 +228,7 @@ fun Lyrics(
) {
repeat(4) { index ->
TextPlaceholder(
color = colorPalette.onOverlayShimmer,
modifier = Modifier
.alpha(1f - index * 0.05f)
)
@ -269,7 +271,7 @@ fun Lyrics(
itemsIndexed(items = synchronizedLyrics.sentences) { index, sentence ->
BasicText(
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
.padding(vertical = 4.dp, horizontal = 32.dp)
)
@ -278,7 +280,7 @@ fun Lyrics(
} else {
BasicText(
text = lyrics,
style = typography.xs.center.medium.color(BlackColorPalette.text),
style = typography.xs.center.medium.color(PureBlackColorPalette.text),
modifier = Modifier
.nestedScroll(remember { nestedScrollConnectionProvider() })
.verticalFadingEdge()
@ -293,7 +295,7 @@ fun Lyrics(
Image(
painter = painterResource(R.drawable.ellipsis_horizontal),
contentDescription = null,
colorFilter = ColorFilter.tint(DarkColorPalette.text),
colorFilter = ColorFilter.tint(DefaultDarkColorPalette.text),
modifier = Modifier
.padding(all = 4.dp)
.clickable {

View file

@ -20,7 +20,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
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.utils.center
import it.vfsfitvnm.vimusic.utils.color
@ -64,7 +64,7 @@ fun PlaybackError(
) {
BasicText(
text = remember { messageProvider() },
style = typography.xs.center.medium.color(BlackColorPalette.text),
style = typography.xs.center.medium.color(PureBlackColorPalette.text),
modifier = Modifier
.background(Color.Black.copy(0.4f))
.padding(all = 8.dp)

View file

@ -25,7 +25,6 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
@ -35,8 +34,9 @@ import it.vfsfitvnm.vimusic.Database
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
import it.vfsfitvnm.vimusic.models.Format
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.onOverlay
import it.vfsfitvnm.vimusic.ui.styling.overlay
import it.vfsfitvnm.vimusic.utils.color
import it.vfsfitvnm.vimusic.utils.medium
import it.vfsfitvnm.vimusic.utils.rememberVolume
@ -53,7 +53,7 @@ fun StatsForNerds(
onDismiss: () -> Unit,
modifier: Modifier = Modifier
) {
val (_, typography) = LocalAppearance.current
val (colorPalette, typography) = LocalAppearance.current
val context = LocalContext.current
val binder = LocalPlayerServiceBinder.current ?: return
@ -105,7 +105,7 @@ fun StatsForNerds(
}
)
}
.background(Color.Black.copy(alpha = 0.8f))
.background(colorPalette.overlay)
.fillMaxSize()
) {
Row(
@ -117,50 +117,50 @@ fun StatsForNerds(
Column(horizontalAlignment = Alignment.End) {
BasicText(
text = "Id",
style = typography.xs.medium.color(BlackColorPalette.text)
style = typography.xs.medium.color(colorPalette.onOverlay)
)
BasicText(
text = "Volume",
style = typography.xs.medium.color(BlackColorPalette.text)
style = typography.xs.medium.color(colorPalette.onOverlay)
)
BasicText(
text = "Loudness",
style = typography.xs.medium.color(BlackColorPalette.text)
style = typography.xs.medium.color(colorPalette.onOverlay)
)
BasicText(
text = "Bitrate",
style = typography.xs.medium.color(BlackColorPalette.text)
style = typography.xs.medium.color(colorPalette.onOverlay)
)
BasicText(
text = "Size",
style = typography.xs.medium.color(BlackColorPalette.text)
style = typography.xs.medium.color(colorPalette.onOverlay)
)
BasicText(
text = "Cached",
style = typography.xs.medium.color(BlackColorPalette.text)
style = typography.xs.medium.color(colorPalette.onOverlay)
)
}
Column {
BasicText(
text = mediaId,
style = typography.xs.medium.color(BlackColorPalette.text)
style = typography.xs.medium.color(colorPalette.onOverlay)
)
BasicText(
text = "${volume.times(100).roundToInt()}%",
style = typography.xs.medium.color(BlackColorPalette.text)
style = typography.xs.medium.color(colorPalette.onOverlay)
)
BasicText(
text = format?.loudnessDb?.let { loudnessDb ->
"%.2f dB".format(loudnessDb)
} ?: "Unknown",
style = typography.xs.medium.color(BlackColorPalette.text)
style = typography.xs.medium.color(colorPalette.onOverlay)
)
BasicText(
text = format?.bitrate?.let { bitrate ->
"${bitrate / 1000} kbps"
} ?: "Unknown",
style = typography.xs.medium.color(BlackColorPalette.text)
style = typography.xs.medium.color(colorPalette.onOverlay)
)
BasicText(
text = format?.contentLength?.let { contentLength ->
@ -169,7 +169,7 @@ fun StatsForNerds(
contentLength
)
} ?: "Unknown",
style = typography.xs.medium.color(BlackColorPalette.text)
style = typography.xs.medium.color(colorPalette.onOverlay)
)
BasicText(
text = buildString {
@ -179,7 +179,7 @@ fun StatsForNerds(
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) {
BasicText(
text = "FETCH MISSING DATA",
style = typography.xxs.medium.color(BlackColorPalette.text),
style = typography.xxs.medium.color(colorPalette.onOverlay),
modifier = Modifier
.clickable(
indication = rememberRipple(bounded = true),

View file

@ -10,6 +10,7 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import androidx.core.content.edit
const val colorPaletteNameKey = "colorPaletteName"
const val colorPaletteModeKey = "colorPaletteMode"
const val thumbnailRoundnessKey = "thumbnailRoundness"
const val coilDiskCacheMaxSizeKey = "coilDiskCacheMaxSize"

View file

@ -49,6 +49,8 @@ dependencyResolutionManagement {
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")
}