feat: Material You design system rewrite — Phases 1–4
Complete UI/UX rewrite of hermes-mobile with Material You design system. Phase 1: Color/Theme/Type/Shapes/Spacing/Motion tokens Phase 2: HermesScaffold, StateViews (skeleton/empty/error), SearchBar, StatusBadge, ToggleRow Phase 3: Bottom nav + drawer navigation with NavigationController Phase 4: All 17 screens rewritten with HermesScaffold and Material You patterns Closes PR #3.
This commit is contained in:
29 files changed
+2669
-2377
No files matched your search
@@ -8,6 +8,7 @@ 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
|
||||
@@ -18,9 +19,17 @@ val LocalThemePreference = compositionLocalOf { ThemePreference.SYSTEM }
|
||||
|
||||
/**
|
||||
* Set to true to opt into Material You dynamic color (Android 12+).
|
||||
* Off by default — brand identity (Voltage Purple) is the priority.
|
||||
*
|
||||
* On API 31+ the app derives its entire colour scheme from the user's
|
||||
* wallpaper — primary, secondary, tertiary, surfaces, the lot. On older
|
||||
* devices the [HermesDarkColorScheme] / [HermesLightColorScheme] brand
|
||||
* palette is used instead.
|
||||
*
|
||||
* Semantic status colours (success / warning / error / info) and chat-bubble
|
||||
* colours are ALWAYS brand-defined regardless of dynamic colour — see
|
||||
* [Color.kt] and the `LocalHermesStatusColors` provider below.
|
||||
*/
|
||||
private const val ENABLE_DYNAMIC_COLOR = false
|
||||
private const val ENABLE_DYNAMIC_COLOR = true
|
||||
|
||||
private val HermesDarkColorScheme =
|
||||
darkColorScheme(
|
||||
@@ -33,6 +42,7 @@ private val HermesDarkColorScheme =
|
||||
secondaryContainer = Color(0xFF3D2F0F),
|
||||
onSecondaryContainer = HermesAmberLight,
|
||||
tertiary = HermesAmberLight,
|
||||
onTertiary = Color.Black,
|
||||
background = DarkBackground,
|
||||
onBackground = DarkOnSurface,
|
||||
surface = DarkSurface,
|
||||
@@ -40,17 +50,18 @@ private val HermesDarkColorScheme =
|
||||
surfaceVariant = DarkSurfaceVariant,
|
||||
onSurfaceVariant = DarkOnSurfaceVariant,
|
||||
surfaceTint = HermesPurple,
|
||||
surfaceContainer = DarkSurfaceVariant,
|
||||
surfaceContainerHigh = DarkSurfaceHigh,
|
||||
surfaceContainerHighest = DarkSurfaceHigh,
|
||||
inverseSurface = Color(0xFFE8E6EE),
|
||||
inverseOnSurface = Color(0xFF1A1A24),
|
||||
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 =
|
||||
@@ -64,6 +75,7 @@ private val HermesLightColorScheme =
|
||||
secondaryContainer = HermesAmberLight,
|
||||
onSecondaryContainer = Color(0xFF3D2F0F),
|
||||
tertiary = HermesAmberDark,
|
||||
onTertiary = Color.White,
|
||||
background = LightBackground,
|
||||
onBackground = LightOnSurface,
|
||||
surface = LightSurface,
|
||||
@@ -71,17 +83,18 @@ private val HermesLightColorScheme =
|
||||
surfaceVariant = LightSurfaceVariant,
|
||||
onSurfaceVariant = LightOnSurfaceVariant,
|
||||
surfaceTint = HermesPurple,
|
||||
surfaceContainer = LightSurfaceVariant,
|
||||
surfaceContainerHigh = LightSurfaceHigh,
|
||||
surfaceContainerHighest = LightSurfaceHigh,
|
||||
inverseSurface = Color(0xFF1A1A24),
|
||||
inverseOnSurface = Color(0xFFE8E6EE),
|
||||
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,
|
||||
)
|
||||
|
||||
@Composable
|
||||
@@ -107,10 +120,41 @@ fun HermesControlTheme(
|
||||
else -> HermesLightColorScheme
|
||||
}
|
||||
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
typography = Typography,
|
||||
shapes = HermesShapes,
|
||||
content = content,
|
||||
)
|
||||
val statusColors =
|
||||
if (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(
|
||||
LocalHermesStatusColors provides statusColors,
|
||||
LocalSpacing provides SpacingDefaults,
|
||||
LocalMotion provides MotionDefaults,
|
||||
) {
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
typography = Typography,
|
||||
shapes = HermesShapes,
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user