package com.m57.hermescontrol.theme import android.os.Build import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.material3.MaterialTheme import androidx.compose.material3.darkColorScheme import androidx.compose.material3.dynamicDarkColorScheme import androidx.compose.material3.dynamicLightColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.compositionLocalOf import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext enum class ThemePreference { SYSTEM, LIGHT, DARK } enum class ThemePreset { DEFAULT, MONOCHROME, GRUVBOX, CATPPUCCIN, AMOLED } val LocalThemePreference = compositionLocalOf { ThemePreference.SYSTEM } val LocalThemePreset = compositionLocalOf { ThemePreset.DEFAULT } /** * Set to true to opt into Material You dynamic color (Android 12+). */ private const val ENABLE_DYNAMIC_COLOR = true private val HermesDarkColorScheme = 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, ) private val HermesLightColorScheme = 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, ) 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), ) @Composable fun HermesControlTheme( themePreference: ThemePreference = LocalThemePreference.current, useDynamicColors: Boolean = true, themePreset: ThemePreset = ThemePreset.DEFAULT, content: @Composable () -> Unit, ) { val darkTheme = when (themePreference) { ThemePreference.SYSTEM -> isSystemInDarkTheme() ThemePreference.LIGHT -> false ThemePreference.DARK -> true } val context = LocalContext.current val dynamicAvailable = useDynamicColors && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S val colorScheme = when { dynamicAvailable && darkTheme -> dynamicDarkColorScheme(context) dynamicAvailable && !darkTheme -> dynamicLightColorScheme(context) else -> { 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 } } } val statusColors = when { themePreset == ThemePreset.GRUVBOX && darkTheme -> { HermesStatusColors( success = Color(0xFFB8BB26), successContainer = Color(0xFF32302F), warning = Color(0xFFFABD2F), warningContainer = Color(0xFF3C3836), error = Color(0xFFFB4934), errorContainer = Color(0xFF282828), info = Color(0xFF83A598), infoContainer = Color(0xFF3C3836), ) } themePreset == ThemePreset.GRUVBOX && !darkTheme -> { HermesStatusColors( success = Color(0xFF98971A), successContainer = Color(0xFFEBDBB2), warning = Color(0xFFD79921), warningContainer = Color(0xFFEBDBB2), error = Color(0xFFCC241D), errorContainer = Color(0xFFEBDBB2), info = Color(0xFF458588), infoContainer = Color(0xFFEBDBB2), ) } themePreset == ThemePreset.CATPPUCCIN && darkTheme -> { HermesStatusColors( success = Color(0xFFA6E3A1), successContainer = Color(0xFF313244), warning = Color(0xFFF9E2AF), warningContainer = Color(0xFF313244), error = Color(0xFFF38BA8), errorContainer = Color(0xFF313244), info = Color(0xFF89B4FA), infoContainer = Color(0xFF313244), ) } themePreset == ThemePreset.CATPPUCCIN && !darkTheme -> { HermesStatusColors( success = Color(0xFF40A02B), successContainer = Color(0xFFE6E9EF), warning = Color(0xFFDF8E1D), warningContainer = Color(0xFFE6E9EF), error = Color(0xFFD20F39), errorContainer = Color(0xFFE6E9EF), info = Color(0xFF1E66F5), infoContainer = Color(0xFFE6E9EF), ) } darkTheme -> { HermesStatusColors( success = StatusGreen, successContainer = StatusGreenContainer, warning = StatusYellow, warningContainer = StatusYellowContainer, error = StatusRed, errorContainer = StatusRedContainer, info = StatusBlue, infoContainer = StatusBlueContainer, ) } else -> { HermesStatusColors( success = Color(0xFF1B873A), successContainer = Color(0xFFD7F5E0), warning = HermesAmberDark, warningContainer = Color(0xFFFFEAB3), error = Color(0xFFB3261E), errorContainer = Color(0xFFF9DEDC), info = Color(0xFF2E6FBD), infoContainer = Color(0xFFD4E7FF), ) } } CompositionLocalProvider( LocalThemePreference provides themePreference, LocalThemePreset provides themePreset, LocalHermesStatusColors provides statusColors, LocalSpacing provides SpacingDefaults, LocalMotion provides MotionDefaults, ) { MaterialTheme( colorScheme = colorScheme, typography = Typography, shapes = HermesShapes, content = content, ) } }