refactor(theme): split per-preset color schemes into theme/presets/ (#594)
* refactor(theme): split per-preset color schemes into theme/presets/ Move each ThemePreset's ColorScheme + status colors into its own file under theme/presets/ (Default, Monochrome, Gruvbox, Catppuccin, Amoled, NeonNoir). Theme.kt becomes a thin dispatcher via resolveColorScheme/resolveStatusColors, making individual themes far easier to create and edit. - AMOLED keeps a dark-only scheme (falls back to default light) - MONOCHROME/AMOLED reuse default status colors (no bespoke semantic set) - aligned to current Voltage Purple palette + on* status-color params Verified: ktlint clean, compileDebugKotlin passes. * refactor(theme): make all preset files uniform 4-token shape Every preset file now exports XxxDarkColorScheme / XxxLightColorScheme / XxxDarkStatusColors / XxxLightStatusColors so they share one shape and import order. MONOCHROME + AMOLED alias the default status colors; AMOLED also gets an explicit AmoledLightColorScheme = DefaultLightColorScheme alias. Theme.kt dispatcher is now a pure lookup (no special-casing) for both color scheme and status colors. No runtime behavior change — pure structural cleanup. Verified: ktlint clean, compileDebugKotlin passes. * docs(theme): add THEMES.md documenting the per-preset convention Co-located in theme/ — covers layout, the uniform 4-token shape, the pure lookup dispatcher, why DEFAULT uses design tokens (intentional, not a bug), and a step-by-step 'add a new theme' recipe. Verified: ktlint clean. --------- Co-authored-by: M57 <m57@hermes-control.app>
This commit is contained in:
1 parent
29b630a2ec
commit
47258bd8b0
8 files changed
+695
-424
No files matched your search
@@ -0,0 +1,113 @@
|
|||||||
|
# Themes
|
||||||
|
|
||||||
|
How theming works in Hermes Control, and how to add or edit a theme.
|
||||||
|
|
||||||
|
## Where themes live
|
||||||
|
|
||||||
|
All theme code is under:
|
||||||
|
|
||||||
|
```
|
||||||
|
app/src/main/java/com/m57/hermescontrol/theme/
|
||||||
|
├── Theme.kt # dispatcher — resolves scheme + status colors per preset
|
||||||
|
├── Color.kt # brand design tokens (DarkSurface, HermesPurple, StatusGreen, …)
|
||||||
|
├── HermesStatusColors.kt # semantic status color model (success/warning/error/info + on*)
|
||||||
|
├── Type.kt / Shapes.kt # typography + shape tokens
|
||||||
|
├── Spacing.kt / Motion.kt # spacing + motion tokens
|
||||||
|
└── presets/ # one file per ThemePreset
|
||||||
|
├── DefaultScheme.kt
|
||||||
|
├── MonochromeScheme.kt
|
||||||
|
├── GruvboxScheme.kt
|
||||||
|
├── CatppuccinScheme.kt
|
||||||
|
├── AmoledScheme.kt
|
||||||
|
└── NeonNoirScheme.kt
|
||||||
|
```
|
||||||
|
|
||||||
|
## The 4-token shape
|
||||||
|
|
||||||
|
Every file in `presets/` is uniform — it exports the same four tokens:
|
||||||
|
|
||||||
|
| Token | Type | Purpose |
|
||||||
|
|-------|------|---------|
|
||||||
|
| `XxxDarkColorScheme` | `ColorScheme` | dark-mode Material 3 scheme |
|
||||||
|
| `XxxLightColorScheme` | `ColorScheme` | light-mode Material 3 scheme |
|
||||||
|
| `XxxDarkStatusColors` | `HermesStatusColors` | dark semantic status colors |
|
||||||
|
| `XxxLightStatusColors` | `HermesStatusColors` | light semantic status colors |
|
||||||
|
|
||||||
|
A preset with no bespoke status set (MONOCHROME, AMOLED) aliases the defaults:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
val MonochromeDarkStatusColors = DefaultDarkStatusColors
|
||||||
|
val MonochromeLightStatusColors = DefaultLightStatusColors
|
||||||
|
```
|
||||||
|
|
||||||
|
AMOLED has no bespoke light scheme, so it aliases the default light scheme too:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
val AmoledLightColorScheme = DefaultLightColorScheme
|
||||||
|
```
|
||||||
|
|
||||||
|
## The dispatcher
|
||||||
|
|
||||||
|
`Theme.kt` is a **pure lookup** — no special-casing. Given a `ThemePreset`
|
||||||
|
and a dark flag, it returns the matching scheme/status from the preset file:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
private fun resolveColorScheme(preset: ThemePreset, darkTheme: Boolean) = when (preset) {
|
||||||
|
ThemePreset.DEFAULT -> if (darkTheme) DefaultDarkColorScheme else DefaultLightColorScheme
|
||||||
|
ThemePreset.MONOCHROME -> if (darkTheme) MonochromeDarkColorScheme else MonochromeLightColorScheme
|
||||||
|
// …one line per preset…
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resolveStatusColors(preset: ThemePreset, darkTheme: Boolean) = when (preset) {
|
||||||
|
ThemePreset.DEFAULT -> if (darkTheme) DefaultDarkStatusColors else DefaultLightStatusColors
|
||||||
|
// …one line per preset…
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Dynamic (Material You) color on API 31+ overrides the resolved scheme when
|
||||||
|
`useDynamicColors = true`.
|
||||||
|
|
||||||
|
## DEFAULT uses design tokens — that's intentional
|
||||||
|
|
||||||
|
`DefaultScheme.kt` imports ~47 named tokens from `Color.kt`
|
||||||
|
(`DarkBackground`, `HermesPurple`, `StatusGreenContainer`, …) and builds its
|
||||||
|
schemes from them. This is **by design**: DEFAULT is the brand reference theme,
|
||||||
|
so a palette change in `Color.kt` flows straight through.
|
||||||
|
|
||||||
|
The other presets are hand-authored community palettes and use **raw hex**
|
||||||
|
(`Color(0xFFFE8019)`), so they only import `Color` (+ `HermesStatusColors`).
|
||||||
|
Do **not** "fix" DEFAULT to raw hex to match them — that would break the token
|
||||||
|
linkage. The asymmetry is semantic, not sloppy.
|
||||||
|
|
||||||
|
## Adding a new theme
|
||||||
|
|
||||||
|
1. **Create** `presets/<Name>Scheme.kt` exporting the 4 tokens:
|
||||||
|
```kotlin
|
||||||
|
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
|
||||||
|
|
||||||
|
val MyThemeDarkColorScheme = darkColorScheme(/* … */)
|
||||||
|
val MyThemeLightColorScheme = lightColorScheme(/* … */)
|
||||||
|
val MyThemeDarkStatusColors = HermesStatusColors(/* … */)
|
||||||
|
val MyThemeLightStatusColors = HermesStatusColors(/* … */)
|
||||||
|
```
|
||||||
|
2. **Add 2 lines** to each `when` in `Theme.kt` (`resolveColorScheme` +
|
||||||
|
`resolveStatusColors`), importing the new tokens at the top of the file.
|
||||||
|
3. **Add the enum entry** `MY_THEME` to `ThemePreset` in `Theme.kt`.
|
||||||
|
4. **Wire the UI**: add the label + selection in
|
||||||
|
`ui/settings/components/AppearanceSection.kt` (and any string resource).
|
||||||
|
5. **Verify**:
|
||||||
|
```bash
|
||||||
|
./ktlint --format app/src/main/java/com/m57/hermescontrol/theme/presets/<Name>Scheme.kt
|
||||||
|
./gradlew compileDebugKotlin
|
||||||
|
```
|
||||||
|
|
||||||
|
## Conventions
|
||||||
|
|
||||||
|
- ktlint 1.2.1 is enforced in CI. Run `./ktlint --format` before committing.
|
||||||
|
- Import order is ASCII-lexicographic (uppercase before lowercase).
|
||||||
|
- Every change goes through a PR — never push directly to `main`.
|
||||||
@@ -3,15 +3,36 @@ package com.m57.hermescontrol.theme
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.darkColorScheme
|
|
||||||
import androidx.compose.material3.dynamicDarkColorScheme
|
import androidx.compose.material3.dynamicDarkColorScheme
|
||||||
import androidx.compose.material3.dynamicLightColorScheme
|
import androidx.compose.material3.dynamicLightColorScheme
|
||||||
import androidx.compose.material3.lightColorScheme
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.compositionLocalOf
|
import androidx.compose.runtime.compositionLocalOf
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import com.m57.hermescontrol.theme.presets.AmoledDarkColorScheme
|
||||||
|
import com.m57.hermescontrol.theme.presets.AmoledDarkStatusColors
|
||||||
|
import com.m57.hermescontrol.theme.presets.AmoledLightColorScheme
|
||||||
|
import com.m57.hermescontrol.theme.presets.AmoledLightStatusColors
|
||||||
|
import com.m57.hermescontrol.theme.presets.CatppuccinDarkColorScheme
|
||||||
|
import com.m57.hermescontrol.theme.presets.CatppuccinDarkStatusColors
|
||||||
|
import com.m57.hermescontrol.theme.presets.CatppuccinLightColorScheme
|
||||||
|
import com.m57.hermescontrol.theme.presets.CatppuccinLightStatusColors
|
||||||
|
import com.m57.hermescontrol.theme.presets.DefaultDarkColorScheme
|
||||||
|
import com.m57.hermescontrol.theme.presets.DefaultDarkStatusColors
|
||||||
|
import com.m57.hermescontrol.theme.presets.DefaultLightColorScheme
|
||||||
|
import com.m57.hermescontrol.theme.presets.DefaultLightStatusColors
|
||||||
|
import com.m57.hermescontrol.theme.presets.GruvboxDarkColorScheme
|
||||||
|
import com.m57.hermescontrol.theme.presets.GruvboxDarkStatusColors
|
||||||
|
import com.m57.hermescontrol.theme.presets.GruvboxLightColorScheme
|
||||||
|
import com.m57.hermescontrol.theme.presets.GruvboxLightStatusColors
|
||||||
|
import com.m57.hermescontrol.theme.presets.MonochromeDarkColorScheme
|
||||||
|
import com.m57.hermescontrol.theme.presets.MonochromeDarkStatusColors
|
||||||
|
import com.m57.hermescontrol.theme.presets.MonochromeLightColorScheme
|
||||||
|
import com.m57.hermescontrol.theme.presets.MonochromeLightStatusColors
|
||||||
|
import com.m57.hermescontrol.theme.presets.NeonNoirDarkColorScheme
|
||||||
|
import com.m57.hermescontrol.theme.presets.NeonNoirDarkStatusColors
|
||||||
|
import com.m57.hermescontrol.theme.presets.NeonNoirLightColorScheme
|
||||||
|
import com.m57.hermescontrol.theme.presets.NeonNoirLightStatusColors
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@@ -26,274 +47,41 @@ enum class BottomNavDisplayMode { ICON_AND_TEXT, ICON_ONLY, TEXT_ONLY }
|
|||||||
val LocalThemePreference = compositionLocalOf { ThemePreference.SYSTEM }
|
val LocalThemePreference = compositionLocalOf { ThemePreference.SYSTEM }
|
||||||
val LocalThemePreset = compositionLocalOf { ThemePreset.DEFAULT }
|
val LocalThemePreset = compositionLocalOf { ThemePreset.DEFAULT }
|
||||||
|
|
||||||
private val HermesDarkColorScheme =
|
/**
|
||||||
darkColorScheme(
|
* Resolve the Material 3 [ColorScheme] for a preset + dark flag.
|
||||||
primary = HermesPurple,
|
*
|
||||||
onPrimary = Color.White,
|
* Every preset exports both a dark and light scheme. AMOLED's light scheme is
|
||||||
primaryContainer = HermesPurpleContainer,
|
* an explicit alias of the brand default light scheme.
|
||||||
onPrimaryContainer = HermesPurpleOnContainer,
|
*/
|
||||||
secondary = HermesAmber,
|
private fun resolveColorScheme(
|
||||||
onSecondary = Color.Black,
|
preset: ThemePreset,
|
||||||
secondaryContainer = Color(0xFF3D2F0F),
|
darkTheme: Boolean,
|
||||||
onSecondaryContainer = HermesAmberLight,
|
) = when (preset) {
|
||||||
tertiary = HermesAmberLight,
|
ThemePreset.DEFAULT -> if (darkTheme) DefaultDarkColorScheme else DefaultLightColorScheme
|
||||||
onTertiary = Color.Black,
|
ThemePreset.MONOCHROME -> if (darkTheme) MonochromeDarkColorScheme else MonochromeLightColorScheme
|
||||||
background = DarkBackground,
|
ThemePreset.GRUVBOX -> if (darkTheme) GruvboxDarkColorScheme else GruvboxLightColorScheme
|
||||||
onBackground = DarkOnSurface,
|
ThemePreset.CATPPUCCIN -> if (darkTheme) CatppuccinDarkColorScheme else CatppuccinLightColorScheme
|
||||||
surface = DarkSurface,
|
ThemePreset.AMOLED -> if (darkTheme) AmoledDarkColorScheme else AmoledLightColorScheme
|
||||||
onSurface = DarkOnSurface,
|
ThemePreset.NEON_NOIR -> if (darkTheme) NeonNoirDarkColorScheme else NeonNoirLightColorScheme
|
||||||
surfaceVariant = DarkSurfaceVariant,
|
}
|
||||||
onSurfaceVariant = DarkOnSurfaceVariant,
|
|
||||||
surfaceTint = HermesPurple,
|
|
||||||
surfaceContainer = DarkSurfaceContainer,
|
|
||||||
surfaceContainerHigh = DarkSurfaceContainerHigh,
|
|
||||||
surfaceContainerHighest = DarkSurfaceContainerHighest,
|
|
||||||
inverseSurface = DarkInverseSurface,
|
|
||||||
inverseOnSurface = DarkInverseOnSurface,
|
|
||||||
error = StatusRed,
|
|
||||||
onError = Color.White,
|
|
||||||
errorContainer = StatusRedContainer,
|
|
||||||
onErrorContainer = Color(0xFFFFB4B4),
|
|
||||||
outline = DarkOutline,
|
|
||||||
outlineVariant = DarkOutlineVariant,
|
|
||||||
scrim = DarkScrim,
|
|
||||||
)
|
|
||||||
|
|
||||||
private val HermesLightColorScheme =
|
/**
|
||||||
lightColorScheme(
|
* Resolve the semantic status colors for a preset + dark flag.
|
||||||
primary = HermesPurpleDark,
|
*
|
||||||
onPrimary = Color.White,
|
* Every preset exports both a dark and light status set. MONOCHROME and AMOLED
|
||||||
primaryContainer = HermesPurpleLight,
|
* alias the brand default status colors (they have no bespoke semantic set).
|
||||||
onPrimaryContainer = Color(0xFF1E0F66),
|
*/
|
||||||
secondary = HermesAmberDark,
|
private fun resolveStatusColors(
|
||||||
onSecondary = Color.White,
|
preset: ThemePreset,
|
||||||
secondaryContainer = HermesAmberLight,
|
darkTheme: Boolean,
|
||||||
onSecondaryContainer = Color(0xFF3D2F0F),
|
) = when (preset) {
|
||||||
tertiary = HermesAmberDark,
|
ThemePreset.DEFAULT -> if (darkTheme) DefaultDarkStatusColors else DefaultLightStatusColors
|
||||||
onTertiary = Color.White,
|
ThemePreset.MONOCHROME -> if (darkTheme) MonochromeDarkStatusColors else MonochromeLightStatusColors
|
||||||
background = LightBackground,
|
ThemePreset.GRUVBOX -> if (darkTheme) GruvboxDarkStatusColors else GruvboxLightStatusColors
|
||||||
onBackground = LightOnSurface,
|
ThemePreset.CATPPUCCIN -> if (darkTheme) CatppuccinDarkStatusColors else CatppuccinLightStatusColors
|
||||||
surface = LightSurface,
|
ThemePreset.AMOLED -> if (darkTheme) AmoledDarkStatusColors else AmoledLightStatusColors
|
||||||
onSurface = LightOnSurface,
|
ThemePreset.NEON_NOIR -> if (darkTheme) NeonNoirDarkStatusColors else NeonNoirLightStatusColors
|
||||||
surfaceVariant = LightSurfaceVariant,
|
}
|
||||||
onSurfaceVariant = LightOnSurfaceVariant,
|
|
||||||
surfaceTint = HermesPurple,
|
|
||||||
surfaceContainer = LightSurfaceContainer,
|
|
||||||
surfaceContainerHigh = LightSurfaceContainerHigh,
|
|
||||||
surfaceContainerHighest = LightSurfaceContainerHighest,
|
|
||||||
inverseSurface = LightInverseSurface,
|
|
||||||
inverseOnSurface = LightInverseOnSurface,
|
|
||||||
error = Color(0xFFB3261E),
|
|
||||||
onError = Color.White,
|
|
||||||
errorContainer = Color(0xFFF9DEDC),
|
|
||||||
onErrorContainer = Color(0xFF410E0B),
|
|
||||||
outline = LightOutline,
|
|
||||||
outlineVariant = LightOutlineVariant,
|
|
||||||
scrim = LightScrim,
|
|
||||||
)
|
|
||||||
|
|
||||||
private val MonochromeDarkColorScheme =
|
|
||||||
darkColorScheme(
|
|
||||||
primary = Color.White,
|
|
||||||
onPrimary = Color.Black,
|
|
||||||
primaryContainer = Color(0xFF2B2B2B),
|
|
||||||
onPrimaryContainer = Color.White,
|
|
||||||
secondary = Color(0xFFB0B0B0),
|
|
||||||
onSecondary = Color.Black,
|
|
||||||
secondaryContainer = Color(0xFF222222),
|
|
||||||
onSecondaryContainer = Color(0xFFE0E0E0),
|
|
||||||
background = Color(0xFF121212),
|
|
||||||
onBackground = Color(0xFFE0E0E0),
|
|
||||||
surface = Color(0xFF1E1E1E),
|
|
||||||
onSurface = Color(0xFFE0E0E0),
|
|
||||||
surfaceVariant = Color(0xFF2B2B2B),
|
|
||||||
onSurfaceVariant = Color(0xFFB0B0B0),
|
|
||||||
outline = Color(0xFF666666),
|
|
||||||
)
|
|
||||||
|
|
||||||
private val MonochromeLightColorScheme =
|
|
||||||
lightColorScheme(
|
|
||||||
primary = Color.Black,
|
|
||||||
onPrimary = Color.White,
|
|
||||||
primaryContainer = Color(0xFFE0E0E0),
|
|
||||||
onPrimaryContainer = Color.Black,
|
|
||||||
secondary = Color(0xFF4A4A4A),
|
|
||||||
onSecondary = Color.White,
|
|
||||||
secondaryContainer = Color(0xFFF0F0F0),
|
|
||||||
onSecondaryContainer = Color(0xFF111111),
|
|
||||||
background = Color(0xFFFFFFFF),
|
|
||||||
onBackground = Color(0xFF111111),
|
|
||||||
surface = Color(0xFFF5F5F5),
|
|
||||||
onSurface = Color(0xFF111111),
|
|
||||||
surfaceVariant = Color(0xFFE0E0E0),
|
|
||||||
onSurfaceVariant = Color(0xFF4A4A4A),
|
|
||||||
outline = Color(0xFF888888),
|
|
||||||
)
|
|
||||||
|
|
||||||
private val GruvboxDarkColorScheme =
|
|
||||||
darkColorScheme(
|
|
||||||
primary = Color(0xFFFE8019),
|
|
||||||
onPrimary = Color(0xFF282828),
|
|
||||||
primaryContainer = Color(0xFFD65D0E),
|
|
||||||
onPrimaryContainer = Color(0xFFFBF1C7),
|
|
||||||
secondary = Color(0xFFFABD2F),
|
|
||||||
onSecondary = Color(0xFF282828),
|
|
||||||
secondaryContainer = Color(0xFF3C3836),
|
|
||||||
onSecondaryContainer = Color(0xFFBDAE93),
|
|
||||||
background = Color(0xFF282828),
|
|
||||||
onBackground = Color(0xFFFBF1C7),
|
|
||||||
surface = Color(0xFF32302F),
|
|
||||||
onSurface = Color(0xFFFBF1C7),
|
|
||||||
surfaceVariant = Color(0xFF3C3836),
|
|
||||||
onSurfaceVariant = Color(0xFFBDAE93),
|
|
||||||
outline = Color(0xFF665C54),
|
|
||||||
)
|
|
||||||
|
|
||||||
private val GruvboxLightColorScheme =
|
|
||||||
lightColorScheme(
|
|
||||||
primary = Color(0xFFD65D0E),
|
|
||||||
onPrimary = Color(0xFFFBF1C7),
|
|
||||||
primaryContainer = Color(0xFFFE8019),
|
|
||||||
onPrimaryContainer = Color(0xFF282828),
|
|
||||||
secondary = Color(0xFF458588),
|
|
||||||
onSecondary = Color(0xFFFBF1C7),
|
|
||||||
secondaryContainer = Color(0xFFEBDBB2),
|
|
||||||
onSecondaryContainer = Color(0xFF3C3836),
|
|
||||||
background = Color(0xFFFBF1C7),
|
|
||||||
onBackground = Color(0xFF282828),
|
|
||||||
surface = Color(0xFFF2E5BC),
|
|
||||||
onSurface = Color(0xFF282828),
|
|
||||||
surfaceVariant = Color(0xFFEBDBB2),
|
|
||||||
onSurfaceVariant = Color(0xFF7C6F64),
|
|
||||||
outline = Color(0xFFA89984),
|
|
||||||
)
|
|
||||||
|
|
||||||
private val CatppuccinDarkColorScheme =
|
|
||||||
darkColorScheme(
|
|
||||||
primary = Color(0xFFCBA6F7),
|
|
||||||
onPrimary = Color(0xFF11111B),
|
|
||||||
primaryContainer = Color(0xFF585B70),
|
|
||||||
onPrimaryContainer = Color(0xFFF5E0DC),
|
|
||||||
secondary = Color(0xFF89B4FA),
|
|
||||||
onSecondary = Color(0xFF11111B),
|
|
||||||
secondaryContainer = Color(0xFF313244),
|
|
||||||
onSecondaryContainer = Color(0xFFBAC2DE),
|
|
||||||
background = Color(0xFF1E1E2E),
|
|
||||||
onBackground = Color(0xFFCDD6F4),
|
|
||||||
surface = Color(0xFF252538),
|
|
||||||
onSurface = Color(0xFFCDD6F4),
|
|
||||||
surfaceVariant = Color(0xFF313244),
|
|
||||||
onSurfaceVariant = Color(0xFFA6ADC8),
|
|
||||||
outline = Color(0xFF585B70),
|
|
||||||
)
|
|
||||||
|
|
||||||
private val CatppuccinLightColorScheme =
|
|
||||||
lightColorScheme(
|
|
||||||
primary = Color(0xFF8839EF),
|
|
||||||
onPrimary = Color(0xFFEFF1F5),
|
|
||||||
primaryContainer = Color(0xFFCCD0DA),
|
|
||||||
onPrimaryContainer = Color(0xFF4C4F69),
|
|
||||||
secondary = Color(0xFF1E66F5),
|
|
||||||
onSecondary = Color(0xFFEFF1F5),
|
|
||||||
secondaryContainer = Color(0xFFE6E9EF),
|
|
||||||
onSecondaryContainer = Color(0xFF4C4F69),
|
|
||||||
background = Color(0xFFEFF1F5),
|
|
||||||
onBackground = Color(0xFF4C4F69),
|
|
||||||
surface = Color(0xFFE6E9EF),
|
|
||||||
onSurface = Color(0xFF4C4F69),
|
|
||||||
surfaceVariant = Color(0xFFCCD0DA),
|
|
||||||
onSurfaceVariant = Color(0xFF6C6F85),
|
|
||||||
outline = Color(0xFF9CA0B0),
|
|
||||||
)
|
|
||||||
|
|
||||||
private val AmoledDarkColorScheme =
|
|
||||||
darkColorScheme(
|
|
||||||
primary = HermesPurple,
|
|
||||||
onPrimary = Color.White,
|
|
||||||
primaryContainer = Color(0xFF1A1040),
|
|
||||||
onPrimaryContainer = HermesPurpleOnContainer,
|
|
||||||
secondary = HermesAmber,
|
|
||||||
onSecondary = Color.Black,
|
|
||||||
secondaryContainer = Color(0xFF2A2000),
|
|
||||||
onSecondaryContainer = HermesAmberLight,
|
|
||||||
background = Color.Black,
|
|
||||||
onBackground = Color(0xFFE8E6EE),
|
|
||||||
surface = Color(0xFF08080A),
|
|
||||||
onSurface = Color(0xFFE8E6EE),
|
|
||||||
surfaceVariant = Color(0xFF121218),
|
|
||||||
onSurfaceVariant = Color(0xFFB6B2C4),
|
|
||||||
outline = Color(0xFF3A3A4A),
|
|
||||||
)
|
|
||||||
|
|
||||||
private val NeonNoirDarkColorScheme =
|
|
||||||
darkColorScheme(
|
|
||||||
primary = Color(0xFFFF6BF4),
|
|
||||||
onPrimary = Color(0xFF1A001A),
|
|
||||||
primaryContainer = Color(0xFF3A003A),
|
|
||||||
onPrimaryContainer = Color(0xFFFFCCF2),
|
|
||||||
secondary = Color(0xFFA78BFA),
|
|
||||||
onSecondary = Color(0xFF0F0B1A),
|
|
||||||
secondaryContainer = Color(0xFF2B1F59),
|
|
||||||
onSecondaryContainer = Color(0xFFD9CCFF),
|
|
||||||
tertiary = Color(0xFF60F0FF),
|
|
||||||
onTertiary = Color(0xFF003B40),
|
|
||||||
tertiaryContainer = Color(0xFF004F59),
|
|
||||||
onTertiaryContainer = Color(0xFFBFFAFF),
|
|
||||||
background = Color(0xFF0F0B1A),
|
|
||||||
onBackground = Color(0xFFE8E0F0),
|
|
||||||
surface = Color(0xFF1A1530),
|
|
||||||
onSurface = Color(0xFFE8E0F0),
|
|
||||||
surfaceVariant = Color(0xFF2B2540),
|
|
||||||
onSurfaceVariant = Color(0xFF9A90B0),
|
|
||||||
surfaceTint = Color(0xFFFF6BF4),
|
|
||||||
surfaceContainer = Color(0xFF1A1530),
|
|
||||||
surfaceContainerHigh = Color(0xFF252040),
|
|
||||||
surfaceContainerHighest = Color(0xFF2F2A50),
|
|
||||||
inverseSurface = Color(0xFFE8E0F0),
|
|
||||||
inverseOnSurface = Color(0xFF0F0B1A),
|
|
||||||
error = Color(0xFFFF3D68),
|
|
||||||
onError = Color.White,
|
|
||||||
errorContainer = Color(0xFF3A0A14),
|
|
||||||
onErrorContainer = Color(0xFFFFB3C0),
|
|
||||||
outline = Color(0xFF3A3060),
|
|
||||||
outlineVariant = Color(0xFF2E2545),
|
|
||||||
scrim = Color(0xFF000000),
|
|
||||||
)
|
|
||||||
|
|
||||||
private val NeonNoirLightColorScheme =
|
|
||||||
lightColorScheme(
|
|
||||||
primary = Color(0xFFC440A8),
|
|
||||||
onPrimary = Color.White,
|
|
||||||
primaryContainer = Color(0xFFFFD9F2),
|
|
||||||
onPrimaryContainer = Color(0xFF3A003A),
|
|
||||||
secondary = Color(0xFF7C4DFF),
|
|
||||||
onSecondary = Color.White,
|
|
||||||
secondaryContainer = Color(0xFFEDE0FF),
|
|
||||||
onSecondaryContainer = Color(0xFF1E0066),
|
|
||||||
tertiary = Color(0xFF0098A6),
|
|
||||||
onTertiary = Color.White,
|
|
||||||
tertiaryContainer = Color(0xFFBFFAFF),
|
|
||||||
onTertiaryContainer = Color(0xFF003B40),
|
|
||||||
background = Color(0xFFF5F0FA),
|
|
||||||
onBackground = Color(0xFF0F0B1A),
|
|
||||||
surface = Color.White,
|
|
||||||
onSurface = Color(0xFF0F0B1A),
|
|
||||||
surfaceVariant = Color(0xFFEDE6F5),
|
|
||||||
onSurfaceVariant = Color(0xFF7A7090),
|
|
||||||
surfaceTint = Color(0xFFC440A8),
|
|
||||||
surfaceContainer = Color(0xFFFDF8FF),
|
|
||||||
surfaceContainerHigh = Color(0xFFF0EDF5),
|
|
||||||
surfaceContainerHighest = Color(0xFFE6E0ED),
|
|
||||||
inverseSurface = Color(0xFF0F0B1A),
|
|
||||||
inverseOnSurface = Color(0xFFE8E0F0),
|
|
||||||
error = Color(0xFFB3261E),
|
|
||||||
onError = Color.White,
|
|
||||||
errorContainer = Color(0xFFF9DEDC),
|
|
||||||
onErrorContainer = Color(0xFF410E0B),
|
|
||||||
outline = Color(0xFFBFB8CC),
|
|
||||||
outlineVariant = Color(0xFFD9D2E3),
|
|
||||||
scrim = Color(0xFF000000),
|
|
||||||
)
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun HermesControlTheme(
|
fun HermesControlTheme(
|
||||||
@@ -312,165 +100,17 @@ fun HermesControlTheme(
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val dynamicAvailable = useDynamicColors && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
|
val dynamicAvailable = useDynamicColors && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
|
||||||
val colorScheme =
|
val colorScheme =
|
||||||
when {
|
if (dynamicAvailable) {
|
||||||
dynamicAvailable && darkTheme -> {
|
if (darkTheme) {
|
||||||
dynamicDarkColorScheme(context)
|
dynamicDarkColorScheme(context)
|
||||||
}
|
} else {
|
||||||
|
|
||||||
dynamicAvailable && !darkTheme -> {
|
|
||||||
dynamicLightColorScheme(context)
|
dynamicLightColorScheme(context)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
else -> {
|
resolveColorScheme(themePreset, darkTheme)
|
||||||
when (themePreset) {
|
|
||||||
ThemePreset.DEFAULT -> if (darkTheme) HermesDarkColorScheme else HermesLightColorScheme
|
|
||||||
ThemePreset.MONOCHROME -> if (darkTheme) MonochromeDarkColorScheme else MonochromeLightColorScheme
|
|
||||||
ThemePreset.GRUVBOX -> if (darkTheme) GruvboxDarkColorScheme else GruvboxLightColorScheme
|
|
||||||
ThemePreset.CATPPUCCIN -> if (darkTheme) CatppuccinDarkColorScheme else CatppuccinLightColorScheme
|
|
||||||
ThemePreset.AMOLED -> if (darkTheme) AmoledDarkColorScheme else HermesLightColorScheme
|
|
||||||
ThemePreset.NEON_NOIR -> if (darkTheme) NeonNoirDarkColorScheme else NeonNoirLightColorScheme
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val statusColors =
|
val statusColors = resolveStatusColors(themePreset, darkTheme)
|
||||||
when {
|
|
||||||
themePreset == ThemePreset.GRUVBOX && darkTheme -> {
|
|
||||||
HermesStatusColors(
|
|
||||||
success = Color(0xFFB8BB26),
|
|
||||||
successContainer = Color(0xFF32302F),
|
|
||||||
onSuccess = Color(0xFF282828),
|
|
||||||
warning = Color(0xFFFABD2F),
|
|
||||||
warningContainer = Color(0xFF3C3836),
|
|
||||||
onWarning = Color(0xFF282828),
|
|
||||||
error = Color(0xFFFB4934),
|
|
||||||
errorContainer = Color(0xFF282828),
|
|
||||||
onError = Color(0xFF282828),
|
|
||||||
info = Color(0xFF83A598),
|
|
||||||
infoContainer = Color(0xFF3C3836),
|
|
||||||
onInfo = Color(0xFF282828),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
themePreset == ThemePreset.GRUVBOX && !darkTheme -> {
|
|
||||||
HermesStatusColors(
|
|
||||||
success = Color(0xFF98971A),
|
|
||||||
successContainer = Color(0xFFEBDBB2),
|
|
||||||
onSuccess = Color(0xFFEBDBB2),
|
|
||||||
warning = Color(0xFFD79921),
|
|
||||||
warningContainer = Color(0xFFEBDBB2),
|
|
||||||
onWarning = Color(0xFFEBDBB2),
|
|
||||||
error = Color(0xFFCC241D),
|
|
||||||
errorContainer = Color(0xFFEBDBB2),
|
|
||||||
onError = Color(0xFFEBDBB2),
|
|
||||||
info = Color(0xFF458588),
|
|
||||||
infoContainer = Color(0xFFEBDBB2),
|
|
||||||
onInfo = Color(0xFFEBDBB2),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
themePreset == ThemePreset.CATPPUCCIN && darkTheme -> {
|
|
||||||
HermesStatusColors(
|
|
||||||
success = Color(0xFFA6E3A1),
|
|
||||||
successContainer = Color(0xFF313244),
|
|
||||||
onSuccess = Color(0xFF11111B),
|
|
||||||
warning = Color(0xFFF9E2AF),
|
|
||||||
warningContainer = Color(0xFF313244),
|
|
||||||
onWarning = Color(0xFF11111B),
|
|
||||||
error = Color(0xFFF38BA8),
|
|
||||||
errorContainer = Color(0xFF313244),
|
|
||||||
onError = Color(0xFF11111B),
|
|
||||||
info = Color(0xFF89B4FA),
|
|
||||||
infoContainer = Color(0xFF313244),
|
|
||||||
onInfo = Color(0xFF11111B),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
themePreset == ThemePreset.CATPPUCCIN && !darkTheme -> {
|
|
||||||
HermesStatusColors(
|
|
||||||
success = Color(0xFF40A02B),
|
|
||||||
successContainer = Color(0xFFE6E9EF),
|
|
||||||
onSuccess = Color(0xFFE6E9EF),
|
|
||||||
warning = Color(0xFFDF8E1D),
|
|
||||||
warningContainer = Color(0xFFE6E9EF),
|
|
||||||
onWarning = Color(0xFFE6E9EF),
|
|
||||||
error = Color(0xFFD20F39),
|
|
||||||
errorContainer = Color(0xFFE6E9EF),
|
|
||||||
onError = Color(0xFFE6E9EF),
|
|
||||||
info = Color(0xFF1E66F5),
|
|
||||||
infoContainer = Color(0xFFE6E9EF),
|
|
||||||
onInfo = Color(0xFFE6E9EF),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
themePreset == ThemePreset.NEON_NOIR && darkTheme -> {
|
|
||||||
HermesStatusColors(
|
|
||||||
success = Color(0xFF6FEA8B),
|
|
||||||
successContainer = Color(0xFF0A3A14),
|
|
||||||
onSuccess = Color(0xFF0F0B1A),
|
|
||||||
warning = Color(0xFFFFB347),
|
|
||||||
warningContainer = Color(0xFF3A2000),
|
|
||||||
onWarning = Color(0xFF0F0B1A),
|
|
||||||
error = Color(0xFFFF3D68),
|
|
||||||
errorContainer = Color(0xFF3A0A14),
|
|
||||||
onError = Color(0xFF0F0B1A),
|
|
||||||
info = Color(0xFF60F0FF),
|
|
||||||
infoContainer = Color(0xFF003B40),
|
|
||||||
onInfo = Color(0xFF0F0B1A),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
themePreset == ThemePreset.NEON_NOIR && !darkTheme -> {
|
|
||||||
HermesStatusColors(
|
|
||||||
success = Color(0xFF1B873A),
|
|
||||||
successContainer = Color(0xFFD7F5E0),
|
|
||||||
onSuccess = Color(0xFFFDF8FF),
|
|
||||||
warning = Color(0xFFB87800),
|
|
||||||
warningContainer = Color(0xFFFFEAB3),
|
|
||||||
onWarning = Color(0xFFFDF8FF),
|
|
||||||
error = Color(0xFFB3261E),
|
|
||||||
errorContainer = Color(0xFFF9DEDC),
|
|
||||||
onError = Color(0xFFFDF8FF),
|
|
||||||
info = Color(0xFF2E6FBD),
|
|
||||||
infoContainer = Color(0xFFD4E7FF),
|
|
||||||
onInfo = Color(0xFFFDF8FF),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
darkTheme -> {
|
|
||||||
HermesStatusColors(
|
|
||||||
success = StatusGreen,
|
|
||||||
successContainer = StatusGreenContainer,
|
|
||||||
onSuccess = StatusGreyLight,
|
|
||||||
warning = StatusYellow,
|
|
||||||
warningContainer = StatusYellowContainer,
|
|
||||||
onWarning = StatusGreyLight,
|
|
||||||
error = StatusRed,
|
|
||||||
errorContainer = StatusRedContainer,
|
|
||||||
onError = StatusGreyLight,
|
|
||||||
info = StatusBlue,
|
|
||||||
infoContainer = StatusBlueContainer,
|
|
||||||
onInfo = StatusGreyLight,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
HermesStatusColors(
|
|
||||||
success = Color(0xFF1B873A),
|
|
||||||
successContainer = Color(0xFFD7F5E0),
|
|
||||||
onSuccess = Color(0xFFFDF8FF),
|
|
||||||
warning = HermesAmberDark,
|
|
||||||
warningContainer = Color(0xFFFFEAB3),
|
|
||||||
onWarning = Color(0xFFFDF8FF),
|
|
||||||
error = Color(0xFFB3261E),
|
|
||||||
errorContainer = Color(0xFFF9DEDC),
|
|
||||||
onError = Color(0xFFFDF8FF),
|
|
||||||
info = Color(0xFF2E6FBD),
|
|
||||||
infoContainer = Color(0xFFD4E7FF),
|
|
||||||
onInfo = Color(0xFFFDF8FF),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
LocalThemePreference provides themePreference,
|
LocalThemePreference provides themePreference,
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package com.m57.hermescontrol.theme.presets
|
||||||
|
|
||||||
|
import androidx.compose.material3.darkColorScheme
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import com.m57.hermescontrol.theme.HermesAmber
|
||||||
|
import com.m57.hermescontrol.theme.HermesAmberLight
|
||||||
|
import com.m57.hermescontrol.theme.HermesPurple
|
||||||
|
import com.m57.hermescontrol.theme.HermesPurpleOnContainer
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AMOLED color scheme (dark only).
|
||||||
|
*
|
||||||
|
* AMOLED has no light variant — callers fall back to the brand default light
|
||||||
|
* scheme for light mode.
|
||||||
|
*/
|
||||||
|
val AmoledDarkColorScheme =
|
||||||
|
darkColorScheme(
|
||||||
|
primary = HermesPurple,
|
||||||
|
onPrimary = Color.White,
|
||||||
|
primaryContainer = Color(0xFF1A1040),
|
||||||
|
onPrimaryContainer = HermesPurpleOnContainer,
|
||||||
|
secondary = HermesAmber,
|
||||||
|
onSecondary = Color.Black,
|
||||||
|
secondaryContainer = Color(0xFF2A2000),
|
||||||
|
onSecondaryContainer = HermesAmberLight,
|
||||||
|
background = Color.Black,
|
||||||
|
onBackground = Color(0xFFE8E6EE),
|
||||||
|
surface = Color(0xFF08080A),
|
||||||
|
onSurface = Color(0xFFE8E6EE),
|
||||||
|
surfaceVariant = Color(0xFF121218),
|
||||||
|
onSurfaceVariant = Color(0xFFB6B2C4),
|
||||||
|
outline = Color(0xFF3A3A4A),
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AMOLED has no bespoke light scheme — reuse the brand default light scheme.
|
||||||
|
*/
|
||||||
|
val AmoledLightColorScheme = DefaultLightColorScheme
|
||||||
|
|
||||||
|
/** AMOLED status colors (dark) — reuses the brand default set. */
|
||||||
|
val AmoledDarkStatusColors = DefaultDarkStatusColors
|
||||||
|
|
||||||
|
/** AMOLED status colors (light) — reuses the brand default set. */
|
||||||
|
val AmoledLightStatusColors = DefaultLightStatusColors
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
/** Catppuccin color scheme (dark). */
|
||||||
|
val CatppuccinDarkColorScheme =
|
||||||
|
darkColorScheme(
|
||||||
|
primary = Color(0xFFCBA6F7),
|
||||||
|
onPrimary = Color(0xFF11111B),
|
||||||
|
primaryContainer = Color(0xFF585B70),
|
||||||
|
onPrimaryContainer = Color(0xFFF5E0DC),
|
||||||
|
secondary = Color(0xFF89B4FA),
|
||||||
|
onSecondary = Color(0xFF11111B),
|
||||||
|
secondaryContainer = Color(0xFF313244),
|
||||||
|
onSecondaryContainer = Color(0xFFBAC2DE),
|
||||||
|
background = Color(0xFF1E1E2E),
|
||||||
|
onBackground = Color(0xFFCDD6F4),
|
||||||
|
surface = Color(0xFF252538),
|
||||||
|
onSurface = Color(0xFFCDD6F4),
|
||||||
|
surfaceVariant = Color(0xFF313244),
|
||||||
|
onSurfaceVariant = Color(0xFFA6ADC8),
|
||||||
|
outline = Color(0xFF585B70),
|
||||||
|
)
|
||||||
|
|
||||||
|
/** Catppuccin color scheme (light). */
|
||||||
|
val CatppuccinLightColorScheme =
|
||||||
|
lightColorScheme(
|
||||||
|
primary = Color(0xFF8839EF),
|
||||||
|
onPrimary = Color(0xFFEFF1F5),
|
||||||
|
primaryContainer = Color(0xFFCCD0DA),
|
||||||
|
onPrimaryContainer = Color(0xFF4C4F69),
|
||||||
|
secondary = Color(0xFF1E66F5),
|
||||||
|
onSecondary = Color(0xFFEFF1F5),
|
||||||
|
secondaryContainer = Color(0xFFE6E9EF),
|
||||||
|
onSecondaryContainer = Color(0xFF4C4F69),
|
||||||
|
background = Color(0xFFEFF1F5),
|
||||||
|
onBackground = Color(0xFF4C4F69),
|
||||||
|
surface = Color(0xFFE6E9EF),
|
||||||
|
onSurface = Color(0xFF4C4F69),
|
||||||
|
surfaceVariant = Color(0xFFCCD0DA),
|
||||||
|
onSurfaceVariant = Color(0xFF6C6F85),
|
||||||
|
outline = Color(0xFF9CA0B0),
|
||||||
|
)
|
||||||
|
|
||||||
|
/** Catppuccin status colors (dark). */
|
||||||
|
val CatppuccinDarkStatusColors =
|
||||||
|
HermesStatusColors(
|
||||||
|
success = Color(0xFFA6E3A1),
|
||||||
|
successContainer = Color(0xFF313244),
|
||||||
|
onSuccess = Color(0xFF11111B),
|
||||||
|
warning = Color(0xFFF9E2AF),
|
||||||
|
warningContainer = Color(0xFF313244),
|
||||||
|
onWarning = Color(0xFF11111B),
|
||||||
|
error = Color(0xFFF38BA8),
|
||||||
|
errorContainer = Color(0xFF313244),
|
||||||
|
onError = Color(0xFF11111B),
|
||||||
|
info = Color(0xFF89B4FA),
|
||||||
|
infoContainer = Color(0xFF313244),
|
||||||
|
onInfo = Color(0xFF11111B),
|
||||||
|
)
|
||||||
|
|
||||||
|
/** Catppuccin status colors (light). */
|
||||||
|
val CatppuccinLightStatusColors =
|
||||||
|
HermesStatusColors(
|
||||||
|
success = Color(0xFF40A02B),
|
||||||
|
successContainer = Color(0xFFE6E9EF),
|
||||||
|
onSuccess = Color(0xFFE6E9EF),
|
||||||
|
warning = Color(0xFFDF8E1D),
|
||||||
|
warningContainer = Color(0xFFE6E9EF),
|
||||||
|
onWarning = Color(0xFFE6E9EF),
|
||||||
|
error = Color(0xFFD20F39),
|
||||||
|
errorContainer = Color(0xFFE6E9EF),
|
||||||
|
onError = Color(0xFFE6E9EF),
|
||||||
|
info = Color(0xFF1E66F5),
|
||||||
|
infoContainer = Color(0xFFE6E9EF),
|
||||||
|
onInfo = Color(0xFFE6E9EF),
|
||||||
|
)
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
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.DarkBackground
|
||||||
|
import com.m57.hermescontrol.theme.DarkInverseOnSurface
|
||||||
|
import com.m57.hermescontrol.theme.DarkInverseSurface
|
||||||
|
import com.m57.hermescontrol.theme.DarkOnSurface
|
||||||
|
import com.m57.hermescontrol.theme.DarkOnSurfaceVariant
|
||||||
|
import com.m57.hermescontrol.theme.DarkOutline
|
||||||
|
import com.m57.hermescontrol.theme.DarkOutlineVariant
|
||||||
|
import com.m57.hermescontrol.theme.DarkScrim
|
||||||
|
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.DarkSurfaceVariant
|
||||||
|
import com.m57.hermescontrol.theme.HermesAmber
|
||||||
|
import com.m57.hermescontrol.theme.HermesAmberDark
|
||||||
|
import com.m57.hermescontrol.theme.HermesAmberLight
|
||||||
|
import com.m57.hermescontrol.theme.HermesPurple
|
||||||
|
import com.m57.hermescontrol.theme.HermesPurpleContainer
|
||||||
|
import com.m57.hermescontrol.theme.HermesPurpleDark
|
||||||
|
import com.m57.hermescontrol.theme.HermesPurpleLight
|
||||||
|
import com.m57.hermescontrol.theme.HermesPurpleOnContainer
|
||||||
|
import com.m57.hermescontrol.theme.HermesStatusColors
|
||||||
|
import com.m57.hermescontrol.theme.LightBackground
|
||||||
|
import com.m57.hermescontrol.theme.LightInverseOnSurface
|
||||||
|
import com.m57.hermescontrol.theme.LightInverseSurface
|
||||||
|
import com.m57.hermescontrol.theme.LightOnSurface
|
||||||
|
import com.m57.hermescontrol.theme.LightOnSurfaceVariant
|
||||||
|
import com.m57.hermescontrol.theme.LightOutline
|
||||||
|
import com.m57.hermescontrol.theme.LightOutlineVariant
|
||||||
|
import com.m57.hermescontrol.theme.LightScrim
|
||||||
|
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.LightSurfaceVariant
|
||||||
|
import com.m57.hermescontrol.theme.StatusBlue
|
||||||
|
import com.m57.hermescontrol.theme.StatusBlueContainer
|
||||||
|
import com.m57.hermescontrol.theme.StatusGreen
|
||||||
|
import com.m57.hermescontrol.theme.StatusGreenContainer
|
||||||
|
import com.m57.hermescontrol.theme.StatusGreyLight
|
||||||
|
import com.m57.hermescontrol.theme.StatusRed
|
||||||
|
import com.m57.hermescontrol.theme.StatusRedContainer
|
||||||
|
import com.m57.hermescontrol.theme.StatusYellow
|
||||||
|
import com.m57.hermescontrol.theme.StatusYellowContainer
|
||||||
|
|
||||||
|
/** Brand default color scheme (dark) — Voltage Purple primary. */
|
||||||
|
val DefaultDarkColorScheme =
|
||||||
|
darkColorScheme(
|
||||||
|
primary = HermesPurple,
|
||||||
|
onPrimary = Color.White,
|
||||||
|
primaryContainer = HermesPurpleContainer,
|
||||||
|
onPrimaryContainer = HermesPurpleOnContainer,
|
||||||
|
secondary = HermesAmber,
|
||||||
|
onSecondary = Color.Black,
|
||||||
|
secondaryContainer = Color(0xFF3D2F0F),
|
||||||
|
onSecondaryContainer = HermesAmberLight,
|
||||||
|
tertiary = HermesAmberLight,
|
||||||
|
onTertiary = Color.Black,
|
||||||
|
background = DarkBackground,
|
||||||
|
onBackground = DarkOnSurface,
|
||||||
|
surface = DarkSurface,
|
||||||
|
onSurface = DarkOnSurface,
|
||||||
|
surfaceVariant = DarkSurfaceVariant,
|
||||||
|
onSurfaceVariant = DarkOnSurfaceVariant,
|
||||||
|
surfaceTint = HermesPurple,
|
||||||
|
surfaceContainer = DarkSurfaceContainer,
|
||||||
|
surfaceContainerHigh = DarkSurfaceContainerHigh,
|
||||||
|
surfaceContainerHighest = DarkSurfaceContainerHighest,
|
||||||
|
inverseSurface = DarkInverseSurface,
|
||||||
|
inverseOnSurface = DarkInverseOnSurface,
|
||||||
|
error = StatusRed,
|
||||||
|
onError = Color.White,
|
||||||
|
errorContainer = StatusRedContainer,
|
||||||
|
onErrorContainer = Color(0xFFFFB4B4),
|
||||||
|
outline = DarkOutline,
|
||||||
|
outlineVariant = DarkOutlineVariant,
|
||||||
|
scrim = DarkScrim,
|
||||||
|
)
|
||||||
|
|
||||||
|
/** Brand default color scheme (light) — Voltage Purple primary. */
|
||||||
|
val DefaultLightColorScheme =
|
||||||
|
lightColorScheme(
|
||||||
|
primary = HermesPurpleDark,
|
||||||
|
onPrimary = Color.White,
|
||||||
|
primaryContainer = HermesPurpleLight,
|
||||||
|
onPrimaryContainer = Color(0xFF1E0F66),
|
||||||
|
secondary = HermesAmberDark,
|
||||||
|
onSecondary = Color.White,
|
||||||
|
secondaryContainer = HermesAmberLight,
|
||||||
|
onSecondaryContainer = Color(0xFF3D2F0F),
|
||||||
|
tertiary = HermesAmberDark,
|
||||||
|
onTertiary = Color.White,
|
||||||
|
background = LightBackground,
|
||||||
|
onBackground = LightOnSurface,
|
||||||
|
surface = LightSurface,
|
||||||
|
onSurface = LightOnSurface,
|
||||||
|
surfaceVariant = LightSurfaceVariant,
|
||||||
|
onSurfaceVariant = LightOnSurfaceVariant,
|
||||||
|
surfaceTint = HermesPurple,
|
||||||
|
surfaceContainer = LightSurfaceContainer,
|
||||||
|
surfaceContainerHigh = LightSurfaceContainerHigh,
|
||||||
|
surfaceContainerHighest = LightSurfaceContainerHighest,
|
||||||
|
inverseSurface = LightInverseSurface,
|
||||||
|
inverseOnSurface = LightInverseOnSurface,
|
||||||
|
error = Color(0xFFB3261E),
|
||||||
|
onError = Color.White,
|
||||||
|
errorContainer = Color(0xFFF9DEDC),
|
||||||
|
onErrorContainer = Color(0xFF410E0B),
|
||||||
|
outline = LightOutline,
|
||||||
|
outlineVariant = LightOutlineVariant,
|
||||||
|
scrim = LightScrim,
|
||||||
|
)
|
||||||
|
|
||||||
|
/** Default status colors (dark). */
|
||||||
|
val DefaultDarkStatusColors =
|
||||||
|
HermesStatusColors(
|
||||||
|
success = StatusGreen,
|
||||||
|
successContainer = StatusGreenContainer,
|
||||||
|
onSuccess = StatusGreyLight,
|
||||||
|
warning = StatusYellow,
|
||||||
|
warningContainer = StatusYellowContainer,
|
||||||
|
onWarning = StatusGreyLight,
|
||||||
|
error = StatusRed,
|
||||||
|
errorContainer = StatusRedContainer,
|
||||||
|
onError = StatusGreyLight,
|
||||||
|
info = StatusBlue,
|
||||||
|
infoContainer = StatusBlueContainer,
|
||||||
|
onInfo = StatusGreyLight,
|
||||||
|
)
|
||||||
|
|
||||||
|
/** Default status colors (light). */
|
||||||
|
val DefaultLightStatusColors =
|
||||||
|
HermesStatusColors(
|
||||||
|
success = Color(0xFF1B873A),
|
||||||
|
successContainer = Color(0xFFD7F5E0),
|
||||||
|
onSuccess = Color(0xFFFDF8FF),
|
||||||
|
warning = HermesAmberDark,
|
||||||
|
warningContainer = Color(0xFFFFEAB3),
|
||||||
|
onWarning = Color(0xFFFDF8FF),
|
||||||
|
error = Color(0xFFB3261E),
|
||||||
|
errorContainer = Color(0xFFF9DEDC),
|
||||||
|
onError = Color(0xFFFDF8FF),
|
||||||
|
info = Color(0xFF2E6FBD),
|
||||||
|
infoContainer = Color(0xFFD4E7FF),
|
||||||
|
onInfo = Color(0xFFFDF8FF),
|
||||||
|
)
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
/** Gruvbox color scheme (dark). */
|
||||||
|
val GruvboxDarkColorScheme =
|
||||||
|
darkColorScheme(
|
||||||
|
primary = Color(0xFFFE8019),
|
||||||
|
onPrimary = Color(0xFF282828),
|
||||||
|
primaryContainer = Color(0xFFD65D0E),
|
||||||
|
onPrimaryContainer = Color(0xFFFBF1C7),
|
||||||
|
secondary = Color(0xFFFABD2F),
|
||||||
|
onSecondary = Color(0xFF282828),
|
||||||
|
secondaryContainer = Color(0xFF3C3836),
|
||||||
|
onSecondaryContainer = Color(0xFFBDAE93),
|
||||||
|
background = Color(0xFF282828),
|
||||||
|
onBackground = Color(0xFFFBF1C7),
|
||||||
|
surface = Color(0xFF32302F),
|
||||||
|
onSurface = Color(0xFFFBF1C7),
|
||||||
|
surfaceVariant = Color(0xFF3C3836),
|
||||||
|
onSurfaceVariant = Color(0xFFBDAE93),
|
||||||
|
outline = Color(0xFF665C54),
|
||||||
|
)
|
||||||
|
|
||||||
|
/** Gruvbox color scheme (light). */
|
||||||
|
val GruvboxLightColorScheme =
|
||||||
|
lightColorScheme(
|
||||||
|
primary = Color(0xFFD65D0E),
|
||||||
|
onPrimary = Color(0xFFFBF1C7),
|
||||||
|
primaryContainer = Color(0xFFFE8019),
|
||||||
|
onPrimaryContainer = Color(0xFF282828),
|
||||||
|
secondary = Color(0xFF458588),
|
||||||
|
onSecondary = Color(0xFFFBF1C7),
|
||||||
|
secondaryContainer = Color(0xFFEBDBB2),
|
||||||
|
onSecondaryContainer = Color(0xFF3C3836),
|
||||||
|
background = Color(0xFFFBF1C7),
|
||||||
|
onBackground = Color(0xFF282828),
|
||||||
|
surface = Color(0xFFF2E5BC),
|
||||||
|
onSurface = Color(0xFF282828),
|
||||||
|
surfaceVariant = Color(0xFFEBDBB2),
|
||||||
|
onSurfaceVariant = Color(0xFF7C6F64),
|
||||||
|
outline = Color(0xFFA89984),
|
||||||
|
)
|
||||||
|
|
||||||
|
/** Gruvbox status colors (dark). */
|
||||||
|
val GruvboxDarkStatusColors =
|
||||||
|
HermesStatusColors(
|
||||||
|
success = Color(0xFFB8BB26),
|
||||||
|
successContainer = Color(0xFF32302F),
|
||||||
|
onSuccess = Color(0xFF282828),
|
||||||
|
warning = Color(0xFFFABD2F),
|
||||||
|
warningContainer = Color(0xFF3C3836),
|
||||||
|
onWarning = Color(0xFF282828),
|
||||||
|
error = Color(0xFFFB4934),
|
||||||
|
errorContainer = Color(0xFF282828),
|
||||||
|
onError = Color(0xFF282828),
|
||||||
|
info = Color(0xFF83A598),
|
||||||
|
infoContainer = Color(0xFF3C3836),
|
||||||
|
onInfo = Color(0xFF282828),
|
||||||
|
)
|
||||||
|
|
||||||
|
/** Gruvbox status colors (light). */
|
||||||
|
val GruvboxLightStatusColors =
|
||||||
|
HermesStatusColors(
|
||||||
|
success = Color(0xFF98971A),
|
||||||
|
successContainer = Color(0xFFEBDBB2),
|
||||||
|
onSuccess = Color(0xFFEBDBB2),
|
||||||
|
warning = Color(0xFFD79921),
|
||||||
|
warningContainer = Color(0xFFEBDBB2),
|
||||||
|
onWarning = Color(0xFFEBDBB2),
|
||||||
|
error = Color(0xFFCC241D),
|
||||||
|
errorContainer = Color(0xFFEBDBB2),
|
||||||
|
onError = Color(0xFFEBDBB2),
|
||||||
|
info = Color(0xFF458588),
|
||||||
|
infoContainer = Color(0xFFEBDBB2),
|
||||||
|
onInfo = Color(0xFFEBDBB2),
|
||||||
|
)
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.m57.hermescontrol.theme.presets
|
||||||
|
|
||||||
|
import androidx.compose.material3.darkColorScheme
|
||||||
|
import androidx.compose.material3.lightColorScheme
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
||||||
|
/** Monochrome color scheme (dark). */
|
||||||
|
val MonochromeDarkColorScheme =
|
||||||
|
darkColorScheme(
|
||||||
|
primary = Color.White,
|
||||||
|
onPrimary = Color.Black,
|
||||||
|
primaryContainer = Color(0xFF2B2B2B),
|
||||||
|
onPrimaryContainer = Color.White,
|
||||||
|
secondary = Color(0xFFB0B0B0),
|
||||||
|
onSecondary = Color.Black,
|
||||||
|
secondaryContainer = Color(0xFF222222),
|
||||||
|
onSecondaryContainer = Color(0xFFE0E0E0),
|
||||||
|
background = Color(0xFF121212),
|
||||||
|
onBackground = Color(0xFFE0E0E0),
|
||||||
|
surface = Color(0xFF1E1E1E),
|
||||||
|
onSurface = Color(0xFFE0E0E0),
|
||||||
|
surfaceVariant = Color(0xFF2B2B2B),
|
||||||
|
onSurfaceVariant = Color(0xFFB0B0B0),
|
||||||
|
outline = Color(0xFF666666),
|
||||||
|
)
|
||||||
|
|
||||||
|
/** Monochrome color scheme (light). */
|
||||||
|
val MonochromeLightColorScheme =
|
||||||
|
lightColorScheme(
|
||||||
|
primary = Color.Black,
|
||||||
|
onPrimary = Color.White,
|
||||||
|
primaryContainer = Color(0xFFE0E0E0),
|
||||||
|
onPrimaryContainer = Color.Black,
|
||||||
|
secondary = Color(0xFF4A4A4A),
|
||||||
|
onSecondary = Color.White,
|
||||||
|
secondaryContainer = Color(0xFFF0F0F0),
|
||||||
|
onSecondaryContainer = Color(0xFF111111),
|
||||||
|
background = Color(0xFFFFFFFF),
|
||||||
|
onBackground = Color(0xFF111111),
|
||||||
|
surface = Color(0xFFF5F5F5),
|
||||||
|
onSurface = Color(0xFF111111),
|
||||||
|
surfaceVariant = Color(0xFFE0E0E0),
|
||||||
|
onSurfaceVariant = Color(0xFF4A4A4A),
|
||||||
|
outline = Color(0xFF888888),
|
||||||
|
)
|
||||||
|
|
||||||
|
/** Monochrome status colors (dark) — reuses the brand default set. */
|
||||||
|
val MonochromeDarkStatusColors = DefaultDarkStatusColors
|
||||||
|
|
||||||
|
/** Monochrome status colors (light) — reuses the brand default set. */
|
||||||
|
val MonochromeLightStatusColors = DefaultLightStatusColors
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
/** Neon Noir color scheme (dark). */
|
||||||
|
val NeonNoirDarkColorScheme =
|
||||||
|
darkColorScheme(
|
||||||
|
primary = Color(0xFFFF6BF4),
|
||||||
|
onPrimary = Color(0xFF1A001A),
|
||||||
|
primaryContainer = Color(0xFF3A003A),
|
||||||
|
onPrimaryContainer = Color(0xFFFFCCF2),
|
||||||
|
secondary = Color(0xFFA78BFA),
|
||||||
|
onSecondary = Color(0xFF0F0B1A),
|
||||||
|
secondaryContainer = Color(0xFF2B1F59),
|
||||||
|
onSecondaryContainer = Color(0xFFD9CCFF),
|
||||||
|
tertiary = Color(0xFF60F0FF),
|
||||||
|
onTertiary = Color(0xFF003B40),
|
||||||
|
tertiaryContainer = Color(0xFF004F59),
|
||||||
|
onTertiaryContainer = Color(0xFFBFFAFF),
|
||||||
|
background = Color(0xFF0F0B1A),
|
||||||
|
onBackground = Color(0xFFE8E0F0),
|
||||||
|
surface = Color(0xFF1A1530),
|
||||||
|
onSurface = Color(0xFFE8E0F0),
|
||||||
|
surfaceVariant = Color(0xFF2B2540),
|
||||||
|
onSurfaceVariant = Color(0xFF9A90B0),
|
||||||
|
surfaceTint = Color(0xFFFF6BF4),
|
||||||
|
surfaceContainer = Color(0xFF1A1530),
|
||||||
|
surfaceContainerHigh = Color(0xFF252040),
|
||||||
|
surfaceContainerHighest = Color(0xFF2F2A50),
|
||||||
|
inverseSurface = Color(0xFFE8E0F0),
|
||||||
|
inverseOnSurface = Color(0xFF0F0B1A),
|
||||||
|
error = Color(0xFFFF3D68),
|
||||||
|
onError = Color.White,
|
||||||
|
errorContainer = Color(0xFF3A0A14),
|
||||||
|
onErrorContainer = Color(0xFFFFB3C0),
|
||||||
|
outline = Color(0xFF3A3060),
|
||||||
|
outlineVariant = Color(0xFF2E2545),
|
||||||
|
scrim = Color(0xFF000000),
|
||||||
|
)
|
||||||
|
|
||||||
|
/** Neon Noir color scheme (light). */
|
||||||
|
val NeonNoirLightColorScheme =
|
||||||
|
lightColorScheme(
|
||||||
|
primary = Color(0xFFC440A8),
|
||||||
|
onPrimary = Color.White,
|
||||||
|
primaryContainer = Color(0xFFFFD9F2),
|
||||||
|
onPrimaryContainer = Color(0xFF3A003A),
|
||||||
|
secondary = Color(0xFF7C4DFF),
|
||||||
|
onSecondary = Color.White,
|
||||||
|
secondaryContainer = Color(0xFFEDE0FF),
|
||||||
|
onSecondaryContainer = Color(0xFF1E0066),
|
||||||
|
tertiary = Color(0xFF0098A6),
|
||||||
|
onTertiary = Color.White,
|
||||||
|
tertiaryContainer = Color(0xFFBFFAFF),
|
||||||
|
onTertiaryContainer = Color(0xFF003B40),
|
||||||
|
background = Color(0xFFF5F0FA),
|
||||||
|
onBackground = Color(0xFF0F0B1A),
|
||||||
|
surface = Color.White,
|
||||||
|
onSurface = Color(0xFF0F0B1A),
|
||||||
|
surfaceVariant = Color(0xFFEDE6F5),
|
||||||
|
onSurfaceVariant = Color(0xFF7A7090),
|
||||||
|
surfaceTint = Color(0xFFC440A8),
|
||||||
|
surfaceContainer = Color(0xFFFDF8FF),
|
||||||
|
surfaceContainerHigh = Color(0xFFF0EDF5),
|
||||||
|
surfaceContainerHighest = Color(0xFFE6E0ED),
|
||||||
|
inverseSurface = Color(0xFF0F0B1A),
|
||||||
|
inverseOnSurface = Color(0xFFE8E0F0),
|
||||||
|
error = Color(0xFFB3261E),
|
||||||
|
onError = Color.White,
|
||||||
|
errorContainer = Color(0xFFF9DEDC),
|
||||||
|
onErrorContainer = Color(0xFF410E0B),
|
||||||
|
outline = Color(0xFFBFB8CC),
|
||||||
|
outlineVariant = Color(0xFFD9D2E3),
|
||||||
|
scrim = Color(0xFF000000),
|
||||||
|
)
|
||||||
|
|
||||||
|
/** Neon Noir status colors (dark). */
|
||||||
|
val NeonNoirDarkStatusColors =
|
||||||
|
HermesStatusColors(
|
||||||
|
success = Color(0xFF6FEA8B),
|
||||||
|
successContainer = Color(0xFF0A3A14),
|
||||||
|
onSuccess = Color(0xFF0F0B1A),
|
||||||
|
warning = Color(0xFFFFB347),
|
||||||
|
warningContainer = Color(0xFF3A2000),
|
||||||
|
onWarning = Color(0xFF0F0B1A),
|
||||||
|
error = Color(0xFFFF3D68),
|
||||||
|
errorContainer = Color(0xFF3A0A14),
|
||||||
|
onError = Color(0xFF0F0B1A),
|
||||||
|
info = Color(0xFF60F0FF),
|
||||||
|
infoContainer = Color(0xFF003B40),
|
||||||
|
onInfo = Color(0xFF0F0B1A),
|
||||||
|
)
|
||||||
|
|
||||||
|
/** Neon Noir status colors (light). */
|
||||||
|
val NeonNoirLightStatusColors =
|
||||||
|
HermesStatusColors(
|
||||||
|
success = Color(0xFF1B873A),
|
||||||
|
successContainer = Color(0xFFD7F5E0),
|
||||||
|
onSuccess = Color(0xFFFDF8FF),
|
||||||
|
warning = Color(0xFFB87800),
|
||||||
|
warningContainer = Color(0xFFFFEAB3),
|
||||||
|
onWarning = Color(0xFFFDF8FF),
|
||||||
|
error = Color(0xFFB3261E),
|
||||||
|
errorContainer = Color(0xFFF9DEDC),
|
||||||
|
onError = Color(0xFFFDF8FF),
|
||||||
|
info = Color(0xFF2E6FBD),
|
||||||
|
infoContainer = Color(0xFFD4E7FF),
|
||||||
|
onInfo = Color(0xFFFDF8FF),
|
||||||
|
)
|
||||||
Reference in new issue
Block a user