fix: wire theme switching — replace all hardcoded Amber colors with LocalKaizenAccent

All 7 files that imported Amber/AmberDeep/OnAmber/BlobX now read from
LocalKaizenAccent.current instead. Theme switching in settings actually
changes the UI now: message bubbles, send button, orb, blobs, sidebar
highlights, model sheet, stream blocks, login screen, and settings
toggles all respond to the selected theme.
This commit is contained in:
Bruno Deanoz 2026-06-21 18:29:42 +02:00
parent 918659422b
commit d468ec893f
7 changed files with 56 additions and 48 deletions

View file

@ -49,9 +49,7 @@ import dev.kaizen.app.chat.MeshBackground
import dev.kaizen.app.net.DEFAULT_BASE_URL import dev.kaizen.app.net.DEFAULT_BASE_URL
import dev.kaizen.app.net.LoginResult import dev.kaizen.app.net.LoginResult
import dev.kaizen.app.net.SessionViewModel import dev.kaizen.app.net.SessionViewModel
import dev.kaizen.app.ui.theme.Amber import dev.kaizen.app.ui.theme.LocalKaizenAccent
import dev.kaizen.app.ui.theme.AmberDeep
import dev.kaizen.app.ui.theme.OnAmber
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import dev.kaizen.app.R import dev.kaizen.app.R
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -65,6 +63,7 @@ import kotlinx.coroutines.launch
@Composable @Composable
fun LoginScreen(session: SessionViewModel, modifier: Modifier = Modifier) { fun LoginScreen(session: SessionViewModel, modifier: Modifier = Modifier) {
val cs = MaterialTheme.colorScheme val cs = MaterialTheme.colorScheme
val accent = LocalKaizenAccent.current
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val ctx = androidx.compose.ui.platform.LocalContext.current val ctx = androidx.compose.ui.platform.LocalContext.current
@ -165,6 +164,7 @@ private fun GlassField(
) { ) {
val cs = MaterialTheme.colorScheme val cs = MaterialTheme.colorScheme
val isDark = isSystemInDarkTheme() val isDark = isSystemInDarkTheme()
val accent = LocalKaizenAccent.current
val glassBg = if (isDark) { val glassBg = if (isDark) {
Brush.verticalGradient(listOf(Color(0xFF1E293B).copy(alpha = 0.72f), Color(0xFF0F172A).copy(alpha = 0.85f))) Brush.verticalGradient(listOf(Color(0xFF1E293B).copy(alpha = 0.72f), Color(0xFF0F172A).copy(alpha = 0.85f)))
@ -196,7 +196,7 @@ private fun GlassField(
value = value, value = value,
onValueChange = onValueChange, onValueChange = onValueChange,
textStyle = TextStyle(color = cs.onBackground, fontSize = 16.sp), textStyle = TextStyle(color = cs.onBackground, fontSize = 16.sp),
cursorBrush = SolidColor(Amber), cursorBrush = SolidColor(accent.primary),
singleLine = true, singleLine = true,
visualTransformation = if (password) PasswordVisualTransformation() else androidx.compose.ui.text.input.VisualTransformation.None, visualTransformation = if (password) PasswordVisualTransformation() else androidx.compose.ui.text.input.VisualTransformation.None,
keyboardOptions = KeyboardOptions(keyboardType = keyboardType, imeAction = imeAction), keyboardOptions = KeyboardOptions(keyboardType = keyboardType, imeAction = imeAction),
@ -209,8 +209,9 @@ private fun GlassField(
@Composable @Composable
private fun SignInButton(enabled: Boolean, loading: Boolean, onClick: () -> Unit) { private fun SignInButton(enabled: Boolean, loading: Boolean, onClick: () -> Unit) {
val cs = MaterialTheme.colorScheme val cs = MaterialTheme.colorScheme
val accent = LocalKaizenAccent.current
val fill = if (enabled || loading) { val fill = if (enabled || loading) {
Modifier.background(Brush.linearGradient(listOf(Amber, AmberDeep))) Modifier.background(Brush.linearGradient(listOf(accent.primary, accent.primaryDeep)))
} else { } else {
Modifier.background(cs.surface) Modifier.background(cs.surface)
} }
@ -227,11 +228,11 @@ private fun SignInButton(enabled: Boolean, loading: Boolean, onClick: () -> Unit
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
) { ) {
if (loading) { if (loading) {
CircularProgressIndicator(color = OnAmber, strokeWidth = 2.4.dp, modifier = Modifier.size(22.dp)) CircularProgressIndicator(color = accent.onPrimary, strokeWidth = 2.4.dp, modifier = Modifier.size(22.dp))
} else { } else {
Text( Text(
stringResource(R.string.login_submit), stringResource(R.string.login_submit),
color = if (enabled) OnAmber else cs.onSurfaceVariant, color = if (enabled) accent.onPrimary else cs.onSurfaceVariant,
fontSize = 16.sp, fontSize = 16.sp,
fontWeight = FontWeight.SemiBold, fontWeight = FontWeight.SemiBold,
) )

View file

@ -35,11 +35,7 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import dev.kaizen.app.ui.motion.Durations import dev.kaizen.app.ui.motion.Durations
import dev.kaizen.app.ui.sensor.rememberTiltState import dev.kaizen.app.ui.sensor.rememberTiltState
import dev.kaizen.app.ui.theme.Amber import dev.kaizen.app.ui.theme.LocalKaizenAccent
import dev.kaizen.app.ui.theme.AmberDeep
import dev.kaizen.app.ui.theme.BlobAmber
import dev.kaizen.app.ui.theme.BlobCoral
import dev.kaizen.app.ui.theme.BlobTeal
import dev.kaizen.app.ui.theme.DITHER_ALPHA import dev.kaizen.app.ui.theme.DITHER_ALPHA
import dev.kaizen.app.ui.theme.rememberDitherBrush import dev.kaizen.app.ui.theme.rememberDitherBrush
@ -47,6 +43,7 @@ import dev.kaizen.app.ui.theme.rememberDitherBrush
@Composable @Composable
fun MeshBackground(content: @Composable BoxScope.() -> Unit) { fun MeshBackground(content: @Composable BoxScope.() -> Unit) {
val dark = isSystemInDarkTheme() val dark = isSystemInDarkTheme()
val accent = LocalKaizenAccent.current
val base = MaterialTheme.colorScheme.background val base = MaterialTheme.colorScheme.background
// Blobs are subtler in light mode. // Blobs are subtler in light mode.
val factor = if (dark) 1f else 0.55f val factor = if (dark) 1f else 0.55f
@ -68,9 +65,9 @@ fun MeshBackground(content: @Composable BoxScope.() -> Unit) {
drawRect(brush = ditherBrush, alpha = DITHER_ALPHA) drawRect(brush = ditherBrush, alpha = DITHER_ALPHA)
}, },
) { ) {
Blob(BlobAmber, 360.dp, (-60f + drift * 30f).dp, (-40f + drift * 24f).dp, 0.30f * factor) Blob(accent.blob1, 360.dp, (-60f + drift * 30f).dp, (-40f + drift * 24f).dp, 0.30f * factor)
Blob(BlobCoral, 380.dp, (170f - drift * 44f).dp, (150f + drift * 40f).dp, 0.24f * factor) Blob(accent.blob2, 380.dp, (170f - drift * 44f).dp, (150f + drift * 40f).dp, 0.24f * factor)
Blob(BlobTeal, 300.dp, (30f + drift * 50f).dp, (560f - drift * 36f).dp, 0.22f * factor) Blob(accent.blob4, 300.dp, (30f + drift * 50f).dp, (560f - drift * 36f).dp, 0.22f * factor)
// Vignette: darken the edges so the center comes forward (dark mode only). // Vignette: darken the edges so the center comes forward (dark mode only).
if (dark) { if (dark) {
Box( Box(
@ -113,6 +110,7 @@ fun KaizenOrb(
amplitude: Float? = null amplitude: Float? = null
) { ) {
val isDark = isSystemInDarkTheme() val isDark = isSystemInDarkTheme()
val accent = LocalKaizenAccent.current
val transition = rememberInfiniteTransition(label = "orb") val transition = rememberInfiniteTransition(label = "orb")
// Slow breathing loop (7s for idle, 2.4s fast breath for streaming/recording thinking) // Slow breathing loop (7s for idle, 2.4s fast breath for streaming/recording thinking)
@ -151,7 +149,7 @@ fun KaizenOrb(
colors = if (recording) { colors = if (recording) {
listOf(Color(0xFFE0A23E).copy(alpha = 0.45f), Color.Transparent) listOf(Color(0xFFE0A23E).copy(alpha = 0.45f), Color.Transparent)
} else { } else {
listOf(Amber.copy(alpha = if (streaming) 0.55f else 0.32f), Color.Transparent) listOf(accent.primary.copy(alpha = if (streaming) 0.55f else 0.32f), Color.Transparent)
} }
), ),
CircleShape, CircleShape,
@ -179,7 +177,7 @@ fun KaizenOrb(
colorStops = arrayOf( colorStops = arrayOf(
0.0f to Color(0xFFFFF1D6), // Ultra bright glowing cream-white core 0.0f to Color(0xFFFFF1D6), // Ultra bright glowing cream-white core
0.35f to Color(0xFFFFCC80), // Rich luminous warm amber 0.35f to Color(0xFFFFCC80), // Rich luminous warm amber
0.75f to AmberDeep, // Saturated golden amber 0.75f to accent.primaryDeep, // Saturated accent
1.0f to Color(0xFF8D4F00) // Deep bronze-amber shadow edge (creates high contrast!) 1.0f to Color(0xFF8D4F00) // Deep bronze-amber shadow edge (creates high contrast!)
), ),
center = baseGradientCenter, center = baseGradientCenter,
@ -210,10 +208,10 @@ fun KaizenOrb(
val sweepBrush1 = Brush.sweepGradient( val sweepBrush1 = Brush.sweepGradient(
colorStops = arrayOf( colorStops = arrayOf(
0.0f to Color.Transparent, 0.0f to Color.Transparent,
0.16f to Amber.copy(alpha = 0.65f), 0.16f to accent.primary.copy(alpha = 0.65f),
0.33f to Color.White.copy(alpha = 0.55f), 0.33f to Color.White.copy(alpha = 0.55f),
0.50f to Color.Transparent, 0.50f to Color.Transparent,
0.66f to AmberDeep.copy(alpha = 0.50f), 0.66f to accent.primaryDeep.copy(alpha = 0.50f),
1.0f to Color.Transparent 1.0f to Color.Transparent
), ),
center = coreCenter center = coreCenter
@ -230,7 +228,7 @@ fun KaizenOrb(
0.0f to Color.Transparent, 0.0f to Color.Transparent,
0.25f to Color.White.copy(alpha = 0.40f), 0.25f to Color.White.copy(alpha = 0.40f),
0.50f to Color.Transparent, 0.50f to Color.Transparent,
0.75f to Amber.copy(alpha = 0.50f), 0.75f to accent.primary.copy(alpha = 0.50f),
1.0f to Color.Transparent 1.0f to Color.Transparent
), ),
center = coreCenter center = coreCenter

View file

@ -64,9 +64,7 @@ import dev.kaizen.app.ui.effect.GlassTiers
import dev.kaizen.app.ui.effect.KaizenShadows import dev.kaizen.app.ui.effect.KaizenShadows
import dev.kaizen.app.ui.motion.Durations import dev.kaizen.app.ui.motion.Durations
import dev.kaizen.app.ui.shape.KaizenShapes import dev.kaizen.app.ui.shape.KaizenShapes
import dev.kaizen.app.ui.theme.Amber import dev.kaizen.app.ui.theme.LocalKaizenAccent
import dev.kaizen.app.ui.theme.AmberDeep
import dev.kaizen.app.ui.theme.OnAmber
import dev.kaizen.app.R import dev.kaizen.app.R
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import java.time.LocalDateTime import java.time.LocalDateTime
@ -189,13 +187,14 @@ fun ModePillsRow(selected: Set<Int>, onToggle: (Int) -> Unit, modifier: Modifier
fun MessageRow(message: Message) { fun MessageRow(message: Message) {
val cs = MaterialTheme.colorScheme val cs = MaterialTheme.colorScheme
val isDark = isSystemInDarkTheme() val isDark = isSystemInDarkTheme()
val accent = LocalKaizenAccent.current
val hasAttachments = message.attachments.isNotEmpty() val hasAttachments = message.attachments.isNotEmpty()
if (message.role == Role.User) { if (message.role == Role.User) {
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) { Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) {
val shape = KaizenShapes.lg val shape = KaizenShapes.lg
val borderBrush = remember { Brush.verticalGradient(listOf(Amber.copy(alpha = 0.45f), AmberDeep.copy(alpha = 0.15f))) } val borderBrush = remember(accent) { Brush.verticalGradient(listOf(accent.primary.copy(alpha = 0.45f), accent.primaryDeep.copy(alpha = 0.15f))) }
val bgBrush = remember { Brush.verticalGradient(listOf(Amber.copy(alpha = 0.18f), AmberDeep.copy(alpha = 0.08f))) } val bgBrush = remember(accent) { Brush.verticalGradient(listOf(accent.primary.copy(alpha = 0.18f), accent.primaryDeep.copy(alpha = 0.08f))) }
Box( Box(
Modifier Modifier
@ -312,10 +311,11 @@ fun ChatInput(
} }
Box(Modifier.weight(1f).heightIn(min = 36.dp).padding(horizontal = 4.dp), contentAlignment = Alignment.CenterStart) { Box(Modifier.weight(1f).heightIn(min = 36.dp).padding(horizontal = 4.dp), contentAlignment = Alignment.CenterStart) {
if (value.isEmpty()) Text(stringResource(R.string.chat_input_placeholder), color = cs.onSurfaceVariant, fontSize = 16.sp) if (value.isEmpty()) Text(stringResource(R.string.chat_input_placeholder), color = cs.onSurfaceVariant, fontSize = 16.sp)
val accent = LocalKaizenAccent.current
BasicTextField( BasicTextField(
value = value, onValueChange = onValueChange, value = value, onValueChange = onValueChange,
textStyle = TextStyle(color = cs.onBackground, fontSize = 16.sp, lineHeight = 22.sp), textStyle = TextStyle(color = cs.onBackground, fontSize = 16.sp, lineHeight = 22.sp),
cursorBrush = SolidColor(Amber), maxLines = 6, modifier = Modifier.fillMaxWidth(), cursorBrush = SolidColor(accent.primary), maxLines = 6, modifier = Modifier.fillMaxWidth(),
) )
} }
GhostIconButton(Icons.Rounded.Call, "Anruf") GhostIconButton(Icons.Rounded.Call, "Anruf")
@ -383,7 +383,8 @@ private fun SendButton(enabled: Boolean, onClick: () -> Unit) {
val interaction = remember { MutableInteractionSource() } val interaction = remember { MutableInteractionSource() }
val pressed by interaction.collectIsPressedAsState() val pressed by interaction.collectIsPressedAsState()
val pressScale by animateFloatAsState(if (pressed) 0.86f else 1f, label = "send") val pressScale by animateFloatAsState(if (pressed) 0.86f else 1f, label = "send")
val fill = if (enabled) Modifier.background(Brush.linearGradient(listOf(Amber, AmberDeep))) val accent = LocalKaizenAccent.current
val fill = if (enabled) Modifier.background(Brush.linearGradient(listOf(accent.primary, accent.primaryDeep)))
else Modifier.background(cs.surface) else Modifier.background(cs.surface)
Box( Box(
@ -392,7 +393,7 @@ private fun SendButton(enabled: Boolean, onClick: () -> Unit) {
.clickable(interactionSource = interaction, indication = null, enabled = enabled, onClick = onClick), .clickable(interactionSource = interaction, indication = null, enabled = enabled, onClick = onClick),
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
) { ) {
SendArrow(color = if (enabled) OnAmber else cs.onSurfaceVariant) SendArrow(color = if (enabled) accent.onPrimary else cs.onSurfaceVariant)
} }
} }

View file

@ -21,7 +21,7 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import dev.kaizen.app.net.KaizenModel import dev.kaizen.app.net.KaizenModel
import dev.kaizen.app.ui.theme.Amber import dev.kaizen.app.ui.theme.LocalKaizenAccent
import dev.kaizen.app.haptics.rememberHaptics import dev.kaizen.app.haptics.rememberHaptics
/** Human label + composite-id resolver for the top pill — falls back to a de-prefixed id. */ /** Human label + composite-id resolver for the top pill — falls back to a de-prefixed id. */
@ -32,6 +32,7 @@ fun modelDisplayName(modelId: String, models: List<KaizenModel>): String =
@Composable @Composable
fun ModelPill(label: String, onClick: () -> Unit, modifier: Modifier = Modifier) { fun ModelPill(label: String, onClick: () -> Unit, modifier: Modifier = Modifier) {
val cs = MaterialTheme.colorScheme val cs = MaterialTheme.colorScheme
val accent = LocalKaizenAccent.current
Row( Row(
modifier = modifier modifier = modifier
.clip(KaizenShapes.xl) .clip(KaizenShapes.xl)
@ -108,6 +109,7 @@ fun ModelSheet(
onDismiss: () -> Unit, onDismiss: () -> Unit,
) { ) {
val cs = MaterialTheme.colorScheme val cs = MaterialTheme.colorScheme
val accent = LocalKaizenAccent.current
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
var query by remember { mutableStateOf("") } var query by remember { mutableStateOf("") }
val groups = remember(models, favorites, query) { buildGroups(models, favorites, query) } val groups = remember(models, favorites, query) { buildGroups(models, favorites, query) }
@ -152,7 +154,7 @@ fun ModelSheet(
value = query, value = query,
onValueChange = { query = it }, onValueChange = { query = it },
singleLine = true, singleLine = true,
cursorBrush = SolidColor(Amber), cursorBrush = SolidColor(accent.primary),
textStyle = androidx.compose.ui.text.TextStyle( textStyle = androidx.compose.ui.text.TextStyle(
color = cs.onBackground, color = cs.onBackground,
fontSize = 14.sp fontSize = 14.sp
@ -221,6 +223,7 @@ private fun ModelRow(
onToggleFavorite: () -> Unit, onToggleFavorite: () -> Unit,
) { ) {
val cs = MaterialTheme.colorScheme val cs = MaterialTheme.colorScheme
val accent = LocalKaizenAccent.current
val haptics = rememberHaptics() val haptics = rememberHaptics()
val providerInfo = remember(model.id, model.provider) { getProviderInfo(model.id, model.provider) } val providerInfo = remember(model.id, model.provider) { getProviderInfo(model.id, model.provider) }
@ -231,14 +234,14 @@ private fun ModelRow(
.clip(KaizenShapes.md) .clip(KaizenShapes.md)
.background( .background(
if (selected) { if (selected) {
Amber.copy(alpha = 0.08f) accent.primary.copy(alpha = 0.08f)
} else { } else {
cs.surfaceVariant.copy(alpha = 0.15f) cs.surfaceVariant.copy(alpha = 0.15f)
} }
) )
.border( .border(
width = 1.dp, width = 1.dp,
color = if (selected) Amber.copy(alpha = 0.25f) else Color.Transparent, color = if (selected) accent.primary.copy(alpha = 0.25f) else Color.Transparent,
shape = KaizenShapes.md shape = KaizenShapes.md
) )
.clickable { haptics.tick(); onClick() } .clickable { haptics.tick(); onClick() }
@ -290,7 +293,7 @@ private fun ModelRow(
Icon( Icon(
imageVector = if (favorite) Icons.Rounded.Star else Icons.Rounded.StarBorder, imageVector = if (favorite) Icons.Rounded.Star else Icons.Rounded.StarBorder,
contentDescription = "Favorit", contentDescription = "Favorit",
tint = if (favorite) Amber else cs.onSurfaceVariant.copy(alpha = 0.35f), tint = if (favorite) accent.primary else cs.onSurfaceVariant.copy(alpha = 0.35f),
modifier = Modifier.size(20.dp), modifier = Modifier.size(20.dp),
) )
} }
@ -300,7 +303,7 @@ private fun ModelRow(
Icon( Icon(
Icons.Rounded.Check, Icons.Rounded.Check,
contentDescription = "Ausgewählt", contentDescription = "Ausgewählt",
tint = Amber, tint = accent.primary,
modifier = Modifier.size(20.dp) modifier = Modifier.size(20.dp)
) )
} }

View file

@ -46,7 +46,7 @@ import dev.kaizen.app.ui.effect.GlassTiers
import dev.kaizen.app.ui.effect.KaizenShadows import dev.kaizen.app.ui.effect.KaizenShadows
import dev.kaizen.app.ui.shape.KaizenShapes import dev.kaizen.app.ui.shape.KaizenShapes
import dev.kaizen.app.R import dev.kaizen.app.R
import dev.kaizen.app.ui.theme.Amber import dev.kaizen.app.ui.theme.LocalKaizenAccent
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import java.time.Instant import java.time.Instant
import java.time.LocalDate import java.time.LocalDate
@ -243,14 +243,15 @@ fun KaizenSidebar(
private fun HistoryItemRow(item: ConversationSummary, selected: Boolean, onClick: () -> Unit) { private fun HistoryItemRow(item: ConversationSummary, selected: Boolean, onClick: () -> Unit) {
val cs = MaterialTheme.colorScheme val cs = MaterialTheme.colorScheme
val isDark = isSystemInDarkTheme() val isDark = isSystemInDarkTheme()
val accent = LocalKaizenAccent.current
val itemBg = when { val itemBg = when {
selected -> Amber.copy(alpha = 0.14f) selected -> accent.primary.copy(alpha = 0.14f)
isDark -> Color(0x0AFFFFFF) isDark -> Color(0x0AFFFFFF)
else -> Color(0x05000000) else -> Color(0x05000000)
} }
val itemBorder = when { val itemBorder = when {
selected -> Amber.copy(alpha = 0.35f) selected -> accent.primary.copy(alpha = 0.35f)
isDark -> Color.White.copy(alpha = 0.04f) isDark -> Color.White.copy(alpha = 0.04f)
else -> Color.Black.copy(alpha = 0.03f) else -> Color.Black.copy(alpha = 0.03f)
} }
@ -266,7 +267,7 @@ private fun HistoryItemRow(item: ConversationSummary, selected: Boolean, onClick
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
if (item.pinned) { if (item.pinned) {
Icon(Icons.Rounded.Star, null, tint = Amber, modifier = Modifier.size(14.dp)) Icon(Icons.Rounded.Star, null, tint = accent.primary, modifier = Modifier.size(14.dp))
Spacer(Modifier.width(8.dp)) Spacer(Modifier.width(8.dp))
} }
Text( Text(
@ -279,7 +280,7 @@ private fun HistoryItemRow(item: ConversationSummary, selected: Boolean, onClick
) )
if (item.locked) { if (item.locked) {
Spacer(Modifier.width(8.dp)) Spacer(Modifier.width(8.dp))
Icon(Icons.Rounded.Lock, stringResource(R.string.chat_locked_badge), tint = Amber, modifier = Modifier.size(15.dp)) Icon(Icons.Rounded.Lock, stringResource(R.string.chat_locked_badge), tint = accent.primary, modifier = Modifier.size(15.dp))
} }
} }
} }

View file

@ -46,12 +46,13 @@ import androidx.compose.ui.unit.sp
import dev.kaizen.app.net.SearchSource import dev.kaizen.app.net.SearchSource
import dev.kaizen.app.net.ToolEvent import dev.kaizen.app.net.ToolEvent
import dev.kaizen.app.ui.shape.KaizenShapes import dev.kaizen.app.ui.shape.KaizenShapes
import dev.kaizen.app.ui.theme.Amber import dev.kaizen.app.ui.theme.LocalKaizenAccent
@Composable @Composable
fun ReasoningBlock(reasoning: String, streaming: Boolean = false) { fun ReasoningBlock(reasoning: String, streaming: Boolean = false) {
val cs = MaterialTheme.colorScheme val cs = MaterialTheme.colorScheme
val isDark = isSystemInDarkTheme() val isDark = isSystemInDarkTheme()
val accent = LocalKaizenAccent.current
var expanded by remember { mutableStateOf(streaming) } var expanded by remember { mutableStateOf(streaming) }
val bg = if (isDark) Color.White.copy(alpha = 0.05f) else Color.Black.copy(alpha = 0.03f) val bg = if (isDark) Color.White.copy(alpha = 0.05f) else Color.Black.copy(alpha = 0.03f)
@ -71,7 +72,7 @@ fun ReasoningBlock(reasoning: String, streaming: Boolean = false) {
.padding(horizontal = 12.dp, vertical = 8.dp), .padding(horizontal = 12.dp, vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
Icon(Icons.Rounded.Psychology, null, tint = Amber, modifier = Modifier.size(16.dp)) Icon(Icons.Rounded.Psychology, null, tint = accent.primary, modifier = Modifier.size(16.dp))
Spacer(Modifier.width(8.dp)) Spacer(Modifier.width(8.dp))
Text( Text(
"Gedankengang", "Gedankengang",
@ -101,6 +102,7 @@ fun ReasoningBlock(reasoning: String, streaming: Boolean = false) {
fun ToolEventsBlock(tools: List<ToolEvent>, streaming: Boolean = false) { fun ToolEventsBlock(tools: List<ToolEvent>, streaming: Boolean = false) {
val cs = MaterialTheme.colorScheme val cs = MaterialTheme.colorScheme
val isDark = isSystemInDarkTheme() val isDark = isSystemInDarkTheme()
val accent = LocalKaizenAccent.current
val bg = if (isDark) Color.White.copy(alpha = 0.04f) else Color.Black.copy(alpha = 0.02f) val bg = if (isDark) Color.White.copy(alpha = 0.04f) else Color.Black.copy(alpha = 0.02f)
val borderColor = if (isDark) Color.White.copy(alpha = 0.06f) else Color.Black.copy(alpha = 0.04f) val borderColor = if (isDark) Color.White.copy(alpha = 0.06f) else Color.Black.copy(alpha = 0.04f)
@ -123,7 +125,7 @@ fun ToolEventsBlock(tools: List<ToolEvent>, streaming: Boolean = false) {
val tint = when (tool.type) { val tint = when (tool.type) {
"end" -> Color(0xFF10B981) "end" -> Color(0xFF10B981)
"error" -> Color(0xFFEF4444) "error" -> Color(0xFFEF4444)
else -> Amber else -> accent.primary
} }
Icon(icon, null, tint = tint, modifier = Modifier.size(14.dp)) Icon(icon, null, tint = tint, modifier = Modifier.size(14.dp))
Spacer(Modifier.width(8.dp)) Spacer(Modifier.width(8.dp))

View file

@ -54,8 +54,7 @@ import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import dev.kaizen.app.ui.theme.Amber import dev.kaizen.app.ui.theme.LocalKaizenAccent
import dev.kaizen.app.ui.theme.AmberDeep
import dev.kaizen.app.ui.theme.Oklab import dev.kaizen.app.ui.theme.Oklab
import dev.kaizen.app.ui.theme.themes.KaizenThemeId import dev.kaizen.app.ui.theme.themes.KaizenThemeId
@ -159,6 +158,7 @@ fun SettingsInputCapsule(
) { ) {
val cs = MaterialTheme.colorScheme val cs = MaterialTheme.colorScheme
val isDark = isSystemInDarkTheme() val isDark = isSystemInDarkTheme()
val accent = LocalKaizenAccent.current
val inputGlassBg = if (isDark) Color(0x12FFFFFF) else Color(0x06000000) val inputGlassBg = if (isDark) Color(0x12FFFFFF) else Color(0x06000000)
val inputGlassBorder = if (isDark) Color.White.copy(alpha = 0.06f) else Color.Black.copy(alpha = 0.04f) val inputGlassBorder = if (isDark) Color.White.copy(alpha = 0.06f) else Color.Black.copy(alpha = 0.04f)
@ -180,7 +180,7 @@ fun SettingsInputCapsule(
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.Medium fontWeight = FontWeight.Medium
), ),
cursorBrush = SolidColor(Amber), cursorBrush = SolidColor(accent.primary),
singleLine = true, singleLine = true,
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) )
@ -196,6 +196,7 @@ fun ThemeOptionPill(
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val isDark = isSystemInDarkTheme() val isDark = isSystemInDarkTheme()
val accent = LocalKaizenAccent.current
// Exact OKLCH brand stops sourced directly from amber.css, blue.css, aurora.css, and mono.css // Exact OKLCH brand stops sourced directly from amber.css, blue.css, aurora.css, and mono.css
val (colorStart, colorEnd) = remember(themeId, isDark) { val (colorStart, colorEnd) = remember(themeId, isDark) {
@ -231,7 +232,7 @@ fun ThemeOptionPill(
.border( .border(
width = if (selected) 2.5.dp else 1.2.dp, width = if (selected) 2.5.dp else 1.2.dp,
brush = if (selected) { brush = if (selected) {
Brush.verticalGradient(listOf(Amber, AmberDeep)) Brush.verticalGradient(listOf(accent.primary, accent.primaryDeep))
} else { } else {
Brush.verticalGradient(listOf(Color.White.copy(alpha = 0.35f), Color.White.copy(alpha = 0.05f))) Brush.verticalGradient(listOf(Color.White.copy(alpha = 0.35f), Color.White.copy(alpha = 0.05f)))
}, },
@ -269,6 +270,7 @@ fun AppearanceTogglePill(
) { ) {
val cs = MaterialTheme.colorScheme val cs = MaterialTheme.colorScheme
val isDark = isSystemInDarkTheme() val isDark = isSystemInDarkTheme()
val accent = LocalKaizenAccent.current
val glassBorder = remember(isDark) { val glassBorder = remember(isDark) {
if (isDark) { if (isDark) {
@ -284,7 +286,7 @@ fun AppearanceTogglePill(
.clip(KaizenShapes.circle) .clip(KaizenShapes.circle)
.background( .background(
if (selected) { if (selected) {
Amber.copy(alpha = 0.16f) accent.primary.copy(alpha = 0.16f)
} else { } else {
if (isDark) Color(0x0AFFFFFF) else Color(0x82FFFFFF) if (isDark) Color(0x0AFFFFFF) else Color(0x82FFFFFF)
} }
@ -292,7 +294,7 @@ fun AppearanceTogglePill(
.border( .border(
width = if (selected) 1.5.dp else 1.dp, width = if (selected) 1.5.dp else 1.dp,
brush = if (selected) { brush = if (selected) {
Brush.verticalGradient(listOf(Amber.copy(alpha = 0.50f), Amber.copy(alpha = 0.15f))) Brush.verticalGradient(listOf(accent.primary.copy(alpha = 0.50f), accent.primary.copy(alpha = 0.15f)))
} else { } else {
glassBorder glassBorder
}, },