fix(theme): complete M3 tokens and monochrome status colors (#681)

This commit is contained in:
M57 authored and GitHub committed 2026-07-22 15:31:09 +03:00
1 parent 7854c26365
commit 58420d7b2a
9 files changed
+198 -11

No files matched your search

@@ -30,6 +30,8 @@ val HermesAmberDark = Color(0xFFC68400)
val DarkBackground = Color(0xFF0B0B11)
val DarkSurface = Color(0xFF121218)
val DarkSurfaceVariant = Color(0xFF1C1C26)
val DarkSurfaceContainerLowest = Color(0xFF07070C)
val DarkSurfaceContainerLow = Color(0xFF0F0F14)
val DarkSurfaceContainer = Color(0xFF1C1C26)
val DarkSurfaceContainerHigh = Color(0xFF262633)
val DarkSurfaceContainerHighest = Color(0xFF30303D)
@@ -46,6 +48,8 @@ val DarkScrim = Color(0xFF000000)
val LightBackground = Color(0xFFF7F6FB)
val LightSurface = Color(0xFFFFFFFF)
val LightSurfaceVariant = Color(0xFFEFEDF4)
val LightSurfaceContainerLowest = Color(0xFFFFFFFF)
val LightSurfaceContainerLow = Color(0xFFF3F1F8)
val LightSurfaceContainer = Color(0xFFEFEDF4)
val LightSurfaceContainerHigh = Color(0xFFE6E3EE)
val LightSurfaceContainerHighest = Color(0xFFDDD9EA)
@@ -33,11 +33,11 @@ Every file in `presets/` is uniform — it exports the same four tokens:
| `XxxDarkStatusColors` | `HermesStatusColors` | dark semantic status colors |
| `XxxLightStatusColors` | `HermesStatusColors` | light semantic status colors |
A preset with no bespoke status set (MONOCHROME, AMOLED) aliases the defaults:
A preset with no bespoke status set (AMOLED) aliases the defaults:
```kotlin
val MonochromeDarkStatusColors = DefaultDarkStatusColors
val MonochromeLightStatusColors = DefaultLightStatusColors
val AmoledDarkStatusColors = DefaultDarkStatusColors
val AmoledLightStatusColors = DefaultLightStatusColors
```
AMOLED has no bespoke light scheme, so it aliases the default light scheme too:
@@ -64,8 +64,8 @@ private fun resolveStatusColors(preset: ThemePreset, darkTheme: Boolean) = when
}
```
Dynamic (Material You) color on API 31+ overrides the resolved scheme when
`useDynamicColors = true`.
Dynamic (Material You) color on API 31+ overrides the DEFAULT scheme when
`useDynamicColors = true` and `themePreset == ThemePreset.DEFAULT`.
## DEFAULT uses design tokens — that's intentional
@@ -95,7 +95,8 @@ fun HermesControlTheme(
}
val context = LocalContext.current
val dynamicAvailable = useDynamicColors && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
val dynamicAvailable =
useDynamicColors && themePreset == ThemePreset.DEFAULT && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
val colorScheme =
if (dynamicAvailable) {
if (darkTheme) {
@@ -19,17 +19,36 @@ val AmoledDarkColorScheme =
onPrimary = Color.White,
primaryContainer = Color(0xFF1A1040),
onPrimaryContainer = HermesPurpleOnContainer,
inversePrimary = Color(0xFF6750A4),
secondary = HermesAmber,
onSecondary = Color.Black,
secondaryContainer = Color(0xFF2A2000),
onSecondaryContainer = HermesAmberLight,
tertiary = HermesAmberLight,
onTertiary = Color.Black,
tertiaryContainer = Color(0xFF2A2000),
onTertiaryContainer = HermesAmberLight,
background = Color.Black,
onBackground = Color(0xFFE8E6EE),
surface = Color(0xFF08080A),
surface = Color.Black,
onSurface = Color(0xFFE8E6EE),
surfaceVariant = Color(0xFF121218),
onSurfaceVariant = Color(0xFFB6B2C4),
surfaceTint = HermesPurple,
surfaceContainerLowest = Color.Black,
surfaceContainerLow = Color(0xFF08080A),
surfaceContainer = Color(0xFF0E0E12),
surfaceContainerHigh = Color(0xFF16161C),
surfaceContainerHighest = Color(0xFF1F1F28),
inverseSurface = Color(0xFFE8E6EE),
inverseOnSurface = Color.Black,
error = Color(0xFFCF6679),
onError = Color.Black,
errorContainer = Color(0xFF3700B3),
onErrorContainer = Color(0xFFF2B8B5),
outline = Color(0xFF3A3A4A),
outlineVariant = Color(0xFF252532),
scrim = Color.Black,
)
/**
@@ -12,17 +12,36 @@ val CatppuccinDarkColorScheme =
onPrimary = Color(0xFF11111B),
primaryContainer = Color(0xFF585B70),
onPrimaryContainer = Color(0xFFF5E0DC),
inversePrimary = Color(0xFF8839EF),
secondary = Color(0xFF89B4FA),
onSecondary = Color(0xFF11111B),
secondaryContainer = Color(0xFF313244),
onSecondaryContainer = Color(0xFFBAC2DE),
tertiary = Color(0xFFF5C2E7),
onTertiary = Color(0xFF11111B),
tertiaryContainer = Color(0xFF45475A),
onTertiaryContainer = Color(0xFFF5E0DC),
background = Color(0xFF1E1E2E),
onBackground = Color(0xFFCDD6F4),
surface = Color(0xFF252538),
onSurface = Color(0xFFCDD6F4),
surfaceVariant = Color(0xFF313244),
onSurfaceVariant = Color(0xFFA6ADC8),
surfaceTint = Color(0xFFCBA6F7),
surfaceContainerLowest = Color(0xFF11111B),
surfaceContainerLow = Color(0xFF181825),
surfaceContainer = Color(0xFF1E1E2E),
surfaceContainerHigh = Color(0xFF252538),
surfaceContainerHighest = Color(0xFF313244),
inverseSurface = Color(0xFFCDD6F4),
inverseOnSurface = Color(0xFF1E1E2E),
error = Color(0xFFF38BA8),
onError = Color(0xFF11111B),
errorContainer = Color(0xFF45475A),
onErrorContainer = Color(0xFFF38BA8),
outline = Color(0xFF585B70),
outlineVariant = Color(0xFF45475A),
scrim = Color(0xFF11111B),
)
/** Catppuccin color scheme (light). */
@@ -32,17 +51,36 @@ val CatppuccinLightColorScheme =
onPrimary = Color(0xFFEFF1F5),
primaryContainer = Color(0xFFCCD0DA),
onPrimaryContainer = Color(0xFF4C4F69),
inversePrimary = Color(0xFFCBA6F7),
secondary = Color(0xFF1E66F5),
onSecondary = Color(0xFFEFF1F5),
secondaryContainer = Color(0xFFE6E9EF),
onSecondaryContainer = Color(0xFF4C4F69),
tertiary = Color(0xFFEA76CB),
onTertiary = Color(0xFFEFF1F5),
tertiaryContainer = Color(0xFFBCC0CC),
onTertiaryContainer = Color(0xFF4C4F69),
background = Color(0xFFEFF1F5),
onBackground = Color(0xFF4C4F69),
surface = Color(0xFFE6E9EF),
onSurface = Color(0xFF4C4F69),
surfaceVariant = Color(0xFFCCD0DA),
onSurfaceVariant = Color(0xFF6C6F85),
surfaceTint = Color(0xFF8839EF),
surfaceContainerLowest = Color(0xFFFFFFFF),
surfaceContainerLow = Color(0xFFE6E9EF),
surfaceContainer = Color(0xFFEFF1F5),
surfaceContainerHigh = Color(0xFFE6E9EF),
surfaceContainerHighest = Color(0xFFCCD0DA),
inverseSurface = Color(0xFF4C4F69),
inverseOnSurface = Color(0xFFEFF1F5),
error = Color(0xFFD20F39),
onError = Color(0xFFEFF1F5),
errorContainer = Color(0xFFF2D5CF),
onErrorContainer = Color(0xFFD20F39),
outline = Color(0xFF9CA0B0),
outlineVariant = Color(0xFFBCC0CC),
scrim = Color(0xFFDCE0E8),
)
/** Catppuccin status colors (dark). */
@@ -15,6 +15,8 @@ import com.m57.hermescontrol.theme.DarkSurface
import com.m57.hermescontrol.theme.DarkSurfaceContainer
import com.m57.hermescontrol.theme.DarkSurfaceContainerHigh
import com.m57.hermescontrol.theme.DarkSurfaceContainerHighest
import com.m57.hermescontrol.theme.DarkSurfaceContainerLow
import com.m57.hermescontrol.theme.DarkSurfaceContainerLowest
import com.m57.hermescontrol.theme.DarkSurfaceVariant
import com.m57.hermescontrol.theme.HermesAmber
import com.m57.hermescontrol.theme.HermesAmberDark
@@ -37,6 +39,8 @@ import com.m57.hermescontrol.theme.LightSurface
import com.m57.hermescontrol.theme.LightSurfaceContainer
import com.m57.hermescontrol.theme.LightSurfaceContainerHigh
import com.m57.hermescontrol.theme.LightSurfaceContainerHighest
import com.m57.hermescontrol.theme.LightSurfaceContainerLow
import com.m57.hermescontrol.theme.LightSurfaceContainerLowest
import com.m57.hermescontrol.theme.LightSurfaceVariant
import com.m57.hermescontrol.theme.StatusBlue
import com.m57.hermescontrol.theme.StatusBlueContainer
@@ -55,12 +59,15 @@ val DefaultDarkColorScheme =
onPrimary = Color.White,
primaryContainer = HermesPurpleContainer,
onPrimaryContainer = HermesPurpleOnContainer,
inversePrimary = HermesPurpleDark,
secondary = HermesAmber,
onSecondary = Color.Black,
secondaryContainer = Color(0xFF3D2F0F),
onSecondaryContainer = HermesAmberLight,
tertiary = HermesAmberLight,
onTertiary = Color.Black,
tertiaryContainer = Color(0xFF3D2F0F),
onTertiaryContainer = HermesAmberLight,
background = DarkBackground,
onBackground = DarkOnSurface,
surface = DarkSurface,
@@ -68,6 +75,8 @@ val DefaultDarkColorScheme =
surfaceVariant = DarkSurfaceVariant,
onSurfaceVariant = DarkOnSurfaceVariant,
surfaceTint = HermesPurple,
surfaceContainerLowest = DarkSurfaceContainerLowest,
surfaceContainerLow = DarkSurfaceContainerLow,
surfaceContainer = DarkSurfaceContainer,
surfaceContainerHigh = DarkSurfaceContainerHigh,
surfaceContainerHighest = DarkSurfaceContainerHighest,
@@ -89,12 +98,15 @@ val DefaultLightColorScheme =
onPrimary = Color.White,
primaryContainer = HermesPurpleLight,
onPrimaryContainer = Color(0xFF1E0F66),
inversePrimary = HermesPurpleLight,
secondary = HermesAmberDark,
onSecondary = Color.White,
secondaryContainer = HermesAmberLight,
onSecondaryContainer = Color(0xFF3D2F0F),
tertiary = HermesAmberDark,
onTertiary = Color.White,
tertiaryContainer = HermesAmberLight,
onTertiaryContainer = Color(0xFF3D2F0F),
background = LightBackground,
onBackground = LightOnSurface,
surface = LightSurface,
@@ -102,6 +114,8 @@ val DefaultLightColorScheme =
surfaceVariant = LightSurfaceVariant,
onSurfaceVariant = LightOnSurfaceVariant,
surfaceTint = HermesPurple,
surfaceContainerLowest = LightSurfaceContainerLowest,
surfaceContainerLow = LightSurfaceContainerLow,
surfaceContainer = LightSurfaceContainer,
surfaceContainerHigh = LightSurfaceContainerHigh,
surfaceContainerHighest = LightSurfaceContainerHighest,
@@ -12,17 +12,36 @@ val GruvboxDarkColorScheme =
onPrimary = Color(0xFF282828),
primaryContainer = Color(0xFFD65D0E),
onPrimaryContainer = Color(0xFFFBF1C7),
inversePrimary = Color(0xFFD65D0E),
secondary = Color(0xFFFABD2F),
onSecondary = Color(0xFF282828),
secondaryContainer = Color(0xFF3C3836),
onSecondaryContainer = Color(0xFFBDAE93),
tertiary = Color(0xFF8EC07C),
onTertiary = Color(0xFF282828),
tertiaryContainer = Color(0xFF458588),
onTertiaryContainer = Color(0xFFFBF1C7),
background = Color(0xFF282828),
onBackground = Color(0xFFFBF1C7),
surface = Color(0xFF32302F),
onSurface = Color(0xFFFBF1C7),
surfaceVariant = Color(0xFF3C3836),
onSurfaceVariant = Color(0xFFBDAE93),
surfaceTint = Color(0xFFFE8019),
surfaceContainerLowest = Color(0xFF1D2021),
surfaceContainerLow = Color(0xFF282828),
surfaceContainer = Color(0xFF32302F),
surfaceContainerHigh = Color(0xFF3C3836),
surfaceContainerHighest = Color(0xFF504945),
inverseSurface = Color(0xFFFBF1C7),
inverseOnSurface = Color(0xFF282828),
error = Color(0xFFFB4934),
onError = Color(0xFF282828),
errorContainer = Color(0xFFCC241D),
onErrorContainer = Color(0xFFFBF1C7),
outline = Color(0xFF665C54),
outlineVariant = Color(0xFF504945),
scrim = Color(0xFF1D2021),
)
/** Gruvbox color scheme (light). */
@@ -32,17 +51,36 @@ val GruvboxLightColorScheme =
onPrimary = Color(0xFFFBF1C7),
primaryContainer = Color(0xFFFE8019),
onPrimaryContainer = Color(0xFF282828),
inversePrimary = Color(0xFFFE8019),
secondary = Color(0xFF458588),
onSecondary = Color(0xFFFBF1C7),
secondaryContainer = Color(0xFFEBDBB2),
onSecondaryContainer = Color(0xFF3C3836),
tertiary = Color(0xFF689D6A),
onTertiary = Color(0xFFFBF1C7),
tertiaryContainer = Color(0xFFD5C4A1),
onTertiaryContainer = Color(0xFF282828),
background = Color(0xFFFBF1C7),
onBackground = Color(0xFF282828),
surface = Color(0xFFF2E5BC),
onSurface = Color(0xFF282828),
surfaceVariant = Color(0xFFEBDBB2),
onSurfaceVariant = Color(0xFF7C6F64),
surfaceTint = Color(0xFFD65D0E),
surfaceContainerLowest = Color(0xFFFFFFFF),
surfaceContainerLow = Color(0xFFF9F5D7),
surfaceContainer = Color(0xFFFBF1C7),
surfaceContainerHigh = Color(0xFFF2E5BC),
surfaceContainerHighest = Color(0xFFEBDBB2),
inverseSurface = Color(0xFF282828),
inverseOnSurface = Color(0xFFFBF1C7),
error = Color(0xFFCC241D),
onError = Color(0xFFFBF1C7),
errorContainer = Color(0xFFF9F5D7),
onErrorContainer = Color(0xFF9D0006),
outline = Color(0xFFA89984),
outlineVariant = Color(0xFFD5C4A1),
scrim = Color(0xFF3C3836),
)
/** Gruvbox status colors (dark). */
@@ -3,6 +3,7 @@ package com.m57.hermescontrol.theme.presets
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.ui.graphics.Color
import com.m57.hermescontrol.theme.HermesStatusColors
/** Monochrome color scheme (dark). */
val MonochromeDarkColorScheme =
@@ -11,17 +12,36 @@ val MonochromeDarkColorScheme =
onPrimary = Color.Black,
primaryContainer = Color(0xFF2B2B2B),
onPrimaryContainer = Color.White,
inversePrimary = Color(0xFF121212),
secondary = Color(0xFFB0B0B0),
onSecondary = Color.Black,
secondaryContainer = Color(0xFF222222),
onSecondaryContainer = Color(0xFFE0E0E0),
tertiary = Color(0xFFD0D0D0),
onTertiary = Color.Black,
tertiaryContainer = Color(0xFF333333),
onTertiaryContainer = Color(0xFFE0E0E0),
background = Color(0xFF121212),
onBackground = Color(0xFFE0E0E0),
surface = Color(0xFF1E1E1E),
onSurface = Color(0xFFE0E0E0),
surfaceVariant = Color(0xFF2B2B2B),
onSurfaceVariant = Color(0xFFB0B0B0),
surfaceTint = Color.White,
surfaceContainerLowest = Color(0xFF0F0F0F),
surfaceContainerLow = Color(0xFF1A1A1A),
surfaceContainer = Color(0xFF1E1E1E),
surfaceContainerHigh = Color(0xFF252525),
surfaceContainerHighest = Color(0xFF2C2C2C),
inverseSurface = Color(0xFFE0E0E0),
inverseOnSurface = Color(0xFF121212),
error = Color(0xFFE0E0E0),
onError = Color.Black,
errorContainer = Color(0xFF404040),
onErrorContainer = Color(0xFFE0E0E0),
outline = Color(0xFF666666),
outlineVariant = Color(0xFF444444),
scrim = Color.Black,
)
/** Monochrome color scheme (light). */
@@ -31,21 +51,68 @@ val MonochromeLightColorScheme =
onPrimary = Color.White,
primaryContainer = Color(0xFFE0E0E0),
onPrimaryContainer = Color.Black,
inversePrimary = Color(0xFFE0E0E0),
secondary = Color(0xFF4A4A4A),
onSecondary = Color.White,
secondaryContainer = Color(0xFFF0F0F0),
onSecondaryContainer = Color(0xFF111111),
tertiary = Color(0xFF333333),
onTertiary = Color.White,
tertiaryContainer = Color(0xFFE8E8E8),
onTertiaryContainer = Color(0xFF111111),
background = Color(0xFFFFFFFF),
onBackground = Color(0xFF111111),
surface = Color(0xFFF5F5F5),
onSurface = Color(0xFF111111),
surfaceVariant = Color(0xFFE0E0E0),
onSurfaceVariant = Color(0xFF4A4A4A),
surfaceTint = Color.Black,
surfaceContainerLowest = Color(0xFFFFFFFF),
surfaceContainerLow = Color(0xFFF8F8F8),
surfaceContainer = Color(0xFFF5F5F5),
surfaceContainerHigh = Color(0xFFEEEEEE),
surfaceContainerHighest = Color(0xFFE3E3E3),
inverseSurface = Color(0xFF111111),
inverseOnSurface = Color(0xFFE0E0E0),
error = Color(0xFF111111),
onError = Color.White,
errorContainer = Color(0xFFD6D6D6),
onErrorContainer = Color(0xFF111111),
outline = Color(0xFF888888),
outlineVariant = Color(0xFFCCCCCC),
scrim = Color.Black,
)
/** Monochrome status colors (dark) — reuses the brand default set. */
val MonochromeDarkStatusColors = DefaultDarkStatusColors
/** Monochrome status colors (dark). */
val MonochromeDarkStatusColors =
HermesStatusColors(
success = Color(0xFFE0E0E0),
successContainer = Color(0xFF2A2A2A),
onSuccess = Color(0xFF121212),
warning = Color(0xFFCCCCCC),
warningContainer = Color(0xFF333333),
onWarning = Color(0xFF121212),
error = Color(0xFFFFFFFF),
errorContainer = Color(0xFF404040),
onError = Color(0xFF121212),
info = Color(0xFFB0B0B0),
infoContainer = Color(0xFF242424),
onInfo = Color(0xFF121212),
)
/** Monochrome status colors (light) — reuses the brand default set. */
val MonochromeLightStatusColors = DefaultLightStatusColors
/** Monochrome status colors (light). */
val MonochromeLightStatusColors =
HermesStatusColors(
success = Color(0xFF222222),
successContainer = Color(0xFFE5E5E5),
onSuccess = Color(0xFFFFFFFF),
warning = Color(0xFF444444),
warningContainer = Color(0xFFE0E0E0),
onWarning = Color(0xFFFFFFFF),
error = Color(0xFF000000),
errorContainer = Color(0xFFD6D6D6),
onError = Color(0xFFFFFFFF),
info = Color(0xFF555555),
infoContainer = Color(0xFFEAEAEA),
onInfo = Color(0xFFFFFFFF),
)
@@ -12,6 +12,7 @@ val NeonNoirDarkColorScheme =
onPrimary = Color(0xFF1A001A),
primaryContainer = Color(0xFF3A003A),
onPrimaryContainer = Color(0xFFFFCCF2),
inversePrimary = Color(0xFFC440A8),
secondary = Color(0xFFA78BFA),
onSecondary = Color(0xFF0F0B1A),
secondaryContainer = Color(0xFF2B1F59),
@@ -27,6 +28,8 @@ val NeonNoirDarkColorScheme =
surfaceVariant = Color(0xFF2B2540),
onSurfaceVariant = Color(0xFF9A90B0),
surfaceTint = Color(0xFFFF6BF4),
surfaceContainerLowest = Color(0xFF0A0712),
surfaceContainerLow = Color(0xFF140F22),
surfaceContainer = Color(0xFF1A1530),
surfaceContainerHigh = Color(0xFF252040),
surfaceContainerHighest = Color(0xFF2F2A50),
@@ -48,6 +51,7 @@ val NeonNoirLightColorScheme =
onPrimary = Color.White,
primaryContainer = Color(0xFFFFD9F2),
onPrimaryContainer = Color(0xFF3A003A),
inversePrimary = Color(0xFFFF6BF4),
secondary = Color(0xFF7C4DFF),
onSecondary = Color.White,
secondaryContainer = Color(0xFFEDE0FF),
@@ -63,6 +67,8 @@ val NeonNoirLightColorScheme =
surfaceVariant = Color(0xFFEDE6F5),
onSurfaceVariant = Color(0xFF7A7090),
surfaceTint = Color(0xFFC440A8),
surfaceContainerLowest = Color(0xFFFFFFFF),
surfaceContainerLow = Color(0xFFFAF5FF),
surfaceContainer = Color(0xFFFDF8FF),
surfaceContainerHigh = Color(0xFFF0EDF5),
surfaceContainerHighest = Color(0xFFE6E0ED),