From 75ca8c0e7b2c34c0f7bb4ac9812f765e342bc067 Mon Sep 17 00:00:00 2001 From: Bruno Deanoz Date: Tue, 23 Jun 2026 12:22:38 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20visual=20refresh=20=E2=80=94=20lighter?= =?UTF-8?q?=20typography,=20message=20animations,=20richer=20themes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Typography: body text W400→W300 for airier feel, headings scaled up (H1 26sp, H2 22sp, H3 18sp), W600/W500 weight hierarchy for contrast. Animations: animateItem() on LazyColumn messages — 350ms fade-in, spring placement, 200ms fade-out. Themes: blobs 20% larger + better full-screen distribution, higher alpha on OLED (0.48 peak), light mode factor 0.65→0.78, reduced vignette, distinct primaryDeep per theme for richer gradients. --- app/src/main/java/dev/kaizen/app/chat/Background.kt | 12 ++++++------ .../main/java/dev/kaizen/app/chat/ChatComponents.kt | 11 ++++++----- app/src/main/java/dev/kaizen/app/chat/ChatScreen.kt | 11 ++++++++++- app/src/main/java/dev/kaizen/app/chat/Markdown.kt | 10 +++++----- app/src/main/java/dev/kaizen/app/ui/theme/Type.kt | 4 ++-- .../dev/kaizen/app/ui/theme/themes/AmberTheme.kt | 2 +- .../dev/kaizen/app/ui/theme/themes/AuroraTheme.kt | 2 +- .../java/dev/kaizen/app/ui/theme/themes/BlauTheme.kt | 2 +- .../java/dev/kaizen/app/ui/theme/themes/MonoTheme.kt | 2 +- 9 files changed, 33 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/dev/kaizen/app/chat/Background.kt b/app/src/main/java/dev/kaizen/app/chat/Background.kt index ccd038f..ebaa2cb 100644 --- a/app/src/main/java/dev/kaizen/app/chat/Background.kt +++ b/app/src/main/java/dev/kaizen/app/chat/Background.kt @@ -45,7 +45,7 @@ fun MeshBackground(animateBlobs: Boolean = true, content: @Composable BoxScope.( val dark = isSystemInDarkTheme() val accent = LocalKaizenAccent.current val base = MaterialTheme.colorScheme.background - val factor = if (dark) 1f else 0.65f + val factor = if (dark) 1f else 0.78f val drift = if (animateBlobs) { val transition = rememberInfiniteTransition(label = "blobs") @@ -70,14 +70,14 @@ fun MeshBackground(animateBlobs: Boolean = true, content: @Composable BoxScope.( drawRect(brush = ditherBrush, alpha = DITHER_ALPHA) }, ) { - Blob(accent.blob1, 360.dp, (-60f + drift * 30f).dp, (-40f + drift * 24f).dp, 0.42f * factor) - Blob(accent.blob2, 380.dp, (170f - drift * 44f).dp, (150f + drift * 40f).dp, 0.36f * factor) - Blob(accent.blob3, 320.dp, (220f + drift * 36f).dp, (80f - drift * 28f).dp, 0.30f * factor) - Blob(accent.blob4, 300.dp, (30f + drift * 50f).dp, (560f - drift * 36f).dp, 0.34f * factor) + Blob(accent.blob1, 440.dp, (-80f + drift * 40f).dp, (-60f + drift * 30f).dp, 0.48f * factor) + Blob(accent.blob2, 460.dp, (140f - drift * 50f).dp, (200f + drift * 50f).dp, 0.40f * factor) + Blob(accent.blob3, 400.dp, (-30f + drift * 60f).dp, (450f - drift * 40f).dp, 0.36f * factor) + Blob(accent.blob4, 420.dp, (180f + drift * 40f).dp, (620f - drift * 44f).dp, 0.38f * factor) if (dark) { Box( Modifier.fillMaxSize().background( - Brush.radialGradient(listOf(Color.Transparent, base.copy(alpha = 0.40f))), + Brush.radialGradient(listOf(Color.Transparent, base.copy(alpha = 0.35f))), ), ) } diff --git a/app/src/main/java/dev/kaizen/app/chat/ChatComponents.kt b/app/src/main/java/dev/kaizen/app/chat/ChatComponents.kt index 2c88a86..aeae916 100644 --- a/app/src/main/java/dev/kaizen/app/chat/ChatComponents.kt +++ b/app/src/main/java/dev/kaizen/app/chat/ChatComponents.kt @@ -135,11 +135,11 @@ fun EmptyHero(userName: String, onPick: (String) -> Unit, modifier: Modifier = M ) { KaizenOrb(104.dp) Spacer(Modifier.height(24.dp)) - Text("${greeting(now.hour)}, $userName", color = cs.onSurfaceVariant, fontSize = 17.sp) + Text("${greeting(now.hour)}, $userName", color = cs.onSurfaceVariant, fontSize = 17.sp, fontWeight = FontWeight.W300) Spacer(Modifier.height(6.dp)) - Text(stringResource(R.string.hero_headline), color = cs.onBackground, fontSize = 32.sp, fontWeight = FontWeight.Bold) + Text(stringResource(R.string.hero_headline), color = cs.onBackground, fontSize = 32.sp, fontWeight = FontWeight.W600) Spacer(Modifier.height(8.dp)) - Text(dateLine, color = cs.onSurfaceVariant.copy(alpha = 0.7f), fontSize = 13.sp) + Text(dateLine, color = cs.onSurfaceVariant.copy(alpha = 0.7f), fontSize = 13.sp, fontWeight = FontWeight.W300) } } @@ -520,7 +520,7 @@ fun MessageRow( if (hasAttachments) AttachmentGrid(message.attachments, Modifier.padding(6.dp)) if (message.content.isNotBlank()) { Text( - message.content, color = cs.onBackground, fontSize = 16.sp, lineHeight = 26.sp, + message.content, color = cs.onBackground, fontSize = 16.sp, lineHeight = 26.sp, fontWeight = FontWeight.W300, modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = if (hasAttachments) 4.dp else 13.dp, bottom = 13.dp), ) } @@ -784,10 +784,11 @@ fun ChatInput( stringResource(R.string.chat_input_placeholder), color = cs.onSurfaceVariant.copy(alpha = 0.5f), fontSize = 16.sp, + fontWeight = FontWeight.W300, ) BasicTextField( value = value, onValueChange = onValueChange, - textStyle = TextStyle(color = cs.onBackground, fontSize = 16.sp, lineHeight = 24.sp), + textStyle = TextStyle(color = cs.onBackground, fontSize = 16.sp, lineHeight = 24.sp, fontWeight = FontWeight.W300), cursorBrush = SolidColor(accent.primary), maxLines = 6, modifier = Modifier.fillMaxWidth(), ) } diff --git a/app/src/main/java/dev/kaizen/app/chat/ChatScreen.kt b/app/src/main/java/dev/kaizen/app/chat/ChatScreen.kt index 30d50e5..2c7dd78 100644 --- a/app/src/main/java/dev/kaizen/app/chat/ChatScreen.kt +++ b/app/src/main/java/dev/kaizen/app/chat/ChatScreen.kt @@ -88,6 +88,9 @@ import android.media.MediaPlayer import android.media.MediaRecorder import android.widget.Toast import androidx.core.content.ContextCompat +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.spring +import androidx.compose.animation.core.tween import kotlinx.coroutines.Job import kotlinx.coroutines.async import kotlinx.coroutines.launch @@ -866,6 +869,11 @@ fun ChatScreen( verticalArrangement = Arrangement.spacedBy(24.dp), ) { items(messages, key = { it.id }) { message -> + Box(Modifier.animateItem( + fadeInSpec = tween(350), + placementSpec = spring(stiffness = Spring.StiffnessMediumLow), + fadeOutSpec = tween(200), + )) { MessageRow( message = message, onDelete = if (conversationId != null && !isStreaming) { wireId -> @@ -904,6 +912,7 @@ fun ChatScreen( } else null, isPlayingTts = playingTtsForId == message.id, ) + } } } @@ -1014,7 +1023,7 @@ fun ChatScreen( modelDisplayName(displayModel, models), color = MaterialTheme.colorScheme.onBackground, fontSize = 13.sp, - fontWeight = FontWeight.Medium, + fontWeight = FontWeight.W300, maxLines = 1, modifier = Modifier.widthIn(max = 180.dp), overflow = androidx.compose.ui.text.style.TextOverflow.Ellipsis, diff --git a/app/src/main/java/dev/kaizen/app/chat/Markdown.kt b/app/src/main/java/dev/kaizen/app/chat/Markdown.kt index f11fd15..0547638 100644 --- a/app/src/main/java/dev/kaizen/app/chat/Markdown.kt +++ b/app/src/main/java/dev/kaizen/app/chat/Markdown.kt @@ -461,9 +461,9 @@ fun MarkdownText(text: String, streaming: Boolean = false, modifier: Modifier = if (idx > 0) Spacer(Modifier.height(18.dp)) val rendered = inlineMarkdown(block.text + if (isLast) cursor else "", cs.onBackground, inlineCodeColor, inlineCodeBg, linkColor) ClickableMarkdownText(rendered, context, cs.onBackground, - fontSize = when (block.level) { 1 -> 22.sp; 2 -> 19.sp; else -> 17.sp }, - fontWeight = FontWeight.Bold, - lineHeight = when (block.level) { 1 -> 30.sp; 2 -> 27.sp; else -> 24.sp }, + fontSize = when (block.level) { 1 -> 26.sp; 2 -> 22.sp; else -> 18.sp }, + fontWeight = when (block.level) { 1 -> FontWeight.W600; 2 -> FontWeight.W600; else -> FontWeight.W500 }, + lineHeight = when (block.level) { 1 -> 34.sp; 2 -> 30.sp; else -> 26.sp }, ) Spacer(Modifier.height(8.dp)) } @@ -592,7 +592,7 @@ fun MarkdownText(text: String, streaming: Boolean = false, modifier: Modifier = val appendCursor = isLast && itemIdx == block.items.lastIndex val rendered = inlineMarkdown(item.text + if (appendCursor) cursor else "", cs.onBackground, inlineCodeColor, inlineCodeBg, linkColor) ClickableMarkdownText(rendered, context, cs.onBackground, - fontSize = 16.sp, lineHeight = 26.sp, + fontSize = 16.sp, lineHeight = 26.sp, fontWeight = FontWeight.W300, modifier = Modifier.weight(1f), ) } @@ -641,7 +641,7 @@ fun MarkdownText(text: String, streaming: Boolean = false, modifier: Modifier = if (idx > 0) Spacer(Modifier.height(12.dp)) val rendered = inlineMarkdown(block.text + if (isLast) cursor else "", cs.onBackground, inlineCodeColor, inlineCodeBg, linkColor) ClickableMarkdownText(rendered, context, cs.onBackground, - fontSize = 16.sp, lineHeight = 26.sp, + fontSize = 16.sp, lineHeight = 26.sp, fontWeight = FontWeight.W300, ) } diff --git a/app/src/main/java/dev/kaizen/app/ui/theme/Type.kt b/app/src/main/java/dev/kaizen/app/ui/theme/Type.kt index 73ad3db..610e2b8 100644 --- a/app/src/main/java/dev/kaizen/app/ui/theme/Type.kt +++ b/app/src/main/java/dev/kaizen/app/ui/theme/Type.kt @@ -88,14 +88,14 @@ val Typography = Typography( ), bodyLarge = TextStyle( fontFamily = InterVariable, - fontWeight = FontWeight.W400, + fontWeight = FontWeight.W300, fontSize = 16.sp, lineHeight = 24.sp, letterSpacing = 0.08.sp, ), bodyMedium = TextStyle( fontFamily = InterVariable, - fontWeight = FontWeight.W400, + fontWeight = FontWeight.W300, fontSize = 14.sp, lineHeight = 20.sp, letterSpacing = 0.11.sp, diff --git a/app/src/main/java/dev/kaizen/app/ui/theme/themes/AmberTheme.kt b/app/src/main/java/dev/kaizen/app/ui/theme/themes/AmberTheme.kt index 91e562c..0c90d0c 100644 --- a/app/src/main/java/dev/kaizen/app/ui/theme/themes/AmberTheme.kt +++ b/app/src/main/java/dev/kaizen/app/ui/theme/themes/AmberTheme.kt @@ -12,7 +12,7 @@ val AmberTheme = KaizenThemeSpec( label = "Amber", light = KaizenAccentScheme( primary = p3(0.811f, 0.608f, 0.126f), // oklch(0.72 0.14 83) - primaryDeep = p3(0.811f, 0.608f, 0.126f), + primaryDeep = p3(0.680f, 0.480f, 0.050f), // oklch(0.62 0.15 83) richer gold onPrimary = p3(0.015f, 0.013f, 0.009f), // oklch(0.10 0.005 83) ring = p3(0.811f, 0.608f, 0.126f), blob1 = p3(0.992f, 0.767f, 0.282f), // oklch(0.85 0.15 83) gold diff --git a/app/src/main/java/dev/kaizen/app/ui/theme/themes/AuroraTheme.kt b/app/src/main/java/dev/kaizen/app/ui/theme/themes/AuroraTheme.kt index 4cd332f..0fa5607 100644 --- a/app/src/main/java/dev/kaizen/app/ui/theme/themes/AuroraTheme.kt +++ b/app/src/main/java/dev/kaizen/app/ui/theme/themes/AuroraTheme.kt @@ -14,7 +14,7 @@ val AuroraTheme = KaizenThemeSpec( label = "Aurora", light = KaizenAccentScheme( primary = p3(0.724f, 0.328f, 0.812f), // oklch(0.62 0.20 320) purple - primaryDeep = p3(0.724f, 0.328f, 0.812f), + primaryDeep = p3(0.580f, 0.200f, 0.700f), // oklch(0.50 0.22 320) deeper purple onPrimary = p3(1.000f, 0.979f, 1.000f), // oklch(0.99 0.01 320) ring = p3(0.724f, 0.328f, 0.812f), blob1 = p3(0.855f, 0.540f, 0.926f), // oklch(0.75 0.16 320) purple diff --git a/app/src/main/java/dev/kaizen/app/ui/theme/themes/BlauTheme.kt b/app/src/main/java/dev/kaizen/app/ui/theme/themes/BlauTheme.kt index 7d95dc1..9e5aff0 100644 --- a/app/src/main/java/dev/kaizen/app/ui/theme/themes/BlauTheme.kt +++ b/app/src/main/java/dev/kaizen/app/ui/theme/themes/BlauTheme.kt @@ -12,7 +12,7 @@ val BlauTheme = KaizenThemeSpec( label = "Blau", light = KaizenAccentScheme( primary = p3(0.168f, 0.513f, 0.962f), // oklch(0.62 0.19 257) - primaryDeep = p3(0.168f, 0.513f, 0.962f), + primaryDeep = p3(0.090f, 0.380f, 0.820f), // oklch(0.52 0.20 257) deeper blue onPrimary = p3(0.971f, 0.989f, 1.000f), // oklch(0.99 0.01 257) ring = p3(0.168f, 0.513f, 0.962f), blob1 = p3(0.464f, 0.725f, 1.000f), // oklch(0.78 0.15 257) sky diff --git a/app/src/main/java/dev/kaizen/app/ui/theme/themes/MonoTheme.kt b/app/src/main/java/dev/kaizen/app/ui/theme/themes/MonoTheme.kt index c727004..158f426 100644 --- a/app/src/main/java/dev/kaizen/app/ui/theme/themes/MonoTheme.kt +++ b/app/src/main/java/dev/kaizen/app/ui/theme/themes/MonoTheme.kt @@ -12,7 +12,7 @@ val MonoTheme = KaizenThemeSpec( label = "Mono", light = KaizenAccentScheme( primary = p3(0.104f, 0.104f, 0.104f), // oklch(0.22 0 255) near-black - primaryDeep = p3(0.104f, 0.104f, 0.104f), + primaryDeep = p3(0.050f, 0.050f, 0.050f), // oklch(0.14 0 255) deeper black onPrimary = p3(0.987f, 0.987f, 0.987f), // oklch(0.99 0 255) near-white ring = p3(0.104f, 0.104f, 0.104f), blob1 = p3(0.806f, 0.806f, 0.806f), // oklch(0.85 0 255) light gray