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 =
|
||||
artwork?.let {
|
||||
val mid = scrollPx + barHeightPx / 2f
|
||||
@@ -180,7 +175,7 @@ fun AlbumDetailScreen(
|
||||
HeroGradient(
|
||||
colors = artwork,
|
||||
scrollPx = { scrollPx },
|
||||
modifier = Modifier.fillMaxSize().alpha(gradientAlpha),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
|
||||
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
|
||||
fun rememberArtworkColors(ref: CoverArtRef?): ArtworkColors? {
|
||||
fun rememberArtworkColors(ref: CoverArtRef?): ArtworkColors {
|
||||
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
|
||||
|
||||
@@ -4,7 +4,7 @@ import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
private val SubtracksColorScheme =
|
||||
internal val SubtracksColorScheme =
|
||||
darkColorScheme(
|
||||
primary = White,
|
||||
onPrimary = Black,
|
||||
|
||||
Reference in New Issue
Block a user