mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-11 15:29:15 +01:00
fade between artwork themes instead of snapping
This commit is contained in:
@@ -162,11 +162,6 @@ fun AlbumDetailScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val gradientAlpha by animateFloatAsState(
|
|
||||||
targetValue = if (artwork != null) 1f else 0f,
|
|
||||||
animationSpec = tween(durationMillis = 600),
|
|
||||||
label = "gradientAlpha",
|
|
||||||
)
|
|
||||||
val barColor =
|
val barColor =
|
||||||
artwork?.let {
|
artwork?.let {
|
||||||
val mid = scrollPx + barHeightPx / 2f
|
val mid = scrollPx + barHeightPx / 2f
|
||||||
@@ -180,7 +175,7 @@ fun AlbumDetailScreen(
|
|||||||
HeroGradient(
|
HeroGradient(
|
||||||
colors = artwork,
|
colors = artwork,
|
||||||
scrollPx = { scrollPx },
|
scrollPx = { scrollPx },
|
||||||
modifier = Modifier.fillMaxSize().alpha(gradientAlpha),
|
modifier = Modifier.fillMaxSize(),
|
||||||
)
|
)
|
||||||
|
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
|
|||||||
@@ -0,0 +1,116 @@
|
|||||||
|
package com.subtracks.ui.theme
|
||||||
|
|
||||||
|
import androidx.compose.animation.core.Animatable
|
||||||
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.material3.ColorScheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.lerp
|
||||||
|
|
||||||
|
private const val THEME_TRANSITION_MS = 600
|
||||||
|
|
||||||
|
fun baseArtworkColors(): ArtworkColors =
|
||||||
|
ArtworkColors(
|
||||||
|
scheme = SubtracksColorScheme,
|
||||||
|
gradientHigh = SubtracksColorScheme.surfaceContainerHigh,
|
||||||
|
gradientLow = SubtracksColorScheme.background,
|
||||||
|
accents = listOf(SubtracksColorScheme.surfaceContainerHighest, SubtracksColorScheme.surfaceContainerLow),
|
||||||
|
darkPrimary = SubtracksColorScheme.background,
|
||||||
|
blobSeed = 0,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun rememberAnimatedArtworkColors(target: ArtworkColors?): ArtworkColors {
|
||||||
|
val base = remember { baseArtworkColors() }
|
||||||
|
var from by remember { mutableStateOf(target ?: base) }
|
||||||
|
var to by remember { mutableStateOf(target ?: base) }
|
||||||
|
val progress = remember { Animatable(1f) }
|
||||||
|
|
||||||
|
LaunchedEffect(target) {
|
||||||
|
val next = target ?: base
|
||||||
|
if (next !== to) {
|
||||||
|
from = to
|
||||||
|
to = next
|
||||||
|
progress.snapTo(0f)
|
||||||
|
progress.animateTo(1f, tween(durationMillis = THEME_TRANSITION_MS))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val fraction = progress.value
|
||||||
|
return remember(from, to, fraction) { lerpArtworkColors(from, to, fraction) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun lerpArtworkColors(
|
||||||
|
a: ArtworkColors,
|
||||||
|
b: ArtworkColors,
|
||||||
|
t: Float,
|
||||||
|
): ArtworkColors =
|
||||||
|
ArtworkColors(
|
||||||
|
scheme = lerpScheme(a.scheme, b.scheme, t),
|
||||||
|
gradientHigh = lerp(a.gradientHigh, b.gradientHigh, t),
|
||||||
|
gradientLow = lerp(a.gradientLow, b.gradientLow, t),
|
||||||
|
accents = b.accents.mapIndexed { index, color -> lerp(a.accents.getOrElse(index) { color }, color, t) },
|
||||||
|
darkPrimary = lerp(a.darkPrimary, b.darkPrimary, t),
|
||||||
|
blobSeed = b.blobSeed,
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun lerpScheme(
|
||||||
|
a: ColorScheme,
|
||||||
|
b: ColorScheme,
|
||||||
|
t: Float,
|
||||||
|
): ColorScheme =
|
||||||
|
a.copy(
|
||||||
|
primary = lerp(a.primary, b.primary, t),
|
||||||
|
onPrimary = lerp(a.onPrimary, b.onPrimary, t),
|
||||||
|
primaryContainer = lerp(a.primaryContainer, b.primaryContainer, t),
|
||||||
|
onPrimaryContainer = lerp(a.onPrimaryContainer, b.onPrimaryContainer, t),
|
||||||
|
inversePrimary = lerp(a.inversePrimary, b.inversePrimary, t),
|
||||||
|
secondary = lerp(a.secondary, b.secondary, t),
|
||||||
|
onSecondary = lerp(a.onSecondary, b.onSecondary, t),
|
||||||
|
secondaryContainer = lerp(a.secondaryContainer, b.secondaryContainer, t),
|
||||||
|
onSecondaryContainer = lerp(a.onSecondaryContainer, b.onSecondaryContainer, t),
|
||||||
|
tertiary = lerp(a.tertiary, b.tertiary, t),
|
||||||
|
onTertiary = lerp(a.onTertiary, b.onTertiary, t),
|
||||||
|
tertiaryContainer = lerp(a.tertiaryContainer, b.tertiaryContainer, t),
|
||||||
|
onTertiaryContainer = lerp(a.onTertiaryContainer, b.onTertiaryContainer, t),
|
||||||
|
background = lerp(a.background, b.background, t),
|
||||||
|
onBackground = lerp(a.onBackground, b.onBackground, t),
|
||||||
|
surface = lerp(a.surface, b.surface, t),
|
||||||
|
onSurface = lerp(a.onSurface, b.onSurface, t),
|
||||||
|
surfaceVariant = lerp(a.surfaceVariant, b.surfaceVariant, t),
|
||||||
|
onSurfaceVariant = lerp(a.onSurfaceVariant, b.onSurfaceVariant, t),
|
||||||
|
surfaceTint = lerp(a.surfaceTint, b.surfaceTint, t),
|
||||||
|
inverseSurface = lerp(a.inverseSurface, b.inverseSurface, t),
|
||||||
|
inverseOnSurface = lerp(a.inverseOnSurface, b.inverseOnSurface, t),
|
||||||
|
error = lerp(a.error, b.error, t),
|
||||||
|
onError = lerp(a.onError, b.onError, t),
|
||||||
|
errorContainer = lerp(a.errorContainer, b.errorContainer, t),
|
||||||
|
onErrorContainer = lerp(a.onErrorContainer, b.onErrorContainer, t),
|
||||||
|
outline = lerp(a.outline, b.outline, t),
|
||||||
|
outlineVariant = lerp(a.outlineVariant, b.outlineVariant, t),
|
||||||
|
scrim = lerp(a.scrim, b.scrim, t),
|
||||||
|
surfaceBright = lerp(a.surfaceBright, b.surfaceBright, t),
|
||||||
|
surfaceDim = lerp(a.surfaceDim, b.surfaceDim, t),
|
||||||
|
surfaceContainer = lerp(a.surfaceContainer, b.surfaceContainer, t),
|
||||||
|
surfaceContainerHigh = lerp(a.surfaceContainerHigh, b.surfaceContainerHigh, t),
|
||||||
|
surfaceContainerHighest = lerp(a.surfaceContainerHighest, b.surfaceContainerHighest, t),
|
||||||
|
surfaceContainerLow = lerp(a.surfaceContainerLow, b.surfaceContainerLow, t),
|
||||||
|
surfaceContainerLowest = lerp(a.surfaceContainerLowest, b.surfaceContainerLowest, t),
|
||||||
|
primaryFixed = lerp(a.primaryFixed, b.primaryFixed, t),
|
||||||
|
primaryFixedDim = lerp(a.primaryFixedDim, b.primaryFixedDim, t),
|
||||||
|
onPrimaryFixed = lerp(a.onPrimaryFixed, b.onPrimaryFixed, t),
|
||||||
|
onPrimaryFixedVariant = lerp(a.onPrimaryFixedVariant, b.onPrimaryFixedVariant, t),
|
||||||
|
secondaryFixed = lerp(a.secondaryFixed, b.secondaryFixed, t),
|
||||||
|
secondaryFixedDim = lerp(a.secondaryFixedDim, b.secondaryFixedDim, t),
|
||||||
|
onSecondaryFixed = lerp(a.onSecondaryFixed, b.onSecondaryFixed, t),
|
||||||
|
onSecondaryFixedVariant = lerp(a.onSecondaryFixedVariant, b.onSecondaryFixedVariant, t),
|
||||||
|
tertiaryFixed = lerp(a.tertiaryFixed, b.tertiaryFixed, t),
|
||||||
|
tertiaryFixedDim = lerp(a.tertiaryFixedDim, b.tertiaryFixedDim, t),
|
||||||
|
onTertiaryFixed = lerp(a.onTertiaryFixed, b.onTertiaryFixed, t),
|
||||||
|
onTertiaryFixedVariant = lerp(a.onTertiaryFixedVariant, b.onTertiaryFixedVariant, t),
|
||||||
|
)
|
||||||
@@ -158,9 +158,10 @@ private fun blendHue(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun rememberArtworkColors(ref: CoverArtRef?): ArtworkColors? {
|
fun rememberArtworkColors(ref: CoverArtRef?): ArtworkColors {
|
||||||
val seeds by rememberArtworkSeed(ref)
|
val seeds by rememberArtworkSeed(ref)
|
||||||
return remember(seeds) { seeds?.let { (primary, secondary) -> artworkColorsFromSeeds(primary, secondary) } }
|
val target = remember(seeds) { seeds?.let { (primary, secondary) -> artworkColorsFromSeeds(primary, secondary) } }
|
||||||
|
return rememberAnimatedArtworkColors(target)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import androidx.compose.material3.MaterialTheme
|
|||||||
import androidx.compose.material3.darkColorScheme
|
import androidx.compose.material3.darkColorScheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
|
||||||
private val SubtracksColorScheme =
|
internal val SubtracksColorScheme =
|
||||||
darkColorScheme(
|
darkColorScheme(
|
||||||
primary = White,
|
primary = White,
|
||||||
onPrimary = Black,
|
onPrimary = Black,
|
||||||
|
|||||||
Reference in New Issue
Block a user