mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-12 01:07:46 +00:00
feat: derive Material3 container colors from the selected accent
The accent-color setting only overrode primary/secondary/tertiary, leaving every Material3 *Container role (primaryContainer, secondaryContainer, tertiaryContainer and their on-colors), inversePrimary and surfaceTint at Material's baseline violet. Container-backed surfaces — settings icon boxes, selected reaction chips, zap-amount chips, calendar selection, relay-group top bars — therefore stayed purple no matter which accent was chosen. Complete the dark/light schemes so those roles are derived from the accent: containers are a faint accent tint composited over the base surface, on-colors are the accent (dark) or a deepened accent (light), and on-accent fills pick black/white by WCAG contrast (also fixing white-on-teal for the purple theme's bright secondary). Mobile app only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D1F9jXNwRGTP8qmsV3Wd69
This commit is contained in:
@@ -46,6 +46,8 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.graphics.compositeOver
|
||||
import androidx.compose.ui.graphics.lerp
|
||||
import androidx.compose.ui.graphics.luminance
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
@@ -93,25 +95,84 @@ private fun accentSecondary(
|
||||
dark: Boolean,
|
||||
): Color = if (accent == AccentColorType.PURPLE) Teal200 else accentPrimary(accent, dark)
|
||||
|
||||
private fun darkColors(accent: AccentColorType) =
|
||||
darkColorScheme(
|
||||
primary = accentPrimary(accent, dark = true),
|
||||
secondary = accentSecondary(accent, dark = true),
|
||||
tertiary = accentSecondary(accent, dark = true),
|
||||
// Black or white — whichever has the higher WCAG contrast ratio against a solid accent fill
|
||||
// (primary/secondary/tertiary). Runs once per scheme build (not on a render path), so the
|
||||
// luminance() cost is irrelevant here. Picks black on the light pastel accents used in the dark
|
||||
// theme and on the purple theme's bright teal secondary, white on the deep accents used in light.
|
||||
private fun onAccent(color: Color): Color {
|
||||
val luminance = color.luminance()
|
||||
val contrastOnBlack = (luminance + 0.05f) / 0.05f
|
||||
val contrastOnWhite = 1.05f / (luminance + 0.05f)
|
||||
return if (contrastOnBlack >= contrastOnWhite) Color.Black else Color.White
|
||||
}
|
||||
|
||||
// Faint accent-tinted fill for the Material3 "container" roles (primaryContainer, etc.), laid
|
||||
// over the theme's base surface. Left unset, these roles fall back to Material's baseline violet,
|
||||
// which is why container-backed UI (settings icon boxes, selected reaction chips, zap-amount
|
||||
// chips, calendar selection, relay-group top bars) stayed purple under every accent.
|
||||
private fun accentContainer(
|
||||
color: Color,
|
||||
surface: Color,
|
||||
alpha: Float,
|
||||
): Color = color.copy(alpha = alpha).compositeOver(surface)
|
||||
|
||||
// Text/icon color drawn on an accentContainer. The container sits close to the base surface, so
|
||||
// in the dark theme the light accent reads directly; in the light theme it is deepened toward
|
||||
// black to stay legible on the pale tint.
|
||||
private fun onAccentContainer(
|
||||
color: Color,
|
||||
dark: Boolean,
|
||||
): Color = if (dark) color else lerp(color, Color.Black, 0.30f)
|
||||
|
||||
private fun darkColors(accent: AccentColorType): ColorScheme {
|
||||
val primary = accentPrimary(accent, dark = true)
|
||||
val secondary = accentSecondary(accent, dark = true)
|
||||
val surface = Color.Black
|
||||
return darkColorScheme(
|
||||
primary = primary,
|
||||
onPrimary = onAccent(primary),
|
||||
primaryContainer = accentContainer(primary, surface, 0.16f),
|
||||
onPrimaryContainer = onAccentContainer(primary, dark = true),
|
||||
secondary = secondary,
|
||||
onSecondary = onAccent(secondary),
|
||||
secondaryContainer = accentContainer(secondary, surface, 0.16f),
|
||||
onSecondaryContainer = onAccentContainer(secondary, dark = true),
|
||||
tertiary = secondary,
|
||||
onTertiary = onAccent(secondary),
|
||||
tertiaryContainer = accentContainer(secondary, surface, 0.16f),
|
||||
onTertiaryContainer = onAccentContainer(secondary, dark = true),
|
||||
inversePrimary = accentPrimary(accent, dark = false),
|
||||
surfaceTint = primary,
|
||||
background = Color.Black,
|
||||
surface = Color.Black,
|
||||
surfaceDim = Color.Black,
|
||||
surfaceVariant = Color(red = 29, green = 26, blue = 34),
|
||||
)
|
||||
}
|
||||
|
||||
private fun lightColors(accent: AccentColorType) =
|
||||
lightColorScheme(
|
||||
primary = accentPrimary(accent, dark = false),
|
||||
secondary = accentSecondary(accent, dark = false),
|
||||
tertiary = accentSecondary(accent, dark = false),
|
||||
private fun lightColors(accent: AccentColorType): ColorScheme {
|
||||
val primary = accentPrimary(accent, dark = false)
|
||||
val secondary = accentSecondary(accent, dark = false)
|
||||
val surface = Color.White
|
||||
return lightColorScheme(
|
||||
primary = primary,
|
||||
onPrimary = onAccent(primary),
|
||||
primaryContainer = accentContainer(primary, surface, 0.12f),
|
||||
onPrimaryContainer = onAccentContainer(primary, dark = false),
|
||||
secondary = secondary,
|
||||
onSecondary = onAccent(secondary),
|
||||
secondaryContainer = accentContainer(secondary, surface, 0.12f),
|
||||
onSecondaryContainer = onAccentContainer(secondary, dark = false),
|
||||
tertiary = secondary,
|
||||
onTertiary = onAccent(secondary),
|
||||
tertiaryContainer = accentContainer(secondary, surface, 0.12f),
|
||||
onTertiaryContainer = onAccentContainer(secondary, dark = false),
|
||||
inversePrimary = accentPrimary(accent, dark = true),
|
||||
surfaceTint = primary,
|
||||
surfaceContainerHighest = Color(red = 236, green = 230, blue = 240),
|
||||
surfaceVariant = Color(red = 250, green = 245, blue = 252),
|
||||
)
|
||||
}
|
||||
|
||||
private val DarkColorPalette = darkColors(AccentColorType.PURPLE)
|
||||
private val LightColorPalette = lightColors(AccentColorType.PURPLE)
|
||||
|
||||
Reference in New Issue
Block a user