git.iko.soy/opencode-android
on 8bc2cce help sign in
148 lines 5.4 kB history raw
1package soy.iko.opencode.ui.theme
3import android.app.Activity
4import android.content.Context
5import android.content.ContextWrapper
6import android.os.Build
7import androidx.compose.foundation.isSystemInDarkTheme
8import androidx.compose.material3.MaterialTheme
9import androidx.compose.material3.darkColorScheme
10import androidx.compose.material3.dynamicDarkColorScheme
11import androidx.compose.material3.dynamicLightColorScheme
12import androidx.compose.material3.lightColorScheme
13import androidx.compose.runtime.Composable
14import androidx.compose.runtime.SideEffect
15import androidx.compose.ui.graphics.Color
16import androidx.compose.ui.platform.LocalContext
17import androidx.compose.ui.platform.LocalView
18import androidx.core.view.WindowCompat
20/**
21 * Tokyo Night — a dark, muted blue/purple palette. Every Material 3 color role is set
22 * explicitly (not just primary/secondary/tertiary) so components that read `error`,
23 * `primaryContainer`, `surfaceVariant`, `outline`, etc. match the brand instead of
24 * falling back to stock M3 defaults that clash with it.
25 *
26 * Source palette (Tokyo Night):
27 * bg #1A1B26 fg #C0CAF5 blue #7AA2F7 cyan #7DCFFF
28 * green #9ECE6A magenta #BB9AF7 red #F7768E yellow #E0AF68
29 * comment #565F89 gutter #414868
30 */
31private val DarkColors = darkColorScheme(
32 primary = Color(0xFF7AA2F7),
33 onPrimary = Color(0xFF112036),
34 primaryContainer = Color(0xFF2A3A5C),
35 onPrimaryContainer = Color(0xFFD6E2FF),
36 secondary = Color(0xFF9ECE6A),
37 onSecondary = Color(0xFF13260A),
38 secondaryContainer = Color(0xFF2B3B1F),
39 onSecondaryContainer = Color(0xFFD2F0A0),
40 tertiary = Color(0xFFBB9AF7),
41 onTertiary = Color(0xFF221036),
42 tertiaryContainer = Color(0xFF3A2A55),
43 onTertiaryContainer = Color(0xFFE6D6FF),
44 error = Color(0xFFF7768E),
45 onError = Color(0xFF370610),
46 errorContainer = Color(0xFF5C1A24),
47 onErrorContainer = Color(0xFFFFD9DE),
48 background = Color(0xFF1A1B26),
49 onBackground = Color(0xFFC0CAF5),
50 surface = Color(0xFF1F2335),
51 onSurface = Color(0xFFC0CAF5),
52 surfaceVariant = Color(0xFF2D3247),
53 onSurfaceVariant = Color(0xFF9AA5CE),
54 surfaceTint = Color(0xFF7AA2F7),
55 inverseSurface = Color(0xFFC0CAF5),
56 inverseOnSurface = Color(0xFF1A1B26),
57 outline = Color(0xFF565F89),
58 outlineVariant = Color(0xFF414868),
59 scrim = Color(0xFF000000),
62/**
63 * Tokyo Night Light — the day-mode counterpart. Pairs the same hue family with a soft
64 * off-white background so the brand identity survives a light setting instead of
65 * snapping to stock M3 purple-grey.
66 */
67private val LightColors = lightColorScheme(
68 primary = Color(0xFF34548A),
69 onPrimary = Color(0xFFFFFFFF),
70 primaryContainer = Color(0xFFD6E2FF),
71 onPrimaryContainer = Color(0xFF001A41),
72 secondary = Color(0xFF485E30),
73 onSecondary = Color(0xFFFFFFFF),
74 secondaryContainer = Color(0xFFC8F0A0),
75 onSecondaryContainer = Color(0xFF0E2000),
76 tertiary = Color(0xFF5A4A78),
77 onTertiary = Color(0xFFFFFFFF),
78 tertiaryContainer = Color(0xFFE6D6FF),
79 onTertiaryContainer = Color(0xFF180038),
80 error = Color(0xFF9B1C2E),
81 onError = Color(0xFFFFFFFF),
82 errorContainer = Color(0xFFFFD9DE),
83 onErrorContainer = Color(0xFF410008),
84 background = Color(0xFFF6F7FB),
85 onBackground = Color(0xFF1A1B26),
86 surface = Color(0xFFF1F3FA),
87 onSurface = Color(0xFF1A1B26),
88 surfaceVariant = Color(0xFFE0E4F0),
89 onSurfaceVariant = Color(0xFF444B6E),
90 surfaceTint = Color(0xFF34548A),
91 inverseSurface = Color(0xFF2D3247),
92 inverseOnSurface = Color(0xFFEEF0FB),
93 outline = Color(0xFF747DAA),
94 outlineVariant = Color(0xFFC3C8DA),
95 scrim = Color(0xFF000000),
98@Composable
99fun OpencodeTheme(
100 darkTheme: Boolean = isSystemInDarkTheme(),
101 dynamicColor: Boolean = false,
102 content: @Composable () -> Unit,
103) {
104 val context = LocalContext.current
105 val colorScheme = when {
106 dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ->
107 if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
108 darkTheme -> DarkColors
109 else -> LightColors
110 }
111 val view = LocalView.current
112 if (!view.isInEditMode) {
113 SideEffect {
114 val window = view.context.findActivity()?.window ?: return@SideEffect
115 WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = !darkTheme
116 }
117 }
118 MaterialTheme(
119 colorScheme = colorScheme,
120 typography = OpencodeTypography,
121 shapes = OpencodeShapes,
122 content = content,
123 )
126/**
127 * Preview swatches for the Tokyo Night palettes, exposed so the Settings theme picker
128 * can show color dots without reaching into the (otherwise private) full color schemes.
129 * Each list is [primary, secondary, tertiary, background].
130 */
131val DarkPaletteSwatches: List<Color> = listOf(
132 DarkColors.primary,
133 DarkColors.secondary,
134 DarkColors.tertiary,
135 DarkColors.background,
137val LightPaletteSwatches: List<Color> = listOf(
138 LightColors.primary,
139 LightColors.secondary,
140 LightColors.tertiary,
141 LightColors.background,
144private tailrec fun Context.findActivity(): Activity? = when (this) {
145 is Activity -> this
146 is ContextWrapper -> baseContext.findActivity()
147 else -> null