keep the accent blobs dimmer than the primary button

This commit is contained in:
austinried
2026-10-04 00:29:53 +00:00
parent 7303e23d62
commit e8e2c38aaa
3 changed files with 50 additions and 2 deletions
@@ -35,7 +35,8 @@ private const val SEED_ART_SIZE_PX = 128
private const val PERIOD_SCREENS = 2f
private const val BLOB_ZONE = 0.62f
private const val BLOB_COUNT = 4
private const val ACCENT_MAX_LUMINANCE = 0.34f
private const val ACCENT_MAX_LUMINANCE = 0.18f
private const val PRIMARY_MIN_LUMINANCE = 0.30f
private const val MIN_GRADIENT_SATURATION = 0.30f
private const val HERO_DARKEN_MAX = 1.0f
private const val DARKEN_START_SCREENS = 0.5f
@@ -66,7 +67,7 @@ fun artworkColorsFromSeeds(
l: Float,
) = Color.hsl(h % 360f, sat.coerceIn(0f, 1f), l.coerceIn(0f, 1f))
val primary = tone(hue, s, 0.62f)
val primary = tone(hue, s, 0.62f).withMinLuminance(PRIMARY_MIN_LUMINANCE)
val background = tone(hue, (s * 0.35f).coerceAtMost(0.20f), 0.06f)
val onBackground = tone(hue, (s * 0.10f).coerceAtMost(0.08f), 0.95f)
@@ -138,6 +139,19 @@ private fun Color.withMaxLuminance(max: Float): Color {
return color
}
private fun Color.withMinLuminance(min: Float): Color {
if (luminance() >= min) return this
val (h, s, initial) = toHsl()
var lightness = initial
var color = this
var guard = 0
while (color.luminance() < min && guard++ < 40) {
lightness = (lightness + 0.02f).coerceAtMost(0.95f)
color = Color.hsl(h, s, lightness)
}
return color
}
fun ArtworkColors.gradientColorAt(fraction: Float): Color {
if (fraction.isNaN()) return gradientHigh
val f = fraction.mod(1f)
@@ -51,6 +51,7 @@ import com.subtracks.ui.settings.AddSourceState
import com.subtracks.ui.settings.SettingsScreen
import com.subtracks.ui.theme.SubtracksTheme
import com.subtracks.ui.theme.artworkColorsFromSeed
import com.subtracks.ui.theme.artworkColorsFromSeeds
import kotlinx.coroutines.flow.flowOf
import org.junit.After
import org.junit.Before
@@ -133,6 +134,26 @@ class AppScreenshotTest {
composeRule.onRoot().captureRoboImage("src/test/screenshots/album_detail.png")
}
@Test
fun albumDetailCool() {
composeRule.setContent {
SubtracksTheme {
AlbumDetailScreen(
album = Fixtures.albums.first(),
songs = Fixtures.songs,
coverArt = { id, _ -> id?.let { CoverArtRef(it, "test:$it") } },
artwork = artworkColorsFromSeeds(Color.rgb(45, 115, 240), Color.rgb(40, 180, 140)),
onBack = {},
onSongClick = {},
playingSongId = Fixtures.songs.first().id,
modifier = Modifier.fillMaxSize(),
)
}
}
awaitText("Everything In Its Right Place")
composeRule.onRoot().captureRoboImage("src/test/screenshots/album_detail_cool.png")
}
@Test
fun artistDetail() {
composeRule.setContent {
@@ -35,6 +35,19 @@ class ArtworkColorsTest {
)
}
@Test
fun buttonStandsOutFromGradient() {
for (seed in seeds) {
val colors = artworkColorsFromSeed(seed)
val primary = colors.scheme.primary
assertTrue("primary vs gradientHigh for $seed", contrast(primary, colors.gradientHigh) >= 2f)
assertTrue("primary vs gradientLow for $seed", contrast(primary, colors.gradientLow) >= 2f)
for (accent in colors.accents) {
assertTrue("accent dimmer than primary for $seed", primary.luminance() > accent.luminance())
}
}
}
private fun contrast(
a: Color,
b: Color,