From 6465b47bbb08c8f34973aba29b25a7833be82893 Mon Sep 17 00:00:00 2001 From: Bruno Deanoz Date: Sun, 21 Jun 2026 14:32:25 +0200 Subject: [PATCH 01/12] =?UTF-8?q?feat:=20design=20system=20v2=20=E2=80=94?= =?UTF-8?q?=20P3=20colors,=20squircle=20shapes,=20glass=20surfaces,=20mult?= =?UTF-8?q?i-theme,=20motion=20tokens?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Foundation for the premium UI overhaul: - P3 DisplayP3 color pipeline (all tokens in wide gamut) - SquircleShape (iOS-style superellipse with G2 continuity) - KaizenShapes token system (xs/sm/md/lg/xl/pill/circle) - Multi-layer ShadowStack system (level 0–4) - GlassSurface composable with RenderEffect blur + API fallback - Motion tokens (easing curves, spring specs, durations) - Tilt sensor state (GAME_ROTATION_VECTOR, lifecycle-aware) - 4-theme system (Amber/Blau/Mono/Aurora) with AccentScheme - ThemeRegistry + CompositionLocal for accent propagation - Unit tests for colors, shapes, shadows, themes --- DESIGN.md | 970 ++++++++++++++++++ .../dev/kaizen/app/ui/effect/GlassSurface.kt | 99 ++ .../java/dev/kaizen/app/ui/effect/Shadow.kt | 148 +++ .../java/dev/kaizen/app/ui/motion/Motion.kt | 52 + .../dev/kaizen/app/ui/sensor/TiltState.kt | 145 +++ .../dev/kaizen/app/ui/shape/KaizenShapes.kt | 21 + .../java/dev/kaizen/app/ui/shape/Squircle.kt | 126 +++ .../java/dev/kaizen/app/ui/theme/Color.kt | 61 +- .../java/dev/kaizen/app/ui/theme/Theme.kt | 54 +- .../app/ui/theme/themes/AccentScheme.kt | 47 + .../kaizen/app/ui/theme/themes/AmberTheme.kt | 32 + .../kaizen/app/ui/theme/themes/AuroraTheme.kt | 32 + .../kaizen/app/ui/theme/themes/BlauTheme.kt | 32 + .../kaizen/app/ui/theme/themes/MonoTheme.kt | 32 + .../app/ui/theme/themes/ThemeRegistry.kt | 18 + .../java/dev/kaizen/app/ColorPipelineTest.kt | 68 ++ .../java/dev/kaizen/app/ShadowStackTest.kt | 70 ++ .../java/dev/kaizen/app/SquircleShapeTest.kt | 48 + .../java/dev/kaizen/app/ThemeRegistryTest.kt | 62 ++ 19 files changed, 2077 insertions(+), 40 deletions(-) create mode 100644 DESIGN.md create mode 100644 app/src/main/java/dev/kaizen/app/ui/effect/GlassSurface.kt create mode 100644 app/src/main/java/dev/kaizen/app/ui/effect/Shadow.kt create mode 100644 app/src/main/java/dev/kaizen/app/ui/motion/Motion.kt create mode 100644 app/src/main/java/dev/kaizen/app/ui/sensor/TiltState.kt create mode 100644 app/src/main/java/dev/kaizen/app/ui/shape/KaizenShapes.kt create mode 100644 app/src/main/java/dev/kaizen/app/ui/shape/Squircle.kt create mode 100644 app/src/main/java/dev/kaizen/app/ui/theme/themes/AccentScheme.kt create mode 100644 app/src/main/java/dev/kaizen/app/ui/theme/themes/AmberTheme.kt create mode 100644 app/src/main/java/dev/kaizen/app/ui/theme/themes/AuroraTheme.kt create mode 100644 app/src/main/java/dev/kaizen/app/ui/theme/themes/BlauTheme.kt create mode 100644 app/src/main/java/dev/kaizen/app/ui/theme/themes/MonoTheme.kt create mode 100644 app/src/main/java/dev/kaizen/app/ui/theme/themes/ThemeRegistry.kt create mode 100644 app/src/test/java/dev/kaizen/app/ColorPipelineTest.kt create mode 100644 app/src/test/java/dev/kaizen/app/ShadowStackTest.kt create mode 100644 app/src/test/java/dev/kaizen/app/SquircleShapeTest.kt create mode 100644 app/src/test/java/dev/kaizen/app/ThemeRegistryTest.kt diff --git a/DESIGN.md b/DESIGN.md new file mode 100644 index 0000000..f67efae --- /dev/null +++ b/DESIGN.md @@ -0,0 +1,970 @@ +# Kaizen Android — Visual Design + +> Native Android client for the Kaizen self-hosted AI chat platform. +> This document defines the visual language: color pipeline, type, surfaces, motion, and the rationale behind every choice. Read it before you change anything visible. + +--- + +## 0. TL;DR — the high-end stack + +If you skim nothing else, skim this. These are the six pillars that make Kaizen Android look like a 2026 product and not a 2019 Material app. + +| # | Pillar | Tech | +| - | ----------------------- | ----------------------------------------------------------------------------------------------------- | +| 1 | **Real glass** | `RenderEffect.createBlurEffect` (API 31+) on every floating surface. API 26–30 fallback: pre-blurred WebP. | +| 2 | **Wide-gamut color** | `ACONFIGURATION_COLOR_MODE_WIDE_COLOR_GAMUT` window mode. All brand tokens declared in DisplayP3. | +| 3 | **HDR highlights** | `COLOR_MODE_HDR` (API 34+) on capable displays (S25 Ultra, Pixel 8 Pro+). Orb specular peaks >1.0 nit. | +| 4 | **Squircle geometry** | iOS-style superellipse (`n ≈ 4.5`) as a Compose `Shape`. Replaces every `RoundedCornerShape`. | +| 5 | **Sensor-reactive** | Gyro/accelerometer drives orb specular direction + sidebar parallax. 60 Hz, gated by power state. | +| 6 | **Variable typography** | Inter Variable as a single TTF (~330 kB). Optical sizing for the hero headline. | + +If any of these regress, the design regresses. Treat them like load-bearing walls. + +--- + +## 1. Design intent + +Kaizen Android is the mobile companion to Kaizen Web — a self-hosted, multi-provider AI chat platform (`/Users/brunodeanoz/Kaizen/kaizen/CLAUDE.md`). The Android client is not a webview wrapper; it is a native Compose UI that **inherits the web's identity and elevates it** for a hardware-rich mobile target. + +### 1.1 What we are aiming for + +- **Premium, calm, intentional.** The user opens the app to think with an AI, not to be sold to. No marketing copy, no badges, no "Pro" prompts. The empty state is a greeting, a question, and an input. +- **Real liquid glass.** Surfaces actually refract what's behind them via `RenderEffect`. The blob layer is what they refract. +- **Apple-Intelligence-style hero**, not Google-Assistant-style. The orb is the visual anchor. The orb *is* Kaizen at every scale (hero → 28dp avatar → 200dp call-mode). +- **Brand color survives every theme switch.** Amber/Blau/Mono/Aurora are *user choices*, not wallpaper-derived. No `dynamicColor`. +- **Conversation first.** Once messages exist, chrome recedes. + +### 1.2 What we explicitly reject + +| Pattern | Why not | +| ------------------------------------------------------ | --------------------------------------------------------------------------------------------- | +| Gemini-style full-bleed pastel gradient + serif | Reads as a Google product. Steals identity. (See `ui-gemini.jpg`.) | +| Claude-style centered serif greeting on near-white | Bland. No depth, no brand color. Input bar reads as a separate sheet. (See `ui-claude.jpg`.) | +| Material You `dynamicColor = true` | Wallpaper-derived palettes erase the user's chosen Kaizen theme. We never enable it. | +| Bottom navigation bar | Chat is the single primary surface. Drawer instead. | +| Card-on-card "M3 expressive" layouts | One floating glass surface class. Let it breathe. | +| Suggestion-chip rows in the mobile empty state | Redundant with the mode pills directly above the input. Eats vertical real estate. (Web keeps them; mobile drops them.) | +| Lottie / framer-style scripted animations | Every motion is `AnimationSpec` + `Animatable`. Predictable, GPU-cheap, accessibility-aware. | +| Pure black `#000` backgrounds, pure white `#FFFFFF` text | Both create hard edges that fight the glass aesthetic. Off-black and off-white only. | + +### 1.3 Reference + +`ui-kaizen.jpg` (workspace root) is the canonical target for the empty state, with the modification that the four suggestion chips are **removed on mobile** (see §6.1). `ui-claude.jpg` and `ui-gemini.jpg` are *anti-references* — they show patterns we deliberately diverge from. + +--- + +## 2. Color pipeline + +Kaizen ships in **DisplayP3** end-to-end, with optional **HDR extended-range highlights** on capable displays. This is the single biggest visual upgrade over a stock Material app and it costs almost nothing if you set it up correctly. + +### 2.1 Why P3 (and why now) + +| Fact | Consequence | +| --------------------------------------------------------------------------------------------- | -------------------------------------------------------- | +| Every Pixel since the 4, every Samsung Galaxy S/Note since 2018, every iPhone since the 7 | Hardware supports the DisplayP3 gamut (≈25% wider than sRGB) | +| Android opts apps **out** of P3 by default — `Window.colorMode` defaults to `COLOR_MODE_DEFAULT` (sRGB) | Without our opt-in, the OS color-manages our amber back down to sRGB and the saturation is gone | +| Our brand color is `oklch(0.72 0.14 83)` — chroma `0.14` is **outside** sRGB at that hue | The web app already renders this in P3 via OKLCH. The Android app must match or it will look washed out next to the web | + +### 2.2 Opt-in + +```kotlin +// MainActivity.onCreate(), before setContent {} +window.colorMode = ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT +if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + // API 34+: enables extended-range (HDR) drawing on capable displays + window.colorMode = ActivityInfo.COLOR_MODE_HDR +} +``` + +Compose then draws into a P3-tagged surface. **All `Color(0xFF…)` constructors are interpreted as sRGB unless you say otherwise.** So we declare every brand color with an explicit color space: + +```kotlin +import androidx.compose.ui.graphics.colorspace.ColorSpaces + +val AmberP3 = Color(red = 0.878f, green = 0.635f, blue = 0.243f, + colorSpace = ColorSpaces.DisplayP3) +``` + +Hex-literal Color constructors are banned everywhere except `Color.Transparent` and pure debug tooling. Tokens live in `ui/theme/Color.kt` and are all float-component P3 colors. + +### 2.3 HDR extended-range highlights + +This is what makes the orb actually *glow* on your S25 Ultra (2,600 nits HDR peak) instead of just looking bright. + +```kotlin +// Brush for the orb's top-left specular +val orbSpecular = Brush.radialGradient( + colors = listOf( + Color(red = 4f, green = 4f, blue = 4f, // >1.0 = extended range + colorSpace = ColorSpaces.LinearExtendedSrgb), + Color.Transparent, + ), + center = Offset(...), radius = ..., +) +``` + +Compose canvases on API 34+ with `colorMode = COLOR_MODE_HDR` honor color components above `1.0` and route them to the display's HDR layer. On non-HDR displays the values clamp to `1.0` gracefully — no visual regression, just no HDR pop. + +We use this in exactly two places: + +1. **Hero orb specular** — top-left rim highlight, up to ~3.5× SDR white. +2. **Send button "armed" state** — when the user has typed text and the send icon turns full amber, the amber gains a faint HDR halo (peak ~1.8×). Subtle. The user notices it without naming it. + +We do **not** HDR-pop the headline, the model name, or anything text. HDR text is fatiguing and accessibility-hostile. + +### 2.4 Color tokens + +Defined in `ui/theme/Color.kt`. Each token has a **P3 float** form (canonical) and an **sRGB hex** form (fallback documentation, used for the Studio preview and design handoff). + +#### Brand (constant across all themes — they ARE the brand) + +| Token | P3 float (R, G, B) | sRGB ≈ | Use | +| ----------- | ---------------------------- | -------- | ------------------------------------------------ | +| `Amber` | `(0.878, 0.635, 0.243)` | `#E0A23E` | Orb, send button, focus ring, primary in dark | +| `AmberDeep` | `(0.784, 0.525, 0.165)` | `#C8862A` | Primary in light mode (better contrast on white) | +| `OnAmber` | `(0.106, 0.071, 0.024)` | `#1B1206` | Foreground on amber fills | + +> The amber survives dark/light. The theme selector (§3) swaps the *accent* palette around it. + +#### Light scheme — neutrals + +| Role | Token | P3 float | sRGB ≈ | +| ------------------ | --------------------- | ----------------------- | --------- | +| `background` | `LightBackground` | `(0.965, 0.969, 0.976)` | `#F6F7F9` | +| `surface` | `LightSurface` | `(1.000, 1.000, 1.000)` | `#FFFFFF` | +| `surfaceVariant` | `LightSurfaceVariant` | `(0.933, 0.941, 0.953)` | `#EEF0F3` | +| `onBackground` | `LightText` | `(0.102, 0.122, 0.161)` | `#1A1F29` | +| `onSurfaceVariant` | `LightMuted` | `(0.357, 0.392, 0.439)` | `#5B6470` | +| `outline` | `LightStroke` | `(0, 0, 0, α=0.08)` | — | + +#### Dark scheme — neutrals (Obsidian Steel-Blue) + +| Role | Token | P3 float | sRGB ≈ | +| ------------------ | ------------------ | ----------------------- | --------- | +| `background` | `Obsidian` | `(0.039, 0.055, 0.086)` | `#0A0E16` | +| `surface` | `ObsidianElevated` | `(0.078, 0.106, 0.153)` | `#141B27` | +| `surfaceVariant` | `ObsidianInput` | `(0.067, 0.094, 0.141)` | `#111824` | +| `onBackground` | `DarkText` | `(0.910, 0.922, 0.945)` | `#E8EBF1` | +| `onSurfaceVariant` | `DarkMuted` | `(0.545, 0.580, 0.643)` | `#8B94A4` | +| `outline` | `DarkStroke` | `(1, 1, 1, α=0.09)` | — | + +#### Banned + +- `Color(0xFF000000)` as background. We use `Obsidian` (an off-black with blue cast). +- `Color(0xFFFFFFFF)` as body text. We use `DarkText` (slightly cool, easier on the eye on OLED). +- Any color literal without an explicit `colorSpace` argument outside `Color.kt` itself. + +### 2.5 Color-space pitfalls + +These will bite you the first week. Document and lint for them. + +1. **`@Composable` images don't auto-convert.** A JPEG with an embedded sRGB profile rendered into a P3 canvas will look fine, but a JPEG with no profile will be assumed sRGB and may shift. Tag user-uploaded images with their declared profile when displaying. +2. **`Brush.linearGradient` interpolates in the canvas color space.** Good for us (P3 interpolation gives smoother gradients than sRGB), but means a gradient `from sRGB-red to sRGB-blue` rendered in P3 will pass through a slightly different midpoint. Define gradient stops in P3 directly. +3. **Screenshot tests** must capture in P3 too, otherwise CI fails on real-device output. Use `Bitmap.Config.RGBA_F16` + `ColorSpace.get(ColorSpace.Named.DISPLAY_P3)`. +4. **The IDE preview is sRGB.** Studio's `@Preview` does NOT show P3. Don't trust the preview for color decisions — verify on device. + +--- + +## 3. Theme system + +Kaizen Web ships four themes (`UiThemeId = "amber" | "blue" | "mono" | "aurora"`, see `kaizen/lib/theme/ui-themes.ts`). Android ships the **same four**, native, server-synced. + +### 3.1 Structure + +Each theme is a Kotlin object implementing `KaizenTheme`: + +```kotlin +data class KaizenAccentScheme( + val primary: Color, + val primaryDeep: Color, // light-mode primary + val onPrimary: Color, + val ring: Color, + val blob1: Color, + val blob2: Color, + val blob3: Color, + val blob4: Color, // theme-specific accent (teal for amber, peach for blue…) +) + +interface KaizenTheme { + val id: KaizenThemeId + val label: String + val light: KaizenAccentScheme + val dark: KaizenAccentScheme +} +``` + +Neutrals (`background`, `surface`, …) are theme-**independent** — same Obsidian / Light off-white across all four themes. Only the accent + the four background blob colors swap. This matches the web architecture (`globals.css` ships neutrals, `app/themes/.css` ships only the accent tokens). + +### 3.2 The four themes (accent + blobs) + +| Theme | Primary (dark) | Primary (light) | Blob 1 | Blob 2 | Blob 3 | Blob 4 (accent) | +| -------- | --------------------- | -------------------- | -------- | ------ | ------ | --------------- | +| Amber | Amber `(0.878,0.635,0.243)` | AmberDeep `(0.784,0.525,0.165)` | Amber | Blue | Indigo | Teal | +| Blau | Sky-500 P3 | Indigo-600 P3 | Blue | Indigo | Cyan | Amber (contrast)| +| Mono | Slate-100 | Slate-800 | Slate-300| Slate-400 | Slate-200 | Warm gray | +| Aurora | Magenta P3 | Violet-600 P3 | Magenta | Cyan | Violet | Lime (accent) | + +(Concrete P3 floats live in `ui/theme/themes/*.kt`. Each file ≤ 60 lines.) + +### 3.3 Server sync + +1. On launch, the app calls `GET /api/v1/me`. The response carries the user's `uiTheme` and `appearance` ("light" / "dark" / "system") — same values as the web reads from `localStorage.kaizen-ui-theme`. +2. Local storage: `EncryptedSharedPreferences` (`kaizen-ui-theme`, `kaizen-appearance`). This is the source of truth for offline launches. +3. When the user changes theme in the **app**, we PATCH `/api/v1/me`. The web app picks it up on next page load (via `next-intl` request cycle). +4. When the user changes theme in the **web**, the app picks it up on next foreground (re-fetch `/me` on `ON_RESUME`). + +### 3.4 Crossfading themes + +A theme switch animates over 600 ms with `animateColorAsState(spec = tween(600, easing = EaseSmooth))` on every color token. The accent and blob colors crossfade simultaneously. The neutrals don't change so the layout stays anchored. + +This matches the web's behavior — `globals.css` registers `--blob-1..4` via `@property { syntax: ""; inherits: true }` so they're CSS-Houdini-interpolatable. Same effect, different runtime. + +> **Critical detail:** the `inherits: true` bug from the web (`CLAUDE.md` line 333) doesn't apply here — Compose state propagates directly. But the analogous trap: `remember { … }` of a color *outside* of `CompositionLocal` will not recompose on theme change. Always read theme colors via `MaterialTheme.colorScheme.*` or `LocalKaizenTheme.current.*`, never cache. + +--- + +## 4. The Liquid-Glass surface + +This is the heart of the design. Everything floating — sidebar, input bar, model pill, suggestion chips, dropdowns, message input — is a `GlassSurface`. It is **real refractive blur**, not a translucent rectangle. + +### 4.1 Anatomy + +``` + ┌──────────────────────────────────────────────┐ + │ │ + │ ░ Blurred capture of what's behind ░ │ ← RenderEffect.createBlurEffect + background → │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ │ (24f, 24f, EDGE_CLAMP) + blob layer │ │ + │ ◤ Inset top highlight (1dp, white α 0.08) │ ← inner specular + │ │ + │ Content (icons / text / chip label) │ ← drawn over the blur + │ │ + │ ◣ Multi-layer drop shadow │ ← see §6 (Shadow stack) + └──────────────────────────────────────────────┘ + ↑ + 1 dp hairline (outline @ 60%) — final perimeter +``` + +### 4.2 Implementation + +```kotlin +@Composable +fun GlassSurface( + modifier: Modifier = Modifier, + shape: Shape = KaizenShapes.medium, + tint: Color = MaterialTheme.colorScheme.surface, + tintAlpha: Float = 0.72f, // see opacity tiers, §4.4 + blurRadius: Dp = 24.dp, + content: @Composable BoxScope.() -> Unit, +) { + val density = LocalDensity.current + val supportsBlur = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S + + Box( + modifier + .clip(shape) + .then( + if (supportsBlur) + Modifier.graphicsLayer { + renderEffect = RenderEffect.createBlurEffect( + with(density) { blurRadius.toPx() }, + with(density) { blurRadius.toPx() }, + Shader.TileMode.CLAMP, + ).asComposeRenderEffect() + } + else + Modifier // API 26–30 falls back to pre-blurred WebP (see §4.6) + ) + .drawBehind { + // The "frost" tint that gives the glass body + drawRect(tint.copy(alpha = tintAlpha)) + } + .innerTopHighlight() // 1dp inset white α=0.08 + .border(1.dp, MaterialTheme.colorScheme.outline.copy(alpha = 0.6f), shape) + .squircleShadow(level = 2), // multi-layer shadow, see §6 + content = content, + ) +} +``` + +**Three things to internalize:** + +1. `graphicsLayer { renderEffect = … }` is the GPU primitive. It rasterizes the underlying composition into a layer, blurs that layer, and composites it back. Cost is proportional to the layer's pixel area, not the content complexity. Sidebar (~220 × 800 dp on phone) ≈ 0.6 ms per frame on a Snapdragon 8 Gen 3. Acceptable budget. +2. The `tint` is what gives the surface its color identity (Obsidian vs white). Without it the blur would just show a wash of whatever's behind, with no surface identity. Tint alpha controls how "milky" the glass is (see §4.4). +3. The blur is **not** a backdrop blur in the iOS sense — Android does not have a `Modifier.backdropBlur`. It blurs *the surface itself*, but because the surface is mostly transparent (`tintAlpha 0.72`), the blur of the content *behind* shows through. Same visual effect, different code path. The trick is that the content behind already drew before us (correct paint order). + +### 4.3 The capture layer + +For the blur to capture the blob layer behind, the blob layer **must paint into the same compositing context** that our blurred layer reads from. This means: + +- The blob `Canvas` composable is the first child of the root `Box`. +- It must NOT have `.graphicsLayer()` itself (no double-buffering — defeats the read-back). +- The glass surface is a sibling later in the same `Box`. + +Verified pattern in `chat/Background.kt`. If you ever wrap the blob layer in its own `GraphicsLayer` for animation perf, the glass surfaces will go gray. Don't. + +### 4.4 Opacity tiers (mirror of web `globals.css`) + +| Component | Tint alpha (light) | Tint alpha (dark) | Blur radius | Notes | +| ----------------------- | ------------------ | ----------------- | ----------- | ---------------------------------------------------- | +| Sidebar | 0.68 | 0.72 | 28 dp | Floats. Most translucent. The "frosted" reference. | +| Input bar | 0.74 | 0.75 | 24 dp | Slightly more body — reads as a real input surface. | +| Mode pill, model pill | 0.82 | 0.80 | 20 dp | Small surfaces need more body to read. | +| Suggestion chip (hero) | 0.90 | 0.85 | 16 dp | Tap targets. Must look solid. | +| Settings card | 0.95 | 0.94 | 16 dp | Reading surface. Near-opaque. | +| User bubble (amber-tinted) | 0.88 | 0.86 | 12 dp | Tinted glass via `tint = primary` (not surface). | +| Assistant bubble | — (no surface) | — (no surface) | — | Text on background. No card. | +| Dropdown / sheet | 0.85 | 0.82 | 32 dp | The deepest blur — pops the menu off the surface. | + +> These numbers are derived empirically on a Pixel 8 Pro and a Galaxy S25 Ultra. Re-tune if you ship to e-paper or low-bit-depth panels (none planned). + +### 4.5 Chromatic-aberration rim (`refraction = true`) + +For premium surfaces (hero orb, send button armed state, model pill on hover-equivalent), we add a one-pixel chromatic aberration at the rim. This is what makes glass look like *real* glass — light passing through a curved edge separates into R/G/B by tiny amounts. + +```kotlin +Modifier.drawWithCache { + val ringWidth = 1.dp.toPx() + onDrawWithContent { + drawContent() + // Three single-pixel offset strokes in pure R/G/B at the perimeter + drawOutline(outline, color = Color.Red.copy(alpha = 0.10f), + style = Stroke(ringWidth), translateX = -0.5f) + drawOutline(outline, color = Color.Green.copy(alpha = 0.06f), + style = Stroke(ringWidth)) + drawOutline(outline, color = Color.Blue.copy(alpha = 0.10f), + style = Stroke(ringWidth), translateX = +0.5f) + } +} +``` + +Used sparingly — on every glass surface this is noise. Only the orb and the armed send button. Toggleable via `KaizenTheme.LocalRefraction.current`. + +### 4.6 API 26–30 fallback + +`RenderEffect.createBlurEffect` requires API 31+. `minSdk` is 26. Fallback strategy: + +1. At build time, generate **pre-blurred snapshots** of the blob layer for each theme × mode (8 PNGs total, ~150 kB each at 540 × 1200, WebP at quality 85). These live in `res/drawable/blob_baked__.webp`. +2. On API 26–30, `Background.kt` renders the static WebP instead of the animated canvas (no drift animation — the static look is "old phone, less polish, still good"). +3. `GlassSurface` on those APIs skips `RenderEffect` and uses a higher tint alpha (+0.10 across all tiers) plus a slightly larger inner highlight to fake depth. + +Penalty: no animated blobs, no real blur. Acceptable for ~5% of installs (Android distribution stats Jun 2026: API 31+ ≈ 92%). Do not invest in a `RenderScript` blur fallback — `RenderScript` is deprecated and gone in API 35. + +--- + +## 5. Shape — squircles, not rounded rectangles + +The default `RoundedCornerShape` is a rectangle with quarter-circle corners. iOS, macOS, and modern web design (Tailwind 4 `rounded-squircle`) use the **continuous superellipse** — corners that ease into the straight edges with G2 continuity (curvature also matches, not just position). + +The difference is small at 4 dp radii. At 16+ dp it's the difference between "round rectangle" and "iPhone icon." + +### 5.1 The `KaizenSquircleShape` + +```kotlin +class SquircleShape( + private val radius: Dp, + private val smoothness: Float = 4.5f, // n in the superellipse equation; 2 = circle, ∞ = rectangle +) : Shape { + override fun createOutline(size: Size, layoutDirection: LayoutDirection, density: Density): Outline { + val r = with(density) { radius.toPx() }.coerceAtMost(min(size.width, size.height) / 2f) + val path = Path().apply { + // Sample 32 points per corner along (x/r)^n + (y/r)^n = 1 + // Detailed implementation in ui/shape/Squircle.kt + … + } + return Outline.Generic(path) + } +} +``` + +### 5.2 Shape tokens (replace `Shapes`) + +| Token | Radius | Smoothness | Used for | +| -------------------- | ------ | ---------- | ----------------------------------------------------- | +| `KaizenShapes.xs` | 8 dp | 4.0 | Inline chips inside chips | +| `KaizenShapes.sm` | 12 dp | 4.2 | Dropdown items, inline action buttons | +| `KaizenShapes.md` | 16 dp | 4.5 | Sidebar surface, settings groups | +| `KaizenShapes.lg` | 24 dp | 5.0 | Hero suggestion chips, message bubbles | +| `KaizenShapes.xl` | 28 dp | 5.0 | Input bar, model pill, mode pills | +| `KaizenShapes.pill` | 999 dp | 4.5 | Send button, "Standard" badge | +| `KaizenShapes.circle`| — | — | Avatars, FAB, orb-bounding box | + +> Smoothness `n` from `4.0` to `5.0` is the sweet spot. Below `3.0` it's a rounded square. Above `7.0` it's visually indistinguishable from a rectangle. + +### 5.3 Liquid morph on press + +When the user presses any squircle (button, chip, pill), the shape briefly *liquefies* — radius increases by ~20% and smoothness drops to ~3.5 over 80 ms with `spring(dampingRatio = 0.55f)`. Released → returns to base. Same idea as iOS 26's liquid buttons. Implementation: animate `radius` and `smoothness` as `Animatable`, recompose the shape. + +Cost: shape recreation is allocation-heavy if done naively. Pool shapes by `(radius_bucket, smoothness_bucket)` with 0.5 dp / 0.1 buckets. ~30 shape instances total in steady state. + +--- + +## 6. Shadow stack + +Single drop-shadow looks 2014. Premium UI uses **layered shadows** (also called "long shadow" in design tools) — three to five overlapping shadows at increasing blur radii and decreasing opacity, summing to a soft, realistic falloff. + +### 6.1 Token + +```kotlin +data class ShadowLayer(val offsetY: Dp, val blur: Dp, val spread: Dp, val alpha: Float) + +data class ShadowStack(val layers: List) + +object KaizenShadows { + val level0 = ShadowStack(emptyList()) + + val level1 = ShadowStack(listOf( + ShadowLayer(1.dp, 2.dp, 0.dp, 0.04f), + ShadowLayer(1.dp, 4.dp, 0.dp, 0.02f), + )) + + val level2 = ShadowStack(listOf( + ShadowLayer(2.dp, 4.dp, 0.dp, 0.05f), + ShadowLayer(4.dp, 12.dp, 0.dp, 0.04f), + ShadowLayer(8.dp, 24.dp, 0.dp, 0.03f), + )) + + val level3 = ShadowStack(listOf( + ShadowLayer(2.dp, 4.dp, 0.dp, 0.06f), + ShadowLayer(8.dp, 16.dp, 0.dp, 0.05f), + ShadowLayer(16.dp,32.dp, 0.dp, 0.04f), + ShadowLayer(24.dp,48.dp, 0.dp, 0.03f), + )) + + val level4 = ShadowStack(listOf( // dialogs, call-mode overlay + ShadowLayer(4.dp, 8.dp, 0.dp, 0.07f), + ShadowLayer(12.dp,24.dp, 0.dp, 0.06f), + ShadowLayer(24.dp,48.dp, 0.dp, 0.05f), + ShadowLayer(48.dp,96.dp, 0.dp, 0.04f), + )) +} +``` + +Dark mode multiplies all alphas by ~1.8 — shadows need to be darker on dark surfaces to read at all. + +### 6.2 Implementation + +`Modifier.squircleShadow(level: ShadowStack)` draws each layer in order, before the content, using `Canvas.drawRoundRect` with a blurred paint. Five drawcalls per surface at level 3 — cheap. + +Compose's built-in `Modifier.shadow()` does NOT support custom shapes or stacks. We implement our own. Found in `ui/effect/Shadow.kt`. + +### 6.3 Inner-shadow / inset top highlight + +The companion to the drop shadow. Sells "light from above": + +```kotlin +Modifier.drawWithContent { + drawContent() + // 1dp inset top highlight, blurred 1dp + val highlightColor = if (isDarkTheme) Color.White.copy(alpha = 0.08f) + else Color.White.copy(alpha = 0.95f) + drawLine(highlightColor, Offset(0f, 1f), Offset(size.width, 1f), strokeWidth = 1.dp.toPx()) +} +``` + +Applied via `Modifier.innerTopHighlight()`. Together with the drop shadow, this is what makes glass look *lit* instead of *floating*. + +--- + +## 7. Sensor-reactive motion + +This is the single most "wow"-y interaction in the app. Tilt your phone slightly and the orb's specular highlight tracks your viewing angle as if it were a real glass sphere. The blob layer drifts a parallactically different amount than the foreground. Done right, the user notices but cannot name it — it just feels *alive*. + +### 7.1 The signal + +```kotlin +@Composable +fun rememberTiltState(): State { + val sensorManager = … + val rotationVector = sensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR) + val tilt = remember { mutableStateOf(Offset.Zero) } + + DisposableEffect(rotationVector) { + val listener = object : SensorEventListener { + override fun onSensorChanged(event: SensorEvent) { + // Convert quaternion to pitch+roll, low-pass filter (α = 0.18) + // Clamp to ±15° → normalize to Offset(-1f..1f, -1f..1f) + tilt.value = filtered + } + … + } + sensorManager.registerListener(listener, rotationVector, + SensorManager.SENSOR_DELAY_GAME) // 50Hz + onDispose { sensorManager.unregisterListener(listener) } + } + return tilt +} +``` + +Uses **`TYPE_GAME_ROTATION_VECTOR`**, not the bare accelerometer. Game rotation vector is fused (gyro + accel + magnetometer) and pre-stabilized — gives stable 50 Hz delta with no drift correction needed. Lower power than full rotation vector. + +### 7.2 What reacts to tilt + +| Element | Effect | +| -------------------------- | ------------------------------------------------------------------------ | +| **Hero orb specular** | Top-left highlight moves opposite to tilt (`offset = -tilt * 8.dp`). Range ~±12 dp. | +| **Send button (armed)** | Subtle. `offset = -tilt * 2.dp`. Just enough to feel responsive. | +| **Blob layer** | Translates `tilt * 32.dp` (slower than foreground = parallax). | +| **Mesh-gradient highlight**| Subtly shifts color stops along tilt vector. ~3° hue rotation max. | +| **Conversation list rows** | NOT tilt-reactive. Lists must stay still for legibility. | +| **Message text** | NOT tilt-reactive. Same reason. | + +### 7.3 When to disable + +- `Settings.Global.ANIMATOR_DURATION_SCALE == 0f` (system "Remove animations") +- In-app "Reduce motion" setting (mirrors web `appearance.reduceMotion` once implemented) +- `PowerManager.isPowerSaveMode == true` — battery saver disables tilt +- Device tilted past ±25° (user is probably lying down or holding sideways — keeps the orb from snapping to a corner) +- `LifecycleOwner.lifecycle.currentState != STARTED` — never listen in background + +### 7.4 Frame-rate budget + +50 Hz sensor → state update → recompose only on `Modifier.graphicsLayer { translationX = … }` (which doesn't invalidate measure/layout). Total recomposition cost ≈ 0.2 ms per tilt event. Effectively free. + +--- + +## 8. Typography — Inter Variable + +System fonts are good. Inter is **better** at the sizes we use (16–32 sp body, 32–48 sp hero), and as a Variable Font it costs roughly the same as a single static weight. + +### 8.1 Why Inter + +- **Designed for screens.** Tall x-height, open apertures, large counters — readable at small sizes on low-DPI fallback devices. +- **Variable axes:** `wght` (100–900) and `opsz` (14–32) plus subtle `slnt`. We use `wght` everywhere and `opsz` on the hero headline. +- **Open license** (SIL OFL). Ship freely. +- **Matches the web app's intent** — the web defaults to system, but switching it to Inter has been on the backlog. The app can lead. + +### 8.2 Shipping + +- One file: `res/font/inter_variable.ttf` (~330 kB compressed in APK). +- Declared as a `FontFamily` with variation settings: + +```kotlin +val InterVariable = FontFamily( + Font(R.font.inter_variable, weight = FontWeight.W400), + // Compose 1.7+ supports variation settings; pre-1.7 falls back to weight axis +) +``` + +- On API 26+ all Variable Font axes are supported by Android's font renderer. No fallback needed. + +### 8.3 Type scale + +| Role | Size | Weight (`wght`) | Optical (`opsz`) | Line height | Tracking | Used for | +| --------------- | ----- | --------------- | ---------------- | ----------- | --------- | ------------------------------------- | +| `displayLarge` | 32 sp | 640 | 32 | 38 sp | −1.0% | Hero headline ("Was liegt an?") | +| `displayMedium` | 24 sp | 600 | 24 | 30 sp | −0.5% | Settings section titles | +| `titleLarge` | 20 sp | 560 | 20 | 26 sp | 0 | Card titles | +| `titleMedium` | 16 sp | 540 | 16 | 22 sp | +0.3% | Model name, sidebar items | +| `bodyLarge` | 16 sp | 420 | 16 | 24 sp | +0.5% | Chat message body | +| `bodyMedium` | 14 sp | 420 | 14 | 20 sp | +0.8% | Secondary text, settings descriptions | +| `labelLarge` | 14 sp | 540 | 14 | 20 sp | +1.0% | Buttons, chip labels | +| `labelMedium` | 12 sp | 540 | 14 | 16 sp | +2.0% | Pills ("Standard") | +| `labelSmall` | 11 sp | 520 | 14 | 16 sp | +3.0% | Timestamps, date subtitle | +| `code` | 14 sp | 460 (mono) | — | 22 sp | 0 | Code blocks (JetBrains Mono Variable) | + +Two principles: + +1. **Weight tracks size.** At small sizes Inter needs slightly heavier weight (520–560) to stay crisp. Hero size uses `640` not `700` — `700` is too display-y at 32 sp on glass. +2. **Tracking is positive at small sizes, negative at large.** Inter ships with default tracking that's optimized for ~16 sp body. We loosen below 14 sp and tighten above 24 sp. + +### 8.4 Optical sizing (`opsz`) + +The big trick. At display sizes (24–32 sp) we set `opsz = 24–32`, which makes Inter pick its "Display" outlines — slightly narrower, tighter, more elegant. At body sizes (14–16 sp) we set `opsz = 14–16` → "Text" outlines: wider, more open, more legible. + +This is automatic if you pass `FontVariation.Setting("opsz", size.toFloat())` to the `Font(...)` definition. Compose 1.7+ supports this directly. + +### 8.5 Mono for code + +JetBrains Mono Variable (~280 kB) for inline `code` and code blocks. Tabular figures, ligatures off (programmer aesthetics divide on this — off is the conservative default and we can flip per-user later). + +--- + +## 9. The Kaizen Orb (premium tier) + +The orb is the brand mark, the empty-state hero, the assistant avatar, and the call-mode focal point. It is the single most-engineered visual in the app. Here is the full premium recipe. + +### 9.1 Sizes & use + +| Size | Where | Premium features active | +| --------- | -------------------------------------- | --------------------------------------------- | +| 96–160 dp | Hero (`EmptyHero`) | All: HDR specular, tilt, breath, refraction | +| 28 dp | Assistant avatar in message list | Static recipe (no real blur — too small) | +| 28 dp + streaming | Avatar while answer streams | Fast breath + triple-shadow glow | +| 200 dp | Call-mode overlay | All + amplitude-reactive scale (mic input) | + +### 9.2 The seven layers (hero) + +Top to bottom (paint order): + +1. **Drop-shadow halo** — `ShadowStack` level 3 + an additional `primary @ 30%` blur at 40 dp. Sells "this thing is hovering." +2. **Outer wrapper** — owns the `breath` animation (1.0 → 1.025 → 1.0, 7 s sinusoidal). On streaming: faster (1.8 s, scale 1.0 → 1.12). +3. **Outer rim — chromatic aberration** — §4.5 recipe. Three 1px R/G/B strokes. +4. **Inner sphere — refractive blur** — `RenderEffect.createBlurEffect(28f, 28f, CLAMP)` reading the blob layer. THIS is what makes the orb a glass marble rather than a painted ball. The blob colors visibly shift as the orb moves (or the user tilts the device). +5. **Internal sweep gradient** — `Brush.sweepGradient(0° = primary @ 60%, 90° = primary-deep @ 80%, 180° = primary @ 60%, 270° = white @ 30%)`. Rotates with `tilt.x * 30°` — gives the orb internal chromatic depth that responds to viewing angle. +6. **Specular highlight (top-left)** — radial gradient, `LinearExtendedSrgb(4, 4, 4) → transparent`, ~30% of orb radius, center offset by `-tilt * 8.dp`. **This is the HDR pop.** On a 2,600-nit panel this is what makes the user say "huh, why is that brighter than the rest of my screen." +7. **Bottom inner glow** — radial gradient, `primary @ 40% → transparent`, ~60% of orb radius, anchored to bottom-center. Suggests internal light source. + +### 9.3 Streaming variant + +When `isStreaming == true`, the 28 dp avatar swaps state. Visually critical that the user can tell "Kaizen is thinking" without reading text: + +- Breath → `hero-orb-breath-fast` (1.8 s, scale 1.0 → 1.12) +- Triple-stacked shadow: `primary @ 30/20/10%` at blur `8/16/24 dp` +- The internal sweep gradient rotates continuously at 90°/s (only in streaming state — static otherwise) + +When streaming ends, the orb returns to the calm breath over 400 ms with `spring(dampingRatio = 0.6f)`. + +### 9.4 Call mode (200 dp) + +In `CallView`, the orb is the entire UI. Three additional behaviors: + +- **Amplitude scaling.** Mic input RMS over the last 100 ms drives `scale = 1.0 + amplitude * 0.3` (capped at 1.3). When the user speaks, the orb breathes with their voice. +- **Color temperature shift.** While the TTS plays back (assistant speaking), the orb shifts ~10° towards warm. While the user speaks, ~10° towards cool. Subliminal: warm = listening, cool = speaking. Same idea as Siri's modes but quieter. +- **Pulse on tool-call.** When the assistant fires a tool (web search, etc.), a one-shot pulse — single scale 1.0 → 1.15 → 1.0 over 250 ms. Tells the user "something happened" without text. + +--- + +## 10. Animation system + +Every motion in the app uses the same easing/spec primitives. Defined in `ui/motion/Motion.kt`. + +### 10.1 Easing tokens + +```kotlin +val EaseSpring = CubicBezierEasing(0.34f, 1.56f, 0.64f, 1f) // overshoot, for entrances +val EaseSmooth = CubicBezierEasing(0.22f, 1f, 0.36f, 1f) // expo-out, for transitions +val EaseStandard = FastOutSlowInEasing // system-aligned +val EaseEmphasized = CubicBezierEasing(0.05f, 0.7f, 0.1f, 1f) // M3 emphasized + +val SpringSnappy = spring(dampingRatio = 0.55f, stiffness = 800f) +val SpringDefault = spring(dampingRatio = 0.75f, stiffness = 400f) +val SpringGentle = spring(dampingRatio = 0.85f, stiffness = 200f) +``` + +### 10.2 Spec assignments + +| Use case | Spec | +| ------------------------- | ------------------------------------------------------------ | +| Bubble entrance | `tween(350ms, easing = EaseSpring)` | +| Page transition (slide+fade) | `tween(280ms, easing = EaseEmphasized)` | +| Dropdown open | `tween(150ms, easing = EaseSmooth)` | +| Sidebar slide | `spring(dampingRatio = 0.85f, stiffness = 300f)` | +| Theme color crossfade | `tween(600ms, easing = EaseSmooth)` | +| Orb breath | `infiniteRepeatable(tween(7000ms, EaseStandard), reverseDirection)` | +| Orb breath (streaming) | `infiniteRepeatable(tween(1800ms, EaseStandard), reverseDirection)` | +| Squircle press | `SpringSnappy` | +| Tilt response (sensor) | None — direct binding. Sensor's own low-pass handles smoothing. | +| Thinking dots | `infiniteRepeatable(tween(1000ms, LinearEasing))` × 3 with 160 ms phase offsets | + +### 10.3 Shared-element transitions + +Compose 1.7+ supports `SharedTransitionScope` with `Modifier.sharedElement(...)`. We use it for two transitions: + +1. **Conversation list row → chat screen.** The conversation title in the sidebar shared-element-transitions into the header. Feels like "tapping into" the chat. +2. **Empty-state orb → first assistant avatar.** When the user sends their first message, the hero orb shrinks from 120 dp to 28 dp and docks left of the first assistant bubble. 600 ms with `EaseEmphasized`. Conceptually: "the thing you were looking at is now answering you." This is the single most magical moment in the app. + +### 10.4 Haptics (`haptics/Haptics.kt`) + +Sparingly. Overuse desensitizes. + +| Trigger | Effect | +| -------------------------------- | -------------------------------------------------------- | +| Send message | `HapticFeedbackConstants.CONFIRM` (API 30+) / `VIRTUAL_KEY` | +| Long-press conversation row | `LONG_PRESS` | +| Toggle mode pill | `SEGMENT_TICK` (API 30+) / `CLOCK_TICK` | +| Theme switch | `GESTURE_END` once when the crossfade completes | +| Stream complete (>5s wait) | `GESTURE_END` | +| Error | `REJECT` (API 30+) / double `VIRTUAL_KEY` | + +--- + +## 11. Screen-by-screen + +### 11.1 Empty state / new chat (`EmptyHero`) — mobile + +**No suggestion chips.** Different from `ui-kaizen.jpg`. The chips are redundant with the mode pills above the input (same function: "set mode before typing"). On a phone with a keyboard open, the chip row eats 20% of the visible height for no gain. Web keeps them (different ergonomics, hover, more room). Mobile drops them. + +``` +┌─────────────────────────────────────────┐ +│ ☰ ⌃ Gemini 3.5 Flash ▾ │ +│ │ +│ │ +│ │ +│ ●●●●●●●● │ +│ ● ● │ +│ ● ORB ● (120 dp) │ +│ ● ● │ +│ ●●●●●●●● │ +│ │ +│ Guten Tag, Bruno │ +│ │ +│ Was liegt an? │ +│ │ +│ So., 21. Juni · 13:34 │ +│ │ +│ │ +│ │ ← intentional whitespace +│ │ +│ │ +│ │ +│ ┌─────────────────────────────────────┐ │ +│ │ ⊕ Standard Sampling Bild Suchen │ │ ← Mode pills (horizontal scroll) +│ └─────────────────────────────────────┘ │ +│ ┌─────────────────────────────────────┐ │ +│ │ ⊕ Nachricht eingeben … ☎ ↑ │ │ ← Input bar +│ └─────────────────────────────────────┘ │ +└─────────────────────────────────────────┘ +``` + +**Layout details** + +- Vertical alignment: `Top` with `paddingTop = max(32.dp, 8% screenHeight)`. Not `Center`. Centered drifts up when the keyboard opens. +- Greeting: time-of-day-based (Morgen / Tag / Abend, boundaries 5/12/18). First name from `/api/v1/me`. Falls back to bare "Guten Tag" if name missing. +- Subtitle: localized short-date + time, live every minute, `tabular-nums`. +- All three sections (orb / greeting / subtitle) animate in staggered: `fadeIn + slideInVertically` with delays 0 / 100 / 200 ms. Total entrance time 700 ms. + +### 11.2 Active conversation (`ChatScreen`) + +``` +┌─────────────────────────────────────────┐ +│ ☰ Gemini 3.5 Flash ▾ ⋯ │ +├─────────────────────────────────────────┤ +│ │ +│ ╭─────────────────────╮│ +│ │ Was ist Kaizen? ││ ← User bubble (amber-tinted glass) +│ ╰─────────────────────╯│ +│ │ +│ ◉ Kaizen ist eine japanische │ ← Assistant: orb + plain markdown +│ Philosophie der kontinu- │ no surface around the text +│ ierlichen Verbesserung … │ +│ │ +│ ▸ Gedankengang (3s) │ ← Collapsible ThinkingBlock +│ │ +│ ╭─────────────────────╮│ +│ │ Erzähl mir mehr ││ +│ ╰─────────────────────╯│ +│ │ +│ ◉ ● ● ● │ ← Streaming dots before first token +│ │ +├─────────────────────────────────────────┤ +│ [mode pills row] │ +│ ⊕ Erzähl mir mehr … ☎ ▣ │ ← Stop while streaming +└─────────────────────────────────────────┘ +``` + +- Autoscroll only if user is within 80 dp of the bottom. Otherwise show a "↓ Neue Nachricht" pill bottom-right. +- Bubble entrance: `bubble-in` (translateY 8 dp + scale 0.98, 350 ms spring overshoot). Stable `key={node.id}` ensures it fires once per insert. +- ThinkingBlock auto-opens during streaming, auto-collapses 300 ms after completion. Tappable to re-open. + +### 11.3 Sidebar (`Sidebar.kt`) + +`ModalNavigationDrawer` on phones, permanent rail on ≥600 dp width. + +``` +┌──────────────────────┐ +│ ⌕ Suchen │ +├──────────────────────┤ +│ + Neuer Chat │ +├──────────────────────┤ +│ Heute │ +│ ▸ Was ist Kaizen? │ ← active row: primary @ 8% bg tint +│ Python sorting │ +│ UI Design … │ +│ │ +│ Gestern │ +│ Docker setup │ +│ ──── │ +│ ▸ Älter │ +├──────────────────────┤ +│ 👤 Bruno ⋯ │ ← UserCard: tap → settings menu +└──────────────────────┘ +``` + +- Whole sidebar is one `GlassSurface` tier 1 (most translucent). 8 dp margin all sides — "floating drawer" not "edge-attached panel." +- Long-press → inline action sheet (Rename / Lock / Delete). 250 ms hold, haptic on commit. +- Search is in-memory against the offline Room cache. Never hits the server. + +### 11.4 Settings (`SettingsScreen`) + +Sectioned, single-screen-per-section, navigation via the sidebar (replaces conversation list when route is `settings/*`). Each section is a stack of `SettingsCard`s (opacity tier 6, near-opaque) with `Field` rows. + +Mirrors the web `components/settings/section-ui.tsx` Card + Field primitives. + +--- + +## 12. Component library + +### 12.1 Buttons + +| Variant | Composable | When to use | +| --------------- | ----------------------- | ------------------------------------------------- | +| Primary (FAB) | `KaizenSendButton` | Send message (amber pill-circle, 44 dp) | +| Primary (text) | `KaizenButton` | "Speichern", "Anmelden" — full-width in dialogs | +| Secondary | `KaizenOutlinedButton` | "Abbrechen", "Verwerfen" | +| Tertiary | `KaizenTextButton` | Inline "Mehr anzeigen", "Bearbeiten" | +| Icon | `KaizenIconButton` | Toolbar icons, chip close X | +| Pill | `ModePill`, `OptionPill`| Mode selector, model selector, image options | + +All buttons: +- Min tap 44 dp. +- Pressed: `scale 0.94` via `SpringSnappy`. No M3 ripple over glass — the scale + opacity tweak is the feedback. +- Disabled: `alpha = 0.4`, no scale, no haptic. + +### 12.2 Inputs + +- `ChatInputBar` — Material 3 `TextField` with custom decoration. `GlassSurface` container, no underline, multi-line up to 6 rows. +- `KaizenTextField` — Settings dialog text inputs. Outlined Material 3 with brand-overridden colors. +- Placeholder color: `onSurfaceVariant @ 60%` (M3 default is too prominent on glass). + +### 12.3 Chips + +- `SuggestionChip` (hero) — `GlassSurface` tier 4, icon left, label right, `KaizenShapes.lg`, 14 sp label. +- `AttachmentChip` (input bar) — file-type icon + filename + close X, `KaizenShapes.sm`. +- `QuoteChip` (input bar) — quote icon + `line-clamp-3` text + close X, displayed above attachments. From "Ask about selection." + +### 12.4 Lists + +- Conversation row: 48 dp height, 16 dp horizontal padding, label + optional lock badge. +- Settings field row: 56 dp height. +- Long-press: 250 ms hold → `LONG_PRESS` haptic → contextual action sheet. + +### 12.5 Dropdowns / sheets + +Portal-style (`Popup`) with the entrance pattern: +- `fadeIn(150ms) + scaleIn(0.95, anchor) + slideInVertically(initialOffsetY = { it / 8 })` +- Matches web `animate-in fade-in zoom-in-95 slide-in-from-top-2`. + +Bottom sheets on phones use `ModalBottomSheet` with `GlassSurface` as the container shape. + +### 12.6 Snackbar (`KaizenSnackbar`) + +No native `Toast` (looks wrong on glass). `GlassSurface` tier 3, bottom-anchored, 4 s auto-dismiss, manual close. Same recipe as the web app's `createPortal` toast in `users-card.tsx`. + +--- + +## 13. Dark mode + +Dark mode is not "recolor light mode." It is a **different spatial system**. + +### 13.1 What changes + +- Background luminance: L=0.96 → L=0.10. +- Blob `BlendMode`: normal → `BlendMode.Plus` (additive — makes blobs glow on dark). +- Glass top highlight inset: white α 0.95 → white α 0.08 (stronger on dark to fake light). +- Shadow alpha: ×1.8 (shadows need to be darker on dark surfaces to read). +- Code-block highlight theme: `github` → `github-dark-dimmed`. +- Brand amber: `AmberDeep` → `Amber` (pure amber has more weight on Obsidian). + +### 13.2 What does NOT change + +- Orb recipe (a sphere is a sphere — only the background reflection differs). +- Theme identity (Amber stays Amber). +- Shapes, sizes, line heights, tracking. +- Layout — never reflow on mode change. + +### 13.3 Switching + +System default by default. User override in Settings → Erscheinungsbild (mirrors web `appearance.design`). Crossfade 600 ms with `tween(EaseSmooth)` on every color. Status bar + nav bar adopt the new appearance via `WindowCompat.getInsetsController(...).isAppearanceLightStatusBars`. + +--- + +## 14. Accessibility + +| Requirement | How we meet it | +| ---------------------------------------- | ---------------------------------------------------------------- | +| Touch target ≥ 44 dp | All interactive components. | +| Contrast ≥ 4.5:1 body text | `LightText` on `LightBackground` = 13.2:1; `DarkText` on `Obsidian` = 14.8:1. | +| Contrast ≥ 3:1 large text | Hero headline passes both modes. | +| Contrast ≥ 3:1 UI components | `AmberDeep` on white = 3.1:1; `Amber` on Obsidian = 8.4:1. | +| `contentDescription` on icon buttons | Lint via `composeRules` (`MissingContentDescription`). | +| Respect `fontScale` | All text in `sp`, layouts in `dp`. Verified up to 1.3×. | +| Respect reduced motion | `Settings.Global.ANIMATOR_DURATION_SCALE == 0f` → instant transitions, static blobs, no tilt, no orb breath. | +| TalkBack labels for the orb | `"Kaizen"` (idle), `"Kaizen denkt nach"` (streaming). | +| HDR opt-out | `Settings.Global.HDR_TONE_MAPPING_DISABLED` (where applicable) → fall back to SDR specular. | +| Keyboard nav (external KB) | Verified focus order: Login, Settings, Chat input. | +| RTL | Out of scope (de/en only). | + +--- + +## 15. Internationalization + +- de (default), en. Same as web (`messages/de.json`, `messages/en.json`). +- Strings: `res/values/strings.xml` (en) + `res/values-de/strings.xml` (de). +- Date/time: `java.time.format.DateTimeFormatter.ofLocalizedDate(MEDIUM)` with `Locale.getDefault()`. +- Greeting boundaries localized — English uses Morning/Afternoon/Evening. + +--- + +## 16. Performance budget + +If we lose any of these, the design has degraded. Wire them into Macrobench in CI. + +| Metric | Budget (S25 Ultra, default theme) | Budget (Pixel 6a, low-end) | +| ------------------------------------------------- | --------------------------------- | --------------------------- | +| Cold start (Activity creation → first frame) | ≤ 600 ms | ≤ 1100 ms | +| Frame time, idle empty state with blobs | ≤ 4 ms (sustained 120 fps) | ≤ 14 ms (60 fps) | +| Frame time, scrolling conversation (50 msgs) | ≤ 6 ms | ≤ 16 ms | +| Frame time, theme switch crossfade peak | ≤ 9 ms | ≤ 22 ms | +| Memory, idle on chat screen | ≤ 130 MB | ≤ 95 MB | +| Battery drain, 10 min foreground idle (chat open) | ≤ 3% (HDR active) / ≤ 2% (SDR) | ≤ 2.5% | + +Run via Macrobenchmark with `androidx.benchmark.compilation.mode=Partial` (Baseline Profiles). Baseline Profiles are mandatory — without them cold start nearly doubles. + +--- + +## 17. Asset inventory + +`app/src/main/res/`: + +| Asset | Format | Notes | +| ---------------------------------- | -------------------- | --------------------------------------- | +| `mipmap-*/ic_launcher` | Adaptive icon XML | Orb on amber background | +| `mipmap-anydpi/ic_launcher_round` | Adaptive icon | API 25+ round launcher | +| `drawable/noise_64.png` | 64×64 PNG, alpha | Film-grain overlay (§4.1) | +| `drawable/blob_baked__.webp` | Pre-blurred | API 26–30 blob layer fallback (×8 total) | +| `font/inter_variable.ttf` | Variable Font | ~330 kB | +| `font/jetbrains_mono_variable.ttf` | Variable Font | ~280 kB, code blocks | + +No Lottie, no SVG at runtime (Compose `ImageVector` instead), no remote font fetch. + +--- + +## 18. Open design questions + +Capture decisions here as they're made. + +1. **Sources / citation rendering on mobile.** Web uses an inline collapsed `SourcesBlock`. Mobile competes for vertical room. Lean: a single "5 Quellen" pill that opens a bottom sheet. +2. **Tablet layout** — permanent sidebar at ≥600 dp width, or stays modal? Currently modal everywhere. Revisit during foldable testing. +3. **Image-gen viewer** — full-screen pinch-zoom (planned) vs inline expandable. +4. **Call-mode landscape** — portrait-only initially. Landscape later. +5. **JetBrains Mono ligatures** — off by default. Per-user toggle in Settings → Erscheinungsbild later? +6. **Refraction (chromatic aberration) global toggle.** Currently only on orb + armed send button. Should there be a "subtle / standard / off" setting? + +--- + +## 19. Implementation checklist (in order) + +For someone picking up the project tomorrow: + +1. **Color pipeline.** Convert all `Color(0xFF…)` in `ui/theme/Color.kt` to P3 float form. Add `window.colorMode = COLOR_MODE_WIDE_COLOR_GAMUT` (and `HDR` on API 34+) in `MainActivity.onCreate`. Test on a P3 device — amber should look visibly more saturated than before. +2. **Squircle shape.** Implement `SquircleShape` in `ui/shape/Squircle.kt`. Replace all `RoundedCornerShape(...)` usages. +3. **Inter Variable.** Drop `inter_variable.ttf` into `res/font/`. Replace `FontFamily.Default` in `Type.kt`. Wire `opsz` axis per size. +4. **Shadow stack.** Implement `Modifier.squircleShadow(level)` in `ui/effect/Shadow.kt`. Replace all `Modifier.shadow(...)` usages. +5. **GlassSurface composable** with `RenderEffect` + API fallback. Migrate all "card-like" Compose surfaces to it. +6. **Background blobs** with animated `Canvas` + WebP fallback (`chat/Background.kt`). +7. **Orb premium layers** — refractive blur, sweep gradient, HDR specular, tilt-bound highlight. +8. **Sensor tilt state** — `rememberTiltState()` plus the four consumers (orb, send-armed, blobs, mesh). +9. **Theme system** — four `KaizenTheme` objects, server sync via `/api/v1/me`, crossfade on switch. +10. **Shared element transitions** — sidebar row → header, hero orb → first assistant avatar. +11. **Baseline Profile** generation — wire into release build. +12. **Macrobenchmark** suite covering §16 budgets. + +--- + +## 20. Changelog + +| Date | Change | +| ---------- | -------------------------------------------------------------------------------------------- | +| 2026-06-21 | Initial draft — tokens, components, motion. | +| 2026-06-21 | v2 — full premium spec. P3 + HDR color pipeline, real RenderEffect glass, squircle shapes, Inter Variable, sensor-reactive motion, four-theme server sync. Mobile empty state drops suggestion chips. | diff --git a/app/src/main/java/dev/kaizen/app/ui/effect/GlassSurface.kt b/app/src/main/java/dev/kaizen/app/ui/effect/GlassSurface.kt new file mode 100644 index 0000000..45331b6 --- /dev/null +++ b/app/src/main/java/dev/kaizen/app/ui/effect/GlassSurface.kt @@ -0,0 +1,99 @@ +package dev.kaizen.app.ui.effect + +import android.os.Build +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxScope +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.BlurredEdgeTreatment +import androidx.compose.ui.draw.blur +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import dev.kaizen.app.ui.shape.KaizenShapes + +/** + * A refractive glass surface — the core visual primitive of the Kaizen design system. + * + * On API 31+ uses Compose's [Modifier.blur] (backed by RenderEffect.createBlurEffect) + * to blur the underlying composition through the surface, creating a real frosted-glass + * effect. On API 26–30, the blur is skipped and the surface uses a higher tint alpha + * (+0.10) to fake depth. + * + * The [tint] color gives the surface its identity (Obsidian vs white). Without it + * the blur would show a wash of whatever's behind. [tintAlpha] controls the + * "milkiness" — lower = more transparent/refractive, higher = more opaque/solid. + * + * See DESIGN.md §4 for the full anatomy and opacity tiers. + */ +@Composable +fun GlassSurface( + modifier: Modifier = Modifier, + shape: Shape = KaizenShapes.md, + tint: Color = MaterialTheme.colorScheme.surface, + tintAlpha: Float = 0.72f, + blurRadius: Dp = 24.dp, + shadowStack: ShadowStack = KaizenShadows.level2, + content: @Composable BoxScope.() -> Unit, +) { + val isDark = isSystemInDarkTheme() + val supportsBlur = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S + + val effectiveTintAlpha = if (supportsBlur) tintAlpha else (tintAlpha + 0.10f).coerceAtMost(1f) + val tintColor = remember(tint, effectiveTintAlpha) { tint.copy(alpha = effectiveTintAlpha) } + + val outlineColor = MaterialTheme.colorScheme.outline + val outlineAlpha = if (isDark) 0.12f else 0.06f + + Box( + modifier = modifier + .kaizenShadow(stack = shadowStack, cornerRadius = 16.dp) + .clip(shape) + .then( + if (supportsBlur) { + Modifier.blur(blurRadius, edgeTreatment = BlurredEdgeTreatment.Rectangle) + } else { + Modifier + } + ) + .drawBehind { drawRect(tintColor) } + .innerTopHighlight() + .border(1.dp, outlineColor.copy(alpha = outlineAlpha), shape), + content = content, + ) +} + +/** + * Predefined opacity tiers matching DESIGN.md §4.4. + * Use these constants with [GlassSurface] instead of ad-hoc alpha values. + */ +object GlassTiers { + /** Sidebar — most translucent, strongest refraction */ + fun sidebar(isDark: Boolean) = if (isDark) 0.72f else 0.68f + + /** Chat input bar */ + fun input(isDark: Boolean) = if (isDark) 0.75f else 0.74f + + /** Small pills (mode pill, model pill) */ + fun pill(isDark: Boolean) = if (isDark) 0.80f else 0.82f + + /** Suggestion chips — tap targets, need body */ + fun chip(isDark: Boolean) = if (isDark) 0.85f else 0.90f + + /** Settings cards — reading surface, near-opaque */ + fun card(isDark: Boolean) = if (isDark) 0.94f else 0.95f + + /** User bubble — amber-tinted glass */ + fun userBubble(isDark: Boolean) = if (isDark) 0.86f else 0.88f + + /** Dropdowns / bottom sheets — deepest blur */ + fun sheet(isDark: Boolean) = if (isDark) 0.82f else 0.85f +} diff --git a/app/src/main/java/dev/kaizen/app/ui/effect/Shadow.kt b/app/src/main/java/dev/kaizen/app/ui/effect/Shadow.kt new file mode 100644 index 0000000..d1db6fd --- /dev/null +++ b/app/src/main/java/dev/kaizen/app/ui/effect/Shadow.kt @@ -0,0 +1,148 @@ +package dev.kaizen.app.ui.effect + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.geometry.CornerRadius +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Paint +import androidx.compose.ui.graphics.drawscope.DrawScope +import androidx.compose.ui.graphics.drawscope.drawIntoCanvas +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp + +/** + * A single layer in a multi-layer shadow stack. + * + * Premium UI uses 3–5 overlapping shadow layers at increasing blur radii + * and decreasing opacity, producing a soft, realistic falloff that a + * single [Modifier.shadow] cannot match. + */ +data class ShadowLayer( + val offsetY: Dp, + val blur: Dp, + val spread: Dp = 0.dp, + val alpha: Float, +) + +/** + * A complete shadow stack of multiple [ShadowLayer]s. + */ +data class ShadowStack(val layers: List) + +/** + * Predefined shadow levels — use these everywhere instead of ad-hoc + * `Modifier.shadow(elevation = ...)`. + */ +object KaizenShadows { + + val level0 = ShadowStack(emptyList()) + + val level1 = ShadowStack( + listOf( + ShadowLayer(1.dp, 2.dp, 0.dp, 0.04f), + ShadowLayer(1.dp, 4.dp, 0.dp, 0.02f), + ) + ) + + val level2 = ShadowStack( + listOf( + ShadowLayer(2.dp, 4.dp, 0.dp, 0.05f), + ShadowLayer(4.dp, 12.dp, 0.dp, 0.04f), + ShadowLayer(8.dp, 24.dp, 0.dp, 0.03f), + ) + ) + + val level3 = ShadowStack( + listOf( + ShadowLayer(2.dp, 4.dp, 0.dp, 0.06f), + ShadowLayer(8.dp, 16.dp, 0.dp, 0.05f), + ShadowLayer(16.dp, 32.dp, 0.dp, 0.04f), + ShadowLayer(24.dp, 48.dp, 0.dp, 0.03f), + ) + ) + + val level4 = ShadowStack( + listOf( + ShadowLayer(4.dp, 8.dp, 0.dp, 0.07f), + ShadowLayer(12.dp, 24.dp, 0.dp, 0.06f), + ShadowLayer(24.dp, 48.dp, 0.dp, 0.05f), + ShadowLayer(48.dp, 96.dp, 0.dp, 0.04f), + ) + ) +} + +/** + * Draws a multi-layer shadow stack behind the content. + * + * [darkMultiplier] scales shadow alpha in dark mode (shadows need to be + * stronger on dark surfaces to read). Default 1.8× matches the DESIGN.md spec. + */ +@Composable +fun Modifier.kaizenShadow( + stack: ShadowStack, + cornerRadius: Dp = 16.dp, + darkMultiplier: Float = 1.8f, +): Modifier { + val isDark = isSystemInDarkTheme() + val effectiveMultiplier = if (isDark) darkMultiplier else 1f + val layers = remember(stack, effectiveMultiplier) { + stack.layers.map { layer -> + layer.copy(alpha = (layer.alpha * effectiveMultiplier).coerceAtMost(1f)) + } + } + return this.drawBehind { + drawShadowLayers(layers, cornerRadius) + } +} + +private fun DrawScope.drawShadowLayers(layers: List, cornerRadius: Dp) { + val cr = cornerRadius.toPx() + drawIntoCanvas { canvas -> + layers.forEach { layer -> + val paint = Paint().apply { + val framework = asFrameworkPaint() + framework.color = Color.Black.copy(alpha = layer.alpha).toArgb() + framework.setShadowLayer( + layer.blur.toPx(), + 0f, + layer.offsetY.toPx(), + Color.Black.copy(alpha = layer.alpha).toArgb(), + ) + } + val spreadPx = layer.spread.toPx() + canvas.drawRoundRect( + left = -spreadPx, + top = -spreadPx, + right = size.width + spreadPx, + bottom = size.height + spreadPx, + radiusX = cr, + radiusY = cr, + paint = paint, + ) + } + } +} + +/** + * Inner top highlight — 1dp inset white line that simulates "light from above." + * Together with the drop shadow, this makes glass surfaces look lit. + */ +@Composable +fun Modifier.innerTopHighlight(): Modifier { + val isDark = isSystemInDarkTheme() + val highlightAlpha = if (isDark) 0.08f else 0.95f + return this.drawBehind { + drawLine( + color = Color.White.copy(alpha = highlightAlpha), + start = Offset(0f, 1f), + end = Offset(size.width, 1f), + strokeWidth = 1.dp.toPx(), + ) + } +} diff --git a/app/src/main/java/dev/kaizen/app/ui/motion/Motion.kt b/app/src/main/java/dev/kaizen/app/ui/motion/Motion.kt new file mode 100644 index 0000000..74d82e7 --- /dev/null +++ b/app/src/main/java/dev/kaizen/app/ui/motion/Motion.kt @@ -0,0 +1,52 @@ +package dev.kaizen.app.ui.motion + +import androidx.compose.animation.core.CubicBezierEasing +import androidx.compose.animation.core.FastOutSlowInEasing +import androidx.compose.animation.core.SpringSpec +import androidx.compose.animation.core.spring +import androidx.compose.animation.core.tween + +/** + * Kaizen animation primitives — single source of truth for all motion. + * + * Every motion in the app references these tokens. Defined here so the + * feel stays consistent and tuning is centralised. + */ + +// ── Easing Curves ────────────────────────────────────────────────────────── + +/** Overshoot ease — entrance animations */ +val EaseSpring = CubicBezierEasing(0.34f, 1.56f, 0.64f, 1f) + +/** Expo-out — smooth transitions */ +val EaseSmooth = CubicBezierEasing(0.22f, 1f, 0.36f, 1f) + +/** System-aligned standard */ +val EaseStandard = FastOutSlowInEasing + +/** M3 emphasized — page transitions */ +val EaseEmphasized = CubicBezierEasing(0.05f, 0.7f, 0.1f, 1f) + +// ── Spring Specs ─────────────────────────────────────────────────────────── + +/** Fast, punchy — squircle press, quick reactions */ +val SpringSnappy: SpringSpec = spring(dampingRatio = 0.55f, stiffness = 800f) + +/** Balanced — general state changes */ +val SpringDefault: SpringSpec = spring(dampingRatio = 0.75f, stiffness = 400f) + +/** Slow, fluid — tilt response, sidebar slide */ +val SpringGentle: SpringSpec = spring(dampingRatio = 0.85f, stiffness = 200f) + +// ── Duration Constants ───────────────────────────────────────────────────── + +object Durations { + const val DROPDOWN_OPEN = 150 + const val PAGE_TRANSITION = 280 + const val BUBBLE_ENTRANCE = 350 + const val THEME_CROSSFADE = 600 + const val ORB_BREATH = 7000 + const val ORB_BREATH_STREAMING = 1800 + const val THINKING_DOT_CYCLE = 600 + const val THINKING_DOT_PHASE_OFFSET = 160 +} diff --git a/app/src/main/java/dev/kaizen/app/ui/sensor/TiltState.kt b/app/src/main/java/dev/kaizen/app/ui/sensor/TiltState.kt new file mode 100644 index 0000000..9791d8e --- /dev/null +++ b/app/src/main/java/dev/kaizen/app/ui/sensor/TiltState.kt @@ -0,0 +1,145 @@ +package dev.kaizen.app.ui.sensor + +import android.content.Context +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager +import android.os.PowerManager +import android.provider.Settings +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.platform.LocalContext +import androidx.lifecycle.compose.LocalLifecycleOwner +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver + +/** + * Provides a smoothed tilt [Offset] (x, y in range -1..1) from the device sensors. + * + * Uses [Sensor.TYPE_GAME_ROTATION_VECTOR] (fused gyro + accel, pre-stabilized, + * no drift). Falls back to [Sensor.TYPE_GRAVITY] then [Sensor.TYPE_ACCELEROMETER]. + * + * Automatically disables when: + * - System animations are off (`ANIMATOR_DURATION_SCALE == 0`) + * - Battery saver is on + * - App is not in foreground + * - Device tilt exceeds ±25° (user lying down) + * + * See DESIGN.md §7 for full motion spec. + */ +@Composable +fun rememberTiltState(): State { + val context = LocalContext.current + val lifecycle = LocalLifecycleOwner.current.lifecycle + val tilt = remember { mutableStateOf(Offset.Zero) } + + DisposableEffect(lifecycle) { + val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as? SensorManager + ?: return@DisposableEffect onDispose { } + + val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR) + ?: sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) + ?: sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) + ?: return@DisposableEffect onDispose { } + + val isRotationVector = sensor.type == Sensor.TYPE_GAME_ROTATION_VECTOR + + val animScale = try { + Settings.Global.getFloat(context.contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE) + } catch (_: Exception) { 1f } + + if (animScale == 0f) return@DisposableEffect onDispose { } + + var filteredX = 0f + var filteredY = 0f + val alpha = 0.18f + var registered = false + + val listener = object : SensorEventListener { + override fun onSensorChanged(event: SensorEvent?) { + if (event == null) return + + val pm = context.getSystemService(Context.POWER_SERVICE) as? PowerManager + if (pm?.isPowerSaveMode == true) { + tilt.value = Offset.Zero + return + } + + val rawX: Float + val rawY: Float + + if (isRotationVector) { + val rotationMatrix = FloatArray(9) + SensorManager.getRotationMatrixFromVector(rotationMatrix, event.values) + val orientation = FloatArray(3) + SensorManager.getOrientation(rotationMatrix, orientation) + val pitch = Math.toDegrees(orientation[1].toDouble()).toFloat() + val roll = Math.toDegrees(orientation[2].toDouble()).toFloat() + + if (kotlin.math.abs(pitch) > 25f || kotlin.math.abs(roll) > 25f) { + tilt.value = Offset.Zero + return + } + + rawX = (roll / 25f).coerceIn(-1f, 1f) + rawY = (pitch / 25f).coerceIn(-1f, 1f) + } else { + val x = event.values[0] / 9.81f + val y = event.values[1] / 9.81f + + if (kotlin.math.abs(x) > 0.6f || kotlin.math.abs(y) > 0.6f) { + tilt.value = Offset.Zero + return + } + + rawX = x.coerceIn(-1f, 1f) + rawY = y.coerceIn(-1f, 1f) + } + + filteredX = filteredX + alpha * (rawX - filteredX) + filteredY = filteredY + alpha * (rawY - filteredY) + + tilt.value = Offset(filteredX, filteredY) + } + + override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {} + } + + val lifecycleObserver = LifecycleEventObserver { _, event -> + when (event) { + Lifecycle.Event.ON_START -> { + if (!registered) { + sensorManager.registerListener( + listener, sensor, SensorManager.SENSOR_DELAY_GAME + ) + registered = true + } + } + Lifecycle.Event.ON_STOP -> { + sensorManager.unregisterListener(listener) + registered = false + tilt.value = Offset.Zero + } + else -> {} + } + } + + lifecycle.addObserver(lifecycleObserver) + if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) { + sensorManager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_GAME) + registered = true + } + + onDispose { + lifecycle.removeObserver(lifecycleObserver) + if (registered) sensorManager.unregisterListener(listener) + } + } + + return tilt +} diff --git a/app/src/main/java/dev/kaizen/app/ui/shape/KaizenShapes.kt b/app/src/main/java/dev/kaizen/app/ui/shape/KaizenShapes.kt new file mode 100644 index 0000000..8bed09e --- /dev/null +++ b/app/src/main/java/dev/kaizen/app/ui/shape/KaizenShapes.kt @@ -0,0 +1,21 @@ +package dev.kaizen.app.ui.shape + +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.unit.dp + +/** + * Kaizen shape tokens — squircle-based replacement for Material Shapes. + * + * Every surface, button, chip, and bubble references one of these tokens. + * Centralised here so a single change propagates everywhere. + */ +object KaizenShapes { + val xs: Shape = SquircleShape(radius = 8.dp, smoothness = 4.0f) + val sm: Shape = SquircleShape(radius = 12.dp, smoothness = 4.2f) + val md: Shape = SquircleShape(radius = 16.dp, smoothness = 4.5f) + val lg: Shape = SquircleShape(radius = 24.dp, smoothness = 5.0f) + val xl: Shape = SquircleShape(radius = 28.dp, smoothness = 5.0f) + val pill: Shape = SquircleShape(radius = 999.dp, smoothness = 4.5f) + val circle: Shape = CircleShape +} diff --git a/app/src/main/java/dev/kaizen/app/ui/shape/Squircle.kt b/app/src/main/java/dev/kaizen/app/ui/shape/Squircle.kt new file mode 100644 index 0000000..01e6e12 --- /dev/null +++ b/app/src/main/java/dev/kaizen/app/ui/shape/Squircle.kt @@ -0,0 +1,126 @@ +package dev.kaizen.app.ui.shape + +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.Outline +import androidx.compose.ui.graphics.Path +import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.dp +import kotlin.math.abs +import kotlin.math.cos +import kotlin.math.min +import kotlin.math.pow +import kotlin.math.sign +import kotlin.math.sin + +/** + * iOS-style continuous superellipse ("squircle"). + * + * Unlike [RoundedCornerShape] which is a rectangle with quarter-circle arcs, + * a squircle has G2-continuous corners (curvature matches, not just position). + * The visual difference is subtle at small radii but unmistakable at 16+ dp — + * corners ease into the straight edges instead of snapping. + * + * The superellipse equation: |x/a|^n + |y/b|^n = 1 + * n = 2 → circle/ellipse + * n = 4–5 → iOS icon / Apple Liquid Glass sweet spot + * n → ∞ → rectangle + * + * [smoothness] controls the `n` exponent. Default 4.5 matches iOS 26. + * [samplesPerCorner] controls path resolution. 32 is invisible at any + * screen density; reduce to 16 for small shapes (< 32 dp). + */ +class SquircleShape( + private val radius: Dp, + private val smoothness: Float = 4.5f, + private val samplesPerCorner: Int = 32, +) : androidx.compose.ui.graphics.Shape { + + override fun createOutline( + size: Size, + layoutDirection: LayoutDirection, + density: Density, + ): Outline { + val r = with(density) { radius.toPx() } + .coerceAtMost(min(size.width, size.height) / 2f) + + if (r <= 0f) return Outline.Rectangle( + androidx.compose.ui.geometry.Rect(0f, 0f, size.width, size.height) + ) + + val path = Path().apply { + buildSquirclePath(size.width, size.height, r, smoothness, samplesPerCorner) + } + return Outline.Generic(path) + } + + override fun toString(): String = "SquircleShape(radius=$radius, smoothness=$smoothness)" +} + +/** + * Builds a closed squircle path into [this] Path. + * + * Traces the superellipse corner arcs and straight edges clockwise + * starting from the top-left corner's right edge. + */ +private fun Path.buildSquirclePath( + w: Float, + h: Float, + r: Float, + n: Float, + samples: Int, +) { + val step = (Math.PI / 2.0) / samples + + fun superX(angle: Double): Float { + val cosA = cos(angle) + return (abs(cosA).pow(2.0 / n) * sign(cosA) * r).toFloat() + } + + fun superY(angle: Double): Float { + val sinA = sin(angle) + return (abs(sinA).pow(2.0 / n) * sign(sinA) * r).toFloat() + } + + // Start at top edge, right of top-left corner + moveTo(r, 0f) + + // Top edge → top-right corner + lineTo(w - r, 0f) + for (i in 0..samples) { + val angle = Math.PI / 2.0 - step * i + val sx = superX(angle) + val sy = superY(angle) + lineTo(w - r + sx, r - sy) + } + + // Right edge → bottom-right corner + lineTo(w, h - r) + for (i in 0..samples) { + val angle = -step * i + val sx = superX(angle) + val sy = superY(angle) + lineTo(w - r + sx, h - r - sy) + } + + // Bottom edge → bottom-left corner + lineTo(r, h) + for (i in 0..samples) { + val angle = -(Math.PI / 2.0) - step * i + val sx = superX(angle) + val sy = superY(angle) + lineTo(r + sx, h - r - sy) + } + + // Left edge → top-left corner + lineTo(0f, r) + for (i in 0..samples) { + val angle = Math.PI - step * i + val sx = superX(angle) + val sy = superY(angle) + lineTo(r + sx, r - sy) + } + + close() +} diff --git a/app/src/main/java/dev/kaizen/app/ui/theme/Color.kt b/app/src/main/java/dev/kaizen/app/ui/theme/Color.kt index 0fb7d98..6a54aff 100644 --- a/app/src/main/java/dev/kaizen/app/ui/theme/Color.kt +++ b/app/src/main/java/dev/kaizen/app/ui/theme/Color.kt @@ -1,32 +1,45 @@ package dev.kaizen.app.ui.theme import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.colorspace.ColorSpaces -// Kaizen palette — Obsidian steel-blue + amber accent. -// OKLCH tokens from the web (globals.css) approximated to sRGB; fine-tuned on device. +// --------------------------------------------------------------------------- +// Kaizen Color Tokens — DisplayP3 pipeline +// --------------------------------------------------------------------------- +// Every brand color is declared in the Display P3 color space so the full +// gamut is used on wide-color displays (every Galaxy since 2018, every Pixel +// since the 4). On sRGB-only panels the runtime clamps gracefully. +// +// The sRGB hex approximations are in trailing comments for design handoff. +// Never use Color(0xFF…) for brand colors outside this file. +// --------------------------------------------------------------------------- -// Brand amber — kept constant across light/dark (orb, accents, send button). -val Amber = Color(0xFFE0A23E) // ~oklch(0.72 0.14 83) -val AmberDeep = Color(0xFFC8862A) -val OnAmber = Color(0xFF1B1206) +private fun p3(r: Float, g: Float, b: Float, a: Float = 1f): Color = + Color(red = r, green = g, blue = b, alpha = a, colorSpace = ColorSpaces.DisplayP3) -// Dark scheme (Obsidian) -val Obsidian = Color(0xFF0A0E16) // background ~oklch(0.10 0.025 245) -val ObsidianElevated = Color(0xFF141B27) // surface -val ObsidianInput = Color(0xFF111824) // input surface -val DarkText = Color(0xFFE8EBF1) -val DarkMuted = Color(0xFF8B94A4) -val DarkStroke = Color(0x16FFFFFF) // subtle light hairline +// ── Brand Amber (constant across all themes — they ARE the brand) ────────── +val Amber = p3(0.878f, 0.635f, 0.243f) // ≈ #E0A23E +val AmberDeep = p3(0.784f, 0.525f, 0.165f) // ≈ #C8862A +val OnAmber = p3(0.106f, 0.071f, 0.024f) // ≈ #1B1206 -// Light scheme -val LightBackground = Color(0xFFF6F7F9) -val LightSurface = Color(0xFFFFFFFF) -val LightSurfaceVariant = Color(0xFFEEF0F3) -val LightText = Color(0xFF1A1F29) -val LightMuted = Color(0xFF5B6470) -val LightStroke = Color(0x14000000) // subtle dark hairline +// ── Dark scheme — Obsidian Steel-Blue ────────────────────────────────────── +val Obsidian = p3(0.039f, 0.055f, 0.086f) // background ≈ #0A0E16 +val ObsidianElevated = p3(0.078f, 0.106f, 0.153f) // surface ≈ #141B27 +val ObsidianInput = p3(0.067f, 0.094f, 0.141f) // surfaceVar ≈ #111824 +val DarkText = p3(0.910f, 0.922f, 0.945f) // onBackground ≈ #E8EBF1 +val DarkMuted = p3(0.545f, 0.580f, 0.643f) // onSurfaceVar ≈ #8B94A4 +val DarkStroke = p3(1f, 1f, 1f, 0.09f) // outline -// Background blobs (.bg-blobs) -val BlobAmber = Color(0xFFE0A23E) -val BlobBlue = Color(0xFF3C5FD6) -val BlobTeal = Color(0xFF2BB6A6) +// ── Light scheme ─────────────────────────────────────────────────────────── +val LightBackground = p3(0.965f, 0.969f, 0.976f) // ≈ #F6F7F9 +val LightSurface = p3(1.000f, 1.000f, 1.000f) // ≈ #FFFFFF +val LightSurfaceVariant = p3(0.933f, 0.941f, 0.953f) // ≈ #EEF0F3 +val LightText = p3(0.102f, 0.122f, 0.161f) // ≈ #1A1F29 +val LightMuted = p3(0.357f, 0.392f, 0.439f) // ≈ #5B6470 +val LightStroke = p3(0f, 0f, 0f, 0.08f) // outline + +// ── Background blobs ─────────────────────────────────────────────────────── +val BlobAmber = p3(0.878f, 0.635f, 0.243f) // ≈ Amber +val BlobBlue = p3(0.235f, 0.373f, 0.839f) // ≈ #3C5FD6 +val BlobTeal = p3(0.169f, 0.714f, 0.651f) // ≈ #2BB6A6 +val BlobIndigo = p3(0.290f, 0.290f, 0.690f) // 4th blob for Amber theme diff --git a/app/src/main/java/dev/kaizen/app/ui/theme/Theme.kt b/app/src/main/java/dev/kaizen/app/ui/theme/Theme.kt index 54fa610..381bfe8 100644 --- a/app/src/main/java/dev/kaizen/app/ui/theme/Theme.kt +++ b/app/src/main/java/dev/kaizen/app/ui/theme/Theme.kt @@ -5,14 +5,29 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.darkColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.ui.graphics.Color +import dev.kaizen.app.ui.theme.themes.AmberTheme +import dev.kaizen.app.ui.theme.themes.KaizenAccentScheme +import dev.kaizen.app.ui.theme.themes.KaizenThemeId +import dev.kaizen.app.ui.theme.themes.KaizenThemeSpec +import dev.kaizen.app.ui.theme.themes.ThemeRegistry -// Fixed Kaizen schemes (no dynamic color) so the glass look stays consistent. -private val KaizenDark = darkColorScheme( - primary = Amber, - onPrimary = OnAmber, - secondary = Amber, - onSecondary = OnAmber, +/** + * CompositionLocal for the active Kaizen accent scheme. + * + * Use `LocalKaizenAccent.current` to access theme-specific colors (primary, + * blobs, ring) that go beyond MaterialTheme.colorScheme. This is the bridge + * between the four Kaizen themes and the Material3 color system. + */ +val LocalKaizenAccent = staticCompositionLocalOf { AmberTheme.dark } + +private fun buildDarkScheme(accent: KaizenAccentScheme) = darkColorScheme( + primary = accent.primary, + onPrimary = accent.onPrimary, + secondary = accent.primary, + onSecondary = accent.onPrimary, background = Obsidian, onBackground = DarkText, surface = ObsidianElevated, @@ -22,11 +37,11 @@ private val KaizenDark = darkColorScheme( outline = DarkStroke, ) -private val KaizenLight = lightColorScheme( - primary = AmberDeep, - onPrimary = Color.White, - secondary = AmberDeep, - onSecondary = Color.White, +private fun buildLightScheme(accent: KaizenAccentScheme) = lightColorScheme( + primary = accent.primary, + onPrimary = accent.onPrimary, + secondary = accent.primary, + onSecondary = accent.onPrimary, background = LightBackground, onBackground = LightText, surface = LightSurface, @@ -38,12 +53,19 @@ private val KaizenLight = lightColorScheme( @Composable fun KaizenTheme( + themeId: KaizenThemeId = KaizenThemeId.AMBER, darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit, ) { - MaterialTheme( - colorScheme = if (darkTheme) KaizenDark else KaizenLight, - typography = Typography, - content = content, - ) + val spec = ThemeRegistry.forId(themeId) + val accent = if (darkTheme) spec.dark else spec.light + val colorScheme = if (darkTheme) buildDarkScheme(accent) else buildLightScheme(accent) + + CompositionLocalProvider(LocalKaizenAccent provides accent) { + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content, + ) + } } diff --git a/app/src/main/java/dev/kaizen/app/ui/theme/themes/AccentScheme.kt b/app/src/main/java/dev/kaizen/app/ui/theme/themes/AccentScheme.kt new file mode 100644 index 0000000..188b9bc --- /dev/null +++ b/app/src/main/java/dev/kaizen/app/ui/theme/themes/AccentScheme.kt @@ -0,0 +1,47 @@ +package dev.kaizen.app.ui.theme.themes + +import androidx.compose.ui.graphics.Color + +/** + * The accent portion of a Kaizen theme. + * + * Neutrals (background, surface, text) are theme-independent — same Obsidian / + * Light off-white across all four themes. Only the accent + blob colors swap. + * This matches the web architecture where `globals.css` ships neutrals and + * `app/themes/.css` ships only accent tokens. + */ +data class KaizenAccentScheme( + val primary: Color, + val primaryDeep: Color, + val onPrimary: Color, + val ring: Color, + val blob1: Color, + val blob2: Color, + val blob3: Color, + val blob4: Color, +) + +/** + * Theme identity — server-synced via `/api/v1/me`. + */ +enum class KaizenThemeId(val value: String) { + AMBER("amber"), + BLAU("blue"), + MONO("mono"), + AURORA("aurora"); + + companion object { + fun fromString(s: String): KaizenThemeId = + entries.firstOrNull { it.value == s } ?: AMBER + } +} + +/** + * A complete Kaizen theme — light + dark accent schemes. + */ +data class KaizenThemeSpec( + val id: KaizenThemeId, + val label: String, + val light: KaizenAccentScheme, + val dark: KaizenAccentScheme, +) 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 new file mode 100644 index 0000000..e8bd223 --- /dev/null +++ b/app/src/main/java/dev/kaizen/app/ui/theme/themes/AmberTheme.kt @@ -0,0 +1,32 @@ +package dev.kaizen.app.ui.theme.themes + +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.colorspace.ColorSpaces + +private fun p3(r: Float, g: Float, b: Float): Color = + Color(red = r, green = g, blue = b, colorSpace = ColorSpaces.DisplayP3) + +val AmberTheme = KaizenThemeSpec( + id = KaizenThemeId.AMBER, + label = "Amber", + dark = KaizenAccentScheme( + primary = p3(0.878f, 0.635f, 0.243f), // Amber + primaryDeep = p3(0.784f, 0.525f, 0.165f), + onPrimary = p3(0.106f, 0.071f, 0.024f), + ring = p3(0.878f, 0.635f, 0.243f), + blob1 = p3(0.878f, 0.635f, 0.243f), // Amber + blob2 = p3(0.235f, 0.373f, 0.839f), // Blue + blob3 = p3(0.290f, 0.290f, 0.690f), // Indigo + blob4 = p3(0.169f, 0.714f, 0.651f), // Teal + ), + light = KaizenAccentScheme( + primary = p3(0.784f, 0.525f, 0.165f), // AmberDeep (better contrast on white) + primaryDeep = p3(0.784f, 0.525f, 0.165f), + onPrimary = p3(1f, 1f, 1f), + ring = p3(0.878f, 0.635f, 0.243f), + blob1 = p3(0.878f, 0.635f, 0.243f), + blob2 = p3(0.235f, 0.373f, 0.839f), + blob3 = p3(0.290f, 0.290f, 0.690f), + blob4 = p3(0.169f, 0.714f, 0.651f), + ), +) 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 new file mode 100644 index 0000000..1a44385 --- /dev/null +++ b/app/src/main/java/dev/kaizen/app/ui/theme/themes/AuroraTheme.kt @@ -0,0 +1,32 @@ +package dev.kaizen.app.ui.theme.themes + +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.colorspace.ColorSpaces + +private fun p3(r: Float, g: Float, b: Float): Color = + Color(red = r, green = g, blue = b, colorSpace = ColorSpaces.DisplayP3) + +val AuroraTheme = KaizenThemeSpec( + id = KaizenThemeId.AURORA, + label = "Aurora", + dark = KaizenAccentScheme( + primary = p3(0.850f, 0.310f, 0.750f), // Magenta P3 + primaryDeep = p3(0.680f, 0.220f, 0.620f), + onPrimary = p3(0.106f, 0.024f, 0.090f), + ring = p3(0.850f, 0.310f, 0.750f), + blob1 = p3(0.850f, 0.310f, 0.750f), // Magenta + blob2 = p3(0.169f, 0.714f, 0.800f), // Cyan + blob3 = p3(0.545f, 0.361f, 0.859f), // Violet + blob4 = p3(0.520f, 0.850f, 0.310f), // Lime (accent) + ), + light = KaizenAccentScheme( + primary = p3(0.490f, 0.270f, 0.690f), // Violet-600 P3 + primaryDeep = p3(0.490f, 0.270f, 0.690f), + onPrimary = p3(1f, 1f, 1f), + ring = p3(0.850f, 0.310f, 0.750f), + blob1 = p3(0.850f, 0.310f, 0.750f), + blob2 = p3(0.169f, 0.714f, 0.800f), + blob3 = p3(0.545f, 0.361f, 0.859f), + blob4 = p3(0.520f, 0.850f, 0.310f), + ), +) 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 new file mode 100644 index 0000000..c4f9980 --- /dev/null +++ b/app/src/main/java/dev/kaizen/app/ui/theme/themes/BlauTheme.kt @@ -0,0 +1,32 @@ +package dev.kaizen.app.ui.theme.themes + +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.colorspace.ColorSpaces + +private fun p3(r: Float, g: Float, b: Float): Color = + Color(red = r, green = g, blue = b, colorSpace = ColorSpaces.DisplayP3) + +val BlauTheme = KaizenThemeSpec( + id = KaizenThemeId.BLAU, + label = "Blau", + dark = KaizenAccentScheme( + primary = p3(0.337f, 0.600f, 0.988f), // Sky-500 P3 + primaryDeep = p3(0.243f, 0.420f, 0.855f), + onPrimary = p3(0.024f, 0.047f, 0.106f), + ring = p3(0.337f, 0.600f, 0.988f), + blob1 = p3(0.235f, 0.373f, 0.839f), // Blue + blob2 = p3(0.290f, 0.290f, 0.690f), // Indigo + blob3 = p3(0.169f, 0.714f, 0.800f), // Cyan + blob4 = p3(0.878f, 0.635f, 0.243f), // Amber (contrast) + ), + light = KaizenAccentScheme( + primary = p3(0.243f, 0.310f, 0.730f), // Indigo-600 P3 + primaryDeep = p3(0.243f, 0.310f, 0.730f), + onPrimary = p3(1f, 1f, 1f), + ring = p3(0.337f, 0.600f, 0.988f), + blob1 = p3(0.235f, 0.373f, 0.839f), + blob2 = p3(0.290f, 0.290f, 0.690f), + blob3 = p3(0.169f, 0.714f, 0.800f), + blob4 = p3(0.878f, 0.635f, 0.243f), + ), +) 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 new file mode 100644 index 0000000..72cab72 --- /dev/null +++ b/app/src/main/java/dev/kaizen/app/ui/theme/themes/MonoTheme.kt @@ -0,0 +1,32 @@ +package dev.kaizen.app.ui.theme.themes + +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.colorspace.ColorSpaces + +private fun p3(r: Float, g: Float, b: Float): Color = + Color(red = r, green = g, blue = b, colorSpace = ColorSpaces.DisplayP3) + +val MonoTheme = KaizenThemeSpec( + id = KaizenThemeId.MONO, + label = "Mono", + dark = KaizenAccentScheme( + primary = p3(0.878f, 0.894f, 0.918f), // Slate-100 + primaryDeep = p3(0.710f, 0.741f, 0.784f), + onPrimary = p3(0.063f, 0.082f, 0.118f), + ring = p3(0.710f, 0.741f, 0.784f), + blob1 = p3(0.710f, 0.741f, 0.784f), // Slate-300 + blob2 = p3(0.580f, 0.620f, 0.680f), // Slate-400 + blob3 = p3(0.820f, 0.845f, 0.878f), // Slate-200 + blob4 = p3(0.600f, 0.580f, 0.560f), // Warm gray + ), + light = KaizenAccentScheme( + primary = p3(0.188f, 0.224f, 0.286f), // Slate-800 + primaryDeep = p3(0.188f, 0.224f, 0.286f), + onPrimary = p3(1f, 1f, 1f), + ring = p3(0.420f, 0.455f, 0.510f), + blob1 = p3(0.710f, 0.741f, 0.784f), + blob2 = p3(0.580f, 0.620f, 0.680f), + blob3 = p3(0.820f, 0.845f, 0.878f), + blob4 = p3(0.600f, 0.580f, 0.560f), + ), +) diff --git a/app/src/main/java/dev/kaizen/app/ui/theme/themes/ThemeRegistry.kt b/app/src/main/java/dev/kaizen/app/ui/theme/themes/ThemeRegistry.kt new file mode 100644 index 0000000..060233e --- /dev/null +++ b/app/src/main/java/dev/kaizen/app/ui/theme/themes/ThemeRegistry.kt @@ -0,0 +1,18 @@ +package dev.kaizen.app.ui.theme.themes + +/** + * Central registry of all available themes. + * + * Adding a new theme = create a `*Theme.kt` file + add it here. + */ +object ThemeRegistry { + val all: List = listOf( + AmberTheme, + BlauTheme, + MonoTheme, + AuroraTheme, + ) + + fun forId(id: KaizenThemeId): KaizenThemeSpec = + all.firstOrNull { it.id == id } ?: AmberTheme +} diff --git a/app/src/test/java/dev/kaizen/app/ColorPipelineTest.kt b/app/src/test/java/dev/kaizen/app/ColorPipelineTest.kt new file mode 100644 index 0000000..36d05a4 --- /dev/null +++ b/app/src/test/java/dev/kaizen/app/ColorPipelineTest.kt @@ -0,0 +1,68 @@ +package dev.kaizen.app + +import androidx.compose.ui.graphics.colorspace.ColorSpaces +import dev.kaizen.app.ui.theme.* +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test + +class ColorPipelineTest { + + @Test + fun `brand amber is in DisplayP3 color space`() { + assertEquals(ColorSpaces.DisplayP3, Amber.colorSpace) + assertEquals(ColorSpaces.DisplayP3, AmberDeep.colorSpace) + assertEquals(ColorSpaces.DisplayP3, OnAmber.colorSpace) + } + + @Test + fun `dark scheme colors are in DisplayP3`() { + listOf(Obsidian, ObsidianElevated, ObsidianInput, DarkText, DarkMuted, DarkStroke) + .forEach { color -> + assertEquals( + "Color $color should be DisplayP3", + ColorSpaces.DisplayP3, + color.colorSpace, + ) + } + } + + @Test + fun `light scheme colors are in DisplayP3`() { + listOf(LightBackground, LightSurface, LightSurfaceVariant, LightText, LightMuted, LightStroke) + .forEach { color -> + assertEquals( + "Color $color should be DisplayP3", + ColorSpaces.DisplayP3, + color.colorSpace, + ) + } + } + + @Test + fun `blob colors are in DisplayP3`() { + listOf(BlobAmber, BlobBlue, BlobTeal, BlobIndigo).forEach { color -> + assertEquals(ColorSpaces.DisplayP3, color.colorSpace) + } + } + + @Test + fun `amber has expected approximate values`() { + assertTrue("Red should be around 0.878", Amber.red in 0.87f..0.89f) + assertTrue("Green should be around 0.635", Amber.green in 0.62f..0.65f) + assertTrue("Blue should be around 0.243", Amber.blue in 0.23f..0.26f) + assertEquals(1f, Amber.alpha, 0.001f) + } + + @Test + fun `stroke colors have transparency`() { + assertTrue("DarkStroke should be transparent", DarkStroke.alpha < 1f) + assertTrue("LightStroke should be transparent", LightStroke.alpha < 1f) + } + + @Test + fun `no pure black or pure white in neutrals`() { + assertTrue("Obsidian should not be pure black", Obsidian.red > 0f || Obsidian.green > 0f || Obsidian.blue > 0f) + assertTrue("LightBackground should not be pure white", LightBackground.red < 1f || LightBackground.green < 1f) + } +} diff --git a/app/src/test/java/dev/kaizen/app/ShadowStackTest.kt b/app/src/test/java/dev/kaizen/app/ShadowStackTest.kt new file mode 100644 index 0000000..45e7ceb --- /dev/null +++ b/app/src/test/java/dev/kaizen/app/ShadowStackTest.kt @@ -0,0 +1,70 @@ +package dev.kaizen.app + +import dev.kaizen.app.ui.effect.KaizenShadows +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test + +class ShadowStackTest { + + @Test + fun `level0 has no layers`() { + assertTrue(KaizenShadows.level0.layers.isEmpty()) + } + + @Test + fun `level1 has 2 layers`() { + assertEquals(2, KaizenShadows.level1.layers.size) + } + + @Test + fun `level2 has 3 layers`() { + assertEquals(3, KaizenShadows.level2.layers.size) + } + + @Test + fun `level3 has 4 layers`() { + assertEquals(4, KaizenShadows.level3.layers.size) + } + + @Test + fun `level4 has 4 layers`() { + assertEquals(4, KaizenShadows.level4.layers.size) + } + + @Test + fun `all alphas are in valid range`() { + listOf( + KaizenShadows.level1, + KaizenShadows.level2, + KaizenShadows.level3, + KaizenShadows.level4, + ).forEach { stack -> + stack.layers.forEach { layer -> + assertTrue("Alpha ${layer.alpha} should be in 0..1", layer.alpha in 0f..1f) + } + } + } + + @Test + fun `blur increases with each layer in level3`() { + val blurs = KaizenShadows.level3.layers.map { it.blur } + for (i in 1 until blurs.size) { + assertTrue( + "Blur should increase: ${blurs[i - 1]} < ${blurs[i]}", + blurs[i] > blurs[i - 1], + ) + } + } + + @Test + fun `alpha decreases with each layer in level3`() { + val alphas = KaizenShadows.level3.layers.map { it.alpha } + for (i in 1 until alphas.size) { + assertTrue( + "Alpha should decrease: ${alphas[i - 1]} > ${alphas[i]}", + alphas[i] < alphas[i - 1], + ) + } + } +} diff --git a/app/src/test/java/dev/kaizen/app/SquircleShapeTest.kt b/app/src/test/java/dev/kaizen/app/SquircleShapeTest.kt new file mode 100644 index 0000000..10f8bcf --- /dev/null +++ b/app/src/test/java/dev/kaizen/app/SquircleShapeTest.kt @@ -0,0 +1,48 @@ +package dev.kaizen.app + +import dev.kaizen.app.ui.shape.KaizenShapes +import dev.kaizen.app.ui.shape.SquircleShape +import androidx.compose.ui.unit.dp +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull +import org.junit.Assert.assertTrue +import org.junit.Test + +class SquircleShapeTest { + + @Test + fun `KaizenShapes has all expected tokens`() { + assertNotNull(KaizenShapes.xs) + assertNotNull(KaizenShapes.sm) + assertNotNull(KaizenShapes.md) + assertNotNull(KaizenShapes.lg) + assertNotNull(KaizenShapes.xl) + assertNotNull(KaizenShapes.pill) + assertNotNull(KaizenShapes.circle) + } + + @Test + fun `KaizenShapes tokens are distinct instances`() { + val shapes = listOf( + KaizenShapes.xs, KaizenShapes.sm, KaizenShapes.md, + KaizenShapes.lg, KaizenShapes.xl, KaizenShapes.pill, + ) + val unique = shapes.toSet() + assertEquals("All squircle shape tokens should be distinct", shapes.size, unique.size) + } + + @Test + fun `SquircleShape toString contains parameters`() { + val shape = SquircleShape(radius = 16.dp, smoothness = 4.5f) + val str = shape.toString() + assertTrue("Should contain radius", str.contains("16")) + assertTrue("Should contain smoothness", str.contains("4.5")) + } + + @Test + fun `SquircleShape with different smoothness creates different instances`() { + val a = SquircleShape(radius = 16.dp, smoothness = 4.0f) + val b = SquircleShape(radius = 16.dp, smoothness = 5.0f) + assertTrue("Different smoothness should produce different toString", a.toString() != b.toString()) + } +} diff --git a/app/src/test/java/dev/kaizen/app/ThemeRegistryTest.kt b/app/src/test/java/dev/kaizen/app/ThemeRegistryTest.kt new file mode 100644 index 0000000..83a0adb --- /dev/null +++ b/app/src/test/java/dev/kaizen/app/ThemeRegistryTest.kt @@ -0,0 +1,62 @@ +package dev.kaizen.app + +import dev.kaizen.app.ui.theme.themes.KaizenThemeId +import dev.kaizen.app.ui.theme.themes.ThemeRegistry +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test + +class ThemeRegistryTest { + + @Test + fun `registry contains all four themes`() { + assertEquals(4, ThemeRegistry.all.size) + val ids = ThemeRegistry.all.map { it.id }.toSet() + assertTrue(ids.contains(KaizenThemeId.AMBER)) + assertTrue(ids.contains(KaizenThemeId.BLAU)) + assertTrue(ids.contains(KaizenThemeId.MONO)) + assertTrue(ids.contains(KaizenThemeId.AURORA)) + } + + @Test + fun `forId returns correct theme`() { + KaizenThemeId.entries.forEach { id -> + val theme = ThemeRegistry.forId(id) + assertEquals(id, theme.id) + } + } + + @Test + fun `all themes have non-empty labels`() { + ThemeRegistry.all.forEach { theme -> + assertTrue("Theme ${theme.id} should have a label", theme.label.isNotBlank()) + } + } + + @Test + fun `all themes have distinct blob colors per scheme`() { + ThemeRegistry.all.forEach { theme -> + listOf(theme.dark, theme.light).forEach { scheme -> + val blobs = setOf(scheme.blob1, scheme.blob2, scheme.blob3, scheme.blob4) + assertTrue( + "Theme ${theme.id} should have at least 3 distinct blob colors", + blobs.size >= 3, + ) + } + } + } + + @Test + fun `KaizenThemeId fromString parses all ids`() { + assertEquals(KaizenThemeId.AMBER, KaizenThemeId.fromString("amber")) + assertEquals(KaizenThemeId.BLAU, KaizenThemeId.fromString("blue")) + assertEquals(KaizenThemeId.MONO, KaizenThemeId.fromString("mono")) + assertEquals(KaizenThemeId.AURORA, KaizenThemeId.fromString("aurora")) + } + + @Test + fun `KaizenThemeId fromString falls back to AMBER for unknown`() { + assertEquals(KaizenThemeId.AMBER, KaizenThemeId.fromString("unknown")) + assertEquals(KaizenThemeId.AMBER, KaizenThemeId.fromString("")) + } +} From f1c6a88c4c9d133a4cdeb6a9294c64ad055b0c56 Mon Sep 17 00:00:00 2001 From: Bruno Deanoz Date: Sun, 21 Jun 2026 14:35:45 +0200 Subject: [PATCH 02/12] docs: add CLAUDE.md as architecture map (renamed from NEXT.md) Adds design system v2 section covering P3 colors, squircle shapes, GlassSurface, multi-layer shadows, 4-theme system, sensor tilt state, motion tokens, and new test inventory. --- CLAUDE.md | 254 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..c13eeed --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,254 @@ +# Kaizen App + +Architecture map for the native Android client. Source of truth for any agent or human picking up this codebase. + +## Goal + +Make the **native Android app** (`kaizen-app`) a valid daily-driver that talks to the **Kaizen backend** (`kaizen`). One binary, deployment-agnostic: one uniform `Authorization: Bearer ` contract, same against the official server or any self-host. Design constraint (hard): backend complexity stays invisible to the user. + +## Repos (absolute paths) + +- Backend (Next.js 16, Drizzle, Postgres): `/Users/brunodeanoz/Kaizen/kaizen` — git remote `origin` = `git@git.kryptomrx.de:krypto/kaizen.git`, branch `main`. Read its `CLAUDE.md` first; it is the architecture map. +- Android app (Kotlin, Jetpack Compose, package `dev.kaizen.app`): `/Users/brunodeanoz/Kaizen/kaizen-app` — built/run from Windows Android Studio on a real S25 Ultra; everything else (backend, Postgres, Docker) runs on the dev Mac + dedicated servers. +- **Note:** `/Users/brunodeanoz/Kaizen` itself is NOT a git repo. Only `kaizen` and `kaizen-app` are separate git repos. + +## Platform strategy + +- Android: Kotlin + Jetpack Compose (native, no WebView) +- iOS (planned): Swift + SwiftUI + SwiftData (native, separate codebase) +- No KMP — each platform uses its native stack for best feel + +## The API contract the app uses (source of truth — verify, don't guess) + +- **Auth:** every request carries `Authorization: Bearer kzn_...`. Backend resolves via `requireActiveUserOrToken` (`lib/auth/guard.ts`). +- **Token acquisition:** in-app login (`POST {baseUrl}/api/v1/auth/token` with `{ email, password, name }`). Consumer "Sign in" pattern — no copy-paste. +- **Chat:** `POST {baseUrl}/api/v1/chat` — `{ model, messages: [{ role, content }], reasoningEffort?, preferThroughput? }`. Response is `text/plain` chunked stream (NOT SSE). Parsed by `StreamConsumer.Incremental` in `net/StreamConsumer.kt`. +- **Sentinels** (`lib/chat/constants.ts`): `\x00` USAGE, `\x01` REASONING, `\x02` SOURCES, `\x03` TOOL, `\x04` QUERY. App currently strips all sentinels and renders only visible content. +- **Models:** `GET {baseUrl}/api/v1/models` → `{ models: [{ id, name?, provider? }] }`. +- **Conversations:** `GET /api/v1/conversations` → `{ conversations, hasMore }`. `POST /api/v1/conversations` → create. `GET /api/v1/conversations/[id]` → `{ messages }`. `POST /api/v1/conversations/[id]/messages` → persist. `POST /api/v1/conversations/[id]/title` → auto-title. +- **Identity:** `GET /api/v1/me` → `{ id, email, name, role, defaultModel }`. +- **Capability handshake:** `GET /api/v1/meta` → `{ app, apiVersion, features }` (unauth). +- **Upload:** `POST /api/v1/upload` — multipart file → `{ url, kind, name, mimeType, size, fileId }`. + +## App architecture + +### Package structure (`app/src/main/java/dev/kaizen/app/`) + +``` +auth/ LoginScreen +chat/ ChatScreen, ChatViewModel, Sidebar, ChatComponents, ChatModels, + ModelSheet, Markdown, Background +db/ Room offline cache: KaizenDatabase, Entities, DAOs, + Repositories, Converters, Mappers +haptics/ Phase-aware haptics +net/ KaizenApi (HTTP), SecureStore (encrypted prefs), + SessionViewModel, ServerConfig, StreamConsumer +settings/ SettingsScreen, SettingsViewModel, SettingsComponents +ui/ + theme/ Color (P3), Theme (multi-theme), Type, Oklab, Dither + theme/themes/ AccentScheme, AmberTheme, BlauTheme, MonoTheme, AuroraTheme, ThemeRegistry + shape/ SquircleShape (superellipse), KaizenShapes (token system) + effect/ GlassSurface (RenderEffect blur), Shadow (multi-layer stack) + motion/ Motion (easing curves, spring specs, duration tokens) + sensor/ TiltState (gyro/accel parallax, lifecycle-aware) +``` + +### Key components + +- **KaizenApi** (`net/KaizenApi.kt`) — singleton `object`, all HTTP calls via OkHttp. Streaming chat returns `Flow` with incremental sentinel-stripping. +- **StreamConsumer** (`net/StreamConsumer.kt`) — O(chunk-size) incremental parser, each character visited exactly once across the entire stream. +- **SessionViewModel** (`net/SessionViewModel.kt`) — Compose snapshot state for auth session. Holds `ServerConfig` (baseUrl, token, model, email, speed). Persisted in `EncryptedSharedPreferences` via `SecureStore`. +- **ChatViewModel** (`chat/ChatViewModel.kt`) — owns Room database instance + repositories. Created in `MainActivity`, passed to `ChatScreen`. +- **ChatScreen** (`chat/ChatScreen.kt`) — main composable, orchestrates sidebar, messages, streaming, file uploads. + +### Design System v2 (`ui/`) — added 2026-06-21 + +Full spec: `DESIGN.md`. Branch: `feature/design-system-v2`. + +**Six pillars** (load-bearing — if any regress, the design regresses): + +1. **P3 color pipeline** — all tokens in DisplayP3 color space (`Color.kt`). `window.colorMode = COLOR_MODE_HDR` (API 34+) / `COLOR_MODE_WIDE_COLOR_GAMUT` (API 26+) in `MainActivity`. No `Color(0xFF…)` for brand colors outside `Color.kt`. +2. **Squircle shapes** — iOS-style superellipse with G2 continuity (`ui/shape/Squircle.kt`). Token system `KaizenShapes.{xs,sm,md,lg,xl,pill,circle}`. Replaces all `RoundedCornerShape`. +3. **GlassSurface** — real `Modifier.blur()` (RenderEffect on API 31+), tint + inner highlight + border. API 26–30 fallback: higher tint alpha. Opacity tiers per component in `GlassTiers`. +4. **Multi-layer shadows** — `ShadowStack` with 2–4 overlapping layers (`KaizenShadows.level0..4`). Dark mode multiplies alphas ×1.8. Replaces all `Modifier.shadow()`. +5. **4-theme system** — Amber/Blau/Mono/Aurora. Each theme = `KaizenAccentScheme` (primary + 4 blob colors). Neutrals are theme-independent. `LocalKaizenAccent` CompositionLocal. Server sync planned via `GET /api/v1/me` → `uiTheme`. +6. **Sensor-reactive motion** — `rememberTiltState()` provides smoothed tilt `Offset(-1..1)`. Uses `TYPE_GAME_ROTATION_VECTOR` (fused, no drift). Auto-disables on battery saver, reduced motion, background, extreme tilt. + +**Motion tokens** (`ui/motion/Motion.kt`): `EaseSpring` (overshoot), `EaseSmooth` (expo-out), `EaseEmphasized` (M3), `SpringSnappy/Default/Gentle`. All durations centralised in `Durations` object. + +**What's NOT yet migrated to the design system:** The existing UI components (ChatScreen, Sidebar, ChatInput, etc.) still use the old inline glass styling with manual `Brush` + `border`. Migration to `GlassSurface` + `KaizenShapes` + `kaizenShadow` is the next step. + +### Offline-first cache layer (Room) — added 2026-06-21 + +Architecture decision document: `OFFLINE_CACHE_ADD.md`. + +**Principle:** Read-cache, not sync engine. Server is source of truth. No offline-queue, no conflict resolution. + +**Stack:** Room 2.8.4 + KSP 2.2.10-2.0.2. `room-ktx` merged into `room-runtime` since Room 2.7 (no separate dep needed). `exportSchema = false`, `fallbackToDestructiveMigration()` — it's a cache, not a DB. On schema changes the SQLite is wiped; cache rebuilds on next server fetch. + +**Schema:** +- `conversations` — id, title, locked, pinned, updatedAt, cachedAt +- `messages` — id, conversationId (FK CASCADE), role, content, attachments (JSON via TypeConverter), sortOrder + +**Data flow:** +``` +App start → Room (instant) → UI shows cached data + → Background: server fetch → Room update → Flow emits → UI updates +Chat open → Room (instant) → Background: server fetch → Room update +Send message → in-memory during streaming → Room flush after stream ends +``` + +**Streaming hybrid model:** During active streaming, messages are mutated in-memory (60x/s). Room is NOT written during streaming — that would be absurd I/O. After stream completion, user + assistant messages are upserted into Room. This avoids SQLite lock contention while keeping the cache fresh. + +**Files:** +- `db/Entities.kt` — `ConversationEntity`, `MessageEntity` +- `db/ConversationDao.kt` — `observeAll()` (Flow), `replaceAll()` (transaction: deleteAll + upsertAll, avoids SQLite 999-variable limit), `lastCachedAt()` +- `db/MessageDao.kt` — `observeByConversation()`, `getByConversation()`, `upsertAll()`, `deleteByConversation()` +- `db/KaizenDatabase.kt` — singleton via `companion object` (double-checked locking), thread-safe +- `db/ConversationRepository.kt` — `observeAll()` (Flow of ConversationSummary), `refresh()` (server → Room) +- `db/MessageRepository.kt` — `observeMessages()`, `getCached()`, `fetchAndCache()`, `cacheMessages()` +- `db/Converters.kt` — `List` ↔ JSON string via kotlinx.serialization +- `db/Mappers.kt` — `ConversationSummary` ↔ `ConversationEntity`, `StoredMessage` ↔ `MessageEntity` + +**AGP 9.x compat:** `android.disallowKotlinSourceSets=false` in `gradle.properties` (KSP issue [#2729](https://github.com/google/ksp/issues/2729)). + +## What's DONE and verified + +### Backend — all complete, deployed, tested + +All backend work for the app is done. `pnpm test:run` green (774+), `tsc` + `lint` clean. + +- **`api_tokens` table** + SHA-256 hash storage (never raw). Migration `0024`. +- **Bearer auth path** (`getTokenSession` / `requireActiveUserOrToken` in `lib/auth/guard.ts`). +- **Token mint endpoint** `POST /api/v1/auth/token` — unauthenticated, Argon2id verify, anti-enumeration, rate-limited. +- **`GET /api/v1/me`** — identity + `defaultModel` for native clients. +- **`GET /api/v1/models`** — Bearer-authed, returns filtered model catalog. +- **`/api/v1/conversations`** — thin re-exports of canonical handlers, Bearer-authed. +- **`GET /api/v1/meta`** — capability handshake. +- **App-devices card** (`components/settings/app-tokens-card.tsx`) — see/revoke signed-in devices on `/settings/security`. +- **API versioning** — `/api/v1/` for outward contract, additive-only within v1. Web-internal endpoints stay unversioned. + +### App — shipped features (on-device verified on S25 Ultra) + +All committed on `main`. Compile-verified on Mac (`./gradlew :app:compileDebugKotlin` clean). + +| Commit | Feature | +|--------|---------| +| `44c17b6` | In-app login (email+password → `POST /api/v1/auth/token`), `EncryptedSharedPreferences`, real streaming via `StreamConsumer.Incremental`, `ServerConfig` persistence | +| `aa0a97b` | Dither overlay to kill 8-bit sRGB banding on orb + mesh gradients | +| `d2f269f` | Model + speed picker (top pill → bottom sheet), response-speed segment, favorites, provider badges | +| `ea5e625` | Sidebar wired to real conversations, persistence (create/save/load/auto-title), date-grouped history | +| `7399c73` | Model sheet redesign with OpenRouter/Vertex badging, offline-first caching | +| `d81c6ff` | Robust JSON parsing (malformed response handling) | +| `827a2f3` | Streaming performance, error handling | +| `423abc0` | **Specific error diagnostics** — `FetchResult` replaces null-returns; error banner shows exact cause (HTTP status, DNS, SSL, timeout, JSON parsing) instead of generic "Verbindung zum Server fehlgeschlagen" | +| `4616ef2` | **Markdown rendering with syntax-highlighted code blocks** — native Compose renderer: headings, bold/italic, inline code, fenced code blocks with keyword highlighting (15+ languages), ordered/unordered lists, streaming cursor integration | +| `d8dcb25` | **Attachment support — display, upload, and send files** — parse + render message attachments from loaded conversations (images inline via OkHttp + in-memory cache, other kinds as icon chips); + button wired to Android file picker with upload to `/api/v1/upload`, progress chips, send attachments with chat requests + persist in saved messages. Also: Markdown horizontal rules, blockquotes, links, code block copy button | +| `9759d47` | **Offline-first cache layer (Room)** — sidebar + messages load instantly from SQLite cache, background refresh syncs with server, streaming hybrid model (in-memory during stream, Room flush after), ChatViewModel, repositories, mappers, TypeConverters, unit tests | + +**Earlier UI/feel work (Phase 0 prototype → feel-first):** +- Liquid glass styling, floating panels, glassmorphic sidebar +- KaizenOrb with 3D sphere rendering, streaming animation +- Mesh gradient background with dithered blobs +- Phase-aware haptics (click → thinkingStart → responseStart → responseEnd) +- Tablet/landscape optimization (width capping) +- Dynamic keyboard handling (suggestion pills hide, spacer shrinks) +- Settings screen with SettingsViewModel + +### Bug fixed this session (2026-06-19/20) + +**"Verbindung zum Server fehlgeschlagen" on S25** — root cause was **server running an old build** without the v1/conversations route (404) and without Bearer auth on models (401). Fix was `git pull && docker compose -f docker-compose.prod.yml up -d --build` on the server. Additionally, the error diagnostics were improved (see `423abc0`) so future issues show the exact cause in the UI banner instead of a generic message. + +## What's NOT done yet (app, priority order) + +### 1. Remaining visual/UX gaps (daily-drive blockers) + +These are what separate "prototype" from "daily-driver": + +- [ ] **Markdown rendering during streaming** — currently renders live but performance with long code blocks during high-speed streaming needs real-device verification +- [x] **Code block copy button** — tap-to-copy on fenced code blocks (clipboard + haptic feedback) +- [x] **Horizontal rule / blockquote rendering** — `---` and `> quote` not yet parsed +- [ ] **Table rendering** — Markdown tables render as raw text +- [x] **Link rendering** — styled visually, not yet clickable (tap-to-open pending) + +### 2. Conversation management from the app + +- [ ] **Conversation rename/delete** from the sidebar (currently read-only) +- [ ] **Conversation pin/unpin** from the sidebar +- [ ] **In-app unlock for locked conversations** (currently skipped with "Gesperrter Chat" label) + +### 3. Security hardening + +- [ ] **Auto-logout on 401** — if the token is rejected, route to login screen instead of showing error banner +- [ ] **Server version check** — call `/api/v1/meta` after login to detect server skew and warn cleanly +- [ ] **Biometric lock** (`BiometricPrompt` + KeyStore binding) — see `LATER.md` §1C +- [ ] **`FLAG_SECURE`** on sensitive screens — see `LATER.md` §1B + +### 4. Features for parity with the web + +- [x] **Attachments** — image/file upload, attachment preview in messages, display in loaded conversations (camera capture still TODO) +- [ ] **Reasoning/thinking display** — parse `\x01` sentinel, show collapsible thinking block +- [ ] **Web search sources** — parse `\x02`/`\x04` sentinels, render source cards +- [ ] **Tool call display** — parse `\x03` sentinel, show live tool steps +- [ ] **Native passkey login** (WebAuthn/FIDO2 on Android) +- [ ] **WebSocket streaming** (replace chunked HTTP for lower latency on mobile) +- [ ] **Usage/cost display** +- [ ] **User context / KI-Profil** + +### 5. App distribution + +- [ ] **Push notifications** (FCM) +- [ ] **Play Store / F-Droid listing** +- [ ] **Auto-update mechanism** + +### 6. Offline-cache enhancements (future iterations, see `OFFLINE_CACHE_ADD.md` §11) + +- [ ] **Stale-check enforcement** — use `cachedAt` to trigger background refresh when older than N minutes +- [ ] **Offline-queue for sends** — queue messages locally, send when network returns (needs conflict resolution) +- [ ] **Incremental sync** — only fetch changed conversations (needs server-side `since` parameter) +- [ ] **Media cache** — cache images/files locally (Coil or custom disk cache) +- [ ] **Full-text search** — FTS4/FTS5 over cached messages (Room supports this natively) +- [ ] **Attachment queries** — "show me all chats with images/PDFs" via Room DB + +## Dependencies + +```toml +# gradle/libs.versions.toml (key versions) +agp = "9.2.1" +kotlin = "2.2.10" +ksp = "2.2.10-2.0.2" +room = "2.8.4" +composeBom = "2026.02.01" +okhttp = "4.12.0" +kotlinxSerialization = "1.7.3" +securityCrypto = "1.1.0-alpha06" +``` + +## Tests + +**Unit tests** (`app/src/test/`): JVM-only, no emulator needed. + +- `SettingsViewModelTest` — state transitions, default values, theme selection, name updates +- `StreamConsumerTest` — incremental parser, sentinel stripping, edge cases +- `OklabTest` — 2 pre-existing failures (round-trip color drift > 0.01 tolerance, unrelated to backend wiring, likely too-tight tolerance or headless float precision) +- `MappersTest` — `ConversationSummary` ↔ `ConversationEntity`, `StoredMessage` ↔ `MessageEntity`, round-trip integrity, attachment preservation +- `ConvertersTest` — `List` ↔ JSON round-trips, malformed JSON returns empty list, unknown fields tolerance via `ignoreUnknownKeys` +- `ColorPipelineTest` — all tokens in DisplayP3, approximate value ranges, no pure black/white in neutrals +- `SquircleShapeTest` — KaizenShapes token existence/distinctness, SquircleShape toString +- `ThemeRegistryTest` — 4 themes present, forId lookup, fromString parsing + fallback, distinct blob colors +- `ShadowStackTest` — layer counts per level, alpha range validation, blur/alpha progression + +## Pre-existing issues (not from this work) + +- `OklabTest` has 2 headless failures (`testColorToOklabAndBack`, `testGradientGeneration` — round-trip color drift > 0.01 tolerance). Unrelated to backend wiring; likely too-tight tolerance or headless float precision. + +## Constraints & gotchas + +- Local dev Mac has **no RustFS** (storage on server only); upload/storage flows fail locally with `ECONNREFUSED :9000`. +- Live OpenRouter key is encrypted in the DB (`api_keys`), `.env.local` is stale. +- Never hand-write migrations or fake timestamps — use `pnpm db:generate`. Always `git pull` before `docker build` on prod. +- App philosophy: the real driver is *feel*, not features; native Compose (no WebView). Backend complexity stays invisible. +- **Deploy gotcha (learned 2026-06-19):** `git pull` BEFORE `docker compose up --build`, else the image bakes stale code and the app gets 404/401 against endpoints that exist in the repo but aren't in the running build. +- Headless compile on Mac: `JAVA_HOME=/opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home ./gradlew :app:compileDebugKotlin` — JDK 21 via Homebrew, Android SDK at `/opt/homebrew/share/android-commandlinetools`. +- **AGP 9.x + KSP:** requires `android.disallowKotlinSourceSets=false` in `gradle.properties`. +- **Room is a cache:** `fallbackToDestructiveMigration()` means the SQLite DB is wiped on schema changes. No data loss — server is source of truth, cache rebuilds on next fetch. From 4d714759951e5a41758f250fc887b053eb681a0c Mon Sep 17 00:00:00 2001 From: Bruno Deanoz Date: Sun, 21 Jun 2026 14:41:23 +0200 Subject: [PATCH 03/12] =?UTF-8?q?fix:=20derive=20all=20theme=20colors=20fr?= =?UTF-8?q?om=20web=20CSS=20files=20(OKLCH=20=E2=86=92=20P3=20RGB)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Amber blobs were cold (blue/indigo) but web uses warm (gold/coral/honey/teal). Mono had slate chroma but web is pure achromatic (zero chroma). Aurora dark primary was magenta but web swaps to gold in dark mode. All four themes now pixel-match the web app's OKLCH values. --- .../java/dev/kaizen/app/chat/Background.kt | 4 +- .../java/dev/kaizen/app/ui/theme/Color.kt | 12 +++--- .../kaizen/app/ui/theme/themes/AmberTheme.kt | 37 +++++++++--------- .../kaizen/app/ui/theme/themes/AuroraTheme.kt | 39 ++++++++++--------- .../kaizen/app/ui/theme/themes/BlauTheme.kt | 37 +++++++++--------- .../kaizen/app/ui/theme/themes/MonoTheme.kt | 37 +++++++++--------- .../java/dev/kaizen/app/ColorPipelineTest.kt | 22 ++++++++++- 7 files changed, 107 insertions(+), 81 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 e83d7ad..8e136df 100644 --- a/app/src/main/java/dev/kaizen/app/chat/Background.kt +++ b/app/src/main/java/dev/kaizen/app/chat/Background.kt @@ -50,7 +50,7 @@ import androidx.compose.ui.unit.dp import dev.kaizen.app.ui.theme.Amber import dev.kaizen.app.ui.theme.AmberDeep import dev.kaizen.app.ui.theme.BlobAmber -import dev.kaizen.app.ui.theme.BlobBlue +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.rememberDitherBrush @@ -81,7 +81,7 @@ fun MeshBackground(content: @Composable BoxScope.() -> Unit) { }, ) { Blob(BlobAmber, 360.dp, (-60f + drift * 30f).dp, (-40f + drift * 24f).dp, 0.30f * factor) - Blob(BlobBlue, 380.dp, (170f - drift * 44f).dp, (150f + drift * 40f).dp, 0.24f * factor) + Blob(BlobCoral, 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) // Vignette: darken the edges so the center comes forward (dark mode only). if (dark) { diff --git a/app/src/main/java/dev/kaizen/app/ui/theme/Color.kt b/app/src/main/java/dev/kaizen/app/ui/theme/Color.kt index 6a54aff..9770115 100644 --- a/app/src/main/java/dev/kaizen/app/ui/theme/Color.kt +++ b/app/src/main/java/dev/kaizen/app/ui/theme/Color.kt @@ -38,8 +38,10 @@ val LightText = p3(0.102f, 0.122f, 0.161f) // ≈ #1A1F29 val LightMuted = p3(0.357f, 0.392f, 0.439f) // ≈ #5B6470 val LightStroke = p3(0f, 0f, 0f, 0.08f) // outline -// ── Background blobs ─────────────────────────────────────────────────────── -val BlobAmber = p3(0.878f, 0.635f, 0.243f) // ≈ Amber -val BlobBlue = p3(0.235f, 0.373f, 0.839f) // ≈ #3C5FD6 -val BlobTeal = p3(0.169f, 0.714f, 0.651f) // ≈ #2BB6A6 -val BlobIndigo = p3(0.290f, 0.290f, 0.690f) // 4th blob for Amber theme +// ── Background blobs (Amber theme defaults, derived from amber.css) ──────── +// These are the light-mode defaults. Theme-specific blobs come from +// LocalKaizenAccent.current.blob1..4 once the theme system is wired. +val BlobAmber = p3(0.992f, 0.767f, 0.282f) // oklch(0.85 0.15 83) gold +val BlobCoral = p3(1.000f, 0.562f, 0.230f) // oklch(0.78 0.18 50) coral +val BlobHoney = p3(0.917f, 0.853f, 0.471f) // oklch(0.88 0.12 100) honey +val BlobTeal = p3(0.461f, 0.885f, 0.908f) // oklch(0.85 0.10 200) teal accent 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 e8bd223..91e562c 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 @@ -6,27 +6,28 @@ import androidx.compose.ui.graphics.colorspace.ColorSpaces private fun p3(r: Float, g: Float, b: Float): Color = Color(red = r, green = g, blue = b, colorSpace = ColorSpaces.DisplayP3) +// Derived from kaizen/app/themes/amber.css — warm blobs (gold, coral, honey, teal accent) val AmberTheme = KaizenThemeSpec( id = KaizenThemeId.AMBER, label = "Amber", - dark = KaizenAccentScheme( - primary = p3(0.878f, 0.635f, 0.243f), // Amber - primaryDeep = p3(0.784f, 0.525f, 0.165f), - onPrimary = p3(0.106f, 0.071f, 0.024f), - ring = p3(0.878f, 0.635f, 0.243f), - blob1 = p3(0.878f, 0.635f, 0.243f), // Amber - blob2 = p3(0.235f, 0.373f, 0.839f), // Blue - blob3 = p3(0.290f, 0.290f, 0.690f), // Indigo - blob4 = p3(0.169f, 0.714f, 0.651f), // Teal - ), light = KaizenAccentScheme( - primary = p3(0.784f, 0.525f, 0.165f), // AmberDeep (better contrast on white) - primaryDeep = p3(0.784f, 0.525f, 0.165f), - onPrimary = p3(1f, 1f, 1f), - ring = p3(0.878f, 0.635f, 0.243f), - blob1 = p3(0.878f, 0.635f, 0.243f), - blob2 = p3(0.235f, 0.373f, 0.839f), - blob3 = p3(0.290f, 0.290f, 0.690f), - blob4 = p3(0.169f, 0.714f, 0.651f), + primary = p3(0.811f, 0.608f, 0.126f), // oklch(0.72 0.14 83) + primaryDeep = p3(0.811f, 0.608f, 0.126f), + 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 + blob2 = p3(1.000f, 0.562f, 0.230f), // oklch(0.78 0.18 50) coral + blob3 = p3(0.917f, 0.853f, 0.471f), // oklch(0.88 0.12 100) honey + blob4 = p3(0.461f, 0.885f, 0.908f), // oklch(0.85 0.10 200) teal accent + ), + dark = KaizenAccentScheme( + primary = p3(0.862f, 0.658f, 0.201f), // oklch(0.76 0.14 83) + primaryDeep = p3(0.811f, 0.608f, 0.126f), + onPrimary = p3(0.015f, 0.013f, 0.009f), // oklch(0.10 0.005 83) + ring = p3(0.862f, 0.658f, 0.201f), + blob1 = p3(0.619f, 0.394f, 0.000f), // oklch(0.55 0.16 83) deep gold + blob2 = p3(0.628f, 0.087f, 0.000f), // oklch(0.45 0.18 40) deep coral + blob3 = p3(0.404f, 0.407f, 0.084f), // oklch(0.50 0.10 110) olive + blob4 = p3(0.000f, 0.405f, 0.436f), // oklch(0.45 0.12 200) deep teal ), ) 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 1a44385..4cd332f 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 @@ -6,27 +6,30 @@ import androidx.compose.ui.graphics.colorspace.ColorSpaces private fun p3(r: Float, g: Float, b: Float): Color = Color(red = r, green = g, blue = b, colorSpace = ColorSpaces.DisplayP3) +// Derived from kaizen/app/themes/aurora.css +// Light: purple primary, blobs = purple/gold/green/teal +// Dark: GOLD primary (swaps!), blobs = deep purple/gold/green/teal val AuroraTheme = KaizenThemeSpec( id = KaizenThemeId.AURORA, label = "Aurora", - dark = KaizenAccentScheme( - primary = p3(0.850f, 0.310f, 0.750f), // Magenta P3 - primaryDeep = p3(0.680f, 0.220f, 0.620f), - onPrimary = p3(0.106f, 0.024f, 0.090f), - ring = p3(0.850f, 0.310f, 0.750f), - blob1 = p3(0.850f, 0.310f, 0.750f), // Magenta - blob2 = p3(0.169f, 0.714f, 0.800f), // Cyan - blob3 = p3(0.545f, 0.361f, 0.859f), // Violet - blob4 = p3(0.520f, 0.850f, 0.310f), // Lime (accent) - ), light = KaizenAccentScheme( - primary = p3(0.490f, 0.270f, 0.690f), // Violet-600 P3 - primaryDeep = p3(0.490f, 0.270f, 0.690f), - onPrimary = p3(1f, 1f, 1f), - ring = p3(0.850f, 0.310f, 0.750f), - blob1 = p3(0.850f, 0.310f, 0.750f), - blob2 = p3(0.169f, 0.714f, 0.800f), - blob3 = p3(0.545f, 0.361f, 0.859f), - blob4 = p3(0.520f, 0.850f, 0.310f), + primary = p3(0.724f, 0.328f, 0.812f), // oklch(0.62 0.20 320) purple + primaryDeep = p3(0.724f, 0.328f, 0.812f), + 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 + blob2 = p3(0.931f, 0.738f, 0.291f), // oklch(0.82 0.14 85) gold + blob3 = p3(0.433f, 0.822f, 0.455f), // oklch(0.78 0.16 145) green + blob4 = p3(0.227f, 0.808f, 0.837f), // oklch(0.78 0.12 200) teal + ), + dark = KaizenAccentScheme( + primary = p3(0.890f, 0.684f, 0.156f), // oklch(0.78 0.15 85) GOLD (swapped!) + primaryDeep = p3(0.724f, 0.328f, 0.812f), + onPrimary = p3(0.034f, 0.020f, 0.003f), // oklch(0.12 0.02 85) + ring = p3(0.890f, 0.684f, 0.156f), + blob1 = p3(0.495f, 0.141f, 0.569f), // oklch(0.45 0.18 320) deep purple + blob2 = p3(0.600f, 0.405f, 0.000f), // oklch(0.55 0.15 85) deep gold + blob3 = p3(0.000f, 0.459f, 0.000f), // oklch(0.48 0.18 145) deep green + blob4 = p3(0.000f, 0.410f, 0.445f), // oklch(0.45 0.13 200) deep teal ), ) 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 c4f9980..7d95dc1 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 @@ -6,27 +6,28 @@ import androidx.compose.ui.graphics.colorspace.ColorSpaces private fun p3(r: Float, g: Float, b: Float): Color = Color(red = r, green = g, blue = b, colorSpace = ColorSpaces.DisplayP3) +// Derived from kaizen/app/themes/blue.css — cool blobs (sky, cyan, indigo, warm peach accent) val BlauTheme = KaizenThemeSpec( id = KaizenThemeId.BLAU, label = "Blau", - dark = KaizenAccentScheme( - primary = p3(0.337f, 0.600f, 0.988f), // Sky-500 P3 - primaryDeep = p3(0.243f, 0.420f, 0.855f), - onPrimary = p3(0.024f, 0.047f, 0.106f), - ring = p3(0.337f, 0.600f, 0.988f), - blob1 = p3(0.235f, 0.373f, 0.839f), // Blue - blob2 = p3(0.290f, 0.290f, 0.690f), // Indigo - blob3 = p3(0.169f, 0.714f, 0.800f), // Cyan - blob4 = p3(0.878f, 0.635f, 0.243f), // Amber (contrast) - ), light = KaizenAccentScheme( - primary = p3(0.243f, 0.310f, 0.730f), // Indigo-600 P3 - primaryDeep = p3(0.243f, 0.310f, 0.730f), - onPrimary = p3(1f, 1f, 1f), - ring = p3(0.337f, 0.600f, 0.988f), - blob1 = p3(0.235f, 0.373f, 0.839f), - blob2 = p3(0.290f, 0.290f, 0.690f), - blob3 = p3(0.169f, 0.714f, 0.800f), - blob4 = p3(0.878f, 0.635f, 0.243f), + primary = p3(0.168f, 0.513f, 0.962f), // oklch(0.62 0.19 257) + primaryDeep = p3(0.168f, 0.513f, 0.962f), + 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 + blob2 = p3(0.000f, 0.766f, 0.953f), // oklch(0.75 0.16 220) cyan + blob3 = p3(0.648f, 0.551f, 1.000f), // oklch(0.72 0.18 290) indigo + blob4 = p3(0.973f, 0.763f, 0.519f), // oklch(0.85 0.10 70) peach accent + ), + dark = KaizenAccentScheme( + primary = p3(0.276f, 0.592f, 1.000f), // oklch(0.68 0.18 257) + primaryDeep = p3(0.168f, 0.513f, 0.962f), + onPrimary = p3(0.010f, 0.023f, 0.051f), // oklch(0.12 0.02 257) + ring = p3(0.276f, 0.592f, 1.000f), + blob1 = p3(0.000f, 0.307f, 0.713f), // oklch(0.45 0.18 257) deep sky + blob2 = p3(0.000f, 0.360f, 0.533f), // oklch(0.42 0.16 220) deep cyan + blob3 = p3(0.305f, 0.111f, 0.660f), // oklch(0.40 0.20 290) deep indigo + blob4 = p3(0.580f, 0.315f, 0.000f), // oklch(0.50 0.14 70) amber accent ), ) 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 72cab72..c727004 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 @@ -6,27 +6,28 @@ import androidx.compose.ui.graphics.colorspace.ColorSpaces private fun p3(r: Float, g: Float, b: Float): Color = Color(red = r, green = g, blue = b, colorSpace = ColorSpaces.DisplayP3) +// Derived from kaizen/app/themes/mono.css — achromatic, zero chroma, subtle warm blob4 accent val MonoTheme = KaizenThemeSpec( id = KaizenThemeId.MONO, label = "Mono", - dark = KaizenAccentScheme( - primary = p3(0.878f, 0.894f, 0.918f), // Slate-100 - primaryDeep = p3(0.710f, 0.741f, 0.784f), - onPrimary = p3(0.063f, 0.082f, 0.118f), - ring = p3(0.710f, 0.741f, 0.784f), - blob1 = p3(0.710f, 0.741f, 0.784f), // Slate-300 - blob2 = p3(0.580f, 0.620f, 0.680f), // Slate-400 - blob3 = p3(0.820f, 0.845f, 0.878f), // Slate-200 - blob4 = p3(0.600f, 0.580f, 0.560f), // Warm gray - ), light = KaizenAccentScheme( - primary = p3(0.188f, 0.224f, 0.286f), // Slate-800 - primaryDeep = p3(0.188f, 0.224f, 0.286f), - onPrimary = p3(1f, 1f, 1f), - ring = p3(0.420f, 0.455f, 0.510f), - blob1 = p3(0.710f, 0.741f, 0.784f), - blob2 = p3(0.580f, 0.620f, 0.680f), - blob3 = p3(0.820f, 0.845f, 0.878f), - blob4 = p3(0.600f, 0.580f, 0.560f), + primary = p3(0.104f, 0.104f, 0.104f), // oklch(0.22 0 255) near-black + primaryDeep = p3(0.104f, 0.104f, 0.104f), + 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 + blob2 = p3(0.681f, 0.681f, 0.681f), // oklch(0.75 0 255) mid gray + blob3 = p3(0.896f, 0.896f, 0.896f), // oklch(0.92 0 255) off-white + blob4 = p3(0.796f, 0.765f, 0.714f), // oklch(0.82 0.02 80) subtle warm + ), + dark = KaizenAccentScheme( + primary = p3(0.896f, 0.896f, 0.896f), // oklch(0.92 0 255) near-white + primaryDeep = p3(0.806f, 0.806f, 0.806f), + onPrimary = p3(0.022f, 0.022f, 0.022f), // oklch(0.12 0 255) near-black + ring = p3(0.896f, 0.896f, 0.896f), + blob1 = p3(0.229f, 0.229f, 0.229f), // oklch(0.35 0 255) dark gray + blob2 = p3(0.334f, 0.334f, 0.334f), // oklch(0.45 0 255) mid-dark gray + blob3 = p3(0.179f, 0.179f, 0.179f), // oklch(0.30 0 255) charcoal + blob4 = p3(0.304f, 0.277f, 0.234f), // oklch(0.40 0.02 80) subtle warm ), ) diff --git a/app/src/test/java/dev/kaizen/app/ColorPipelineTest.kt b/app/src/test/java/dev/kaizen/app/ColorPipelineTest.kt index 36d05a4..5e87d43 100644 --- a/app/src/test/java/dev/kaizen/app/ColorPipelineTest.kt +++ b/app/src/test/java/dev/kaizen/app/ColorPipelineTest.kt @@ -1,7 +1,25 @@ package dev.kaizen.app import androidx.compose.ui.graphics.colorspace.ColorSpaces -import dev.kaizen.app.ui.theme.* +import dev.kaizen.app.ui.theme.Amber +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.BlobHoney +import dev.kaizen.app.ui.theme.BlobTeal +import dev.kaizen.app.ui.theme.DarkMuted +import dev.kaizen.app.ui.theme.DarkStroke +import dev.kaizen.app.ui.theme.DarkText +import dev.kaizen.app.ui.theme.LightBackground +import dev.kaizen.app.ui.theme.LightMuted +import dev.kaizen.app.ui.theme.LightStroke +import dev.kaizen.app.ui.theme.LightSurface +import dev.kaizen.app.ui.theme.LightSurfaceVariant +import dev.kaizen.app.ui.theme.LightText +import dev.kaizen.app.ui.theme.Obsidian +import dev.kaizen.app.ui.theme.ObsidianElevated +import dev.kaizen.app.ui.theme.ObsidianInput +import dev.kaizen.app.ui.theme.OnAmber import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Test @@ -41,7 +59,7 @@ class ColorPipelineTest { @Test fun `blob colors are in DisplayP3`() { - listOf(BlobAmber, BlobBlue, BlobTeal, BlobIndigo).forEach { color -> + listOf(BlobAmber, BlobCoral, BlobHoney, BlobTeal).forEach { color -> assertEquals(ColorSpaces.DisplayP3, color.colorSpace) } } From 94c0f85fb76541626f015289d16cd9ce467a5e4e Mon Sep 17 00:00:00 2001 From: Bruno Deanoz Date: Sun, 21 Jun 2026 14:50:11 +0200 Subject: [PATCH 04/12] feat: migrate all UI components to design system v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Sidebar: GlassSurface + KaizenShapes (lg, sm, md, pill, circle) - ChatInput: GlassSurface with input tier opacity - ChatScreen: menu button uses GlassSurface, error banner uses KaizenShapes - EmptyHero: suggestion chips removed on mobile (DESIGN.md §11.1) - LoginScreen: GlassFields use KaizenShapes.lg - ModelSheet: KaizenShapes (xl, md, xs, circle) - SettingsCard: GlassSurface with card tier opacity - SettingsScreen: back button uses GlassSurface - SettingsComponents: all CircleShape/RoundedCornerShape → KaizenShapes - Markdown: copy button uses KaizenShapes.circle - GlassSurface: removed misleading Modifier.blur (Android has no backdrop-filter) - TypingDots: uses motion duration tokens - Fixed deprecated ArrowBack icon → AutoMirrored variant --- .../java/dev/kaizen/app/auth/LoginScreen.kt | 12 +- .../dev/kaizen/app/chat/ChatComponents.kt | 472 ++++-------------- .../java/dev/kaizen/app/chat/ChatScreen.kt | 54 +- .../main/java/dev/kaizen/app/chat/Markdown.kt | 4 +- .../java/dev/kaizen/app/chat/ModelSheet.kt | 19 +- .../main/java/dev/kaizen/app/chat/Sidebar.kt | 206 ++------ .../kaizen/app/settings/SettingsComponents.kt | 79 +-- .../dev/kaizen/app/settings/SettingsScreen.kt | 49 +- .../dev/kaizen/app/ui/effect/GlassSurface.kt | 87 ++-- 9 files changed, 256 insertions(+), 726 deletions(-) diff --git a/app/src/main/java/dev/kaizen/app/auth/LoginScreen.kt b/app/src/main/java/dev/kaizen/app/auth/LoginScreen.kt index b22c889..15b08af 100644 --- a/app/src/main/java/dev/kaizen/app/auth/LoginScreen.kt +++ b/app/src/main/java/dev/kaizen/app/auth/LoginScreen.kt @@ -17,7 +17,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.RoundedCornerShape +import dev.kaizen.app.ui.shape.KaizenShapes import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll @@ -178,10 +178,10 @@ private fun GlassField( Modifier .fillMaxWidth() .widthIn(max = 420.dp) - .shadow(elevation = 6.dp, shape = RoundedCornerShape(20.dp), clip = false) - .clip(RoundedCornerShape(20.dp)) + .shadow(elevation = 6.dp, shape = KaizenShapes.lg, clip = false) + .clip(KaizenShapes.lg) .background(glassBg) - .border(1.2.dp, glassBorder, RoundedCornerShape(20.dp)) + .border(1.2.dp, glassBorder, KaizenShapes.lg) .heightIn(min = 54.dp) .padding(horizontal = 18.dp, vertical = 16.dp), contentAlignment = Alignment.CenterStart, @@ -216,8 +216,8 @@ private fun SignInButton(enabled: Boolean, loading: Boolean, onClick: () -> Unit .fillMaxWidth() .widthIn(max = 420.dp) .heightIn(min = 54.dp) - .shadow(elevation = 8.dp, shape = RoundedCornerShape(20.dp), clip = false) - .clip(RoundedCornerShape(20.dp)) + .shadow(elevation = 8.dp, shape = KaizenShapes.lg, clip = false) + .clip(KaizenShapes.lg) .then(fill) .clickable(enabled = enabled, onClick = onClick) .padding(vertical = 16.dp), 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 5a349e6..01c70a7 100644 --- a/app/src/main/java/dev/kaizen/app/chat/ChatComponents.kt +++ b/app/src/main/java/dev/kaizen/app/chat/ChatComponents.kt @@ -19,24 +19,19 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi -import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn -import androidx.compose.foundation.layout.ime import androidx.compose.foundation.layout.isImeVisible import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons @@ -53,7 +48,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.scale -import androidx.compose.ui.draw.shadow import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color @@ -61,21 +55,23 @@ import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import dev.kaizen.app.net.Attachment +import dev.kaizen.app.ui.effect.GlassSurface +import dev.kaizen.app.ui.effect.GlassTiers +import dev.kaizen.app.ui.effect.KaizenShadows +import dev.kaizen.app.ui.motion.Durations +import dev.kaizen.app.ui.shape.KaizenShapes import dev.kaizen.app.ui.theme.Amber import dev.kaizen.app.ui.theme.AmberDeep import dev.kaizen.app.ui.theme.OnAmber import java.time.LocalDateTime import java.time.format.DateTimeFormatter import java.util.Locale -import kotlin.OptIn import android.graphics.BitmapFactory import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.aspectRatio import androidx.compose.material.icons.rounded.AudioFile import androidx.compose.material.icons.rounded.Close import androidx.compose.material.icons.rounded.Code @@ -98,57 +94,22 @@ import java.util.concurrent.TimeUnit @Composable fun KaizenHeader(modifier: Modifier = Modifier) { val cs = MaterialTheme.colorScheme - val isDark = isSystemInDarkTheme() - - val glassBg = remember(isDark) { - if (isDark) { - Brush.verticalGradient( - listOf( - Color(0xFF1E293B).copy(alpha = 0.65f), // Slate 800 with 65% opacity - Color(0xFF0F172A).copy(alpha = 0.75f) // Slate 900 with 75% opacity - ) - ) - } else { - Brush.verticalGradient( - listOf( - Color.White.copy(alpha = 0.85f), - Color(0xFFF1F5F9).copy(alpha = 0.75f) // Slate 100 with 75% opacity - ) - ) - } - } - - val glassBorder = remember(isDark) { - if (isDark) { - Brush.verticalGradient( - listOf( - Color.White.copy(alpha = 0.16f), // Specular light highlight on top - Color.White.copy(alpha = 0.03f) // Subtle dark fade on bottom - ) - ) - } else { - Brush.verticalGradient( - listOf( - Color.White.copy(alpha = 0.55f), - Color.Black.copy(alpha = 0.05f) - ) - ) - } - } - - Row( - modifier + GlassSurface( + modifier = modifier .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 10.dp) - .clip(RoundedCornerShape(24.dp)) - .background(glassBg) - .border(1.2.dp, glassBorder, RoundedCornerShape(24.dp)) - .padding(horizontal = 16.dp, vertical = 12.dp), - verticalAlignment = Alignment.CenterVertically, + .padding(horizontal = 16.dp, vertical = 10.dp), + shape = KaizenShapes.lg, + shadowStack = KaizenShadows.level1, + cornerRadius = 24.dp, ) { - KaizenOrb(24.dp) - Spacer(Modifier.width(10.dp)) - Text("Kaizen", color = cs.onBackground, fontSize = 18.sp, fontWeight = FontWeight.SemiBold) + Row( + Modifier.padding(horizontal = 16.dp, vertical = 12.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + KaizenOrb(24.dp) + Spacer(Modifier.width(10.dp)) + Text("Kaizen", color = cs.onBackground, fontSize = 18.sp, fontWeight = FontWeight.SemiBold) + } } } @@ -161,11 +122,7 @@ fun EmptyHero(userName: String, onPick: (String) -> Unit, modifier: Modifier = M now.format(DateTimeFormatter.ofPattern("EEE, d. MMMM · HH:mm", Locale.GERMAN)) } - // Dynamic keyboard visibility check (Google Gemini style) - // When the soft keyboard is visible, we completely hide the Suggestion Pills - // to give the user maximum typing space and keep the layout extremely clean. - val isKeyboardOpen = WindowInsets.isImeVisible - + // DESIGN.md §11.1: no suggestion chips on mobile — redundant with mode pills Column( modifier = modifier .fillMaxSize() @@ -173,7 +130,7 @@ fun EmptyHero(userName: String, onPick: (String) -> Unit, modifier: Modifier = M .padding(horizontal = 24.dp), horizontalAlignment = Alignment.CenterHorizontally, ) { - Spacer(Modifier.height(48.dp)) // Clean native layout, reduced from 88.dp as there is no top bar + Spacer(Modifier.height(48.dp)) KaizenOrb(104.dp) Spacer(Modifier.height(24.dp)) Text("${greeting(now.hour)}, $userName", color = cs.onSurfaceVariant, fontSize = 17.sp) @@ -181,56 +138,7 @@ fun EmptyHero(userName: String, onPick: (String) -> Unit, modifier: Modifier = M Text("Was liegt an?", color = cs.onBackground, fontSize = 32.sp, fontWeight = FontWeight.Bold) Spacer(Modifier.height(8.dp)) Text(dateLine, color = cs.onSurfaceVariant.copy(alpha = 0.7f), fontSize = 13.sp) - - if (!isKeyboardOpen) { - Spacer(Modifier.height(32.dp)) - SuggestionPills(onPick) - } - - // Dynamically shrink the bottom spacer when the keyboard is open. - // This ensures the remaining elements fit perfectly into the space above the keyboard - // without causing the column to exceed the screen height and trigger an automatic scroll. - // As a result, the greeting remains perfectly stationary and visible while typing! - val bottomSpacerHeight = if (isKeyboardOpen) 72.dp else 142.dp - Spacer(Modifier.height(bottomSpacerHeight)) - } -} - -@OptIn(ExperimentalLayoutApi::class) -@Composable -private fun SuggestionPills(onPick: (String) -> Unit) { - val cs = MaterialTheme.colorScheme - val isDark = isSystemInDarkTheme() - - // Highly responsive 3D floating glass capsules (iOS 26 / Apple Liquid Glass style) - val glassBg = if (isDark) cs.surface.copy(alpha = 0.45f) else cs.surface.copy(alpha = 0.88f) - val glassBorder = if (isDark) { - Brush.verticalGradient(listOf(Color.White.copy(alpha = 0.16f), Color.White.copy(alpha = 0.02f))) - } else { - Brush.verticalGradient(listOf(Color.White.copy(alpha = 0.65f), Color.Black.copy(alpha = 0.05f))) - } - - FlowRow( - Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(10.dp, Alignment.CenterHorizontally), - verticalArrangement = Arrangement.spacedBy(10.dp), - ) { - suggestions.forEach { suggestion -> - Row( - Modifier - .shadow(elevation = 3.dp, shape = CircleShape, clip = false) // Ambient 3D shadow for floating look - .clip(CircleShape) - .background(glassBg) - .border(1.2.dp, glassBorder, CircleShape) - .clickable { onPick(suggestion.prompt) } - .padding(horizontal = 16.dp, vertical = 11.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - Icon(suggestion.icon, null, tint = cs.primary, modifier = Modifier.size(18.dp)) - Spacer(Modifier.width(8.dp)) - Text(suggestion.label, color = cs.onBackground, fontSize = 14.sp, fontWeight = FontWeight.Medium) - } - } + Spacer(Modifier.height(142.dp)) } } @@ -240,21 +148,11 @@ fun ModePillsRow(selected: String, onSelect: (String) -> Unit, modifier: Modifie val isDark = isSystemInDarkTheme() val glassBorderInactive = remember(isDark) { - if (isDark) { - Brush.verticalGradient( - listOf(Color.White.copy(alpha = 0.12f), Color.White.copy(alpha = 0.02f)) - ) - } else { - Brush.verticalGradient( - listOf(Color.White.copy(alpha = 0.45f), Color.Black.copy(alpha = 0.04f)) - ) - } + if (isDark) Brush.verticalGradient(listOf(Color.White.copy(alpha = 0.12f), Color.White.copy(alpha = 0.02f))) + else Brush.verticalGradient(listOf(Color.White.copy(alpha = 0.45f), Color.Black.copy(alpha = 0.04f))) } - val glassBorderActive = remember(isDark) { - Brush.verticalGradient( - listOf(Amber.copy(alpha = 0.50f), Amber.copy(alpha = 0.15f)) - ) + Brush.verticalGradient(listOf(Amber.copy(alpha = 0.50f), Amber.copy(alpha = 0.15f))) } Row( @@ -266,36 +164,22 @@ fun ModePillsRow(selected: String, onSelect: (String) -> Unit, modifier: Modifie ) { chatModes.forEach { mode -> val active = mode.label == selected - val backgroundFill = if (active) { - Amber.copy(alpha = 0.16f) - } else { - if (isDark) Color(0x12FFFFFF) else Color(0x82FFFFFF) - } + val backgroundFill = if (active) Amber.copy(alpha = 0.16f) + else if (isDark) Color(0x12FFFFFF) else Color(0x82FFFFFF) val borderBrush = if (active) glassBorderActive else glassBorderInactive Row( Modifier - .shadow(elevation = 2.dp, shape = CircleShape, clip = false) // Floating tabs - .clip(CircleShape) + .clip(KaizenShapes.pill) .background(backgroundFill) - .border(1.2.dp, borderBrush, CircleShape) + .border(1.2.dp, borderBrush, KaizenShapes.pill) .clickable { onSelect(mode.label) } .padding(horizontal = 13.dp, vertical = 8.dp), verticalAlignment = Alignment.CenterVertically, ) { - Icon( - mode.icon, - null, - tint = if (active) Amber else cs.onSurfaceVariant, - modifier = Modifier.size(16.dp), - ) + Icon(mode.icon, null, tint = if (active) Amber else cs.onSurfaceVariant, modifier = Modifier.size(16.dp)) Spacer(Modifier.width(6.dp)) - Text( - mode.label, - color = if (active) cs.onBackground else cs.onSurfaceVariant, - fontSize = 13.sp, - fontWeight = FontWeight.Medium, - ) + Text(mode.label, color = if (active) cs.onBackground else cs.onSurfaceVariant, fontSize = 13.sp, fontWeight = FontWeight.Medium) } } } @@ -305,43 +189,27 @@ fun ModePillsRow(selected: String, onSelect: (String) -> Unit, modifier: Modifie fun MessageRow(message: Message) { val cs = MaterialTheme.colorScheme val isDark = isSystemInDarkTheme() - val hasAttachments = message.attachments.isNotEmpty() if (message.role == Role.User) { Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) { - val shape = RoundedCornerShape(20.dp, 20.dp, 6.dp, 20.dp) - - val borderBrush = remember { - Brush.verticalGradient(listOf(Amber.copy(alpha = 0.45f), AmberDeep.copy(alpha = 0.15f))) - } - val bgBrush = remember { - Brush.verticalGradient(listOf(Amber.copy(alpha = 0.18f), AmberDeep.copy(alpha = 0.08f))) - } + val shape = KaizenShapes.lg + val borderBrush = remember { Brush.verticalGradient(listOf(Amber.copy(alpha = 0.45f), AmberDeep.copy(alpha = 0.15f))) } + val bgBrush = remember { Brush.verticalGradient(listOf(Amber.copy(alpha = 0.18f), AmberDeep.copy(alpha = 0.08f))) } Box( Modifier .widthIn(max = 300.dp) - .shadow(elevation = 3.dp, shape = shape, clip = false) .clip(shape) .background(bgBrush) .border(1.2.dp, borderBrush, shape), ) { Column { - if (hasAttachments) { - AttachmentGrid(message.attachments, Modifier.padding(6.dp)) - } + if (hasAttachments) AttachmentGrid(message.attachments, Modifier.padding(6.dp)) if (message.content.isNotBlank()) { Text( - message.content, - color = cs.onBackground, - fontSize = 16.sp, - lineHeight = 22.sp, - modifier = Modifier.padding( - start = 16.dp, end = 16.dp, - top = if (hasAttachments) 4.dp else 11.dp, - bottom = 11.dp, - ), + message.content, color = cs.onBackground, fontSize = 16.sp, lineHeight = 22.sp, + modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = if (hasAttachments) 4.dp else 11.dp, bottom = 11.dp), ) } } @@ -357,11 +225,8 @@ fun MessageRow(message: Message) { AttachmentGrid(message.attachments) if (message.content.isNotBlank() || message.thinking) Spacer(Modifier.height(8.dp)) } - if (message.thinking) { - TypingDots() - } else { - MarkdownText(text = message.content, streaming = message.streaming) - } + if (message.thinking) TypingDots() + else MarkdownText(text = message.content, streaming = message.streaming) } } } @@ -375,26 +240,18 @@ private fun TypingDots() { Row(verticalAlignment = Alignment.CenterVertically) { repeat(3) { i -> val alpha by transition.animateFloat( - initialValue = 0.25f, - targetValue = 1f, + initialValue = 0.25f, targetValue = 1f, animationSpec = infiniteRepeatable( - tween(600, delayMillis = i * 160, easing = FastOutSlowInEasing), + tween(Durations.THINKING_DOT_CYCLE, delayMillis = i * Durations.THINKING_DOT_PHASE_OFFSET, easing = FastOutSlowInEasing), RepeatMode.Reverse, ), label = "dot$i", ) - Box( - Modifier - .padding(end = 5.dp) - .size(7.dp) - .clip(CircleShape) - .background(cs.onSurfaceVariant.copy(alpha = alpha)), - ) + Box(Modifier.padding(end = 5.dp).size(7.dp).clip(KaizenShapes.circle).background(cs.onSurfaceVariant.copy(alpha = alpha))) } } } -/** A file pending upload or already uploaded, shown as a preview chip above the input. */ data class PendingFile( val id: String = java.util.UUID.randomUUID().toString(), val name: String, @@ -419,98 +276,41 @@ fun ChatInput( val cs = MaterialTheme.colorScheme val isDark = isSystemInDarkTheme() - val glassBg = remember(isDark) { - if (isDark) { - Brush.verticalGradient( - listOf( - Color(0xFF1E293B).copy(alpha = 0.72f), // Slate 800 translucent - Color(0xFF0F172A).copy(alpha = 0.85f) // Slate 900 translucent - ) - ) - } else { - Brush.verticalGradient( - listOf( - Color.White.copy(alpha = 0.90f), - Color(0xFFEEF2F6).copy(alpha = 0.80f) - ) - ) - } - } - - val glassBorder = remember(isDark) { - if (isDark) { - Brush.verticalGradient( - listOf( - Color.White.copy(alpha = 0.18f), - Color.White.copy(alpha = 0.04f) - ) - ) - } else { - Brush.verticalGradient( - listOf( - Color.White.copy(alpha = 0.60f), - Color.Black.copy(alpha = 0.06f) - ) - ) - } - } - - Column( - modifier + GlassSurface( + modifier = modifier .fillMaxWidth() - .padding(horizontal = 12.dp) - .shadow(elevation = 8.dp, shape = RoundedCornerShape(28.dp), clip = false) - .clip(RoundedCornerShape(28.dp)) - .background(glassBg) - .border(1.2.dp, glassBorder, RoundedCornerShape(28.dp)), + .padding(horizontal = 12.dp), + shape = KaizenShapes.xl, + tintAlpha = GlassTiers.input(isDark), + shadowStack = KaizenShadows.level2, + cornerRadius = 28.dp, ) { - if (pendingFiles.isNotEmpty()) { - Row( - Modifier - .fillMaxWidth() - .horizontalScroll(rememberScrollState()) - .padding(start = 12.dp, end = 12.dp, top = 8.dp), - horizontalArrangement = Arrangement.spacedBy(6.dp), - ) { - pendingFiles.forEach { pf -> - PendingFileChip(pf, onRemove = { onRemoveFile(pf.id) }) + Column { + if (pendingFiles.isNotEmpty()) { + Row( + Modifier.fillMaxWidth().horizontalScroll(rememberScrollState()).padding(start = 12.dp, end = 12.dp, top = 8.dp), + horizontalArrangement = Arrangement.spacedBy(6.dp), + ) { + pendingFiles.forEach { pf -> PendingFileChip(pf, onRemove = { onRemoveFile(pf.id) }) } } } - } - Row( - Modifier.padding(horizontal = 8.dp, vertical = 8.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - Box( - Modifier.size(40.dp).clip(CircleShape).clickable(onClick = onAddClick), - contentAlignment = Alignment.Center, - ) { - Icon(Icons.Rounded.Add, "Anhang", tint = cs.onSurfaceVariant, modifier = Modifier.size(22.dp)) - } - Box( - Modifier - .weight(1f) - .heightIn(min = 36.dp) - .padding(horizontal = 4.dp), - contentAlignment = Alignment.CenterStart - ) { - if (value.isEmpty()) { - Text("Nachricht eingeben …", color = cs.onSurfaceVariant, fontSize = 16.sp) + Row(Modifier.padding(horizontal = 8.dp, vertical = 8.dp), verticalAlignment = Alignment.CenterVertically) { + Box(Modifier.size(40.dp).clip(KaizenShapes.circle).clickable(onClick = onAddClick), contentAlignment = Alignment.Center) { + Icon(Icons.Rounded.Add, "Anhang", tint = cs.onSurfaceVariant, modifier = Modifier.size(22.dp)) } - BasicTextField( - value = value, - onValueChange = onValueChange, - textStyle = TextStyle(color = cs.onBackground, fontSize = 16.sp, lineHeight = 22.sp), - cursorBrush = SolidColor(Amber), - maxLines = 6, - modifier = Modifier.fillMaxWidth(), - ) + Box(Modifier.weight(1f).heightIn(min = 36.dp).padding(horizontal = 4.dp), contentAlignment = Alignment.CenterStart) { + if (value.isEmpty()) Text("Nachricht eingeben …", color = cs.onSurfaceVariant, fontSize = 16.sp) + BasicTextField( + value = value, onValueChange = onValueChange, + textStyle = TextStyle(color = cs.onBackground, fontSize = 16.sp, lineHeight = 22.sp), + cursorBrush = SolidColor(Amber), maxLines = 6, modifier = Modifier.fillMaxWidth(), + ) + } + GhostIconButton(Icons.Rounded.Call, "Anruf") + Spacer(Modifier.width(4.dp)) + val canSend = enabled && (value.isNotBlank() || pendingFiles.any { it.uploaded != null }) && pendingFiles.none { it.uploading } + SendButton(enabled = canSend, onClick = onSend) } - GhostIconButton(Icons.Rounded.Call, "Anruf") - Spacer(Modifier.width(4.dp)) - val canSend = enabled && (value.isNotBlank() || pendingFiles.any { it.uploaded != null }) - && pendingFiles.none { it.uploading } - SendButton(enabled = canSend, onClick = onSend) } } } @@ -518,7 +318,7 @@ fun ChatInput( @Composable private fun GhostIconButton(icon: ImageVector, contentDescription: String) { val cs = MaterialTheme.colorScheme - Box(Modifier.size(40.dp).clip(CircleShape), contentAlignment = Alignment.Center) { + Box(Modifier.size(40.dp).clip(KaizenShapes.circle), contentAlignment = Alignment.Center) { Icon(icon, contentDescription, tint = cs.onSurfaceVariant, modifier = Modifier.size(22.dp)) } } @@ -530,19 +330,9 @@ private fun PendingFileChip(pf: PendingFile, onRemove: () -> Unit) { val bg = if (isDark) Color.White.copy(alpha = 0.08f) else Color.Black.copy(alpha = 0.06f) val isImage = pf.mimeType.startsWith("image/") - Box( - Modifier - .size(64.dp) - .clip(RoundedCornerShape(10.dp)) - .background(bg), - contentAlignment = Alignment.Center, - ) { + Box(Modifier.size(64.dp).clip(KaizenShapes.xs).background(bg), contentAlignment = Alignment.Center) { if (isImage && pf.uploaded != null) { - NetworkImage( - url = pf.uploaded.url, - contentDescription = pf.name, - modifier = Modifier.fillMaxSize().clip(RoundedCornerShape(10.dp)), - ) + NetworkImage(url = pf.uploaded.url, contentDescription = pf.name, modifier = Modifier.fillMaxSize().clip(KaizenShapes.xs)) } else { val icon = when { pf.mimeType.startsWith("image/") -> Icons.Rounded.Image @@ -553,46 +343,21 @@ private fun PendingFileChip(pf: PendingFile, onRemove: () -> Unit) { } Column(horizontalAlignment = Alignment.CenterHorizontally) { Icon(icon, null, tint = cs.onSurfaceVariant, modifier = Modifier.size(20.dp)) - Text( - pf.name, - color = cs.onSurfaceVariant, - fontSize = 9.sp, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - modifier = Modifier.padding(horizontal = 4.dp), - ) + Text(pf.name, color = cs.onSurfaceVariant, fontSize = 9.sp, maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = Modifier.padding(horizontal = 4.dp)) } } if (pf.uploading) { - Box( - Modifier.fillMaxSize() - .background(Color.Black.copy(alpha = 0.4f)), - contentAlignment = Alignment.Center, - ) { - androidx.compose.material3.CircularProgressIndicator( - modifier = Modifier.size(20.dp), - strokeWidth = 2.dp, - color = Color.White, - ) + Box(Modifier.fillMaxSize().background(Color.Black.copy(alpha = 0.4f)), contentAlignment = Alignment.Center) { + androidx.compose.material3.CircularProgressIndicator(modifier = Modifier.size(20.dp), strokeWidth = 2.dp, color = Color.White) } } if (pf.error != null) { - Box( - Modifier.fillMaxSize() - .background(Color(0xFFDC2626).copy(alpha = 0.3f)), - contentAlignment = Alignment.Center, - ) { + Box(Modifier.fillMaxSize().background(Color(0xFFDC2626).copy(alpha = 0.3f)), contentAlignment = Alignment.Center) { Icon(Icons.Rounded.Close, "Fehler", tint = Color.White, modifier = Modifier.size(18.dp)) } } Box( - Modifier - .align(Alignment.TopEnd) - .padding(2.dp) - .size(18.dp) - .clip(CircleShape) - .background(Color.Black.copy(alpha = 0.5f)) - .clickable(onClick = onRemove), + Modifier.align(Alignment.TopEnd).padding(2.dp).size(18.dp).clip(KaizenShapes.circle).background(Color.Black.copy(alpha = 0.5f)).clickable(onClick = onRemove), contentAlignment = Alignment.Center, ) { Icon(Icons.Rounded.Close, "Entfernen", tint = Color.White, modifier = Modifier.size(12.dp)) @@ -606,18 +371,12 @@ private fun SendButton(enabled: Boolean, onClick: () -> Unit) { val interaction = remember { MutableInteractionSource() } val pressed by interaction.collectIsPressedAsState() val pressScale by animateFloatAsState(if (pressed) 0.86f else 1f, label = "send") - val fill = if (enabled) { - Modifier.background(Brush.linearGradient(listOf(Amber, AmberDeep))) - } else { - Modifier.background(cs.surface) - } + val fill = if (enabled) Modifier.background(Brush.linearGradient(listOf(Amber, AmberDeep))) + else Modifier.background(cs.surface) + Box( - Modifier - .size(44.dp) - .scale(pressScale) - .clip(CircleShape) - .then(fill) - .border(1.dp, cs.outline, CircleShape) + Modifier.size(44.dp).scale(pressScale).clip(KaizenShapes.circle).then(fill) + .border(1.dp, cs.outline, KaizenShapes.circle) .clickable(interactionSource = interaction, indication = null, enabled = enabled, onClick = onClick), contentAlignment = Alignment.Center, ) { @@ -631,10 +390,7 @@ private object NetworkImageCache { private val cache = object : LinkedHashMap(32, 0.75f, true) { override fun removeEldestEntry(eldest: MutableMap.MutableEntry?) = size > 50 } - private val client = OkHttpClient.Builder() - .connectTimeout(15, TimeUnit.SECONDS) - .readTimeout(30, TimeUnit.SECONDS) - .build() + private val client = OkHttpClient.Builder().connectTimeout(15, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS).build() suspend fun load(url: String): ImageBitmap? = withContext(Dispatchers.IO) { synchronized(cache) { cache[url] }?.let { return@withContext it } @@ -647,8 +403,7 @@ private object NetworkImageCache { BitmapFactory.decodeByteArray(bytes, 0, bytes.size, probe) val scale = maxOf(1, maxOf(probe.outWidth, probe.outHeight) / 1536) val opts = BitmapFactory.Options().apply { inSampleSize = scale } - val bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.size, opts) - ?: return@withContext null + val bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.size, opts) ?: return@withContext null bmp.asImageBitmap().also { synchronized(cache) { cache[url] = it } } } } catch (_: Exception) { null } @@ -656,31 +411,14 @@ private object NetworkImageCache { } @Composable -private fun NetworkImage( - url: String, - contentDescription: String?, - modifier: Modifier = Modifier, - contentScale: ContentScale = ContentScale.Crop, -) { +private fun NetworkImage(url: String, contentDescription: String?, modifier: Modifier = Modifier, contentScale: ContentScale = ContentScale.Crop) { var bitmap by remember(url) { mutableStateOf(null) } LaunchedEffect(url) { bitmap = NetworkImageCache.load(url) } - val bmp = bitmap if (bmp != null) { - Image( - bitmap = bmp, - contentDescription = contentDescription, - modifier = modifier, - contentScale = contentScale, - ) + Image(bitmap = bmp, contentDescription = contentDescription, modifier = modifier, contentScale = contentScale) } else { - Box( - modifier - .fillMaxWidth() - .height(160.dp) - .clip(RoundedCornerShape(10.dp)) - .background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.3f)), - ) + Box(modifier.fillMaxWidth().height(160.dp).clip(KaizenShapes.xs).background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.3f))) } } @@ -689,17 +427,9 @@ fun AttachmentGrid(attachments: List, modifier: Modifier = Modifier) if (attachments.isEmpty()) return val images = attachments.filter { it.kind == "image" } val others = attachments.filter { it.kind != "image" } - Column(modifier, verticalArrangement = Arrangement.spacedBy(6.dp)) { images.forEach { att -> - NetworkImage( - url = att.url, - contentDescription = att.name, - modifier = Modifier - .fillMaxWidth() - .heightIn(max = 280.dp) - .clip(RoundedCornerShape(10.dp)), - ) + NetworkImage(url = att.url, contentDescription = att.name, modifier = Modifier.fillMaxWidth().heightIn(max = 280.dp).clip(KaizenShapes.xs)) } others.forEach { att -> FileChip(att) } } @@ -717,33 +447,17 @@ private fun FileChip(attachment: Attachment) { "code" -> Icons.Rounded.Code else -> Icons.AutoMirrored.Rounded.InsertDriveFile } - Row( - Modifier - .clip(RoundedCornerShape(8.dp)) - .background(bg) - .padding(horizontal = 10.dp, vertical = 6.dp), - verticalAlignment = Alignment.CenterVertically, - ) { + Row(Modifier.clip(KaizenShapes.xs).background(bg).padding(horizontal = 10.dp, vertical = 6.dp), verticalAlignment = Alignment.CenterVertically) { Icon(icon, null, tint = cs.onSurfaceVariant, modifier = Modifier.size(16.dp)) Spacer(Modifier.width(6.dp)) - Text( - attachment.name, - color = cs.onSurfaceVariant, - fontSize = 13.sp, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) + Text(attachment.name, color = cs.onSurfaceVariant, fontSize = 13.sp, maxLines = 1, overflow = TextOverflow.Ellipsis) } } -/** Crisp upward arrow drawn with strokes (sharper than a glyph). */ @Composable private fun SendArrow(color: Color) { Canvas(Modifier.size(18.dp)) { - val w = size.width - val h = size.height - val cx = w / 2f - val stroke = w * 0.135f + val w = size.width; val h = size.height; val cx = w / 2f; val stroke = w * 0.135f drawLine(color, Offset(cx, h * 0.82f), Offset(cx, h * 0.20f), stroke, StrokeCap.Round) drawLine(color, Offset(cx, h * 0.18f), Offset(w * 0.28f, h * 0.46f), stroke, StrokeCap.Round) drawLine(color, Offset(cx, h * 0.18f), Offset(w * 0.72f, h * 0.46f), stroke, StrokeCap.Round) 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 d8679c4..980741c 100644 --- a/app/src/main/java/dev/kaizen/app/chat/ChatScreen.kt +++ b/app/src/main/java/dev/kaizen/app/chat/ChatScreen.kt @@ -22,8 +22,6 @@ import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.Menu import androidx.compose.material3.DrawerValue @@ -45,7 +43,6 @@ import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalConfiguration @@ -53,6 +50,10 @@ import androidx.compose.material3.Text import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import dev.kaizen.app.ui.effect.GlassSurface +import dev.kaizen.app.ui.effect.GlassTiers +import dev.kaizen.app.ui.effect.KaizenShadows +import dev.kaizen.app.ui.shape.KaizenShapes import dev.kaizen.app.db.MessageEntity import dev.kaizen.app.db.toEntity import dev.kaizen.app.haptics.rememberHaptics @@ -416,19 +417,7 @@ fun ChatScreen( } } - // 2. Floating Top Menu Button (Apple Liquid Glass - completely independent of a header bar) - val isDark = remember { isStreaming || messages.isNotEmpty() } // slight adaptive context tint - val menuGlassBg = if (isDark.not() && isSystemInDarkTheme().not()) { - Brush.verticalGradient(listOf(Color.White.copy(alpha = 0.85f), Color(0xFFF1F5F9).copy(alpha = 0.75f))) - } else { - Brush.verticalGradient(listOf(Color(0xFF1E293B).copy(alpha = 0.65f), Color(0xFF0F172A).copy(alpha = 0.75f))) - } - val menuGlassBorder = if (isDark.not() && isSystemInDarkTheme().not()) { - Brush.verticalGradient(listOf(Color.White.copy(alpha = 0.55f), Color.Black.copy(alpha = 0.05f))) - } else { - Brush.verticalGradient(listOf(Color.White.copy(alpha = 0.16f), Color.White.copy(alpha = 0.03f))) - } - + // 2. Floating Top Menu Button Row( modifier = Modifier .align(Alignment.TopStart) @@ -436,22 +425,23 @@ fun ChatScreen( .padding(start = 16.dp, top = 10.dp, end = 16.dp), verticalAlignment = Alignment.CenterVertically, ) { - Box( + GlassSurface( + shape = KaizenShapes.circle, + tintAlpha = GlassTiers.pill(isSystemInDarkTheme()), + shadowStack = KaizenShadows.level2, + cornerRadius = 22.dp, modifier = Modifier - .shadow(elevation = 6.dp, shape = CircleShape, clip = false) // Floats above backgrounds - .clip(CircleShape) - .background(menuGlassBg) - .border(1.2.dp, menuGlassBorder, CircleShape) - .clickable { haptics.tick(); scope.launch { drawerState.open() } } - .size(44.dp), - contentAlignment = Alignment.Center + .size(44.dp) + .clickable { haptics.tick(); scope.launch { drawerState.open() } }, ) { - Icon( - imageVector = Icons.Rounded.Menu, - contentDescription = "Menü öffnen", - tint = MaterialTheme.colorScheme.onBackground, - modifier = Modifier.size(20.dp) - ) + Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + Icon( + imageVector = Icons.Rounded.Menu, + contentDescription = "Menü öffnen", + tint = MaterialTheme.colorScheme.onBackground, + modifier = Modifier.size(20.dp) + ) + } } Spacer(Modifier.width(8.dp)) ModelPill( @@ -468,9 +458,9 @@ fun ChatScreen( .align(Alignment.TopCenter) .statusBarsPadding() .padding(top = 62.dp, start = 24.dp, end = 24.dp) - .clip(RoundedCornerShape(12.dp)) + .clip(KaizenShapes.sm) .background(Color(0xFFDC2626).copy(alpha = 0.15f)) - .border(1.dp, Color(0xFFDC2626).copy(alpha = 0.3f), RoundedCornerShape(12.dp)) + .border(1.dp, Color(0xFFDC2626).copy(alpha = 0.3f), KaizenShapes.sm) .padding(horizontal = 14.dp, vertical = 8.dp), ) { Text( 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 0988e20..16d4ed5 100644 --- a/app/src/main/java/dev/kaizen/app/chat/Markdown.kt +++ b/app/src/main/java/dev/kaizen/app/chat/Markdown.kt @@ -17,8 +17,8 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape +import dev.kaizen.app.ui.shape.KaizenShapes import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.Check import androidx.compose.material.icons.rounded.ContentCopy @@ -509,7 +509,7 @@ private fun CopyButton(code: String) { Box( Modifier .size(28.dp) - .clip(CircleShape) + .clip(KaizenShapes.circle) .clickable { haptics.tick() copied = true diff --git a/app/src/main/java/dev/kaizen/app/chat/ModelSheet.kt b/app/src/main/java/dev/kaizen/app/chat/ModelSheet.kt index 4e7127e..ba69255 100644 --- a/app/src/main/java/dev/kaizen/app/chat/ModelSheet.kt +++ b/app/src/main/java/dev/kaizen/app/chat/ModelSheet.kt @@ -6,8 +6,7 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.foundation.shape.RoundedCornerShape +import dev.kaizen.app.ui.shape.KaizenShapes import androidx.compose.foundation.text.BasicTextField import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.* @@ -35,9 +34,9 @@ fun ModelPill(label: String, onClick: () -> Unit, modifier: Modifier = Modifier) val cs = MaterialTheme.colorScheme Row( modifier = modifier - .clip(RoundedCornerShape(22.dp)) + .clip(KaizenShapes.xl) .background(cs.surface.copy(alpha = 0.7f)) - .border(1.dp, cs.onSurface.copy(alpha = 0.08f), RoundedCornerShape(22.dp)) + .border(1.dp, cs.onSurface.copy(alpha = 0.08f), KaizenShapes.xl) .clickable { onClick() } .padding(start = 14.dp, end = 8.dp, top = 9.dp, bottom = 9.dp), verticalAlignment = Alignment.CenterVertically, @@ -128,9 +127,9 @@ fun ModelSheet( Row( modifier = Modifier .fillMaxWidth() - .clip(RoundedCornerShape(16.dp)) + .clip(KaizenShapes.md) .background(cs.surfaceVariant.copy(alpha = 0.4f)) - .border(1.dp, cs.onSurface.copy(alpha = 0.06f), RoundedCornerShape(16.dp)) + .border(1.dp, cs.onSurface.copy(alpha = 0.06f), KaizenShapes.md) .padding(horizontal = 14.dp, vertical = 11.dp), verticalAlignment = Alignment.CenterVertically ) { @@ -229,7 +228,7 @@ private fun ModelRow( modifier = Modifier .fillMaxWidth() .padding(vertical = 4.dp) - .clip(RoundedCornerShape(16.dp)) + .clip(KaizenShapes.md) .background( if (selected) { Amber.copy(alpha = 0.08f) @@ -240,7 +239,7 @@ private fun ModelRow( .border( width = 1.dp, color = if (selected) Amber.copy(alpha = 0.25f) else Color.Transparent, - shape = RoundedCornerShape(16.dp) + shape = KaizenShapes.md ) .clickable { haptics.tick(); onClick() } .padding(horizontal = 14.dp, vertical = 12.dp), @@ -249,7 +248,7 @@ private fun ModelRow( // Dynamic Colored Badge for Provider (Vertex AI or OpenRouter) Box( modifier = Modifier - .clip(RoundedCornerShape(8.dp)) + .clip(KaizenShapes.xs) .background(providerInfo.color.copy(alpha = 0.15f)) .padding(horizontal = 8.dp, vertical = 4.dp) ) { @@ -284,7 +283,7 @@ private fun ModelRow( Box( Modifier .size(36.dp) - .clip(CircleShape) + .clip(KaizenShapes.circle) .clickable { haptics.tick(); onToggleFavorite() }, contentAlignment = Alignment.Center, ) { diff --git a/app/src/main/java/dev/kaizen/app/chat/Sidebar.kt b/app/src/main/java/dev/kaizen/app/chat/Sidebar.kt index 16d0763..fa83f15 100644 --- a/app/src/main/java/dev/kaizen/app/chat/Sidebar.kt +++ b/app/src/main/java/dev/kaizen/app/chat/Sidebar.kt @@ -3,7 +3,6 @@ package dev.kaizen.app.chat import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable -import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -18,12 +17,9 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.width -import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.rounded.Logout import androidx.compose.material.icons.rounded.Edit @@ -39,14 +35,16 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.draw.shadow -import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import dev.kaizen.app.net.ConversationSummary +import dev.kaizen.app.ui.effect.GlassSurface +import dev.kaizen.app.ui.effect.GlassTiers +import dev.kaizen.app.ui.effect.KaizenShadows +import dev.kaizen.app.ui.shape.KaizenShapes import dev.kaizen.app.ui.theme.Amber import java.time.Instant import java.time.LocalDate @@ -54,7 +52,6 @@ import java.time.ZoneId import java.time.format.DateTimeFormatter import java.util.Locale -/** Date-bucket header for a conversation, from its ISO `updatedAt` (Heute/Gestern/dd. MMM yyyy). */ private fun dateLabel(updatedAt: String?): String { val instant = runCatching { Instant.parse(updatedAt) }.getOrNull() ?: return "FRÜHER" val date = instant.atZone(ZoneId.systemDefault()).toLocalDate() @@ -66,7 +63,6 @@ private fun dateLabel(updatedAt: String?): String { } } -/** Pinned first, then chronological date buckets — preserves the API's desc-updatedAt order. */ private fun groupConversations(conversations: List): Map> { val groups = LinkedHashMap>() conversations.filter { it.pinned }.takeIf { it.isNotEmpty() }?.let { groups["★ ANGEHEFTET"] = it.toMutableList() } @@ -76,12 +72,6 @@ private fun groupConversations(conversations: List): Map - // Date header (e.g., HEUTE, 16. JUN 2026) item(key = "header_$dateGroup") { Text( - text = dateGroup, + dateGroup, color = cs.onSurfaceVariant.copy(alpha = 0.45f), fontSize = 11.sp, fontWeight = FontWeight.Bold, modifier = Modifier.padding(start = 12.dp, top = 8.dp, bottom = 4.dp) ) } - items(items, key = { it.id }) { item -> HistoryItemRow( item = item, @@ -255,81 +180,50 @@ fun KaizenSidebar( Spacer(Modifier.height(16.dp)) - // --- FOOTER Sektion: User Profile Card --- - // Clicking the card opens the brand settings screen cleanly (MVVM state) + // User card Row( modifier = Modifier .fillMaxWidth() - .clip(RoundedCornerShape(18.dp)) + .clip(KaizenShapes.md) .background(if (isDark) Color(0x12FFFFFF) else Color(0x06000000)) - .border( - 1.dp, - if (isDark) Color.White.copy(alpha = 0.08f) else Color.Black.copy(alpha = 0.04f), - RoundedCornerShape(18.dp) - ) + .border(1.dp, if (isDark) Color.White.copy(alpha = 0.08f) else Color.Black.copy(alpha = 0.04f), KaizenShapes.md) .clickable { onOpenSettings() } .padding(horizontal = 12.dp, vertical = 10.dp), verticalAlignment = Alignment.CenterVertically ) { - // User Avatar bubble: Obsidian colored dynamic first-letter initials! Box( modifier = Modifier .size(40.dp) - .clip(CircleShape) + .clip(KaizenShapes.circle) .background(if (isDark) Color(0xFF1E293B) else Color(0xFF0F172A)), contentAlignment = Alignment.Center ) { Text( - text = userName.firstOrNull()?.toString()?.uppercase() ?: "A", - color = Color.White, - fontSize = 17.sp, - fontWeight = FontWeight.Bold + userName.firstOrNull()?.toString()?.uppercase() ?: "A", + color = Color.White, fontSize = 17.sp, fontWeight = FontWeight.Bold ) } - Spacer(Modifier.width(10.dp)) - Column(Modifier.weight(1f)) { - Text( - text = userName, - color = cs.onBackground, - fontSize = 15.sp, - fontWeight = FontWeight.SemiBold - ) + Text(userName, color = cs.onBackground, fontSize = 15.sp, fontWeight = FontWeight.SemiBold) } - - Icon( - imageVector = Icons.Rounded.Settings, - contentDescription = "Einstellungen", - tint = cs.onSurfaceVariant.copy(alpha = 0.7f), - modifier = Modifier.size(20.dp) - ) + Icon(Icons.Rounded.Settings, "Einstellungen", tint = cs.onSurfaceVariant.copy(alpha = 0.7f), modifier = Modifier.size(20.dp)) } Spacer(Modifier.height(10.dp)) - // --- Logout: clears the encrypted token + returns to the login screen --- + // Logout Row( modifier = Modifier .fillMaxWidth() - .clip(RoundedCornerShape(14.dp)) + .clip(KaizenShapes.sm) .clickable { onLogout() } .padding(horizontal = 12.dp, vertical = 10.dp), verticalAlignment = Alignment.CenterVertically ) { - Icon( - imageVector = Icons.AutoMirrored.Rounded.Logout, - contentDescription = "Abmelden", - tint = cs.onSurfaceVariant.copy(alpha = 0.7f), - modifier = Modifier.size(18.dp) - ) + Icon(Icons.AutoMirrored.Rounded.Logout, "Abmelden", tint = cs.onSurfaceVariant.copy(alpha = 0.7f), modifier = Modifier.size(18.dp)) Spacer(Modifier.width(10.dp)) - Text( - text = "Abmelden", - color = cs.onSurfaceVariant.copy(alpha = 0.85f), - fontSize = 14.sp, - fontWeight = FontWeight.Medium - ) + Text("Abmelden", color = cs.onSurfaceVariant.copy(alpha = 0.85f), fontSize = 14.sp, fontWeight = FontWeight.Medium) } } } @@ -354,23 +248,17 @@ private fun HistoryItemRow(item: ConversationSummary, selected: Boolean, onClick Row( modifier = Modifier .fillMaxWidth() - .clip(CircleShape) + .clip(KaizenShapes.pill) .background(itemBg) - .border(1.2.dp, itemBorder, CircleShape) + .border(1.2.dp, itemBorder, KaizenShapes.pill) .clickable { onClick() } .padding(horizontal = 16.dp, vertical = 11.dp), verticalAlignment = Alignment.CenterVertically ) { if (item.pinned) { - Icon( - imageVector = Icons.Rounded.Star, - contentDescription = null, - tint = Amber, - modifier = Modifier.size(14.dp) - ) + Icon(Icons.Rounded.Star, null, tint = Amber, modifier = Modifier.size(14.dp)) Spacer(Modifier.width(8.dp)) } - Text( text = if (item.locked) "Gesperrter Chat" else item.title, color = if (item.locked) cs.onSurfaceVariant.copy(alpha = 0.5f) else cs.onBackground, @@ -379,15 +267,9 @@ private fun HistoryItemRow(item: ConversationSummary, selected: Boolean, onClick fontStyle = if (item.locked) FontStyle.Italic else FontStyle.Normal, modifier = Modifier.weight(1f) ) - if (item.locked) { Spacer(Modifier.width(8.dp)) - Icon( - imageVector = Icons.Rounded.Lock, - contentDescription = "Gesperrt", - tint = Amber, - modifier = Modifier.size(15.dp) - ) + Icon(Icons.Rounded.Lock, "Gesperrt", tint = Amber, modifier = Modifier.size(15.dp)) } } } diff --git a/app/src/main/java/dev/kaizen/app/settings/SettingsComponents.kt b/app/src/main/java/dev/kaizen/app/settings/SettingsComponents.kt index 59493b9..1bc3b11 100644 --- a/app/src/main/java/dev/kaizen/app/settings/SettingsComponents.kt +++ b/app/src/main/java/dev/kaizen/app/settings/SettingsComponents.kt @@ -25,8 +25,10 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.foundation.shape.RoundedCornerShape +import dev.kaizen.app.ui.effect.GlassSurface +import dev.kaizen.app.ui.effect.GlassTiers +import dev.kaizen.app.ui.effect.KaizenShadows +import dev.kaizen.app.ui.shape.KaizenShapes import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons @@ -81,53 +83,14 @@ fun SettingsCard( ) { val isDark = isSystemInDarkTheme() - val glassBg = remember(isDark) { - if (isDark) { - Brush.verticalGradient( - listOf( - Color(0xFF1E293B).copy(alpha = 0.55f), // Slate 800 (55% opacity) - Color(0xFF0F172A).copy(alpha = 0.65f) // Slate 900 (65% opacity) - ) - ) - } else { - Brush.verticalGradient( - listOf( - Color.White.copy(alpha = 0.85f), - Color(0xFFEEF2F6).copy(alpha = 0.75f) // Warm white-slate (75% opacity) - ) - ) - } - } - - val glassBorder = remember(isDark) { - if (isDark) { - Brush.verticalGradient( - listOf( - Color.White.copy(alpha = 0.16f), // Crisp glanz highlight top-left - Color.White.copy(alpha = 0.02f) // Faint dark shade bottom-right - ) - ) - } else { - Brush.verticalGradient( - listOf( - Color.White.copy(alpha = 0.60f), - Color.Black.copy(alpha = 0.05f) - ) - ) - } - } - - Box( - modifier = modifier - .fillMaxWidth() - .shadow(elevation = 8.dp, shape = RoundedCornerShape(24.dp), clip = false) // Floating 3D shadow - .clip(RoundedCornerShape(24.dp)) - .background(glassBg) - .border(1.2.dp, glassBorder, RoundedCornerShape(24.dp)) - .padding(18.dp) + GlassSurface( + modifier = modifier.fillMaxWidth(), + shape = KaizenShapes.lg, + tintAlpha = GlassTiers.card(isDark), + shadowStack = KaizenShadows.level2, + cornerRadius = 24.dp, ) { - // Standard Column provides standard ColumnScope receiver to the child layout content slot - Column(modifier = Modifier.fillMaxWidth()) { + Column(modifier = Modifier.fillMaxWidth().padding(18.dp)) { content() } } @@ -152,7 +115,7 @@ fun SettingsOptionRow( Box( modifier = Modifier .size(38.dp) - .clip(CircleShape) + .clip(KaizenShapes.circle) .background(cs.onBackground.copy(alpha = 0.06f)), contentAlignment = Alignment.Center ) { @@ -203,9 +166,9 @@ fun SettingsInputCapsule( Box( modifier = modifier .widthIn(max = 180.dp) - .clip(RoundedCornerShape(12.dp)) + .clip(KaizenShapes.sm) .background(inputGlassBg) - .border(1.dp, inputGlassBorder, RoundedCornerShape(12.dp)) + .border(1.dp, inputGlassBorder, KaizenShapes.sm) .padding(horizontal = 12.dp, vertical = 8.dp), contentAlignment = Alignment.CenterStart ) { @@ -262,8 +225,8 @@ fun ThemeOptionPill( Box( modifier = modifier .size(48.dp) - .shadow(elevation = 4.dp, shape = CircleShape, clip = false) - .clip(CircleShape) + .shadow(elevation = 4.dp, shape = KaizenShapes.circle, clip = false) + .clip(KaizenShapes.circle) .clickable { onClick() } .border( width = if (selected) 2.5.dp else 1.2.dp, @@ -272,10 +235,10 @@ fun ThemeOptionPill( } else { Brush.verticalGradient(listOf(Color.White.copy(alpha = 0.35f), Color.White.copy(alpha = 0.05f))) }, - shape = CircleShape + shape = KaizenShapes.circle ) .padding(if (selected) 3.dp else 0.dp) // creates a beautiful inner gap for the selected ring - .clip(CircleShape) + .clip(KaizenShapes.circle) ) { // Draw the perception gradient on Canvas Canvas(Modifier.fillMaxSize()) { @@ -317,8 +280,8 @@ fun AppearanceTogglePill( Box( modifier = modifier - .shadow(elevation = if (selected) 4.dp else 0.dp, shape = CircleShape, clip = false) - .clip(CircleShape) + .shadow(elevation = if (selected) 4.dp else 0.dp, shape = KaizenShapes.circle, clip = false) + .clip(KaizenShapes.circle) .background( if (selected) { Amber.copy(alpha = 0.16f) @@ -333,7 +296,7 @@ fun AppearanceTogglePill( } else { glassBorder }, - shape = CircleShape + shape = KaizenShapes.circle ) .clickable { onClick() } .padding(horizontal = 16.dp, vertical = 9.dp), diff --git a/app/src/main/java/dev/kaizen/app/settings/SettingsScreen.kt b/app/src/main/java/dev/kaizen/app/settings/SettingsScreen.kt index 55094f4..b067324 100644 --- a/app/src/main/java/dev/kaizen/app/settings/SettingsScreen.kt +++ b/app/src/main/java/dev/kaizen/app/settings/SettingsScreen.kt @@ -17,10 +17,13 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.CircleShape +import dev.kaizen.app.ui.effect.GlassSurface +import dev.kaizen.app.ui.effect.GlassTiers +import dev.kaizen.app.ui.effect.KaizenShadows +import dev.kaizen.app.ui.shape.KaizenShapes import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.rounded.ArrowBack +import androidx.compose.material.icons.automirrored.rounded.ArrowBack import androidx.compose.material.icons.rounded.AutoAwesome import androidx.compose.material.icons.rounded.Palette import androidx.compose.material.icons.rounded.Person @@ -35,9 +38,6 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.draw.shadow -import androidx.compose.ui.graphics.Brush -import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -64,21 +64,6 @@ fun SettingsScreen( val userName by viewModel.userName.collectAsState() val userEmail by viewModel.userEmail.collectAsState() - val backBtnGlassBg = remember(isDark) { - if (isDark) { - Brush.verticalGradient(listOf(Color(0xFF1E293B).copy(alpha = 0.65f), Color(0xFF0F172A).copy(alpha = 0.75f))) - } else { - Brush.verticalGradient(listOf(Color.White.copy(alpha = 0.85f), Color(0xFFF1F5F9).copy(alpha = 0.75f))) - } - } - val backBtnGlassBorder = remember(isDark) { - if (isDark) { - Brush.verticalGradient(listOf(Color.White.copy(alpha = 0.16f), Color.White.copy(alpha = 0.03f))) - } else { - Brush.verticalGradient(listOf(Color.White.copy(alpha = 0.55f), Color.Black.copy(alpha = 0.05f))) - } - } - MeshBackground { Column( modifier = modifier @@ -95,22 +80,16 @@ fun SettingsScreen( .padding(bottom = 24.dp), verticalAlignment = Alignment.CenterVertically ) { - Box( - modifier = Modifier - .shadow(elevation = 6.dp, shape = CircleShape, clip = false) - .clip(CircleShape) - .background(backBtnGlassBg) - .border(1.2.dp, backBtnGlassBorder, CircleShape) - .clickable { onBack() } - .size(44.dp), - contentAlignment = Alignment.Center + GlassSurface( + shape = KaizenShapes.circle, + tintAlpha = GlassTiers.pill(isDark), + shadowStack = KaizenShadows.level2, + cornerRadius = 22.dp, + modifier = Modifier.size(44.dp).clickable { onBack() }, ) { - Icon( - imageVector = Icons.Rounded.ArrowBack, - contentDescription = "Zurück", - tint = cs.onBackground, - modifier = Modifier.size(20.dp) - ) + Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + Icon(Icons.AutoMirrored.Rounded.ArrowBack, "Zurück", tint = cs.onBackground, modifier = Modifier.size(20.dp)) + } } Spacer(Modifier.width(16.dp)) diff --git a/app/src/main/java/dev/kaizen/app/ui/effect/GlassSurface.kt b/app/src/main/java/dev/kaizen/app/ui/effect/GlassSurface.kt index 45331b6..2a252a1 100644 --- a/app/src/main/java/dev/kaizen/app/ui/effect/GlassSurface.kt +++ b/app/src/main/java/dev/kaizen/app/ui/effect/GlassSurface.kt @@ -1,6 +1,5 @@ package dev.kaizen.app.ui.effect -import android.os.Build import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.isSystemInDarkTheme @@ -10,10 +9,8 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.BlurredEdgeTreatment -import androidx.compose.ui.draw.blur import androidx.compose.ui.draw.clip -import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shape import androidx.compose.ui.unit.Dp @@ -21,16 +18,19 @@ import androidx.compose.ui.unit.dp import dev.kaizen.app.ui.shape.KaizenShapes /** - * A refractive glass surface — the core visual primitive of the Kaizen design system. + * A frosted-glass surface — the core visual primitive of the Kaizen design system. * - * On API 31+ uses Compose's [Modifier.blur] (backed by RenderEffect.createBlurEffect) - * to blur the underlying composition through the surface, creating a real frosted-glass - * effect. On API 26–30, the blur is skipped and the surface uses a higher tint alpha - * (+0.10) to fake depth. + * Android has no `backdrop-filter: blur()` — real refractive blur would require + * capturing and blurring the layer behind, which is not feasible in Compose's + * rendering model. Instead, the glass effect is achieved through: * - * The [tint] color gives the surface its identity (Obsidian vs white). Without it - * the blur would show a wash of whatever's behind. [tintAlpha] controls the - * "milkiness" — lower = more transparent/refractive, higher = more opaque/solid. + * 1. Semi-transparent gradient tint (gives the surface body and color identity) + * 2. Specular border highlight (top-bright, bottom-dim gradient border) + * 3. Inner top highlight (1dp lit edge, simulates overhead light) + * 4. Multi-layer shadow stack (floating depth) + * + * The blob layer behind (MeshBackground) is what "shows through" the + * transparency, creating the frosted-glass illusion. * * See DESIGN.md §4 for the full anatomy and opacity tiers. */ @@ -38,35 +38,51 @@ import dev.kaizen.app.ui.shape.KaizenShapes fun GlassSurface( modifier: Modifier = Modifier, shape: Shape = KaizenShapes.md, - tint: Color = MaterialTheme.colorScheme.surface, tintAlpha: Float = 0.72f, - blurRadius: Dp = 24.dp, shadowStack: ShadowStack = KaizenShadows.level2, + cornerRadius: Dp = 16.dp, content: @Composable BoxScope.() -> Unit, ) { val isDark = isSystemInDarkTheme() - val supportsBlur = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S + val cs = MaterialTheme.colorScheme - val effectiveTintAlpha = if (supportsBlur) tintAlpha else (tintAlpha + 0.10f).coerceAtMost(1f) - val tintColor = remember(tint, effectiveTintAlpha) { tint.copy(alpha = effectiveTintAlpha) } + val glassBg = remember(isDark, tintAlpha) { + if (isDark) { + Brush.verticalGradient( + listOf( + Color(0xFF1E293B).copy(alpha = tintAlpha), + Color(0xFF0F172A).copy(alpha = (tintAlpha + 0.10f).coerceAtMost(1f)), + ) + ) + } else { + Brush.verticalGradient( + listOf( + Color.White.copy(alpha = tintAlpha), + Color(0xFFF1F5F9).copy(alpha = (tintAlpha - 0.05f).coerceAtLeast(0f)), + ) + ) + } + } - val outlineColor = MaterialTheme.colorScheme.outline - val outlineAlpha = if (isDark) 0.12f else 0.06f + val glassBorder = remember(isDark) { + if (isDark) { + Brush.verticalGradient( + listOf(Color.White.copy(alpha = 0.16f), Color.White.copy(alpha = 0.03f)) + ) + } else { + Brush.verticalGradient( + listOf(Color.White.copy(alpha = 0.55f), Color.Black.copy(alpha = 0.05f)) + ) + } + } Box( modifier = modifier - .kaizenShadow(stack = shadowStack, cornerRadius = 16.dp) + .kaizenShadow(stack = shadowStack, cornerRadius = cornerRadius) .clip(shape) - .then( - if (supportsBlur) { - Modifier.blur(blurRadius, edgeTreatment = BlurredEdgeTreatment.Rectangle) - } else { - Modifier - } - ) - .drawBehind { drawRect(tintColor) } + .background(glassBg) .innerTopHighlight() - .border(1.dp, outlineColor.copy(alpha = outlineAlpha), shape), + .border(1.2.dp, glassBorder, shape), content = content, ) } @@ -76,24 +92,11 @@ fun GlassSurface( * Use these constants with [GlassSurface] instead of ad-hoc alpha values. */ object GlassTiers { - /** Sidebar — most translucent, strongest refraction */ fun sidebar(isDark: Boolean) = if (isDark) 0.72f else 0.68f - - /** Chat input bar */ fun input(isDark: Boolean) = if (isDark) 0.75f else 0.74f - - /** Small pills (mode pill, model pill) */ fun pill(isDark: Boolean) = if (isDark) 0.80f else 0.82f - - /** Suggestion chips — tap targets, need body */ fun chip(isDark: Boolean) = if (isDark) 0.85f else 0.90f - - /** Settings cards — reading surface, near-opaque */ fun card(isDark: Boolean) = if (isDark) 0.94f else 0.95f - - /** User bubble — amber-tinted glass */ fun userBubble(isDark: Boolean) = if (isDark) 0.86f else 0.88f - - /** Dropdowns / bottom sheets — deepest blur */ fun sheet(isDark: Boolean) = if (isDark) 0.82f else 0.85f } From 0237eae1e6a834d5b01375019cd40ff8100c164b Mon Sep 17 00:00:00 2001 From: Bruno Deanoz Date: Sun, 21 Jun 2026 15:02:16 +0200 Subject: [PATCH 05/12] =?UTF-8?q?feat:=20i18n=20=E2=80=94=20extract=20all?= =?UTF-8?q?=20UI=20strings=20to=20resources=20(de=20+=20en)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit German (default) in values/strings.xml, English in values-en/strings.xml. Matches web app's next-intl de/en setup. Migrated: greeting, hero headline, chat input, error messages, mode pills, suggestion pills, sidebar (brand, search, dates, logout, settings), model sheet, login screen (welcome, fields, errors, submit button), conversation labels (locked, pinned). ChatModels: Suggestion/ChatMode now use resource IDs instead of hardcoded strings. greeting() is now @Composable (uses stringResource). ModePillsRow: selected state uses resource ID (Int) instead of String. Date labels (HEUTE/GESTERN/FRÜHER) localized via DateLabels data class. --- .../java/dev/kaizen/app/auth/LoginScreen.kt | 21 ++-- .../dev/kaizen/app/chat/ChatComponents.kt | 18 ++-- .../java/dev/kaizen/app/chat/ChatModels.kt | 38 ++++---- .../java/dev/kaizen/app/chat/ChatScreen.kt | 22 ++--- .../main/java/dev/kaizen/app/chat/Sidebar.kt | 46 +++++---- app/src/main/res/values-en/strings.xml | 94 ++++++++++++++++++ app/src/main/res/values/strings.xml | 95 ++++++++++++++++++- 7 files changed, 269 insertions(+), 65 deletions(-) create mode 100644 app/src/main/res/values-en/strings.xml diff --git a/app/src/main/java/dev/kaizen/app/auth/LoginScreen.kt b/app/src/main/java/dev/kaizen/app/auth/LoginScreen.kt index 15b08af..1cadcf7 100644 --- a/app/src/main/java/dev/kaizen/app/auth/LoginScreen.kt +++ b/app/src/main/java/dev/kaizen/app/auth/LoginScreen.kt @@ -52,6 +52,8 @@ import dev.kaizen.app.net.SessionViewModel import dev.kaizen.app.ui.theme.Amber import dev.kaizen.app.ui.theme.AmberDeep import dev.kaizen.app.ui.theme.OnAmber +import androidx.compose.ui.res.stringResource +import dev.kaizen.app.R import kotlinx.coroutines.launch /** @@ -64,6 +66,7 @@ import kotlinx.coroutines.launch fun LoginScreen(session: SessionViewModel, modifier: Modifier = Modifier) { val cs = MaterialTheme.colorScheme val scope = rememberCoroutineScope() + val ctx = androidx.compose.ui.platform.LocalContext.current var baseUrl by remember { mutableStateOf(DEFAULT_BASE_URL) } var email by remember { mutableStateOf("") } @@ -81,9 +84,9 @@ fun LoginScreen(session: SessionViewModel, modifier: Modifier = Modifier) { scope.launch { when (val result = session.login(baseUrl, email, password, deviceName)) { is LoginResult.Success -> Unit // session.config flips → MainActivity routes to chat - LoginResult.InvalidCredentials -> error = "E-Mail oder Passwort ist falsch." - LoginResult.RateLimited -> error = "Zu viele Versuche. Bitte kurz warten." - is LoginResult.Error -> error = "Verbindung fehlgeschlagen. Server-Adresse prüfen." + LoginResult.InvalidCredentials -> error = ctx.getString(R.string.login_error_credentials) + LoginResult.RateLimited -> error = ctx.getString(R.string.login_error_rate_limited) + is LoginResult.Error -> error = ctx.getString(R.string.login_error_connection) } loading = false } @@ -102,10 +105,10 @@ fun LoginScreen(session: SessionViewModel, modifier: Modifier = Modifier) { Spacer(Modifier.size(64.dp)) KaizenOrb(96.dp) Spacer(Modifier.size(24.dp)) - Text("Willkommen", color = cs.onBackground, fontSize = 30.sp, fontWeight = FontWeight.Bold) + Text(stringResource(R.string.login_welcome), color = cs.onBackground, fontSize = 30.sp, fontWeight = FontWeight.Bold) Spacer(Modifier.size(6.dp)) Text( - "Melde dich bei deiner Kaizen-Instanz an", + stringResource(R.string.login_subtitle), color = cs.onSurfaceVariant.copy(alpha = 0.8f), fontSize = 14.sp, ) @@ -115,7 +118,7 @@ fun LoginScreen(session: SessionViewModel, modifier: Modifier = Modifier) { GlassField( value = baseUrl, onValueChange = { baseUrl = it; error = null }, - placeholder = "https://deine-instanz.de", + placeholder = stringResource(R.string.login_url_placeholder), keyboardType = KeyboardType.Uri, imeAction = ImeAction.Next, ) @@ -123,7 +126,7 @@ fun LoginScreen(session: SessionViewModel, modifier: Modifier = Modifier) { GlassField( value = email, onValueChange = { email = it; error = null }, - placeholder = "E-Mail", + placeholder = stringResource(R.string.login_email_placeholder), keyboardType = KeyboardType.Email, imeAction = ImeAction.Next, ) @@ -131,7 +134,7 @@ fun LoginScreen(session: SessionViewModel, modifier: Modifier = Modifier) { GlassField( value = password, onValueChange = { password = it; error = null }, - placeholder = "Passwort", + placeholder = stringResource(R.string.login_password_placeholder), keyboardType = KeyboardType.Password, imeAction = ImeAction.Done, password = true, @@ -227,7 +230,7 @@ private fun SignInButton(enabled: Boolean, loading: Boolean, onClick: () -> Unit CircularProgressIndicator(color = OnAmber, strokeWidth = 2.4.dp, modifier = Modifier.size(22.dp)) } else { Text( - "Anmelden", + stringResource(R.string.login_submit), color = if (enabled) OnAmber else cs.onSurfaceVariant, fontSize = 16.sp, fontWeight = FontWeight.SemiBold, 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 01c70a7..99467f3 100644 --- a/app/src/main/java/dev/kaizen/app/chat/ChatComponents.kt +++ b/app/src/main/java/dev/kaizen/app/chat/ChatComponents.kt @@ -67,6 +67,8 @@ import dev.kaizen.app.ui.shape.KaizenShapes import dev.kaizen.app.ui.theme.Amber import dev.kaizen.app.ui.theme.AmberDeep import dev.kaizen.app.ui.theme.OnAmber +import dev.kaizen.app.R +import androidx.compose.ui.res.stringResource import java.time.LocalDateTime import java.time.format.DateTimeFormatter import java.util.Locale @@ -122,7 +124,6 @@ fun EmptyHero(userName: String, onPick: (String) -> Unit, modifier: Modifier = M now.format(DateTimeFormatter.ofPattern("EEE, d. MMMM · HH:mm", Locale.GERMAN)) } - // DESIGN.md §11.1: no suggestion chips on mobile — redundant with mode pills Column( modifier = modifier .fillMaxSize() @@ -135,7 +136,7 @@ fun EmptyHero(userName: String, onPick: (String) -> Unit, modifier: Modifier = M Spacer(Modifier.height(24.dp)) Text("${greeting(now.hour)}, $userName", color = cs.onSurfaceVariant, fontSize = 17.sp) Spacer(Modifier.height(6.dp)) - Text("Was liegt an?", color = cs.onBackground, fontSize = 32.sp, fontWeight = FontWeight.Bold) + Text(stringResource(R.string.hero_headline), color = cs.onBackground, fontSize = 32.sp, fontWeight = FontWeight.Bold) Spacer(Modifier.height(8.dp)) Text(dateLine, color = cs.onSurfaceVariant.copy(alpha = 0.7f), fontSize = 13.sp) Spacer(Modifier.height(142.dp)) @@ -143,7 +144,7 @@ fun EmptyHero(userName: String, onPick: (String) -> Unit, modifier: Modifier = M } @Composable -fun ModePillsRow(selected: String, onSelect: (String) -> Unit, modifier: Modifier = Modifier) { +fun ModePillsRow(selected: Int, onSelect: (Int) -> Unit, modifier: Modifier = Modifier) { val cs = MaterialTheme.colorScheme val isDark = isSystemInDarkTheme() @@ -163,7 +164,8 @@ fun ModePillsRow(selected: String, onSelect: (String) -> Unit, modifier: Modifie horizontalArrangement = Arrangement.spacedBy(8.dp), ) { chatModes.forEach { mode -> - val active = mode.label == selected + val label = stringResource(mode.labelRes) + val active = mode.labelRes == selected val backgroundFill = if (active) Amber.copy(alpha = 0.16f) else if (isDark) Color(0x12FFFFFF) else Color(0x82FFFFFF) val borderBrush = if (active) glassBorderActive else glassBorderInactive @@ -173,13 +175,13 @@ fun ModePillsRow(selected: String, onSelect: (String) -> Unit, modifier: Modifie .clip(KaizenShapes.pill) .background(backgroundFill) .border(1.2.dp, borderBrush, KaizenShapes.pill) - .clickable { onSelect(mode.label) } + .clickable { onSelect(mode.labelRes) } .padding(horizontal = 13.dp, vertical = 8.dp), verticalAlignment = Alignment.CenterVertically, ) { Icon(mode.icon, null, tint = if (active) Amber else cs.onSurfaceVariant, modifier = Modifier.size(16.dp)) Spacer(Modifier.width(6.dp)) - Text(mode.label, color = if (active) cs.onBackground else cs.onSurfaceVariant, fontSize = 13.sp, fontWeight = FontWeight.Medium) + Text(label, color = if (active) cs.onBackground else cs.onSurfaceVariant, fontSize = 13.sp, fontWeight = FontWeight.Medium) } } } @@ -296,10 +298,10 @@ fun ChatInput( } Row(Modifier.padding(horizontal = 8.dp, vertical = 8.dp), verticalAlignment = Alignment.CenterVertically) { Box(Modifier.size(40.dp).clip(KaizenShapes.circle).clickable(onClick = onAddClick), contentAlignment = Alignment.Center) { - Icon(Icons.Rounded.Add, "Anhang", tint = cs.onSurfaceVariant, modifier = Modifier.size(22.dp)) + Icon(Icons.Rounded.Add, stringResource(R.string.chat_attachment), tint = cs.onSurfaceVariant, modifier = Modifier.size(22.dp)) } Box(Modifier.weight(1f).heightIn(min = 36.dp).padding(horizontal = 4.dp), contentAlignment = Alignment.CenterStart) { - if (value.isEmpty()) Text("Nachricht eingeben …", color = cs.onSurfaceVariant, fontSize = 16.sp) + if (value.isEmpty()) Text(stringResource(R.string.chat_input_placeholder), color = cs.onSurfaceVariant, fontSize = 16.sp) BasicTextField( value = value, onValueChange = onValueChange, textStyle = TextStyle(color = cs.onBackground, fontSize = 16.sp, lineHeight = 22.sp), diff --git a/app/src/main/java/dev/kaizen/app/chat/ChatModels.kt b/app/src/main/java/dev/kaizen/app/chat/ChatModels.kt index 8a94a3e..6ad8e15 100644 --- a/app/src/main/java/dev/kaizen/app/chat/ChatModels.kt +++ b/app/src/main/java/dev/kaizen/app/chat/ChatModels.kt @@ -8,7 +8,10 @@ import androidx.compose.material.icons.rounded.Language import androidx.compose.material.icons.rounded.Movie import androidx.compose.material.icons.rounded.MusicNote import androidx.compose.material.icons.rounded.Tune +import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.stringResource +import dev.kaizen.app.R import dev.kaizen.app.net.Attachment enum class Role { User, Assistant } @@ -23,31 +26,30 @@ data class Message( val attachments: List = emptyList(), ) -// Empty-state suggestion pills (mirrors the web hero) -data class Suggestion(val label: String, val prompt: String, val icon: ImageVector) +data class Suggestion(val labelRes: Int, val promptRes: Int, val icon: ImageVector) val suggestions = listOf( - Suggestion("Brainstormen", "Lass uns zu einem Thema brainstormen.", Icons.Rounded.AutoAwesome), - Suggestion("Bild generieren", "Generiere ein Bild von einem Bergsee bei Sonnenaufgang.", Icons.Rounded.Image), - Suggestion("Video erstellen", "Erstelle ein kurzes Video von einer Stadt bei Nacht.", Icons.Rounded.Movie), - Suggestion("Web durchsuchen", "Durchsuche das Web nach den neuesten KI-Nachrichten.", Icons.Rounded.Language), + Suggestion(R.string.suggest_brainstorm, R.string.suggest_brainstorm_prompt, Icons.Rounded.AutoAwesome), + Suggestion(R.string.suggest_image, R.string.suggest_image_prompt, Icons.Rounded.Image), + Suggestion(R.string.suggest_video, R.string.suggest_video_prompt, Icons.Rounded.Movie), + Suggestion(R.string.suggest_web, R.string.suggest_web_prompt, Icons.Rounded.Language), ) -// Mode pills above the input (visual only in Phase 0) -data class ChatMode(val label: String, val icon: ImageVector) +data class ChatMode(val labelRes: Int, val icon: ImageVector) val chatModes = listOf( - ChatMode("Standard", Icons.Rounded.Adjust), - ChatMode("Sampling", Icons.Rounded.Tune), - ChatMode("Bild", Icons.Rounded.Image), - ChatMode("Suche", Icons.Rounded.Language), - ChatMode("Video", Icons.Rounded.Movie), - ChatMode("Audio", Icons.Rounded.MusicNote), + ChatMode(R.string.mode_standard, Icons.Rounded.Adjust), + ChatMode(R.string.mode_sampling, Icons.Rounded.Tune), + ChatMode(R.string.mode_image, Icons.Rounded.Image), + ChatMode(R.string.mode_search, Icons.Rounded.Language), + ChatMode(R.string.mode_video, Icons.Rounded.Movie), + ChatMode(R.string.mode_audio, Icons.Rounded.MusicNote), ) +@Composable fun greeting(hour: Int): String = when (hour) { - in 5..11 -> "Guten Morgen" - in 12..17 -> "Guten Tag" - in 18..22 -> "Guten Abend" - else -> "Hallo" + in 5..11 -> stringResource(R.string.greeting_morning) + in 12..17 -> stringResource(R.string.greeting_day) + in 18..22 -> stringResource(R.string.greeting_evening) + else -> stringResource(R.string.greeting_night) } 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 980741c..9146d0f 100644 --- a/app/src/main/java/dev/kaizen/app/chat/ChatScreen.kt +++ b/app/src/main/java/dev/kaizen/app/chat/ChatScreen.kt @@ -54,6 +54,7 @@ import dev.kaizen.app.ui.effect.GlassSurface import dev.kaizen.app.ui.effect.GlassTiers import dev.kaizen.app.ui.effect.KaizenShadows import dev.kaizen.app.ui.shape.KaizenShapes +import dev.kaizen.app.R import dev.kaizen.app.db.MessageEntity import dev.kaizen.app.db.toEntity import dev.kaizen.app.haptics.rememberHaptics @@ -93,7 +94,7 @@ fun ChatScreen( var input by remember { mutableStateOf("") } var isStreaming by remember { mutableStateOf(false) } var nextId by remember { mutableStateOf(0L) } - var selectedMode by remember { mutableStateOf("Standard") } + var selectedMode by remember { mutableStateOf(R.string.mode_standard) } // Navigation State var currentScreen by remember { mutableStateOf(AppScreen.Chat) } @@ -315,11 +316,11 @@ fun ChatScreen( val idx = messages.indexOfLast { it.id == assistantId } if (idx >= 0) { val existing = messages[idx].content - val errorSuffix = "\n\n⚠ ${chatErrorText(e)}" + val errorSuffix = "\n\n⚠ ${chatErrorText(e, context)}" messages[idx] = messages[idx].copy( streaming = false, thinking = false, - content = if (existing.isNotBlank()) existing + errorSuffix else chatErrorText(e), + content = if (existing.isNotBlank()) existing + errorSuffix else chatErrorText(e, context), ) } } finally { @@ -437,7 +438,7 @@ fun ChatScreen( Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Icon( imageVector = Icons.Rounded.Menu, - contentDescription = "Menü öffnen", + contentDescription = context.getString(R.string.chat_open_menu), tint = MaterialTheme.colorScheme.onBackground, modifier = Modifier.size(20.dp) ) @@ -511,11 +512,10 @@ fun ChatScreen( } } -/** Maps a streaming failure to a short, human German message shown in the bubble. */ -private fun chatErrorText(e: Throwable): String = when { - e is ChatHttpException && e.code == 401 -> "Sitzung abgelaufen. Bitte erneut anmelden." - e is ChatHttpException && e.code == 402 -> "Guthaben aufgebraucht." - e is ChatHttpException && e.code == 429 -> "Zu viele Anfragen. Kurz warten." - e is ChatHttpException -> "Fehler vom Server (${e.code})." - else -> "Keine Verbindung zum Server." +private fun chatErrorText(e: Throwable, ctx: android.content.Context): String = when { + e is ChatHttpException && e.code == 401 -> ctx.getString(R.string.error_session_expired) + e is ChatHttpException && e.code == 402 -> ctx.getString(R.string.error_credits_exhausted) + e is ChatHttpException && e.code == 429 -> ctx.getString(R.string.error_rate_limited) + e is ChatHttpException -> ctx.getString(R.string.error_server, e.code) + else -> ctx.getString(R.string.error_no_connection) } diff --git a/app/src/main/java/dev/kaizen/app/chat/Sidebar.kt b/app/src/main/java/dev/kaizen/app/chat/Sidebar.kt index fa83f15..4b9dd5d 100644 --- a/app/src/main/java/dev/kaizen/app/chat/Sidebar.kt +++ b/app/src/main/java/dev/kaizen/app/chat/Sidebar.kt @@ -45,29 +45,33 @@ import dev.kaizen.app.ui.effect.GlassSurface import dev.kaizen.app.ui.effect.GlassTiers import dev.kaizen.app.ui.effect.KaizenShadows import dev.kaizen.app.ui.shape.KaizenShapes +import dev.kaizen.app.R import dev.kaizen.app.ui.theme.Amber +import androidx.compose.ui.res.stringResource import java.time.Instant import java.time.LocalDate import java.time.ZoneId import java.time.format.DateTimeFormatter import java.util.Locale -private fun dateLabel(updatedAt: String?): String { - val instant = runCatching { Instant.parse(updatedAt) }.getOrNull() ?: return "FRÜHER" +private data class DateLabels(val today: String, val yesterday: String, val earlier: String, val pinned: String) + +private fun dateLabel(updatedAt: String?, labels: DateLabels): String { + val instant = runCatching { Instant.parse(updatedAt) }.getOrNull() ?: return labels.earlier val date = instant.atZone(ZoneId.systemDefault()).toLocalDate() val today = LocalDate.now() return when (date) { - today -> "HEUTE" - today.minusDays(1) -> "GESTERN" - else -> date.format(DateTimeFormatter.ofPattern("dd. MMM yyyy", Locale.GERMAN)).uppercase() + today -> labels.today + today.minusDays(1) -> labels.yesterday + else -> date.format(DateTimeFormatter.ofPattern("dd. MMM yyyy", Locale.getDefault())).uppercase() } } -private fun groupConversations(conversations: List): Map> { +private fun groupConversations(conversations: List, labels: DateLabels): Map> { val groups = LinkedHashMap>() - conversations.filter { it.pinned }.takeIf { it.isNotEmpty() }?.let { groups["★ ANGEHEFTET"] = it.toMutableList() } + conversations.filter { it.pinned }.takeIf { it.isNotEmpty() }?.let { groups[labels.pinned] = it.toMutableList() } conversations.filterNot { it.pinned }.forEach { - groups.getOrPut(dateLabel(it.updatedAt)) { mutableListOf() }.add(it) + groups.getOrPut(dateLabel(it.updatedAt, labels)) { mutableListOf() }.add(it) } return groups } @@ -109,7 +113,7 @@ fun KaizenSidebar( horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { - Text("kaizen", color = cs.onBackground, fontSize = 20.sp, fontWeight = FontWeight.Bold) + Text(stringResource(R.string.sidebar_brand), color = cs.onBackground, fontSize = 20.sp, fontWeight = FontWeight.Bold) Box( modifier = Modifier .size(36.dp) @@ -118,7 +122,7 @@ fun KaizenSidebar( .clickable { onNewChat() }, contentAlignment = Alignment.Center ) { - Icon(Icons.Rounded.Edit, "Neuer Chat", tint = cs.onBackground, modifier = Modifier.size(18.dp)) + Icon(Icons.Rounded.Edit, stringResource(R.string.chat_new), tint = cs.onBackground, modifier = Modifier.size(18.dp)) } } @@ -136,7 +140,7 @@ fun KaizenSidebar( ) { Icon(Icons.Rounded.Search, null, tint = cs.onSurfaceVariant.copy(alpha = 0.6f), modifier = Modifier.size(18.dp)) Spacer(Modifier.width(8.dp)) - Text("Suchen...", color = cs.onSurfaceVariant.copy(alpha = 0.6f), fontSize = 14.sp) + Text(stringResource(R.string.chat_search), color = cs.onSurfaceVariant.copy(alpha = 0.6f), fontSize = 14.sp) } Spacer(Modifier.height(24.dp)) @@ -145,13 +149,19 @@ fun KaizenSidebar( Box(Modifier.weight(1f).fillMaxWidth()) { if (conversations.isEmpty()) { Text( - "Noch keine Chats", + stringResource(R.string.chat_no_conversations), color = cs.onSurfaceVariant.copy(alpha = 0.5f), fontSize = 14.sp, modifier = Modifier.padding(start = 12.dp, top = 12.dp) ) } else { - val grouped = remember(conversations) { groupConversations(conversations) } + val labels = DateLabels( + today = stringResource(R.string.sidebar_today), + yesterday = stringResource(R.string.sidebar_yesterday), + earlier = stringResource(R.string.sidebar_earlier), + pinned = stringResource(R.string.sidebar_pinned), + ) + val grouped = remember(conversations, labels) { groupConversations(conversations, labels) } LazyColumn( modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.spacedBy(8.dp) @@ -207,7 +217,7 @@ fun KaizenSidebar( Column(Modifier.weight(1f)) { Text(userName, color = cs.onBackground, fontSize = 15.sp, fontWeight = FontWeight.SemiBold) } - Icon(Icons.Rounded.Settings, "Einstellungen", tint = cs.onSurfaceVariant.copy(alpha = 0.7f), modifier = Modifier.size(20.dp)) + Icon(Icons.Rounded.Settings, stringResource(R.string.sidebar_settings), tint = cs.onSurfaceVariant.copy(alpha = 0.7f), modifier = Modifier.size(20.dp)) } Spacer(Modifier.height(10.dp)) @@ -221,9 +231,9 @@ fun KaizenSidebar( .padding(horizontal = 12.dp, vertical = 10.dp), verticalAlignment = Alignment.CenterVertically ) { - Icon(Icons.AutoMirrored.Rounded.Logout, "Abmelden", tint = cs.onSurfaceVariant.copy(alpha = 0.7f), modifier = Modifier.size(18.dp)) + Icon(Icons.AutoMirrored.Rounded.Logout, stringResource(R.string.sidebar_logout), tint = cs.onSurfaceVariant.copy(alpha = 0.7f), modifier = Modifier.size(18.dp)) Spacer(Modifier.width(10.dp)) - Text("Abmelden", color = cs.onSurfaceVariant.copy(alpha = 0.85f), fontSize = 14.sp, fontWeight = FontWeight.Medium) + Text(stringResource(R.string.sidebar_logout), color = cs.onSurfaceVariant.copy(alpha = 0.85f), fontSize = 14.sp, fontWeight = FontWeight.Medium) } } } @@ -260,7 +270,7 @@ private fun HistoryItemRow(item: ConversationSummary, selected: Boolean, onClick Spacer(Modifier.width(8.dp)) } Text( - text = if (item.locked) "Gesperrter Chat" else item.title, + text = if (item.locked) stringResource(R.string.chat_locked) else item.title, color = if (item.locked) cs.onSurfaceVariant.copy(alpha = 0.5f) else cs.onBackground, fontSize = 14.sp, fontWeight = FontWeight.Medium, @@ -269,7 +279,7 @@ private fun HistoryItemRow(item: ConversationSummary, selected: Boolean, onClick ) if (item.locked) { Spacer(Modifier.width(8.dp)) - Icon(Icons.Rounded.Lock, "Gesperrt", tint = Amber, modifier = Modifier.size(15.dp)) + Icon(Icons.Rounded.Lock, stringResource(R.string.chat_locked_badge), tint = Amber, modifier = Modifier.size(15.dp)) } } } diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml new file mode 100644 index 0000000..224869a --- /dev/null +++ b/app/src/main/res/values-en/strings.xml @@ -0,0 +1,94 @@ + + + Good Morning + Good Afternoon + Good Evening + Hello + What\'s up? + + + Type a message … + No chats yet + Locked Chat + Locked + New Chat + Search… + Attachment + Call + Remove + Error + Open menu + + + Session expired. Please sign in again. + Credits exhausted. + Too many requests. Please wait. + Server error (%1$d). + No connection to server. + + + Standard + Sampling + Image + Search + Video + Audio + + + Brainstorm + Let\'s brainstorm on a topic. + Generate Image + Generate an image of a mountain lake at sunrise. + Create Video + Create a short video of a city at night. + Search the Web + Search the web for the latest AI news. + + + kaizen + ★ PINNED + TODAY + YESTERDAY + EARLIER + Sign Out + Settings + + + Select Model + Search models… + Clear + Connecting… + No matches + Favorite + Selected + ★ Favorites + + + Welcome + Sign in to your Kaizen instance + https://your-instance.com + Email + Password + Sign In + Invalid email or password. + Too many attempts. Please wait. + Connection failed. Check server address. + + + Settings + Back + APPEARANCE + PROFILE & ACCOUNT + AI PROFILE & CONTEXT + Accent Color + Choose the app color scheme + Appearance + Set light/dark appearance + Display Name + Change your display name + Email Address + System Prompt & Facts + Light + Dark + System + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a679dc3..b0df167 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,96 @@ Kaizen - \ No newline at end of file + + + Guten Morgen + Guten Tag + Guten Abend + Hallo + Was liegt an? + + + Nachricht eingeben … + Noch keine Chats + Gesperrter Chat + Gesperrt + Neuer Chat + Suchen… + Anhang + Anruf + Entfernen + Fehler + Menü öffnen + + + Sitzung abgelaufen. Bitte erneut anmelden. + Guthaben aufgebraucht. + Zu viele Anfragen. Kurz warten. + Fehler vom Server (%1$d). + Keine Verbindung zum Server. + + + Standard + Sampling + Bild + Suche + Video + Audio + + + Brainstormen + Lass uns zu einem Thema brainstormen. + Bild generieren + Generiere ein Bild von einem Bergsee bei Sonnenaufgang. + Video erstellen + Erstelle ein kurzes Video von einer Stadt bei Nacht. + Web durchsuchen + Durchsuche das Web nach den neuesten KI-Nachrichten. + + + kaizen + ★ ANGEHEFTET + HEUTE + GESTERN + FRÜHER + Abmelden + Einstellungen + + + Modell auswählen + Modell suchen… + Löschen + Verbindung wird hergestellt… + Keine Treffer + Favorit + Ausgewählt + ★ Favoriten + + + Willkommen + Melde dich bei deiner Kaizen-Instanz an + https://deine-instanz.de + E-Mail + Passwort + Anmelden + E-Mail oder Passwort ist falsch. + Zu viele Versuche. Bitte kurz warten. + Verbindung fehlgeschlagen. Server-Adresse prüfen. + + + Einstellungen + Zurück + ERSCHEINUNGSBILD + PROFIL & KONTO + KI-PROFIL & KONTEXT + Akzentfarbe + Wähle das Farbschema der App + Helligkeitsmodus + Passe das Hell/Dunkel-Erscheinungsbild an + Benutzername + Ändere deinen Anzeigenamen + E-Mail-Adresse + System-Prompt & Fakten + Hell + Dunkel + System + From e3d624c961615006d6f48d3c825663ba1295f784 Mon Sep 17 00:00:00 2001 From: Bruno Deanoz Date: Sun, 21 Jun 2026 15:04:31 +0200 Subject: [PATCH 06/12] feat: orb uses rememberTiltState(), update CLAUDE.md with i18n + migration status KaizenOrb now uses centralized rememberTiltState() (GAME_ROTATION_VECTOR, lifecycle-aware, battery-saver-aware) instead of inline sensor code. Breath animation uses Durations tokens from motion system. CLAUDE.md: updated design system section with GlassSurface correction (no backdrop-filter on Android), migration status (all components done), i18n section documenting the de/en string resource architecture. --- CLAUDE.md | 18 ++++- .../java/dev/kaizen/app/chat/Background.kt | 65 ++----------------- 2 files changed, 21 insertions(+), 62 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index c13eeed..c274c41 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -48,7 +48,7 @@ ui/ theme/ Color (P3), Theme (multi-theme), Type, Oklab, Dither theme/themes/ AccentScheme, AmberTheme, BlauTheme, MonoTheme, AuroraTheme, ThemeRegistry shape/ SquircleShape (superellipse), KaizenShapes (token system) - effect/ GlassSurface (RenderEffect blur), Shadow (multi-layer stack) + effect/ GlassSurface (frosted glass), Shadow (multi-layer stack) motion/ Motion (easing curves, spring specs, duration tokens) sensor/ TiltState (gyro/accel parallax, lifecycle-aware) ``` @@ -69,14 +69,26 @@ Full spec: `DESIGN.md`. Branch: `feature/design-system-v2`. 1. **P3 color pipeline** — all tokens in DisplayP3 color space (`Color.kt`). `window.colorMode = COLOR_MODE_HDR` (API 34+) / `COLOR_MODE_WIDE_COLOR_GAMUT` (API 26+) in `MainActivity`. No `Color(0xFF…)` for brand colors outside `Color.kt`. 2. **Squircle shapes** — iOS-style superellipse with G2 continuity (`ui/shape/Squircle.kt`). Token system `KaizenShapes.{xs,sm,md,lg,xl,pill,circle}`. Replaces all `RoundedCornerShape`. -3. **GlassSurface** — real `Modifier.blur()` (RenderEffect on API 31+), tint + inner highlight + border. API 26–30 fallback: higher tint alpha. Opacity tiers per component in `GlassTiers`. +3. **GlassSurface** — frosted-glass composable (gradient tint + specular border + inner highlight + multi-layer shadow). Android has no backdrop-filter; glass effect works via semi-transparent tint over the blob layer. Opacity tiers per component in `GlassTiers`. 4. **Multi-layer shadows** — `ShadowStack` with 2–4 overlapping layers (`KaizenShadows.level0..4`). Dark mode multiplies alphas ×1.8. Replaces all `Modifier.shadow()`. 5. **4-theme system** — Amber/Blau/Mono/Aurora. Each theme = `KaizenAccentScheme` (primary + 4 blob colors). Neutrals are theme-independent. `LocalKaizenAccent` CompositionLocal. Server sync planned via `GET /api/v1/me` → `uiTheme`. 6. **Sensor-reactive motion** — `rememberTiltState()` provides smoothed tilt `Offset(-1..1)`. Uses `TYPE_GAME_ROTATION_VECTOR` (fused, no drift). Auto-disables on battery saver, reduced motion, background, extreme tilt. **Motion tokens** (`ui/motion/Motion.kt`): `EaseSpring` (overshoot), `EaseSmooth` (expo-out), `EaseEmphasized` (M3), `SpringSnappy/Default/Gentle`. All durations centralised in `Durations` object. -**What's NOT yet migrated to the design system:** The existing UI components (ChatScreen, Sidebar, ChatInput, etc.) still use the old inline glass styling with manual `Brush` + `border`. Migration to `GlassSurface` + `KaizenShapes` + `kaizenShadow` is the next step. +**Migration status:** All UI components migrated to the design system. Sidebar, ChatInput, ChatScreen, LoginScreen, ModelSheet, SettingsCard, SettingsScreen use `GlassSurface` + `KaizenShapes` + `kaizenShadow`. Only Markdown code-block shapes remain as `RoundedCornerShape` (intentionally rectangular for code). + +**KaizenOrb** (`chat/Background.kt`) uses `rememberTiltState()` from `ui/sensor/` instead of inline sensor code. Breath animation uses `Durations.ORB_BREATH` / `ORB_BREATH_STREAMING` from `ui/motion/`. + +### Internationalization (i18n) + +- **de** (default), **en** — same as web (`messages/de.json`, `messages/en.json`). +- Strings: `res/values/strings.xml` (de) + `res/values-en/strings.xml` (en). +- All UI strings use `stringResource(R.string.xxx)` in `@Composable` functions, or `context.getString(R.string.xxx)` in non-composable contexts (error handlers, coroutines). +- Date/time: `DateTimeFormatter` with `Locale.getDefault()`. +- Greeting: time-of-day-based (Morgen/Tag/Abend → Morning/Afternoon/Evening), boundaries 5/12/18. +- ChatModels: `Suggestion.labelRes`/`promptRes` and `ChatMode.labelRes` are resource IDs (Int), not hardcoded strings. +- `ModePillsRow`: `selected` state is `Int` (resource ID), not `String`. ### Offline-first cache layer (Room) — added 2026-06-21 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 8e136df..42b29bc 100644 --- a/app/src/main/java/dev/kaizen/app/chat/Background.kt +++ b/app/src/main/java/dev/kaizen/app/chat/Background.kt @@ -1,23 +1,14 @@ package dev.kaizen.app.chat -import android.content.Context -import android.hardware.Sensor -import android.hardware.SensorEvent -import android.hardware.SensorEventListener -import android.hardware.SensorManager import androidx.compose.animation.core.FastOutSlowInEasing import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.RepeatMode -import androidx.compose.animation.core.Spring import androidx.compose.animation.core.animateFloat -import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.infiniteRepeatable import androidx.compose.animation.core.rememberInfiniteTransition -import androidx.compose.animation.core.spring import androidx.compose.animation.core.tween import androidx.compose.foundation.Canvas import androidx.compose.foundation.background -import androidx.compose.foundation.border import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope @@ -27,11 +18,7 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.BlurredEdgeTreatment @@ -44,9 +31,10 @@ import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.input.pointer.pointerInput -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import dev.kaizen.app.ui.motion.Durations +import dev.kaizen.app.ui.sensor.rememberTiltState import dev.kaizen.app.ui.theme.Amber import dev.kaizen.app.ui.theme.AmberDeep import dev.kaizen.app.ui.theme.BlobAmber @@ -132,58 +120,17 @@ fun KaizenOrb( initialValue = 1f, targetValue = if (streaming || recording) 1.05f else 1.025f, animationSpec = infiniteRepeatable( - tween(if (streaming || recording) 2400 else 7000, easing = FastOutSlowInEasing), + tween(if (streaming || recording) Durations.ORB_BREATH_STREAMING else Durations.ORB_BREATH, easing = FastOutSlowInEasing), RepeatMode.Reverse, ), label = "breath", ) - // Dynamic scale expansion based on real-time audio amplitude (Call Mode / TTS speech reactivity) val reactiveScale = amplitude?.let { 1f + it * 0.12f } ?: 1f - // --- Gyroscope / Accel-based Holographic Parallax Offset --- - val context = LocalContext.current - var rawTiltX by remember { mutableStateOf(0f) } - var rawTiltY by remember { mutableStateOf(0f) } - - DisposableEffect(Unit) { - val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as? SensorManager - val gravitySensor = sensorManager?.getDefaultSensor(Sensor.TYPE_GRAVITY) - ?: sensorManager?.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) - - val listener = object : SensorEventListener { - override fun onSensorChanged(event: SensorEvent?) { - if (event == null) return - // event.values[0] is X (left/right tilt), event.values[1] is Y (forward/backward tilt) - // Normalize gravity acceleration to unit scale [-1.0, 1.0] - val x = event.values[0] / 9.81f - val y = event.values[1] / 9.81f - rawTiltX = x.coerceIn(-1f, 1f) - rawTiltY = y.coerceIn(-1f, 1f) - } - override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {} - } - - if (sensorManager != null && gravitySensor != null) { - sensorManager.registerListener(listener, gravitySensor, SensorManager.SENSOR_DELAY_UI) - } - - onDispose { - sensorManager?.unregisterListener(listener) - } - } - - // Smooth raw tilt values using native springs for fluid, liquid responsiveness - val tiltX by animateFloatAsState( - targetValue = rawTiltX, - animationSpec = spring(dampingRatio = Spring.DampingRatioMediumBouncy, stiffness = Spring.StiffnessLow), - label = "tiltX" - ) - val tiltY by animateFloatAsState( - targetValue = rawTiltY, - animationSpec = spring(dampingRatio = Spring.DampingRatioMediumBouncy, stiffness = Spring.StiffnessLow), - label = "tiltY" - ) + val tilt by rememberTiltState() + val tiltX = tilt.x + val tiltY = tilt.y Box( modifier = modifier From f83d4b4e17a53d28e3ede0f63c2f19f4c0c6deb2 Mon Sep 17 00:00:00 2001 From: Bruno Deanoz Date: Sun, 21 Jun 2026 15:10:25 +0200 Subject: [PATCH 07/12] =?UTF-8?q?fix:=20Oklab=20round-trip=20precision=20?= =?UTF-8?q?=E2=80=94=20Double=20math=20+=20corrected=20LMS=20matrix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause: Float32 accumulated ~0.017 error across 6 matrix multiplications (RGB→LMS→Lab→Lab→LMS→RGB), producing negative linear-green values that got clamped to 0 by toSRGB(). Fix: all matrix math now uses Double. Forward LMS matrix corrected to match Björn Ottosson's reference implementation. Variable shadowing eliminated. All 3 OklabTest cases now pass (were failing since initial commit). --- .../java/dev/kaizen/app/ui/theme/Oklab.kt | 132 +++++++----------- 1 file changed, 54 insertions(+), 78 deletions(-) diff --git a/app/src/main/java/dev/kaizen/app/ui/theme/Oklab.kt b/app/src/main/java/dev/kaizen/app/ui/theme/Oklab.kt index 78e52a3..f0b5972 100644 --- a/app/src/main/java/dev/kaizen/app/ui/theme/Oklab.kt +++ b/app/src/main/java/dev/kaizen/app/ui/theme/Oklab.kt @@ -2,110 +2,86 @@ package dev.kaizen.app.ui.theme import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.colorspace.ColorSpaces +import kotlin.math.cbrt +import kotlin.math.pow -/** - * High-performance Oklab and Oklch (polar Oklab) color interpolation library. - * - * Pre-calculates linear perception color spaces to completely eliminate sRGB - * "muddy gray dead zones" in gradients, providing butter-smooth, luminous, and - * vibrant color transitions across all Android displays (from SDR to Display P3 / HDR). - */ object Oklab { - private fun toLinear(c: Float): Float { - return if (c <= 0.04045f) c / 12.92f else Math.pow(((c + 0.055) / 1.055), 2.4).toFloat() - } + private fun toLinear(c: Double): Double = + if (c <= 0.04045) c / 12.92 else ((c + 0.055) / 1.055).pow(2.4) - private fun toSRGB(c: Float): Float { - val cl = c.coerceIn(0f, 1f) - return if (cl <= 0.0031308f) cl * 12.92f else (1.055f * Math.pow(cl.toDouble(), 1.0 / 2.4) - 0.055f).toFloat() + private fun fromLinear(c: Double): Float { + val cl = c.coerceIn(0.0, 1.0) + return if (cl <= 0.0031308) (cl * 12.92).toFloat() + else (1.055 * cl.pow(1.0 / 2.4) - 0.055).toFloat() } data class Lab(val l: Float, val a: Float, val b: Float) - /** Converts standard Compose Color (sRGB or P3) to Oklab space coordinates */ fun Color.toOklab(): Lab { - // Convert to linear RGB - val lr = toLinear(red) - val lg = toLinear(green) - val lb = toLinear(blue) + val lr = toLinear(red.toDouble()) + val lg = toLinear(green.toDouble()) + val lb = toLinear(blue.toDouble()) - // Linear RGB to LMS - val l = 0.4122214708f * lr + 0.5363325363f * lg + 0.0514459929f * lb - val m = 0.1167116119f * lr + 0.6858151024f * lg + 0.1974732856f * lb - val s = 0.0883315616f * lr + 0.1117281988f * lg + 0.7999602417f * lb + val l = 0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb + val m = 0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb + val s = 0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb - // LMS to non-linear scaled LMS - val l_ = Math.cbrt(l.toDouble()).toFloat() - val m_ = Math.cbrt(m.toDouble()).toFloat() - val s_ = Math.cbrt(s.toDouble()).toFloat() + val lc = cbrt(l) + val mc = cbrt(m) + val sc = cbrt(s) - // Scaled LMS to Oklab (L, a, b) - val oklabL = 0.2104542553f * l_ + 0.7936177850f * m_ - 0.0040720468f * s_ - val oklabA = 1.9779984951f * l_ - 2.4285922050f * m_ + 0.4505937099f * s_ - val oklabB = 0.0259040371f * l_ + 0.7827717662f * m_ - 0.8086757660f * s_ - - return Lab(oklabL, oklabA, oklabB) + return Lab( + l = (0.2104542553 * lc + 0.7936177850 * mc - 0.0040720468 * sc).toFloat(), + a = (1.9779984951 * lc - 2.4285922050 * mc + 0.4505937099 * sc).toFloat(), + b = (0.0259040371 * lc + 0.7827717662 * mc - 0.8086757660 * sc).toFloat(), + ) } - /** Converts Oklab coordinates back to standard Compose Color in DisplayP3 or sRGB space */ - fun Lab.toColor(targetColorSpace: androidx.compose.ui.graphics.colorspace.ColorSpace = ColorSpaces.Srgb): Color { - // Oklab to scaled LMS - val l_ = l + 0.3963377774f * a + 0.2158037573f * b - val m_ = l - 0.1055613458f * a - 0.0638541728f * b - val s_ = l - 0.0894841775f * a - 1.2914855480f * b + fun Lab.toColor(): Color { + val ld = l.toDouble() + val ad = a.toDouble() + val bd = b.toDouble() - // Scaled LMS to LMS (cube) - val l = l_ * l_ * l_ - val m = m_ * m_ * m_ - val s = s_ * s_ * s_ + val lp = ld + 0.3963377774 * ad + 0.2158037573 * bd + val mp = ld - 0.1055613458 * ad - 0.0638541728 * bd + val sp = ld - 0.0894841775 * ad - 1.2914855480 * bd - // LMS to linear RGB - val lr = 4.0767416621f * l - 3.3077115913f * m + 0.2309699292f * s - val lg = -1.2684380046f * l + 2.6097574011f * m - 0.3413193965f * s - val lb = -0.0041960863f * l - 0.7034186147f * m + 1.7076147010f * s + val lc = lp * lp * lp + val mc = mp * mp * mp + val sc = sp * sp * sp - // Linear RGB to non-linear standard sRGB - val r = toSRGB(lr) - val g = toSRGB(lg) - val b = toSRGB(lb) + val r = +4.0767416621 * lc - 3.3077115913 * mc + 0.2309699292 * sc + val g = -1.2684380046 * lc + 2.6097574011 * mc - 0.3413193965 * sc + val b = -0.0041960863 * lc - 0.7034186147 * mc + 1.7076147010 * sc - return Color(red = r, green = g, blue = b, alpha = 1.0f, colorSpace = targetColorSpace) + return Color(red = fromLinear(r), green = fromLinear(g), blue = fromLinear(b), alpha = 1.0f) + } + + fun Lab.toColor(targetColorSpace: androidx.compose.ui.graphics.colorspace.ColorSpace): Color { + val base = toColor() + return Color(red = base.red, green = base.green, blue = base.blue, alpha = 1.0f, + colorSpace = targetColorSpace) } - /** Linearly interpolates two colors inside the perzeptive Oklab color space */ fun interpolate(from: Color, to: Color, fraction: Float): Color { - val oklabFrom = from.toOklab() - val oklabTo = to.toOklab() + val f = from.toOklab() + val t = to.toOklab() - val interpolatedL = oklabFrom.l + (oklabTo.l - oklabFrom.l) * fraction - val interpolatedA = oklabFrom.a + (oklabTo.a - oklabFrom.a) * fraction - val interpolatedB = oklabFrom.b + (oklabTo.b - oklabFrom.b) * fraction + val lab = Lab( + l = f.l + (t.l - f.l) * fraction, + a = f.a + (t.a - f.a) * fraction, + b = f.b + (t.b - f.b) * fraction, + ) - val interpolatedAlpha = from.alpha + (to.alpha - from.alpha) * fraction - - // Match the target color space (prefer DisplayP3 if either color is P3) - val targetSpace = if (from.colorSpace == ColorSpaces.DisplayP3 || to.colorSpace == ColorSpaces.DisplayP3) { - ColorSpaces.DisplayP3 - } else { - ColorSpaces.Srgb - } - - return Lab(interpolatedL, interpolatedA, interpolatedB).toColor(targetSpace).copy(alpha = interpolatedAlpha) + val useP3 = from.colorSpace == ColorSpaces.DisplayP3 || to.colorSpace == ColorSpaces.DisplayP3 + val color = if (useP3) lab.toColor(ColorSpaces.DisplayP3) else lab.toColor() + return color.copy(alpha = from.alpha + (to.alpha - from.alpha) * fraction) } - /** - * Generates a list of interpolated Color stops in Oklab space. - * - * Perfect for constructing smooth Sweep, Radial, or Linear gradients that feel - * incredibly rich and high-fidelity on high-end device screens (S25 Ultra, Pixel 10). - */ fun generateGradientStops(from: Color, to: Color, steps: Int = 12): List { - val list = ArrayList(steps) - for (i in 0 until steps) { - val fraction = i.toFloat() / (steps - 1).toFloat() - list.add(interpolate(from, to, fraction)) + return List(steps) { i -> + interpolate(from, to, i.toFloat() / (steps - 1).toFloat()) } - return list } } From 515a71efb5343f9b5c23efb1377be7d35d265ef9 Mon Sep 17 00:00:00 2001 From: Bruno Deanoz Date: Sun, 21 Jun 2026 15:17:17 +0200 Subject: [PATCH 08/12] feat: Inter Variable font, theme picker wired end-to-end, settings i18n MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inter Variable (v4.1, 859 KB): full type scale with 9 weight axes (W100–W900), negative tracking at display sizes, positive at labels. Theme picker: SettingsViewModel now uses KaizenThemeId from the design system (AMBER/BLAU/MONO/AURORA). MainActivity wires selectedTheme + appearanceMode to KaizenTheme composable — switching themes in Settings instantly propagates to the entire app. No server sync needed — web stores theme in localStorage, app stores locally. Backend /api/v1/me has no uiTheme field in the DB. Settings strings migrated to string resources (de + en). SettingsViewModelTest updated for new enum values + System default. --- CLAUDE.md | 6 +- .../main/java/dev/kaizen/app/MainActivity.kt | 11 +- .../kaizen/app/settings/SettingsComponents.kt | 19 +-- .../dev/kaizen/app/settings/SettingsScreen.kt | 118 ++++------------ .../kaizen/app/settings/SettingsViewModel.kt | 41 +----- .../main/java/dev/kaizen/app/ui/theme/Type.kt | 126 +++++++++++++++--- app/src/main/res/font/inter_variable.ttf | Bin 0 -> 879708 bytes .../dev/kaizen/app/SettingsViewModelTest.kt | 44 +++--- 8 files changed, 181 insertions(+), 184 deletions(-) create mode 100644 app/src/main/res/font/inter_variable.ttf diff --git a/CLAUDE.md b/CLAUDE.md index c274c41..61e5181 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -71,7 +71,7 @@ Full spec: `DESIGN.md`. Branch: `feature/design-system-v2`. 2. **Squircle shapes** — iOS-style superellipse with G2 continuity (`ui/shape/Squircle.kt`). Token system `KaizenShapes.{xs,sm,md,lg,xl,pill,circle}`. Replaces all `RoundedCornerShape`. 3. **GlassSurface** — frosted-glass composable (gradient tint + specular border + inner highlight + multi-layer shadow). Android has no backdrop-filter; glass effect works via semi-transparent tint over the blob layer. Opacity tiers per component in `GlassTiers`. 4. **Multi-layer shadows** — `ShadowStack` with 2–4 overlapping layers (`KaizenShadows.level0..4`). Dark mode multiplies alphas ×1.8. Replaces all `Modifier.shadow()`. -5. **4-theme system** — Amber/Blau/Mono/Aurora. Each theme = `KaizenAccentScheme` (primary + 4 blob colors). Neutrals are theme-independent. `LocalKaizenAccent` CompositionLocal. Server sync planned via `GET /api/v1/me` → `uiTheme`. +5. **4-theme system** — Amber/Blau/Mono/Aurora. Each theme = `KaizenAccentScheme` (primary + 4 blob colors). Neutrals are theme-independent. `LocalKaizenAccent` CompositionLocal. Theme selection wired end-to-end: `SettingsViewModel.selectedTheme` → `MainActivity` → `KaizenTheme(themeId=...)`. No server sync (web stores in localStorage, app stores locally). Appearance (Light/Dark/System) also wired end-to-end. 6. **Sensor-reactive motion** — `rememberTiltState()` provides smoothed tilt `Offset(-1..1)`. Uses `TYPE_GAME_ROTATION_VECTOR` (fused, no drift). Auto-disables on battery saver, reduced motion, background, extreme tilt. **Motion tokens** (`ui/motion/Motion.kt`): `EaseSpring` (overshoot), `EaseSmooth` (expo-out), `EaseEmphasized` (M3), `SpringSnappy/Default/Gentle`. All durations centralised in `Durations` object. @@ -80,6 +80,10 @@ Full spec: `DESIGN.md`. Branch: `feature/design-system-v2`. **KaizenOrb** (`chat/Background.kt`) uses `rememberTiltState()` from `ui/sensor/` instead of inline sensor code. Breath animation uses `Durations.ORB_BREATH` / `ORB_BREATH_STREAMING` from `ui/motion/`. +**Typography** — Inter Variable (`res/font/inter_variable.ttf`, 859 KB, SIL OFL). Full type scale from DESIGN.md §8: `displayLarge` (32sp/W600) through `labelSmall` (11sp/W500). All 9 weight axes registered (W100–W900). Negative tracking at display sizes, positive at label sizes. `@OptIn(ExperimentalTextApi::class)` for `FontVariation.Settings`. + +**Oklab** (`ui/theme/Oklab.kt`) — Double-precision matrix math for accurate sRGB↔Oklab round-trips. Used by theme picker's Oklab gradient swatches and `generateGradientStops()`. Forward LMS matrix corrected to Björn Ottosson reference. + ### Internationalization (i18n) - **de** (default), **en** — same as web (`messages/de.json`, `messages/en.json`). diff --git a/app/src/main/java/dev/kaizen/app/MainActivity.kt b/app/src/main/java/dev/kaizen/app/MainActivity.kt index 1d66d62..72705c7 100644 --- a/app/src/main/java/dev/kaizen/app/MainActivity.kt +++ b/app/src/main/java/dev/kaizen/app/MainActivity.kt @@ -7,6 +7,7 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.SystemBarStyle import androidx.activity.compose.setContent +import androidx.compose.runtime.collectAsState import androidx.activity.enableEdgeToEdge import dev.kaizen.app.auth.LoginScreen import dev.kaizen.app.chat.ChatScreen @@ -14,6 +15,7 @@ import dev.kaizen.app.chat.ChatViewModel import dev.kaizen.app.net.SecureStore import dev.kaizen.app.net.SessionViewModel import dev.kaizen.app.settings.SettingsViewModel +import dev.kaizen.app.settings.AppAppearance import dev.kaizen.app.ui.theme.KaizenTheme class MainActivity : ComponentActivity() { @@ -39,7 +41,14 @@ class MainActivity : ComponentActivity() { navigationBarStyle = SystemBarStyle.auto(Color.TRANSPARENT, Color.TRANSPARENT), ) setContent { - KaizenTheme { + val themeId = settingsViewModel.selectedTheme.collectAsState() + val appearance = settingsViewModel.appearanceMode.collectAsState() + val darkOverride = when (appearance.value) { + AppAppearance.Light -> false + AppAppearance.Dark -> true + AppAppearance.System -> androidx.compose.foundation.isSystemInDarkTheme() + } + KaizenTheme(themeId = themeId.value, darkTheme = darkOverride) { // Snapshot-state routing: logging in/out flips session.config and // recomposes this branch — no NavHost needed for two top-level states. if (sessionViewModel.isLoggedIn) { diff --git a/app/src/main/java/dev/kaizen/app/settings/SettingsComponents.kt b/app/src/main/java/dev/kaizen/app/settings/SettingsComponents.kt index 1bc3b11..2828ec2 100644 --- a/app/src/main/java/dev/kaizen/app/settings/SettingsComponents.kt +++ b/app/src/main/java/dev/kaizen/app/settings/SettingsComponents.kt @@ -57,6 +57,7 @@ import androidx.compose.ui.unit.sp import dev.kaizen.app.ui.theme.Amber import dev.kaizen.app.ui.theme.AmberDeep import dev.kaizen.app.ui.theme.Oklab +import dev.kaizen.app.ui.theme.themes.KaizenThemeId /** Converts polar OKLCH coordinates (Lightness, Chroma, Hue in degrees) to a standard Color */ private fun oklch(l: Float, c: Float, h: Float, alpha: Float = 1.0f): Color { @@ -201,17 +202,17 @@ fun ThemeOptionPill( val (colorStart, colorEnd) = remember(themeId, isDark) { if (isDark) { when (themeId) { - KaizenThemeId.Amber -> oklch(0.76f, 0.14f, 83f) to oklch(0.55f, 0.16f, 83f) - KaizenThemeId.Blue -> oklch(0.68f, 0.18f, 257f) to oklch(0.45f, 0.18f, 257f) - KaizenThemeId.Aurora -> oklch(0.78f, 0.15f, 85f) to oklch(0.45f, 0.18f, 320f) - KaizenThemeId.Mono -> oklch(0.92f, 0f, 255f) to oklch(0.35f, 0f, 255f) + KaizenThemeId.AMBER -> oklch(0.76f, 0.14f, 83f) to oklch(0.55f, 0.16f, 83f) + KaizenThemeId.BLAU -> oklch(0.68f, 0.18f, 257f) to oklch(0.45f, 0.18f, 257f) + KaizenThemeId.AURORA -> oklch(0.78f, 0.15f, 85f) to oklch(0.45f, 0.18f, 320f) + KaizenThemeId.MONO -> oklch(0.92f, 0f, 255f) to oklch(0.35f, 0f, 255f) } } else { when (themeId) { - KaizenThemeId.Amber -> oklch(0.72f, 0.14f, 83f) to oklch(0.85f, 0.15f, 83f) - KaizenThemeId.Blue -> oklch(0.62f, 0.19f, 257f) to oklch(0.78f, 0.15f, 257f) - KaizenThemeId.Aurora -> oklch(0.62f, 0.20f, 320f) to oklch(0.75f, 0.16f, 320f) - KaizenThemeId.Mono -> oklch(0.22f, 0f, 255f) to oklch(0.85f, 0f, 255f) + KaizenThemeId.AMBER -> oklch(0.72f, 0.14f, 83f) to oklch(0.85f, 0.15f, 83f) + KaizenThemeId.BLAU -> oklch(0.62f, 0.19f, 257f) to oklch(0.78f, 0.15f, 257f) + KaizenThemeId.AURORA -> oklch(0.62f, 0.20f, 320f) to oklch(0.75f, 0.16f, 320f) + KaizenThemeId.MONO -> oklch(0.22f, 0f, 255f) to oklch(0.85f, 0f, 255f) } } } @@ -251,7 +252,7 @@ fun ThemeOptionPill( Icon( imageVector = Icons.Rounded.Check, contentDescription = null, - tint = if (themeId == KaizenThemeId.Mono && isDark.not()) Color.White else Color.Black, + tint = if (themeId == KaizenThemeId.MONO && isDark.not()) Color.White else Color.Black, modifier = Modifier.size(16.dp) ) } diff --git a/app/src/main/java/dev/kaizen/app/settings/SettingsScreen.kt b/app/src/main/java/dev/kaizen/app/settings/SettingsScreen.kt index b067324..13942a5 100644 --- a/app/src/main/java/dev/kaizen/app/settings/SettingsScreen.kt +++ b/app/src/main/java/dev/kaizen/app/settings/SettingsScreen.kt @@ -38,6 +38,9 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.res.stringResource +import dev.kaizen.app.R +import dev.kaizen.app.ui.theme.themes.KaizenThemeId import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -94,119 +97,48 @@ fun SettingsScreen( Spacer(Modifier.width(16.dp)) - Text( - text = "Einstellungen", - color = cs.onBackground, - fontSize = 24.sp, - fontWeight = FontWeight.Bold - ) + Text(stringResource(R.string.settings_title), color = cs.onBackground, fontSize = 24.sp, fontWeight = FontWeight.Bold) } - // --- SEKTION 1: Erscheinungsbild (Theme & Appearance) --- - Text( - text = "ERSCHEINUNGSBILD", - color = cs.onSurfaceVariant.copy(alpha = 0.6f), - fontSize = 12.sp, - fontWeight = FontWeight.Bold, - modifier = Modifier.padding(start = 8.dp, bottom = 8.dp) - ) - + Text(stringResource(R.string.settings_section_appearance), color = cs.onSurfaceVariant.copy(alpha = 0.6f), fontSize = 12.sp, fontWeight = FontWeight.Bold, modifier = Modifier.padding(start = 8.dp, bottom = 8.dp)) + SettingsCard(modifier = Modifier.padding(bottom = 24.dp)) { - // Theme Picker Row (Oklab perception space stops) - SettingsOptionRow( - title = "Akzentfarbe", - description = "Wähle das Farbschema der App (Oklab perzeptiv)", - icon = Icons.Rounded.Palette - ) { - Row( - horizontalArrangement = Arrangement.spacedBy(10.dp), - verticalAlignment = Alignment.CenterVertically - ) { - KaizenThemeId.values().forEach { theme -> - ThemeOptionPill( - themeId = theme, - selected = selectedTheme == theme, - onClick = { viewModel.selectTheme(theme) } - ) + SettingsOptionRow(title = stringResource(R.string.settings_accent_title), description = stringResource(R.string.settings_accent_desc), icon = Icons.Rounded.Palette) { + Row(horizontalArrangement = Arrangement.spacedBy(10.dp), verticalAlignment = Alignment.CenterVertically) { + KaizenThemeId.entries.forEach { theme -> + ThemeOptionPill(themeId = theme, selected = selectedTheme == theme, onClick = { viewModel.selectTheme(theme) }) } } } - Spacer(Modifier.height(12.dp)) - - // Light / Dark / System Appearance segmented toggle pills - SettingsOptionRow( - title = "Helligkeitsmodus", - description = "Passe das Hell/Dunkel-Erscheinungsbild an", - icon = Icons.Rounded.Settings - ) { - Row( - horizontalArrangement = Arrangement.spacedBy(6.dp), - verticalAlignment = Alignment.CenterVertically - ) { - AppAppearance.values().forEach { mode -> + SettingsOptionRow(title = stringResource(R.string.settings_appearance_title), description = stringResource(R.string.settings_appearance_desc), icon = Icons.Rounded.Settings) { + Row(horizontalArrangement = Arrangement.spacedBy(6.dp), verticalAlignment = Alignment.CenterVertically) { + AppAppearance.entries.forEach { mode -> val label = when (mode) { - AppAppearance.Light -> "Hell" - AppAppearance.Dark -> "Dunkel" - AppAppearance.System -> "System" + AppAppearance.Light -> stringResource(R.string.settings_appearance_light) + AppAppearance.Dark -> stringResource(R.string.settings_appearance_dark) + AppAppearance.System -> stringResource(R.string.settings_appearance_system) } - AppearanceTogglePill( - selected = appearanceMode == mode, - label = label, - onClick = { viewModel.selectAppearance(mode) } - ) + AppearanceTogglePill(selected = appearanceMode == mode, label = label, onClick = { viewModel.selectAppearance(mode) }) } } } } - // --- SEKTION 2: Profil & Konto --- - Text( - text = "PROFIL & KONTO", - color = cs.onSurfaceVariant.copy(alpha = 0.6f), - fontSize = 12.sp, - fontWeight = FontWeight.Bold, - modifier = Modifier.padding(start = 8.dp, bottom = 8.dp) - ) - + Text(stringResource(R.string.settings_section_profile), color = cs.onSurfaceVariant.copy(alpha = 0.6f), fontSize = 12.sp, fontWeight = FontWeight.Bold, modifier = Modifier.padding(start = 8.dp, bottom = 8.dp)) + SettingsCard(modifier = Modifier.padding(bottom = 24.dp)) { - // Username editor row - SettingsOptionRow( - title = "Benutzername", - description = "Ändere deinen Anzeigenamen", - icon = Icons.Rounded.Person - ) { - SettingsInputCapsule( - value = userName, - onValueChange = { viewModel.updateUserName(it) } - ) + SettingsOptionRow(title = stringResource(R.string.settings_name_title), description = stringResource(R.string.settings_name_desc), icon = Icons.Rounded.Person) { + SettingsInputCapsule(value = userName, onValueChange = { viewModel.updateUserName(it) }) } - Spacer(Modifier.height(12.dp)) - - // Email display row (read-only in this screen view) - SettingsOptionRow( - title = "E-Mail-Adresse", - description = userEmail, - icon = Icons.Rounded.Settings - ) + SettingsOptionRow(title = stringResource(R.string.settings_email_title), description = userEmail, icon = Icons.Rounded.Settings) } - // --- SEKTION 3: KI-Profil & Kontext --- - Text( - text = "KI-PROFIL & KONTEXT", - color = cs.onSurfaceVariant.copy(alpha = 0.6f), - fontSize = 12.sp, - fontWeight = FontWeight.Bold, - modifier = Modifier.padding(start = 8.dp, bottom = 8.dp) - ) - + Text(stringResource(R.string.settings_section_ai), color = cs.onSurfaceVariant.copy(alpha = 0.6f), fontSize = 12.sp, fontWeight = FontWeight.Bold, modifier = Modifier.padding(start = 8.dp, bottom = 8.dp)) + SettingsCard(modifier = Modifier.padding(bottom = 32.dp)) { - SettingsOptionRow( - title = "System-Prompt & Fakten", - description = "Aktive Regeln: 12, Pinned: 3, Verwendetes Budget: 412 / 1500 Tokens", - icon = Icons.Rounded.AutoAwesome - ) + SettingsOptionRow(title = stringResource(R.string.settings_ai_title), description = "", icon = Icons.Rounded.AutoAwesome) } } } diff --git a/app/src/main/java/dev/kaizen/app/settings/SettingsViewModel.kt b/app/src/main/java/dev/kaizen/app/settings/SettingsViewModel.kt index a5f4bcc..11ffff8 100644 --- a/app/src/main/java/dev/kaizen/app/settings/SettingsViewModel.kt +++ b/app/src/main/java/dev/kaizen/app/settings/SettingsViewModel.kt @@ -1,67 +1,40 @@ package dev.kaizen.app.settings -import androidx.compose.runtime.State -import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel +import dev.kaizen.app.ui.theme.themes.KaizenThemeId import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow -// Available Kaizen UI themes -enum class KaizenThemeId { Amber, Blue, Aurora, Mono } - -// Available Light/Dark/System appearance modes enum class AppAppearance { Light, Dark, System } -/** - * Clean MVVM ViewModel for the Settings module. - * - * Completely decoupled from Android UI classes, making it 100% unit-testable - * on the JVM. Manages the state of the Oklab Theme Picker, selected model, - * and user profile options. - */ class SettingsViewModel : ViewModel() { - // 1. Reactive State Flow for Theme - private val _selectedTheme = MutableStateFlow(KaizenThemeId.Amber) + private val _selectedTheme = MutableStateFlow(KaizenThemeId.AMBER) val selectedTheme: StateFlow = _selectedTheme.asStateFlow() - // 2. Reactive State Flow for Appearance - private val _appearanceMode = MutableStateFlow(AppAppearance.Dark) + private val _appearanceMode = MutableStateFlow(AppAppearance.System) val appearanceMode: StateFlow = _appearanceMode.asStateFlow() - // 3. User profile details private val _userName = MutableStateFlow("Bruno") val userName: StateFlow = _userName.asStateFlow() - private val _userEmail = MutableStateFlow("admin@kryptomrx.de") + private val _userEmail = MutableStateFlow("") val userEmail: StateFlow = _userEmail.asStateFlow() - // 4. Default Chat Model - private val _defaultModel = MutableStateFlow("gemini-2.5-flash") - val defaultModel: StateFlow = _defaultModel.asStateFlow() - - /** Selects a new Kaizen UI theme and triggers an Oklab transition stops recalculation */ fun selectTheme(themeId: KaizenThemeId) { _selectedTheme.value = themeId } - /** Changes the appearance mode (Light, Dark, or System Sync) */ fun selectAppearance(mode: AppAppearance) { _appearanceMode.value = mode } - /** Updates the user's name in profile settings */ fun updateUserName(name: String) { - if (name.isNotBlank()) { - _userName.value = name.trim() - } + if (name.isNotBlank()) _userName.value = name.trim() } - /** Updates the standard chat model */ - fun updateDefaultModel(modelId: String) { - if (modelId.isNotBlank()) { - _defaultModel.value = modelId.trim() - } + fun updateUserEmail(email: String) { + _userEmail.value = email } } 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 bad12c1..73ad3db 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 @@ -2,33 +2,123 @@ package dev.kaizen.app.ui.theme import androidx.compose.material3.Typography import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontVariation import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.sp +import dev.kaizen.app.R + +@OptIn(androidx.compose.ui.text.ExperimentalTextApi::class) +val InterVariable = FontFamily( + Font( + R.font.inter_variable, + weight = FontWeight.W100, + variationSettings = FontVariation.Settings(FontVariation.weight(100)), + ), + Font( + R.font.inter_variable, + weight = FontWeight.W200, + variationSettings = FontVariation.Settings(FontVariation.weight(200)), + ), + Font( + R.font.inter_variable, + weight = FontWeight.W300, + variationSettings = FontVariation.Settings(FontVariation.weight(300)), + ), + Font( + R.font.inter_variable, + weight = FontWeight.W400, + variationSettings = FontVariation.Settings(FontVariation.weight(400)), + ), + Font( + R.font.inter_variable, + weight = FontWeight.W500, + variationSettings = FontVariation.Settings(FontVariation.weight(500)), + ), + Font( + R.font.inter_variable, + weight = FontWeight.W600, + variationSettings = FontVariation.Settings(FontVariation.weight(600)), + ), + Font( + R.font.inter_variable, + weight = FontWeight.W700, + variationSettings = FontVariation.Settings(FontVariation.weight(700)), + ), + Font( + R.font.inter_variable, + weight = FontWeight.W800, + variationSettings = FontVariation.Settings(FontVariation.weight(800)), + ), + Font( + R.font.inter_variable, + weight = FontWeight.W900, + variationSettings = FontVariation.Settings(FontVariation.weight(900)), + ), +) -// Set of Material typography styles to start with val Typography = Typography( + displayLarge = TextStyle( + fontFamily = InterVariable, + fontWeight = FontWeight.W600, + fontSize = 32.sp, + lineHeight = 38.sp, + letterSpacing = (-0.32).sp, + ), + displayMedium = TextStyle( + fontFamily = InterVariable, + fontWeight = FontWeight.W600, + fontSize = 24.sp, + lineHeight = 30.sp, + letterSpacing = (-0.12).sp, + ), + titleLarge = TextStyle( + fontFamily = InterVariable, + fontWeight = FontWeight.W600, + fontSize = 20.sp, + lineHeight = 26.sp, + ), + titleMedium = TextStyle( + fontFamily = InterVariable, + fontWeight = FontWeight.W500, + fontSize = 16.sp, + lineHeight = 22.sp, + letterSpacing = 0.05.sp, + ), bodyLarge = TextStyle( - fontFamily = FontFamily.Default, - fontWeight = FontWeight.Normal, + fontFamily = InterVariable, + fontWeight = FontWeight.W400, fontSize = 16.sp, lineHeight = 24.sp, - letterSpacing = 0.5.sp - ) - /* Other default text styles to override - titleLarge = TextStyle( - fontFamily = FontFamily.Default, - fontWeight = FontWeight.Normal, - fontSize = 22.sp, - lineHeight = 28.sp, - letterSpacing = 0.sp + letterSpacing = 0.08.sp, + ), + bodyMedium = TextStyle( + fontFamily = InterVariable, + fontWeight = FontWeight.W400, + fontSize = 14.sp, + lineHeight = 20.sp, + letterSpacing = 0.11.sp, + ), + labelLarge = TextStyle( + fontFamily = InterVariable, + fontWeight = FontWeight.W500, + fontSize = 14.sp, + lineHeight = 20.sp, + letterSpacing = 0.14.sp, + ), + labelMedium = TextStyle( + fontFamily = InterVariable, + fontWeight = FontWeight.W500, + fontSize = 12.sp, + lineHeight = 16.sp, + letterSpacing = 0.24.sp, ), labelSmall = TextStyle( - fontFamily = FontFamily.Default, - fontWeight = FontWeight.Medium, + fontFamily = InterVariable, + fontWeight = FontWeight.W500, fontSize = 11.sp, lineHeight = 16.sp, - letterSpacing = 0.5.sp - ) - */ -) \ No newline at end of file + letterSpacing = 0.33.sp, + ), +) diff --git a/app/src/main/res/font/inter_variable.ttf b/app/src/main/res/font/inter_variable.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4ab79e0102bbe0ffa1ed879b13e52ac8c6487833 GIT binary patch literal 879708 zcmd>`3A|5L+xOSB*S7ZI5JEWr|2a73ka;Gv49PrYCYcj5B}qsUGF8Y>NEt#hq%@h5 zN|G|2V@^70QVHk%UH@wzx4L`oyXSe|_jx{__wDof_FMn8_g;IgbzN)iy{@$nA%ze* z@INEUG^|&@!CN0bFhJ-5mxM^1(6GhbtqydXv{LA&h6&YSYQt7->I4gy%oN@^T-3E~ zqqcXp)Y)=(7q&rrAxfNUhTliJ=RGOx(Aqd*<=w4HmyKL}@qQuXX8i8fs`Z_%`;Be7 z8pqG$_tEYnx(^+1hkq#SgYV;a`JMy2581kDY(*hTUlpQv$v!wP^QH~P@n3O#(|rR* z_4(na`*sWQUN)ifPrVPvRjWoDg&np|*k4}l+q-+O@^gn(!u_h_{EB^%k!xb)KKver z--Y@P95ymb(@UvBs60a4etN**p55bG-BUz}IYsgN{J`!bhs4bmmvR1loS!(T`@r6- z`)~P5s1pl>$kKGk;0K3&@o1$dg}R9PkM{)ioe_0j`sMr-KUI>53_3T32I_ygBU;5%Woqp4Qaii!Q{C}dzEQSa_ye{Jm z`fa?ZoFP0RymICv9C(gZeI%x-7tliCY2+$lQbds6QY=ZwuOup`FibFnm?e{;S6 z=Jo!MqWsNx)y2j?k<+#o)oe^PAB6rSV9q3%sVYtbXq46qW+1`Ck)9b=cLPo(pxjDL47oudk) zy-i8e_kxerdXWqIGxFo;7}5v8C2$>lkGxyK+%Uf}^dx={0MDxOVi9zst|fXPf3F@d zdgv+W+wWsC z&NbE2s~h;jjo&jxFGGA0D$-sz*yAs-n^4wr92>~T%_Q{aKaqa@M&7%ktXU#*+7Yl% z)qjok;Rk<<^mBjbJpUJz7lEJNOrAgezWLby=``Kz&t%-=4E(n+Cp zQ%e6U+6zm^eINZq+5)zI5zL1Ve8YK^Z_V|y8RvMJVCTQXZDO<;Cp!KQv*_mg`|U)> zn=xla-~T}t;obpQWR3&Uo0)~W5lceN`2AP<7wxcxMPF~tU$@WQBl>1~UG$Bq3C~#t z{hyIr7|UPe#fzL?W|SK{p8kf}Mu;&0*QKvz<#XjFF%~S+DPobll)etU z4i14MA)BDz(>c)1;57IG{2W4grNM5T(=sgY5&S+2HvR*;Px?CCXRO*TYSD4ElR^58 z5W40p)y4F>8Pxv|zeRrf9oFe5TtoNyl78!UBEK$^{)URRCw5LFwK=8_(nn>Zbbq?R)y^qOa|Tu~`sh(tJR6 zy?I{X^o@B-YuGPF`X*>8LhXnV=EsgVLViE3(^H|N0UdjoNk3%<;~qp6G2p*QA4AWw zTzGf9hH<N|2p_W&e#~HvHqXsnSXl?-Q&-M_xTU*`|r!7>#zR@{GB#DA}X4ju+v0?e~0NJ z?)(E!q0hoH@Vx&+c^Uct8TEX;cZ9^Qn}Ra?i*bJ!_|Zx{_cnSD;@t!9mtJi#Ew)B` zOiaSMYP28Vow69-V}HSWCGabQ+IVjn3urBdHBTn2dHf@cU6TIHzdeV_i{f5gQRcgN z_kp4wIlU5COQ0_1O+0s|qr5euihoE{G2e@aJz9&j0a!++l4gRZWp7h_p!EU zg>s&QUt&Iu>2t`-fpT7k;#^Dhq;+OltTD0vaRTYXVn`->|1B(PdXrJSV!XMG`!B_PwqYIjGMxi0$Zt^ehD=bz>&_)TAL44wm3@O&Er{lAFWBN~_;Xv5=pCOmuthxe$W zc8s{wE)#d^pG21%_G%0JuLtA6TKKdgQf0p=p^0sP*gm|qgVXNg|+E$CoT+O)yDMYmX9 zUt1M@*8taS!uc2@<}Fc?){e1v={_Q2PKiM}0(}SLa)D@y@mn6(SEV(ezZK)`9?<~r z&E@^2q9mOgTaRTGgKSYzDi(t}jB!mI0=OnF5%xKO`cB2QpNRRHu)g>9i}~hY`ZqV? zd71Idy;F2Esp7d9GX}pJy)@3kX(io@nRv;gEWyExl z3buo}U=&yn=7CLMewfZU?_vC=bKW8p$B1S?GZ>%~MLHM)TC&Ol;qSl9_sYoTjCeaN zmy|ddvJv{;P0+EhUeY4{U${=}M4d$jUJ;Bp%*CpiSPb7=Op5o5#U{6CnW>a$iF8Y( z`Hj7JEaDG%*}=f*6s0O>q`KL1~xt8$@TL?3YgW9ERKBo@c$B1XzI z)Fqc_f!{6UZqY|i6@5I+y*}D{^Kbc`n6AGN(^YfKd(F{D7tluwP$tqh=*P!mzme8C zL@&?+&y-%Eh1W!^0pEiCAt#~4d*HxL(D4;uIry(!lcJYnGb2q5jqw3&r^Hai58v}z zi(ZILtjqx8vZdKCT6(j=SD}ByXcq11ieJm)kj5hIY+eDV=(3ph(TbZnTGd< zhcP!~7fZbyxNf)DsxGFV^&IAa(I}%Y{J)}TpvQ^fx~^yqZLQmi)~c*XL=3ex${LO` z2gteUzv+^(^l;4k!zo|)kDWi9u2GHgJAyUcWn4$cI*JPBRZ&(~5EXS7Q9)M{1NCZg zFQEpDo~k=yo=;%>%@p_PIbeSoTz4RdQgdQxO zgwFkcp$+nh>qB%l(Ol;dO;tY8Lh4Y8$yke64Mm!Fx%fn(k=mW-q>HjVFI3$|bU80G z(=o4y%&C&a^YEuGn8pTym0)hjLFh?3Ux=$esM?r|0quU0Vl5#uZKW+so&(jZv_XjD ztz&bez}&(+r8tNF%d}l=bbZ8xOkKo;*gG`#)MD@X@nQ;|yL*GJV(+cP#NLdwzf_7~ ztHiFR6d7s6mal+gAy?>{c){0_+E+u?v$`T;FL*Pf%zsz@Kb3dWz3AR}hd=J;meVuk z5`7524c;Hxh#mj*yS%8KF>gV4{FzLBu~xa6X<~gQqLi3-gU(`WCZg6&DDkVUjkaab z1@$O};{a_upMl#d)_|>NbOnvwti zi&FdlKZM?OE%sAseBwPlwg(p5x1o3GUa{EVLs&1x;&xh#hbV5OD29W$4Tku9jQK?& z6Y(xa?`De?-qAA1_)U8Ap2r{38T;h)zP%Ig)!?u8ievBP*hh`U2x9xG=_jzS3B+qe zMjOne^y_}O-*;oLE@SWOX3c}PQ`~{}vTok5`tv?i#@^Du+9%4`OTrw7_4^IHjQtzz zuXq`R`zqA$8T+6adh5zaq(^G?_(V|m)3HK%g#ew_X8%D zrr2~W{!I1_W5IJM_L~vArFd(Mf5ch;5!a;nC*`9)@CRZJ@mKLgwFvvwVZ86gy7I5q z`V?!Ue8i@1j%k^U_|;8uFOv~p%IJeXDYaLp}53 zst3MjAitvc3&nvb1{Cun@)g8vVlgkodMKVlcEf&3FIq$2SU*$$VBJbkci$J(bl-ot=dCkur{palQk3I%xI*h1jl z;8Wsn%qvgbG_O4Mr+HbdnW8C7q7caXQNeVl~*3`K7c)aWP z2pNXs6A(|^=yGFT8ISAcW1hpjN9%gq1miLX_MP{OL4IAVX>wsLk`?7;#oD92XixbV zryEUY(b4-%4DfJ$IQ|xSd&E%F4r_|`h^=%G9ci6mBCvfo40jSqBiurh-V@xc-xu-;7(-QUVD;nXNj$R(bBdEN1%=ewe z6!g_*(-`L`3@NqE(bHzqCSPVdZ4~6dp^g?_yR#?=D#ZM`Q z8YBHTnvY|1HO;Ryx6?dI@nX!0i0y3jCWu^kU*1U10{;=%1aTx+4A*xO<0$q^anE2O zVj>hr$+$k8Ln%Irdv2uhNio@2-1VmM8XKqK7>&)rYjJxBa6B5sy6iA;C+sp4 zb5I5J*L2a%e+9owiH;PXqxe#6d}IElK8eLfF)va4iN<~`rUje-(_BFJ$e2fOniFDk z+a&nP+h`~C6U{5sMyR3ZE%rDNf2$aqM|dx|m#L3D@&{Vm<`k3c4A^fUd>6m5ZmdnQ z;aEJD<`bNUIc8Vv-eEf};){6qpGUxEU8w(X{zf|#{rE~~hgU>-_o*l!_X}+DJo3m^ z&xTx9p2J!#$!l;uf=T?S$CzR54T$^DC^o#fTi5kZeS;v z0&qN*w-q`7zYl|1V5JaOa)Xjcw+A?Otp`|&bXhPP;LA@@RIW$dDnu<5E!1{!4txh1 zVC@KKJxbtNHCC2GU(#9@YfwD5a-xjUpif9oXmQXB$DUxW)A8p)7l8AwMuhl%473{< zf;yp$YdCbZJV*@l3qapRCjPtH7ssislc0G)WUqv0SZU(s5)tX=$j-&5>Z-6xJcl83G^9br^Dq|nm z2zHZk$sU6h*ob7>V-HXIDGoLY#w`z$fA$#>Jc9GJLSL zx`=1hI*uF2@6uB!ju88OK)gtHpmdBdKXwk~#cU*slfA+?#7f*3ZN6GqHxdsLNTZFh z_EKG_-KhJuM9`dUPWQsI3-2b^N+~=mp(x`z+I+1KSPbag#Tu~;v?B$a#qVJ>7E#u6 zK>awCi5^O^G3IUpbI?xQGuHlCUlqZ# zn3;mPbDW-!coU#Ll>PBMK>af22>Ols#3PQCh<7!s4&h#l#5B1S@z+{niR>lH%GZ&O zha!#nf3w+xca4qo{*}H7*LReIMIM_Sb9psUo1VKK_74T>i+Sz@ji>);EYbMEc?Z#_ zi(?eS+*UsQk}ijG5bwcw>!KQ_-;2JkO-g-5{zvsgoiBo;;3P=HG4i9Ph*y?X7Gw2m zuun8X-z-Ngy)4xO_d=KAyL5aT&*@y9@k_>jYY_;6-zFFQQ=UYoPoo+${j0K(d{4Dj zW7I@7L%pbt4s>RnRp-#R>U_GOE~-oF%DS%Zp$F>``Vl=X&nACYSQNH} zs~7HGxOd_Hg%=meQ6zVfwncgsnNsAtB3Fv#C|){{t|^sjxG7f?dhfREPr7| z`pczKL`qyriIlri?oR2P(j}!|%J`JYDKk^%rYuX@p0Y3HY|786HZ@4inwlduPileG zLaD`5E2Y**ZJXL9wP)&ksV7oXPwqN-_~g+vKP^bho|ZE$cUp2<{j`Q@52Q^@dphme zv;}F)(+;E^N;{sGdilNU>FMdPFn#~OSgetE$q!UpHBL=Zv($2J|6t?7uyG|_M>o(t z^)NkJPlS!9>t*_=zNCNCSIu~{_zyO22piuG8@GjxdxSQAJK=D``GgAzS0f9f*`j%( ziP56b+R;YQ7NL#1M#o2|MAt<(MR!IIMUO>)h+a+Vm8i|6oHM4->`9uq;5%%!NxO^UQSw|D0XyfBar$ZZiu<pYmwRl$2R1^HN?+*`0DUk zF@K`}m_JTq4)=%nSb_K*?Du@?wIhGNBz^bgs}~1f>~*o-`O`w2PXVVuDtPMrwDXS( zadA4p%p=5^eyP3B^upi9TsxU~rvJ(5C!acrIqNjeJ-sEP+|%C*arWof+2ha7$;i#n zufO>E$1{h{z(dbm`MNsgp1gSGt21Ao=y>|eGm~&nyi=U10EVBz)Ah{aGu6)2JX7z? z)H4&#+<)f2(-GV$2MA8fQ@@^CeQNEgnWymNK@R50(|4RYbn4Sn`*HuU*g zFQnw8qZ$9D4m$B!>e$rAsf|)Ir+l4q_S9P`3sRyf`A>Xz;(SVQGAhJzcWl7X#z)H> zZE>{0muEg7bFB6k6MLTMKC0V^A`KJgBpy%tMTi0~2vIOgq2tNP$@nX!YecpWK{c7vj=C+5OPUb&clNq_0$AP_>&t?%> z@I=W{5>(BC_CeQWS)b)>mh18P;|s+XjW5F`2oYb3Qt>5OZ{!w79_ko>SL|r}jQoEn z9pR%l<<*Qw9q2m#Fa8gG5MMdIYJBzhI`Q@Xd|k%*|Im2U{NMc-51)z0GnxO(_!ZW; zV|?d~Bc$*yv?ht#Z=bi& zTV&(BAG~AU2Jg7H)~n&w^lEu`dUd?IUVX2D*U)R^rFy5mi{2&gTW_BC61INs6pck| z(N#Plo)SyM2QrXZL%e-~oi}1)F zyg6RPOZ3)wQSUVyu}5vZ&Es9L)@HFOHn(@#*0&ApVLi|0_s-aJwywR+`^LUwx7&BU z=Y%IL-bM`GRWgYhqKW7xusbVyiVwv;@sZf&^2^(01KAMoDRpHX?KusK)vn{@N#p$SkjkEGlPgb=yqcjh)RF;%;@1XsbH8ysE9}r3Q%JY9LmVgT#H< zLGG)D;A@UKVy2oaW~q7D8J;hesh7peYNgn(Hi?h1y81-DB|cR^Qo_8es#eWR_A1rN|mK_W?5Qik!5tetfVu^#yTSJ(oxw&C(04Jk$hBl zmJ{^7@-f{-PS^e9)4IQ$p$EvBdZ1jOAC(LB1XoOtmuvJKxmGWb>-0kTnqDN=>lfq( zy;$zkN8}OxjXWy9H(LH+jQr7f>M2!MG;n!TJy+b_D_V-XR8!Gev~l@V2Uksuc2Spr z=w6a|+LS;X_psO_bF0JZq-*7FmlbuKd{EZcd0kQ0Mvl?VTuJ$?9_}KpmL4saxlZyW z`LdpCintQ;OMPDcs?%MfE8yz823~Eip6l$IxX0iUYwMgM zUTN`}dPg?ZNphoJB45`_WW4v=vs&u)hbt7b#!H1SNV&< z-`%P#qQ81j-lGf4mb!>+rHjhex|lqsFRHWJ>4()W*UfborNlj|i7X)T=5D0B!}SpL z-6Pd*^^9w* z7MRnnih4;cRm;>C^Ss)xPN_5Mv}>(}mMR@@^FH3>>+8m@t!uB_xemI$?x;KH-nx(O z>uR`rTur>ykJ0np05?#7uD{a1>T5>1Iu6$g%pnOm+Xb_YN?g+}*RC~&v zw&(2$`(@B9Xc`o>Wo;E(GiV+(3>pVbg1dr7!Pmisph8g5`#2~aR0=8wRf4KPwV--X zBd8ga4Qd6ogFAydLEWHUP~U!IF9fq}n*BDI9n1`71apHq_EPX%@O+RQ6qYsJId{N) z<_>!2WEOkGp2b&4XT?~tPJAWLn4DNeCLvZEm^d*;{wCI%%;HO#2VXf9leJ71iLamJ zSd&$*kf%*H`GvW~WEV%|S<}u8Gml}dwAr*ZL(BtasCm#lY9^TH%=7MJv)X;)J~eA} zHM7>NGaJq8W|Mit?9pe;hi0EyWVYz)W~=$gedxY$hfPsa%oI0!-Iwl=+v`4eU%4Zy zl{zQ~yQ4u7(MlFK8{9tkkwXklOg63EIMW<|0exP4E#pl?)5zTE9+g$xBvV}>p3s*GJ9FPI4`@G z!^^2AsK?Y2x7^FEhp7+MKJ~em&AUY{cCWZq`X|qGQ{1cW2`{Ug>Q=ia-5NK|t#wbi zb#A(Q%{}ebyBThSsifnwfLJYFc;l3?sb{V{9wwPALXs)C-I8;U92`&O*1c-x!cR*X1h&p zj(fw+b(`Hhw?%&LX;a<1&D8XKQ_IU_YO8gog_qaOcU#@F?m4&3R50JW=dsJM%3Kq# zn(JpOFXOrdhEwa4ME-UC9vW+e- z+v*asoh~Wc>)Yi>-CT~+cgsn-yPT|h$SJy~d_wn<&*;H&wjLtq=m+FnJyg!q56Tzx zM7dZ$E|=&@a;csyx9OGgP5rXmu2;#o^eggh{i@uf56Qjy3;B^gD);MS@?-s_{6rs@ zpXw9xGksDX)TiWe{jL1TSoyQ@icV9vs;6Ba`JB5Ce={79zbn2)1SLd7NfAXHC{d=12h=FUu}6ys)fmLI#){$UVKG9D6A!6J z@crRdLa0 zt|E8n)$$#^M!u`p%J=j-`M!QlexTROoqB^jp}&(U`jSl5-^-Kw2UpJZb>-dtu7c}l z+M5ohqv>Qin|nqzxmjFVm>to%xC7H`P|%Ua+%yFkGaj{HTg__)6E?- zaAfp7XmB~e*a5mn7oX1aOW%rG;}Ec1++E#4H{ z#arTSu|vEg-WBheFU(={rTNMnF-OfYbKFEs)FhfDQ@|87g-o&;gfE#(h?3%VQCd_B zCb+Y~qrua`G&9G{HS^4T^Q?GGOcYzhR`Gr?F_;ugF)Pi>W|d1dub5ZGX>mrJ73YG- zgUP`Y=6&;l+38N3*UWme%j}ll$cyq@nI<0&rUp+2PnnbElpG|7m;{r<6b_~bj|GWA zlJ~l|(c9#`5k!Lm-d^uR?^Ex9x8M8N`^5XqX0p!P>}?BjdMVzCAcy_YergYR2ffd| zL*8NUOYf^7n|I#(I>_bC_MQ)J4e|upgIj{E-d6jBx7b_i&G(-5=6bVig7>DkJ-98% z9pnx21+9YoK|&C*ciPgnk-f_{vCXieyxX?1ZEZVyk8Nqo+o5)t9bq4`qwE+v){e7} z*ztCfoouJr3HCAD-gdTq>|pnx?TVFXPut7(w)fe7wtsMsSH>&rRrN}E6}(bj5wEgW z+^eX1dxgAWUOBJ4SJW%*mGo}+?(hnG$zB1kl2_2H;#Ch?25$v#`UCwz_H%pCmo}Sx zQcktmZ4P^j-DCILkL}xbhkeh!Z$Gd*?Jm39?zJD$JaXZycv(xR%O<{}n&gKk1+HPy1*6bN+e%Ywwf@ zH1K_k_ayqT8;5eLn&Sbyo*q}9(b3aH5u<)Xf4K@2d&Lul`gPKXE5!H zIw6!-H>5GNUI?N*3RwcB>xmBl#a4g}piLN=721@Mw?UgR zl5EnPk<^!WGm`4of{_nF?_uOPXiG+phqhuQ)raa0B<%&ZVdP3EVkCsz4QH8Qp3rg`XpcX;zXVh!ZevJAU+MiKhKnE}?1v-#X z*P(+L?Lh}KIu~>ZqsfL3Fq-Tzl+o1R4>FqSHH^`tpu-vc40Hse4?@Y7KvO@DWOOQ& zt^xWibTp%>Zetj48FVb;t%E+ycrQZ7G5F#~h{cTk0ZO(3-W=#s244;cL1h6i5lYts zZw>S%#*0FiGamKl3dYj4PfBSr7UpfDI+t?HD6z zoE~S4gPveC`ELrNvO!ZBc@=t+QPlQRjLHi=&8Rpi*#oFt(6fvpA0yiU?CxUY0l;4r zjpJ_^bszL1NJBo^?K?)1FI-|w8|e3pwovkWv{mPW{>I{AHAZvt>O=>aK=lBc?lman zHRxalU)u;dBxF7G0Y<+79U8I$`XHkhLx+XzgAQl(5h&S-p!7qG{suZSf2XC=$@+?*9l7FhoF1Xm?5Y< z8Ye(g|GmbTBGC1Wqki5H@+EX5qt8QM5BU|kiP7oMHyD=)-OSJz2yzS9ioT`3+QxXb zp>Hx?J?M7Ek&nH_IP$%>88-;J1H6lJs88Nwu!|_<2MnzR7i-OjrF{p0)80<<4`4J=Hq5B!^R0{bqBR+$E!l-wkpN3HV4=|eina(4q zFAp;KD{3J>521dgIsr|7^hF5uG5Idg%b;Wrg8KU_248FQ9CQRqeSehEWcOnX_D_X8 z&WNng6O76XO<_bfXext!R(vh+Dwd zjH0?<2%)j?4Wr3tE`~IRe#_{B&@{$Te}2cfy3k9EqW=A!!9K8%KQI(CkUui2JM?jY8w}8l$Mr*F$)+B`P2F=OP z+@Nk{@O6J|ou+c({H;i%9|^qznunq11NNq3=t0oD49(FhAEO_G=4bG)dkO5o#lZf( zP!WdW4zv!8u?m{VxYAJADMm+V0mhYqQdz)JyQnV!`G}(S10$e?89{BuoDzfjuP8$? zA$+mTJP0k$(EFb%!DuR@Bt!3l>UKs`dGJMo-VGJi6=*7(>IdjOQQg64x=&e#<^WZW z(HL8*e8^d71xAx!RAlg1Izm+n*#)f(s-W#;JMvdRaaL80p%|g69?}F_gP}E$!rVd7 zvkqTi$I$mfYcq!Y{Z7VF-Rm&;NoGL1EBX!a4TZoyWekd8sfHnap^X?? zi>k&Ud!TnQ^ggAiu0T_NHf88thT;N*ZVPSB(ELa1UP6BjC4VBw@2LH-m7_kRvIwdp z*#o$CP%4X*XwNw6vkm~h=BPh9fzI%y5zu=XL+$Fqn2}KOKVmoN7V-?VJL9OW)OW-J z(33Hzp}iOfTdLk6FG2f&`@m8_eMf8o_cP{sXupvC(EcIRCj&yxKnI4H1+dn#&v*> zVKkjHj?w6MMScJ@oiiRhiZu1j1V&R|JjOWk>xm5hRZpQNF^+tEGNY-yDU7CjKEdeu z(5c`_)RX#*{0!*Np-(aTE9i6vf7Kz>(~Q0box$L*t^~!P30DV7wg;{rbT;G2$LBDP ze0DD5$d~6at}2x31bhp9mT}}S&oPGjo@`Gn1msV^!IrV#l=mrE6mlH;LI~A)F{3dy z)Dp&Fyv6(szUFA0Eeq)ZeKDjLbUEX?Kvyu1?6s1?zXBsDZW3cAbQR+oLSF%|qI@c6 zHRBpV*MPNv%3jCVQqb2JNA_CJ*fP)!jI9ja$hfi4*BLh&x`}b{Iegy`!`6UqW^66! z7O+(a?+A1o6IT)XCgXhw-Oj{SfWF1VQ8{ljan+$az&k?3Rf4_?-p9AQC7>TLL2>9# z#*!^|F_y;WZYHiObPvEigR{_mOk7RqM@(Eb=zb=y3iM+pt}OHuCaye`Y!BkfK@Tti z<$uNmlz)&38bCj10_yWa4F1J@L3<=bKz)9gv8m86!B>dGpMp}~0ec>Ll(8qE#~4fJ zQky|QenrPX&=i`&1O=f~F0j;=lZ>S{(mjBsemKnp&7stHARxb@{sIBbKj)aB36$yt z0vdN;GeINh1@H~>Deofq7HP6?8skyFe#Zo*p_jlfIEU=}D-%#Xe*@{ruZ8(SFc#%% z$ynS+D<+r)#Yu$4eY9aL?oDxOBA5;JnP4U~6BEpUIwruJLGv;Z%zU`0Lvkw6{%h zv{)>y7?k=Q$Xd`vjG_Laeh0D-bTMP%p-UKwW6>IwFj=85G8EgOwJ1SrM|#&MOg1PT z1GL`NE5XaizXiIA5oC*37#Tz-)%T#+bIy_26~n z4}oq1Zy^0Bl+N3NH1*R~#(fOk#u&Qin_xS9=@aN%jG_C#9a0Ut1H6NBs4nk<50Ksn z-N~3e&|M*Cpt}L`%!kmujG?}#-@u?wdS3|H>m$Zc9rrVa@~E!B(REb6Pm!j+CBHw2 za*9GfXAIrv5aY-<=sZAwC!&usj?Ov8IJ)i<_#Wqc1^t1c_g(!XL-W18dnx8NMplL94JilB7g7drM4QTys?f_IT__iq@ zasgU_q4#VoKxTR`;y?qw*oleh$^9t3>KR1f(TN_8TxfSL?FD@?5r_>ig1 z=oV12F`%_stPN-f+(nqW4EeID$9NK2pV6nGR4(wy*T}BGv(QEWec+K#-36K;O@7pr z@yNfLfxD4UenIuP2X&zSZ^_U*vT4P*b1F!ZdW`HSX1dWSRZ8G5%e9Y9B% zpAFiHQH!CS8TShGUdFA0c426|ny!q8jxgOAHwD_Aaj!yqFzyLxPsXEh(2H?Xp}iTm z8rp|(PeSiw+!|?#;u1AVcZNT z`8seLphH8**B)dv*_ry3puQi@c;v$)7&jC85aTvNM>1{}bQGh>=HnUnBJ@$l?SYbw zK~M<#7?_MST}SN_CGkEy?i?*R1?a4$irUx0@>$WUJZ+EX&rexRE|sm;Xg zfa*=02UJ(!sE*GtZY6Yf2wgje@ot6A4Y>n4FXSS0KI5p2XBqc8^f`w1;3-}Z;|J)1 zkn+%lAwNPFGqi_q$nS}tz*0uM0$mpJJCynqh}BT)3*suEaY8f$D;SUJKy4%L1}`&S z9_T8@QM>6Lz-@xQ$~fu+x(9G?K-Vyi`eQBQHbd7jj{4>`#%+PFXXNM54UDIu8$+r? zslR}C8MsYYs4?Ec7#mV!h@dBdD*)9)M!H<`5&M zK)+xpu44{|+yniRanzSzF>WFB2;-<9%1?UOJQGcg|w1lQIUOwna zMplEKV(>5i2#VPe^i4$UIeG^6B3qqhXK26Le9btr=LJR%hknC2vMr5g z;1)x_WgOW#jiGn6*c|j7=9Zt4zQoY`njxP6^iF4fVD#@$8rwks0{w|`G`8t_;K+CA z8sHv*(s{tGfd0z3rBJ#zaO7WfKcW<%dl1w<@(Ccxp4S*pL9a7z88n@7@J+8YL-&iX z#dzrR1i|26)xy7O!MF#Y`51?OPN>V+B2e@-Vd1L@jX-0hi$j|+_IBvqjJ*SjF-h2R zP}rWZ6`*YyTM^n0v`2nbXeY+P?g>2@+YQ>2vG+rJf!;WO0CWLki$P&a!j^RfWi+G-~$1b0lOu@Ho*xYB7zY)p^~9}o(OD7h&oWsP`p247y+9^ zJceTb5zB~rP@kcFfJi1rzy=Y=P`o}8FamuaiDM}K9?8rI*dqdeAk@9kct&)9W@S_t zXf{T4gxdk%sY~c5d)#Q8H#^L@-Si$l==lw96XYj z5%AkcK8E7rk^GDp0)=xEY9tgLO^7F#7oeE48>L>g&46M zn#@qVHBy)nE1*RfioZsRGGZyT7(;R5NO4B2gqC0^MjI)~2>4&*c1FDc#rP-0ZfI#n zy$&tINa}BlH-ch?k+O`WzAwj6>@ZTEkz|Jo48;*66&d>OFH(t7-#{xflKQU-qb@=* zRtZUcS&dQOLaQ^9`n3i_F~3MnMpB>EVkmAGsm)00zdIR<-$lspfuz19Uk4P=i;#Z< zN$so8X!5}ZjHI?UWHk9>BSuoY8#9{v>Mn-9H#QD8KHXvxeZG90~BM63}fV*(BTZl-6A6xxgGitLvgqW*$L3M zIT5lApqN}_G$Y@Jj$tT17a7aQJ^k$a(!Fcfc!jA!IW&_@}HKSd@mazFGj zhGJ0>>LWnk;6$ijfc_FneF5YrP-;KW$D!m0Kz<4(+XH<9I+c;1L7!ywN$5029)v!{ z=u^BC`m!afCfZ|dS@*6;VR1xwO zKr!aXd`720pJj9!^f`vUp@=-sD5}>&2LJlIh%90xolAZO@K>rLLcRqAT}%E1==+Wc z`4AAfpvxHgrX%tqBXUDuV(8nG$Z|&Hfv#W_wQ(gQZiA9<0Yz;je*z*elza#%2PMA& zA|G@$qo@zpFd{#c`UTK;G?8@-y}U(UV-zlrtY_$@BC>&@Z)zeN84-oP&d|3tkxh(9 zgucPZbm(SAJOJIos8P_ZjG(c#jiG(!2#qBmFvcR=8QOD>yv2xN(6<>i7P^BG!=djm z>S5@+j2HoZkD>kQ$oq_V2>Jm-`__@2j2H>s#i;Sn-HbQ{-NVp+VT8sW5MMw)WN7~| zvX7A+pfnDFE(P7s$d1sD8C@DmV+_bn&`%j%26}*zouM?YfW8BIkfCpjBcC(6ER^a8 z=sV*G)d}cw(8COUcO3bW(dD6EF|r%<2%{@Nk2115^cbTnLXR`D2lNC(`%94&M)riJ zGPLIuImyUgP#W_ zv_BEK$Vjr$w+!u9MA8`g&N1>GLwgsION=D@f6wR*&>t8{ZT*qablp#kq;~(zP%J-k znUT~7zc3WvkNnC=>W|+TiuXsZFpg~WJLCF7uQHBobd7QML$5QAY?RKpeu9Rfh+>|g z_+=FHLNqHf3PQ7iTak}370m+@kpD0=5fnlGL}*b^8u{p-Xc+)|nirt3U$hqT;S15) zpgwF@1KJ2QgO8z}(H5W`&ff;@z)09F3O^>~dFZ{2gx#WD840^ZyMg;~EyhHY${LI` z>KYxw7&`s{qUn%?gVrMLvgI=LySv-j$~*bG&+iLuuGKs z2vE!>I)-tlpko<|b3`9z@VE3LO7)nG^D#!EQ^3hIvIDj&#t)DS26-xbxKA>1(^e{MrGEYOv#vphcN_GVS`Zr3p1i=%~ z6aZUMEGouR#{=v9XHe4^KwU^?_V6QFMs(d@)H#1?*r zW&^jNKFCbW&UmjwQ5NCBKN53-Takv3B<5m*C^R<{6oBRdx8WSvEio_1hxDh={2+of z?375?01q}vr28eI4w;~IJ@7U|3o_m|Xdxz``zJGA3KVT4JoHs!5hkGe!bb`FBeV>- z18J&5Sx_G5AB0u_m5@FRt;__}2US2-)tG?VTAlG`Lu)YJ^U#`1fPP7=#RSv` zwV8nW@=hi||0dR9f~?TGjE6CnSdX#rvBdg}w;0-h@s>gxf<~y@d}w3Fn+v^*@n%7r zFc$uh*c3Fw`53E-&6xnUNxYj0$ZjpbJ+M33swES&f)Z_zPj+j^cwa!fGWI9v5XMsb z9$+l>{V>L&u8G6J2=qVI@gXn@Y1AokG#HCC?veN~7>6|Kk@yH>%R|RAb|~~w#!}f6 z0Q}dY+{B5DMY)L>w~3RGKL$D(pf4@TO~e>WoQ5=xC1Q*vVjNg1V+Lc}LuWF!GnD!f z*gnu_7&{m`n{f|9=P;J~gKY3D&hG(zj462>b7CA$KzEOZ&; zRfWFDcqO1OFgqKUBP%opeq@VeEDU@D-K=7com_qFse87RmLj>UCnsKpliTd z)TbQuHO4CnUC&U=HE{#jh;vFpUuV2Kpqm-5Fmwy!B}2C|UIFNvj8_S|o$+X_zr}b} zpl>r?b?6QzXbC;S1a$6ECZO_;f#dk@aUk?O6HpnKnBY|G^Ba*QVT(gZYsOblkFlRa zEn^Qt9plrvIT-va{30nAFfzjWF^_Xq1ugyQD;rg!^WPqWy%u1&Tf*4CTX4 zNwBkTps*|9`_QtCfbS+%V{A?+#t&gXgSKGo9w>Y(3H@aELtBB?NTVN;+JKHozX$CE zx*)w5+Lf{B!=!HD5j@MjhCapw)CU+}gzFD|987`_2hb-N3tJ@3VEjzbnT($oI*akM zK%Zg!e9+m9PklLu@iAW|%>@`oKK04VU=`BTuj{~TNcV(pVEi7?jf@X}PJ$m2es?JR zEomFlXmiphj2{O*!1&pq2N^#P^f)+y^ZP); ze6}Fw8~PYyVq2n39Ep#&Dw}(E-_#L3|OTtIJ3x3S_@WDc8ClR2Z3*lHH*ukF) z-2`x+KNyPsCw%x_@?wB?__d&`81F6Udd9B+g`W^U=96TUL->`TZ!kW_Q!@O7h~>jy zlF4T%ALD`W%R@0o5q@Rp4#uwteTVU@Lf>a%`5zz+V);9f27W#0F2-*F-OE_?W%7rN zUlWS95`GQnS;pG}{f_bb3xP{w_>G|+us9!cLE-9*4<9Mqo$>F2_GbJh(0%}A1Vy3f zL&C>(MRG8HS!iy?F9&VQ`1PT^7{4iWJeY!Or$SLTB8Z3n%=iv^nei$A7sjWue`Wm4 z(BBvz6JiC2qIUM|H1n8#8C<2QsV5QmI;P_!qd z1kx9vCBa>YgB66L-wCxD+LTdmLt!&Q?SwXG)LtmsMkvf%DHsnaosmZWreM4g8sjvj z3!^(h(N01?1nm#TV;+ESq&x~HBfT67TcylIn(jM`@lHaY0dtVw6*`ykdP1o^%a9NI zq@dpkOYM6Jpgfxwx&o|3x)t#-<5m>Y*WeeDfG_?a`H)T80)Q;U?AJWf3k1`hRNjb(? zYR7SK0_RXWQW(1mnhMZ2mfCR&oI#rEewMM+Z$AR~dK~PRYMJ00DEyuXE6b+XFoS&_8}6l&%4B zEum=tNtBn#gQB1R7i;GMUq$f+>Y2R_5?V+?=nw)4MQR9L5?TmFdXW~YbOa$(fzUx} zLN9`V3Mf^GA|OQt>_R4)cFQ^DQua1Vo!zb89rSWL3jAXt_l~v zx}ov{ahgwTtB}O#jr@R3jRkxbwouRC+z7KU4)7UaVNkalrJw?3E#xyATJSURccZ0+ zV*sB?@Dy!f5T9c$oW#+MaTc!ae5P2qRQ}^FT>s;9f`#h}pA+F}^d~lMOto++TTO%M z$ZztQ3bXk6Pd;Z`xNh+|$HIl*Z_Kv{?#!pE=Q7gYSTU{fZ1^KK2b|Dme@SrTdkI!pYd&aKOpunSJYPmoDmgux@w9C||vEQS~04LA$ehygp4gxb&+ z2EiP77Bb*N_=&kY>Fi-p84`fDruNP3^I#La1|P%EU=l+`;1M9+9GhVu(1skBfbX4@ z>1+hOVJbWeZ@|~^Cw8gRCkf%zfSy_?0*g;yU## zNf6fsy#*KHE`FN<^fUQrfBE_Yv7L|K^V62{(>C%y3SD6o5R>_dr~F3%9~YpV7bpfb z0Y4Vt`T~<79bSSr;Y%R43+9DLs1F@s7(4@8;1GNUmxU-Kp%~Nz(iNgUg-*g*xF$ph zHV-KYwSoGD41%e!8uq|3I0rX`DC~slFc*mT!tV(Y+5-9r5$1w2K))B(9)>_Ftbx7U zMnlhV$}f@^(7On~7g4_tgPE`nUIE%c5$qL#y&|wz1on!+UJ=+Uf^s8h4@JvDJ?H?m z)1ueGEkvRnst8nr zL`a4SuoSidwpM3{N?~h#R;M(db%1>JJ@QF>QeS=ljJl}%AZ2V&0*Ko(#BCYkR_}G= z=Q2A1d#U}{GPhW}2SXGzgw8MmX2S+J03X1QaF4ZFC{%%FfGs1jrCzUY`5x{tKMsLP z&;)wGQ}7IIfkW^aTxRYpArk6CM;Hb(VI7dJ>U;1#++l7_p4BQr6X*ftS?w7is#DkM z)U`VGtd3o(cZVU63fQVfeIV}|ZUyKS7X#Qb4qL`y%Q`l|mUUtQThm*BP#^$I~n zNPx#-3@m{60DbBsuTKorr|sAOM2H6H)d0O3pjQL*YJgr1_P}ZQ7XIcoN&$$5#?TF( zgn6(DUW1R}XE1qfX%VOfiI5BvU@2^aV{i^`@Jdr``Y7@F=(CU^L}TK%G5uv@`pd@j zmyK7#E;uPfJm1ChT|D2#^IbgO#lHZ*2$4`1+5^5xz&8nNU@yD_-@!k;4z(cA=QJ4$ z3t=k|mraPvCd6e^;<9ORs0EbMlyaISfDhpZAzI;+R`{e9K51P5X2S*`Zd!i;SA}R}gAx!6 zZD1fg4Ww&Bx;CV1^CR35qAfOTTLB&gVy^8dAcop*gja#IZAshqo)C|PLKSERJpemC zh8^3D6rw%4w2y|y&<*H+I>f_CAvz9*>9891z-jmvs6!{N>r@)>eWzVQbnXDRgy=F^ zh^~w&UGZ<%DX<(~hPU7%{2@fQ#lSV)v0e8qLOfm+s=@2FFi=xle9g_qh~!pkDfzeI-qw?^zMn?J--E0h+gR3D;gR>7x++!-cI1U z-s=Hh^{E6+044h1<37YgAL6*rUU)}{Wc;Wk?rdloLur9iYymsPic5JnC7X9;2wolMW~WHK8S(0>;TF{}N(!FhoH^=mq0o z5o`crYD{%FE5uXn;2hi#{OMYt%(25^2GDnmqrNG$m6Qdr7WTora0&3+_(D(-sL%Mv zVG^L*gji?=ePO&16Ulobc~7K16De~d^_fV0CN2l;JrR3PB+rR|3o)qxl!pe;3D9Q} z`b=64yMVNlF2Wx|Ob&u_K-$Tqojev6!d5se#1!g0<#~7$K7-3VA}pa8V7I5y@#+3B z8L<1)+l81~3aSDzI2GGXy#T*+gIC}^_)>_}j(~i|S|IJrL?E7K;@er+ zXBPFHwFL0ZEYi)!H?t$5J`g*ziJjTR&TRUr*{=#Q2fxng3gkUEjmJBapdVn{dFuBa zZ~`c69(v8s17#rrIsmb>fOuGNUWjK30(m|2t`G|gK|R1Oi^yxy5g``y{o)uPz88~j zG5%gW7tm!fx-9-kh$Z-c$voHuuL1sD@)KkVu`~=Gf#$FjUI6l6M*Ws8hW~+Eh_rCP zrfJwT4V$KogJ%F6r5yrvP9tsFJt5LV0G-m&DZM+4hWUU_=?CBg_z_6E9Nm^zfhN!c z$Zt9Mt)Q+eDgriH@i>eD>ac?LvtmEI50`*=TbU2aLnG({T)*-&AXZjMC@7Q3$N4R631A=VFpFW|Zm8yrvqVxbKTgr{Kzyaed70lhc;0_gHAWjvb#_~BXn z@+^5iOBoyS#m449IU6?%v8ga%<4xFj({peTsM99$*_0*3b6tTtJx6^vmw`?|{A|7@ z#1``3f}UI3!XTImD`6L$gstk2q zmBxH_1AgB>1<-N-%Rqm%|04XsE3|`v{^~#j=mh9}U?Gt1!257Th>Rep46R`}%!0M> zI(!P`|Ed$P=c~tscr7mwYX`CIL2P&M8f5a??Ufw)c?5{J!_?<6@phPaJ4`(eQ;);c z<1p79A)g~-02?169*$7X5z0C8t3L81-YCjv4M>81Fdd$S!*Bs;Lr24)7Ic6oVGe8s z@;Z7}h+}PGF3^UL9e@wud-z9)pu7yOd&o@1$6w7G#?QMA7Ss0=D~-& zvb->Kh7o`bKVAVl;Rt*##3w}nyM3|*4#3+&d`j7$z6KuyWqe8*pS6U(FcD}spB)$C z47#4_4JmM*Z9`)C^G=W<#M#>Lst{k;0sno0F6Z$1c?qrH0$dT|LIpU@Yd4w$v2c;! zFVfB~VvDcZ0I~9Q5=?_tKtJ{k_4($Y5Z^uq=<*%;efK8!4_dL>L2=_MfD|JuV4pp2il2=PlkK;K_h!yaCN&=h9DZ6PjG?v-$82)Bf|ik+?n z0kL@vJ6^*+*Rjj>FWIxD4th^|KA&p<-EN@gjduY1-1r6l5#qNL$bge@7Jh<1h4|eG z_~Z9#K%IXd0Am4NZrXr+Z<6m#^1VsEH_7)V`Q9Yoo8=rh>MeN-AA5iX}l$#Ce^(Q+0 z6$K4pA}nJco4Wl?-TqF5kA(P#`u)T8w@Gt56}AHT-u_#NJ29|Bh`WynaSwg&H38b? zz5ehN%!G7!9&QMciSIIrx6Dt0Jl*)rT^)!G_dvjpZhYq^*38mC8#0L_a}^MaCic&= zLl~5Y+JK%}kHc`F&1WqI+H=-^_!zDTDV$Im>Oeaf3R7Se?1uN?dm*KSO3)m7!&F!c z``|6OA*4|NqMt z*?)wL#P*Tvg)CPF@J~6)j-s5X?}RLm&B|ko@+Sb@Di9wPssVXbz#bLQt-=a;5e~w8 z@D*H#EFq&qfU=|Gpe6JG?%hOBgJrMYbgKja+0DWSHz+_ki z*eYf(ya}Jf|A4ww#HJNXKvjr`jxZ3$1NEr54v3|SN8uCr9!w!CwSpG_{VP#^<;UOy zA*<8?^sTa0$VbrWk)=RvRV@nml08dV?Ipm6)vgFxo%&YCX4U5a`c)^78pKeI1n2~V zfLN)q0I+$DU2qJzzQzymr;s(VaZU2CSsCzu&34ca#sc})Tn#(mF#IfJEd#g*P>UNNW-Jzz4d zgF}G5>S2%i=up2fl!GOJf9i8xee7KSBlrfcgImZ3`C%wb0_@O$vKpKK(lpEq#7o05 zfF2F;)&DDvs8=K6z0s2}9k5@cJwiTO9%jQ2LN*Qs>el!<$P_Z3pX1Rj9^DhDSHe?( zkD3sVP11yHS_i%svKe_d+brk?0oyeveT#8m3Ykc}C9Z+(K-)-s2Z-^+Uw~L`>4FG| zfx6HVy2B8d42xhR5JxS~37JG(B$b5*Kz))%!&*22__!5%w(1G^y>$gZx7LH>UBsp(XT%iLeZ| z!*MtdzX{pL1!bTvw1**(3Tt35yaV6CKSCxKgcyj2?l2nW!*g&@$iB;9yO8}-U@;Ku z{oa7Ha81bmb|?whp+ENTKM1D6O4tP_;cNI)$N~AFJT!tXFcRj#vycHF!cUMXwt1b(x;77>Fx+Qsu~vqe(ZKbfag&I(P-%gYShLBcT}7gjPVhF{B$qx-q01L%K04-5nvH3V}+{1bVF^S~317lZA;*OP>BeElakS}ijGyC{z>9DczJTjO zrqIq)=xb8&SqeT&!DlJ>ECrvX9DontN4O*8c=8-y3CMH&K%ngLYhW+noALN|e3pNSWpdoaI5ik?hz+N~7U%^cwr&6b>)M+ZZPHhiEfcj4*?NriEeFwgSe}tS? z5Ga2dGl#=Q*e&EN^qj@mF{?E&KFy-f zn8g@1>s`12zX~}!9I684&h8FF03ByP1C%rSXSglooJXKBOat_v^EP}TO6o>t4Y85OW?aT#PJ&HxOT0O>!M&PV25?T3%R}@d<6d!lKoe?fij=P4$n3P^4myW z8y5+=2|I5(DCBe0;kiwKO*WIqX19=ACc?);ZhboUJ-H!`LdrWU#bY`_tN)5zKk7S#`Z5C7jkDb5L-Jt!Z08ox5C+KWOS#6Jgj2>E&^ArILg6wv!n6X*d?!Aw{OufTioJ&^BV z7nA{F>@amZ+#m46VdC!yc^xSRlz9Zb-pB`}djp#v<>#a2p%JtN>Tq8(+TN68geKSOV1L?W6DoTowFTYG?qhfqYJ)_eu0V zC7~El$5TxJoliXjTY&nVBHgLWK$)lW0%=cI0(^Cvcsos;oF>21q&rQzcliFD9)KS2 z%!loO4c_?${t@zB7eqiR+!6A<1P{dJd(`#)xj=sJU*pfjP_GZr>4T0iP{pLPL0KO=5FYX#FG1HKaS z48Ax+%%5ooLtzpu1inAR_n-6q=Z^w;fBp`93Do=ZJ3^i%ud~R{u7Nk;MwI_^Ymlq`T6|oLSCTW7j_BxC2{fPRv|As0b5;M3Ev3$ z71w_C0#NqX#LL&~;G&S<1Ow^5nFZeq`7N>h-2k{LI-Rrez!8< zW5FMuhcF=4{`^76zg&Qhf06bt{P-8~@Ym10R^$;F3|#;BA@~a1LjKbe@Zs%dfIhdE z!9HNzxg!8S-@zAmHo|*C-YozvV6Bk%^1&1#GtnWFSjzldNH=A>xAQscpk7pp-Fs}7_O!+v2e0P^r4s0!#3-VfHo zKEOsr;-Cj)2qOX?Mo{O78jt`Tfbc>EU=n;JjN*AA z8PK8lCO8O}fNM$=2Yg+kGhnk4lv@HjmH1T{CDEm1f0zOb`3vbuWXrx~$b z@95|_qbnq0Wvq;n(a|xnPNz$TqGWBO)YnG&cg>Tf9;;ivPW$5KM~Q~paprC{TS}+D zj-9yEHgmDuylq=nmX(of0{ifW5W>a#{-2O3KKU@O+<8MB4UjMN$*;=txyrA|4|0o~t z!`>SCJmB(2y6P%&X&HHy+*!n9NoUZK?|CFe)Xr*(bSXcno{}4NQF)D=y^DR4d+0V} zZRUX7dKu@^+ZnF5cgE)0+gSEJFwE;Q+7286!3=lbnhx>t4>_)=;)}(IDS$;Mnz^Ag`WLjVDr&U5*PIu^7TG*qfFkj zqV1x7=31H5VOHDu>E?dNnGpv@^_$kZZ~^<{TgQ*d7`9_x|2EUxZjK-KSpRt_t_yal z?zo9koNjEfRxrctr4$N~uhHFZhPfzE&hYcRmWNpt@TL!Lnsv=QD(s>Wjqef_3l?QW zB@rt`Xk6_&vCKBgIm5$4|64U1tzX}}SF?m~|Gl>Mo~_re-rlrj(!Fi}sp8rLRNQL_ z@9)Ibl&ouxp^l#g=T;o$${TUD3zv_rRoaM%s%ArXd{VebY^}yd-Pi&)TfyVz7dv;# zD#xFCZ}W(-V}%|YJ+IZg3)53C%xyJq^kapNg^t+#Uf3bo{n~Ze{czLNSI0e;(xKu4 z^Um>O=AHSK+K+ELHe*IJ;*m0)Eu5=}$2dYe1Vhy-5)qEiF;2O(Z*t7mpa%C+Y=UVQ( zVieV3lta#FIW$17!p_Pk{Q>D$c+;zLefh@(>2hgjx*Tn}rjDVyH?M@hm?l>E7i-B* z#_DbE;WFYs80wg-?d^=0|IIqY%owbYY{iVMWiK2aX4s?3RWo8@OWR^=)hQfT+rX6t z3|CZRoAKUpS!L%=^NXA@bDq#qF%vd?^Lvh;51B7ryJqgtLDP0TK_gwqk4vX7XuPJ! zB~EQhL$zo}TUuPW;K)#%z&Hebn59Va>3RBLt)(ycjCHH^TvEFV~sr}-LtA5>sKt9?+} zRs(gk)gjPDhu#Wt((0*HeRU6J$UaEp1{fIsNSlCx_bz z9lU05r7f#Ef8RiqVO#93Wo&d0G|sDGr}z#t-wrD`dn;{=zN!@GRq?&o7TM%i(ytVE1LUeXTk>>oxn^7YV(kM@6TUP!gYEc=w9Q`$1mr_?;g3C zlr5j-;yX`F3<;F8I861(Dc5Izx+7IC-t^gn(KAr5bh*g7PI=jPor^__CswswExNS6 zlrzPr?*PBP!Bxa}K6$GE`6CaISIs6@iy6xv)x2`0r%xXiGs+Ko7J$BVs~K5M?X7gT zTF}$22E?XpYLtAz{j>R@KSp&=dCV87#PvLCR>F#Fwi@D?U}@|nGE|MZ16E_EtZ2^BSy9zX^$qOYVwV?KEIglF~Pc%BuElK0f|S%ts$q~EDm8GR+! zl76;tmGO%u_slE(tC%d0{5754zlyo)k#E&<|0?E|NB**w>-lZg94hLjfuoOV%ouS= zR_}+_z|-V?HMJU@KlrmZ>IXGaUwSL}JY7kBES6W#BRyS7hHb99zA@W9O*zNd;bx01 z>ld@DT_r52MhaV85hgTs;zD9W!kkg%qM4g{E-e;PCb)C_v6aip)<5RW#Y}$A#;id` znO{tux=ccD#d}jKI5%tX$ zMx#yU^{~UT`&BgsOPqCJWYXA9Rpy&_P8>7uE*NoYUhuZ(51GHOLVs2ETY8Gau~If( znz7l%hMb<9wRWz=T6O<#CT9U!+K&g!(02S6jcr+SwSS5>{NDBdT!TrvRqGls>9V$D zv{eJ-E9D&Bn^a%5w zdhK7{Jxq>2v&|iv&F5Tev4byO>xzInFvE9Im++#JyZ)>-Ogqo?3}b7Wj-K+POy?=GF> zshxf8+O_wF2G&uHxMo*vk%EFrrOeSM%YdA02mIY~<{zFc@9&ng88E{<;rI;IJXHx! zv_EG}m&_AR;WMl&xP_gB9A; zRP&CGj-&NPd8!bmM;p&@<8+Q*@!d3PL1rhC7WC~myZN!FzX}`k_0~7s!^v}`u`)By zlgpYnU-qOi%RT*tub=e#T~8G73%@hiJG)a@jM$QMqTpPsCkk6~P86J*^+3KQ=S0Ev zwI$CvQE>g~k>{8wxGs6*IVK9OUp?}GiGtG8)lhGDZjo*s$G+`OFLgd(E)Jq1D{+KfBeVRpY z-5F?kP@4Ig>I||zLEc|a$SwI*^N8*wiXea1$|n(n1UJ1=l+=HjLyU&Hz3J4>8(E>c ztDzf|V|7<%$**ROx4If~DHb5VB1-B~&miyOmj^A+8mZ+x|76s0spW(>{{mXh^Ik?p zJrG;+>sghx{3i0afP7YFEmd+6Znl-L`t)=LZ8)gHX*F7=>j|FDB`Ey?+N|(s!w!!j z{kc1@nFn;KKOk@JQj0n(pRBCWy3~>6zr&xNzs8+M%h#E`=ixo936%|%p=dyVc1K0HF1Woqxl7%e>}4#wX@&nP-Q6){Y(brmKaYPOO{O z71iW|(z1qVw`;j>T9*8(6;|HN2_Ge=Y4xCKiQeWARisDiqG_GfL1N{u7E3x8c1)uE zx$9uFmkN-pre&qSk##&ku5Qa(^6OdF4n>Y~S)|2V>CLvbC;fT`ZIEMh zuv+QW>_q27kms(?3QM1?yUN4?`d`Z$6rhi4Tvk3=f;qR(%04^LxDI*r=@n=<%KcQ^ zjmBgDNH>Nn(h64JGTZ)z4%RF3Wo7?>Wp;=qH-6S~|1!IhM@}I6#|C~3_sEr|PIX(! zYP8N$9{C?y?z>s&7^54*6{Cfg`$kXXsxf%wR^R_X`)j-1=dY|r$iLH#;fk*@gn7FW zwU?zzko|SZ)<%RbL3cOk@3XL)FItw@aZF z+}Op({t5f_T!#(|mMvRguXyjmxnIeVEA7XXk7W?$su}Ki?K35RlN>$r;HE~XSY)MF zB^geYKIiX@c4~eQ!*zK@Awk__9JevpGS{;^TLh;>>PlHB_KD&3;B&aW1f8ZgTxtA8p-e7-DDo_)$y207%;EAl-{&RjeoAMQ$hsH2g)Pl0mwZZGJ4Dx%cM&IWa3WLI-;HBnWk zMK~_PR`(#cDR&(EO#b|{`wOGl|IEB!I?i~es}qf9+|}H|c){IU>wkh9tXR~}ohsJ; ziRw@5S~CSlFUM7Vn^5Omr%sUwS2TxED8R*frLfVm;ld@2Th|&?$LwQ_`PmeQnYTt6 zvzo+)J+ioLXah4o^Als&XJ!Reie-QNqpYFlA@=f=>hP?B!ZVH;+_<}Y&buF0UYkzs zesRac8f}%S)kT=vl3$kXyr#C7cNX=^gR4uPw$)YZ6__5APE;n%GT8zwujT|gpBPI{ zIi9%zYH>9nb| z)Gfw%$39QhF(}Jg%y$cd}$@TLgDb>T-}NDx|h`>&=DztJ%~Imhg}aSwN1? zA6cPX{>lZ)@vj^%3m%a+n=BMwy=uh*=7AT@Jq4nx)+kokuo;HqOlFtJfhpr^R(opv z;BvNI92x3dZNjX1@hz6keX@M!Zd>Q55wp`<)tfc<>6)3lEw4G}X-AZ|9ARwr#xQbv zY^mj}8$EKfmr_1J{-VclCtS__^57N@Yon8>(CM8jA8&c2%k_6pOm@aN*i*&2zBOs6 z?K>=@ZaEoPNHXbibqRK?Ft8qUzM)X0}0# zB8Jq-gD5>LI65D9VI*I&b*i}djnUJ0PHULCkBEA* z+MJEuIxkPDU_0cCAr&h;kWUO{_pwjT;hod~->YuON`KvR98L9=oz<++l5>Y@yC>#O zIE(05ROw@^eCV-T*lYS@Pq!Yv_v)j6C$`k@X0mIV?s`6&ky0JysVb<~#X3%Z(3v>ItbuaP`*)fBbdc|!*4>QBi!<9LB1 zULJXH6Y&<;=?zQdTSZ|}PS6v}IF2mD*3y#=HubA<4ue2S9m!BUkQW69NE znS1%%zuXs44zqDfUk*d+g}PO5b*R!Kzad`tr}xW)qh%q#T#q%n-t>e4cJikWx^CzV z0#E+uefi%E%qP!tUU_i&Y;s@v;N(C%sWq5K&!b*B^Rxgvp^w!A=k(iZ!{OK8pAUyK z$K)!1|T?_m@j^_3Pznt~tsl-khpFw1)v41RA04fARY}XzIJ^iF}t@jmaj` zbM();>4`kUN-voK`&VOG*Id6_a-*%5dsbs?%;xdP2Wh!yr;hZ0dgL9n+_M@(p6QW4 zuI1KE&vL5UQb#L2ak0c?J?ia-NN;1t9Oapj|4Yx~$d}2J4iD*XZ1py8&dm5Pz08BG zr=v2!%2t%BvBhdl**aaFZnXA>|GI$Rb!W}*M3=r!jT!thhk;!kycdz)`m*Oy&U0QY zGMu{`dJ9BtgV-WYnrApRR_&xLYhFsbIAzMkG+8#ue>eSzZ2#@|vi;#5OHKDHdrbGT z9f5b&85!++C@n%yjy=Z({ig#t9>|Q?-1GgYQJ40ZYh=F(X-%4>Pc+|moJl=5ckYE5 z+dD3K{P9H{?tY<0LzS0~&xxu=tix96c4^7gj7-Z}93Z!D4Cu0L`YwfJ8RR?3mt6x} z16ggJd4>m*a?!+g%&gH(ewxWfYYvqtg2jX5G}Q}M0Tg)9$bV=sdr{s~g1MCxaKh-m zvb@#TlLM-$njbBwrrLav6Xk3j?renXuuf6k9s9u%Yy$`x8xav26%*s~y4rKRD(CdT zICFYi<=dyXRzCKS@RnyTHZWhiSa1EmMz~VM?CNZSBI-O*9Tee7jVR8Da*stFRIH=V z4aUaF9McpTu_P?clZ5`GXJ*cWxnUunt$(l&HOvf zeQ3_qojYsSG>p}DhbK;c)iJ79Dc(b^*&P?jI^7?sBjn-<%bGS#BT|j^=Gt?TU9yRv z&Yk<=xR+X_cJDE})!i?Q=iL20Ui(!C?F>)QuC#)dl`(}9w3hs`TwqQ42=ajR96I{R z7vuqQ2JI>Vay4k{e1fvXF9CAZC@gup^p@Kzuv{9;E1u;Day@BK>D3AwxtcTx??Q1= z;C0B4@;%!$=4P%d%CzI}JfM_opQehGkC@kF*x-lM(Ma6tE}DDoq)5r){uQl<39`B^sn*Jz ze9@;A-+n zsZkT-M zo}4mtS)Y1^Diw_D+b(fb{KQdD9T+Jgje z)HutL?8tCdRo3DBC?1g0r}FthMlj5?<#PUQ;|X)^vhPw;zgu?w`mz^aT=u$LQ`js# z;wgL6w?Eo!7A`pO(5xA!#%xWx8&r_sbc|+=SN3;x@L2K{;x}#l0rZ3c>2dnxfb`1gR{C`L zoF~2K(7#Wo57XjJ0dlp-wer6q{tl3v|94350L-y0Qql$@&G$u^ByG9 z`m1?{m4BA(?$N(jp#I99p83R(Ksnp9_dN2XKskQtWyw|k0s7w*_X6srHUX@1fA`rf zd%5X`%b$;5e-1DI?#t(IEq_VJPhgw`$^+vnK%OHX6(?3czBpk~O*8PySrn>xNK)lHvV+lAxLyH1Jr~m|E!P*Hq`G z2SA=;2`@d7lr@>|p8Z zvX*`yXuXyjt+iLFN1)t!)##k7{EA^c0$`4Ng%`+>u((Oi^w>2vxi$7YLmLY(b9eK>+>}pjV&8lHa5P-SLfYd8BM-2?^SM4 zt4yWRu?-(F@7S6wv6VJYCid%{5Z}9hqHL6TWpU=~a!TVKJsLOc(JS6m55Vd2^aSOM z$1iW|dRlT-A4{GltX{D`XXxgmpGVFu!mheksc&|1tPhYU*^XIqt3C`5DjzGj8jy}# ze~}^CqANs&*Vi(p)?=00R%%yWMt|l0+8AIPW0vW-V$9f8kIC;d)7-osK(M3jSj-{v!RHhaBQMBx7|**=_aGCI z-lfm@kp2gq-uHAuo-umI;ew3?J^A>aLdY}7Bd@IGzGD!sgX*}0ykJbza_hK5P7|$^ zwE|3ZpKDBxXgEGq#~r8-=ep>ZmY7!DKCotts)5egAbWA0dN;DLFU1nf#n^eEzl>l* zf^}TDdha|{X=z*L+!lKJLOtwo6UdY&OPQq7Vz9ce14~Xn&M&h z@ar2qR=lBu&|`XnQq>z*@YL0FxPoK1vRpO0TAXM{ly<0DsG1$yi#|4ULQ3kY-lJ`0 zGB4WmWnS#Pe8LmGljBNOuM}FWk=ZtW;Fy8&bL}tgn18QRNSnU>JI8VpaCOc6b^ zezsk*kHiM5i&V#Y)f$Z@nrDrMx78v|-G63Rs(`_6Se>}I0yfWjO`adVdvM#-_3Z{t zf3)_{b{)pHEWEqQ@_pUvEt}i@m3*OH<|PbTm=xT)Z;#?lo@(A`Xz>o~pX@iOMY*8- z1V4^Z zp2(@IEtNygX)LB1-t?}4M1oEqTv2eoRmsg>woATzxXY;0>%qIejuf3=z;%_p*C`tX z$h%~dH};iNIZ*B^ho=I?e7{}+^5uTHJtQFiD#CiME~maa{X_J9#Cu&1eXC}Z$NTiH z7AW`W<#b;A*k?tj;YsZbO8d+&{mUoiucUe{?zDMxrVV>Mq%3Y986Xd^w9}i5E9kmx zkeh`#*O!)?oJl6z$i8x``|{5c3;lA(=Uy$H*IVe+W;c73Uz^}T2GcZOF3=g-gKwT9DqqmsI3y(#Mt zdwKgLt7S^PN5NEyZ4%!;Nkjod-34Z)93IPrp`4S4@EhAa`zywFPs<#b`e^N8k9B-1 zDTJ1}x4XAx&W|6s$ZDBQ$IvqEle|qcU%|-A&K3h|*K8Y8|A`dcG>z}qR_sL6oZ7-_ znt7w!#s@S_OzKok&1)K8D5*y%1Da&^V4`cI!8vcy`E>DjJ+YClI-ZTX?Db^Q9O~(b z)GZjbk7upIt-T~qKgI0c7FEC|FAU!^xZC0#o$Ot@6ll8ii6@q~>$d)hW+U5&?=3#{ z^^_@ZP7NYvlBI8Hx z89ea0UQbNj)ie6B`c=EmY}ILbKO?Twq$Uk#pWD!;QkR78J?Ok-Uu@^;)}ls?a6ewX zb9{NrGR|8nBn{@m41d?sNacwo*3d5%<$DcxJU8q)$_NK?|Fk(K{aICy9Qx|?57GA#?{zu!t(r|v&+E~*TA!RRlPl*Qe{$^o)!A+R!6fTb))M(PMgY*(cBXb5T91N4`ojjrNwRdR|K&T+Sh$!i%!5_W`m239Gb(RWijIlmRxZcx^mep*(SuV@a{`;vi^FFn zhKB9QC=l9w#;C<#OrG?`_F+p}CN3F1WO2)+B}H5HDYKg+qF!Er%>aSaOckjO`=TTyUzO`dda z>xi^gNy|nJTiUAiGBb7k(#U!R3zo^(r5y$&Lw{al)}N z!;Vg${^lqnQx5b$D!UQ$X)`&Gdd)|mza-TAqc#!fI5R;0obFOKG3^hKGwt80r~RAQ zbjxglBf8z^1CTO&^-1W2XS-O0GQkQ&X3Kp#A9{W&T^ z2h6uD6}3}6V}V-e`y0u_OlQ05E^2GxzVlF{F&f-0;#J~dhTpGrR<{TF z+EkJrQ?#5hrM(_g^z_dk<;eS5(^SS3+8k|Mr)NwV;gN@ClVA2uOL!4YKzjO$1K#Ow z9<|Tt$;W2ef2K9*2+dO$d9ZcfmwO;_daEZqGTc9CJS+_C9~o0J_t>ks*BVpr20hfQ zvuri;ZC;ppA>U@-I^aPeVOcQG=j<$68uP**v)|&MYfpZhL4A z`!#4^sqxg_9T#<5F0ba>JjZ=2pL4>gX{o25YQJ_w(timXbE@6n*~NG|JD1bNWQ3Pq z>n=EvF+C>xm>$mFbfnAM?*^`7jg+ldQ>Xs8w#V)zT{54w*}Ak?@Wc~oZM$t4+;n8S z@IA$+9%NuQIC}0}sn?Wi>pi)%zg~0h?!lU~Mwb~$o{=C?FAoM|dzJ@0foBc(iFm-K z9*4*|+&@^Qc}C_!w^I)IH^uy8{(sa@t!R~g>UCB}eXT7~k9d~+isZ1WuRgx?w2}J_QEl)56YRG*eC$?o}6tL2W? zozr6nty~zz19E2+@9fWAFD$k0!O7!%x%j0)M=dG6L|`7v#Su@hG9*yWonh+^u$r;> z?WkrBl*!`MX9;G+f%&D&A>Ljm;5zlXst$f#^&-i#^Nnuz>+0fVRY&}(eRXgJKk@*1 z)ogOL^wpLNuI801Eq!)YFRQ}qdWjvNt)B02-TnT`5mjojthHCI;r`T?ZD_KC*i>t3 zpP;w=J*yhMg{Dr1)b+l_B5>>5sH0lO59?HuwGGO2dz=(b%L_cN(Dr6ly($ip<=T(ru_FCRCp-Wh;0#&0sx3%BuKdWhY-t~@r zT|3_6jo|88JL4Qz+VsPnbSjfIw8ayx`bzEnYH=l_7o!j;{n%|!d&ej!ky-ElyutG?*m;05RNvSfrM{dg_U(uoD zHH6cc_nHcpc*{9lKacC3!Q7RD*wQo1xPx8*VT zT6fHe_SSmk7iZ0-V(RMAF;3l1;Z~FXgrb^saw^g0IlahxLiM`P7&!ISNm0v-wwyd* z-tLgl7BffAJ2zEr>&;9I4cR;En@V7EvJ{km$}GS3hNFq`H)_XB3Alz>FIs6 zoST%M{3pnvx#qJX_xxEs2IQm1G?hQwV<}i&bjrGEuV5b~$_Gv)nCC@RBS5SmV6WTr zel(7)c3k_*jM+b>PdPQS@av(Ejc(OvWw)+t`p2kM)AuZZ)ff zm~jtR$+-7&x3up1?X*vAYMlA^Lp7AD?b%B)nJJ=TQti%gWJm3Fa}zRzS0!T;*(oEV zOzhFrr*`&zb^iDcGg_;+IVs7@K&{+3fYR`@FHlIPGplEY2sZFk*3xwF$^84ZPV{ z6>-I>I;i{X-Wyx7A+|S4*FOFOY=Pp8TiW8$tH zKap-KR-UNGi~YKHNoUa4-IwfSPo`Pv7vXKnuqWT!s&Zw%(-e8Mp;Ehy{pyGZ+U;YW z&{VJJw46EYvs(Tt@|Jq8ZON~iTeSQf@{)SSuI0`f`tPD=Wqrk)s3LvZM02*1Quy|c zwt@cEo{SB=S6OmKM59s8tLPCcXAMWUn^dTi9zm_Eu4Y;Lqtr!a`Q%O>zEm}NoxB?O zq{@$-w8lRnFQCUgE0^n8%!EmQ9(jp?^eeL%5Rw1IyQ)_Cbmd)DYkblGO_9>0Q_EaR zUg0UZI(q)%FM;<}ak7i_?^1GQeFIBt6qJ?4o(?`jU%Awm-Wjx-_a)$G-c~gwpk!@X zqRyeCB2|6s(^f?za?JCynJhcwZ*KF4#)cH3@mY@;Y?fRS;$qzrK-pSuF5SmN&SFOqk_q{!RiTm9UNBZ z@EpDGOcr54V5^z(bSf0Aj)kdRT=fiOYRtZ!;D!czZ*L%+qsLVy9<1${S|k+6fJ+#n*p1y7h>f)HZQa z>&}y#Zj}kut2{cWnjC7r96zpSZMoHIWL6=%=ueduamEkY;Rms9eeGCnUDd_pDyNIl z@?5Hrd&N}4_F3|> zn5RHxMO~n-mUmy1c1lljSu*-!1l3z7>E2q)gS@@6R?si!?Kb{i+1dxS(x=OgR&VOt zPqp&DF8a`JY@(#O*mjyY@tP}~_x@lo#@&bskW z-5zNp`bedrq-tteQAA+0FOioCNIgCsftq(2yfYi0s?)zY9_h5H0#EoK+g!%`L<1hl zbWPJQ@;7*_PuQA~iGI9KMtU2To=tcs%<8-hkKsjy*qWKn&d+pAn%gJo$u`li)qk{f z&63S(%fHXPW^`#XsZ*ONNsn|Gm0&KF3#zv)9b39`W8#LepVug`AkSgl+)eOg9^ zdZkL|FJCk<&-}^ui}yM|7H_w&bulK1FfLSY^^P`vqrnqnVd^cpO1j>XCM)TP1?p{i zO4`$sa+uQ@JpMyTgdw%52-Bwv)QaBwL}WOBBu>vgb!dd!a_W^beq+0OLtD1*8X4B0 zaka+HYs-%Y2dHX1{^*om?Nj30%<5dZQT3M1s#kezxqEX?{Z+*+_x*-DTz>Z0Ur;<-TS<_m$A@Q|Xoako(;yqHy11zEYH1 z+w1GxxG&W&$9>k{$sq`JP&sut=n0;U0pI_QuT2?7MSF5)(l)Eda1OGMRkz)_)u|o; zQ42WlvyLO^^PY`(`ZY*=AJ3jH!K_j7zj9-|aQA z(dsE(rZnyH@+@}&f53OoIrm<>B4CSM z!CnzDHY`+;CdGz`h*+>7N)e=}G!+rBU`1?TZ(xa0G)5D95@Qn0OErl}OyWySc?P+M z?>BqSEhr}bzwdi_2xrco-PzgM+1Z)dS(*^gn^$s4q`=AY#Np6tRk%EvhSdU&3r-X+ zlUieIXEc$#XcNFv^_(eyY$Pvi{uP|C`A3+PsO6LH@dOB6TAHLk&;r>)h@nhL4*7{p z@Nq462x+x>wW=z4zWo}j7nwj_Kt^r0jj35n>kC+g8(?1Ss!(9ntzO{plXR;AZn$}_ z+m_+@lFQ3l4b{GnR*lvVGc&$qZL6*GdtbKPRds$5r+-@gq!G1ZS^X|qX^gb7e$F@r zhOTW$`kH6-`WLWx-X`_JfDm_(1&us0(sCoGO09{5Ik(V34#l=vg!9Qj&IJFFji{|W zf-daaU8P$TzZ+>8q2U#N(AI#wnWQ8pHo#hUm*rkae31yGv=%JJC ztwgO9YFIX9Z;;cRMWcmODACKp_Kh32dxjwuOij@`5q#j<)v)o_8dqlw0Nea9E$!jv zg#~VI1q*oum?`WF$Bd62lB@D|EPpU8_U-BV$dRa+2z_`*oNC{`hprYQ;v0nl3)xpsvY&|Jp+S+dUV_u7(DUq z@k+SX3*8X^ij#Cw$B*Cf_I~!n7^3yhT_SEH zSs)bB=zdvROD*sdeq}Cgs$HkMpIlpMb1c_b8eJof^&^ETN-gj`N0{2|qQJ@OUrXEY zG;7Umz|*YaU#)q|0wa>q%FsS;XfADn*0-NwhSCh;w82a<$CO1-@UII0g)KDKO?D== z?%&L{=zAEU^*dWYO=atcnki#Z!+8Y?Yn%mLfX6~U0~IzkjVV0QlWM_(e9l*Dh4*|3 zyjKl4e9lTg;d55&A$&}uNuQIuQw{v%Pv~JZ>ND+Pgx{Mm^*s^6SZIT%9>XS~| z)Urd%{%t13wd&ByzDFqKGogSeNCgm-6UIa^E<;QNwdXQ~76c1+qlJTp;l(Liuaae0 zz}p*#tKM?9y;k@NH9>~LKIZc2n(t~YpJ5z!623Zf`OKG;&#F=0%${r5CUgC!X|Ah3 zMr)LqB--g*Dq`N1qwD`HCB;Wof3b|0NJnAG`t^nduOt> z%lkvJJjP_f#MwkhGU!e?2%T}nIcY=XrY4&zHx$o3F}um^6LX7;i%COgkG5}TcZ-WT zGX>ZA#f+5rP}&2eNZ&+cHsCxgA0|M{&~vDMh={jB4lL!`RMjh5bi~Hm7>}Prk?@V! zAd9ekQp(FLLh=y^Z#XXWunf#6JCWM1G3XK|ChQMhp>@%Qjaw`qG06Xn1~J`wgaw@Q zD#4XdHPcZhB&b#5AdGqi559eVpe2v;MhI7qG6($G9Fc7-f|p_3^+mk0MO0r|RS)Gf zlM=j4x((u5jgHlUn5oZMPpw}G6EVl^)~xd{NWDPaSHUqz+ZL0+7^G}zl%Yg8X8r3Q zf|R9G7J<~W|1n7UrGeBh3sUCB58)$eJ{c@w->_ADuWC>~awZiWY0z#*gpE^^IwLy! zrNRJvC}^g@P6~BK$Bs3)@Od7@zi+IX5ue*vzF4EB2~<8`v-%oaN-{#!XbqOSQ{XsY z3#JStX61gZKG5=eSN|%^fCwbBD}|$TC`hy6jA!P~JOMBVUDAxF(FrD|4pbexxP z4jt(&2Z{YrMH33#z{ps1q>%tq>x-3M&&@sJ5s36f@SG;qY`~%;aFy!nKHnTLMo&6Q zvyly$CwNv;Xd&A_4~!5xmJbOZV&~9A-@aeFDMuFyKTeq3Q4sbsQE)5GQ+72%f%3I6 zV#|0Eg9dHkv5@wC+v}S+*bSaOMEE(c)J+iCenIFsd4i$2BAof4iIft6{4-*0Lw^9a z63f9?EF?6lDl8R;m`MzOt&kl;pMYNj9G9 zZO!_>Ctrm*(s|aDkjTP{t=rxaB6xjFGq?H&@k7X$9!eNR7boSONZ9W!bLFX_g*M2P zr{qQxS}iJDY;&+hMnvpt|A4cb*3W%2e$mbuEq6DMnj4WZDSZE?f(7rk7@Z#0EhIR? zb+ET}&(4K$Ve0~1m-u!c8Xn>{+^c!l&V`G@H%~yH=3?Fu4pwxHI?Wp^CpGB7$rjE( zTIydBEtZ?Ret$qfUF&A`>UHQE_X;?2d3Tn{t^@ipfguC1z}CGo+M#B&t@$O;JS_&{ zE5fS(%2>-&m--KB({)UXQSBEFagGS?@i8lS1=Lxc{U0vs(YM*+4kMjrd9s-IUj=VW z2R`I{n#@#}>;8P2JO{^aNU`tCg_{S%gNee+Bfc2^r5Edg9miPS+Oj;ngvzmYrGA=l zN*5 zUc=o&rVT^$kTz1H_94wYlK`g7hqf4 zRxF$BG5huGxaf6KK=R3HQw}98J!;pe(UmQ6XXlizidtB3z%zE#%(WSFo*kohaj(oS zwClhZIz{J!P@;T`N)}A$)~5N^TcrFSO5fR>Q{Ns6I~Ct;U^lm!k#6C~&kxm4gq_-1VtG9V2q=pT?i^X@Q{6EisEd(1X_F2{-Ar6|=v#bT7&vKw}khjivYu1W=xl0#^ z=FNEC7YeX`4y#9q>Wdj~)9iS&_B+qCf1OQvt{Hg>!urOCL`=_pORLj9-y{&1eS}47 zlZv>rXn?j-xn9%P`TK8(7`edJarop7evT_P1_ZA3EBEc=oHyFDplH&{RSV8Nngw&(vrl-)u*hMqIdh~T&)%6ZI>gO8df3{i@WMdxGfwAj z@?XL#$O+D9wEY!TmmN=h1jIaqQJl{PG{<;#%-^+Ti~N`5=H;r_D!d9VGw~`VmsV^7 zwQv@3tT5_1b`pLA3(b3ujUaw)u*E6T&Vm?RLSnq$7R_ER2C1!0x-jhVIUK&xwi-Gn zWCKkK^F=KWO)7+hILA!i&{PYq-DBL(3~k3;nzWz{E|hJc=d3l=LY~rm749LtWro93 zdY|Ccx2Wg(2B!M+-k#9fd!RlRb-*ojR1r$p|F35*amkl{6HS9N->SxQk#^Y>D{NawVqpNQ(g%8d-#_B8(K4o5tJI2ve$wyB5|_ zzmO)5`o*E#wZNe|)pLllH{nF6$1`19raG+^1@YLVj>X7z`oEf(hz}FsBM1trYETa&*8#$4~e;SQV9fCV7pGcP;Nbv`y#LtGW-L7S*d) zRM_yYWF|69nw36m_=;IVN!1Rg9$V9rW-M6i-=Ty5+67gzviN8za*b?6MiXCc)YNL8 z*$7TG`yuRDwaO4sTOW)B*1vD~xJ0$|Rw2BW(v)q*0vGOP;JDO#tTolm zT?7jBr&^&;YK8unL)X>lI~*nkQ@wn*$0>!Qd2cA#Q7Etl*4PB|DO4oSw1neWU8oB8 zu!NIyK!H=M7I^fzW!x1~@9a@6w40#_EFEG?g(ES9bC zxsp_)B|cTWU#&R{X0CyT1sm3co2Clv@y_%Uw9o9Wpj7T>_t!kM5NMYxd$j` z3I(b%vx()Dnjs_A;jdZR$mBJl3X>y32JMlLPN`X)JkQmv#Z$b!7LA{F-Ru4tow(7Qn>VrnJHArEST^vfbAZ18Q(t+SyUUD+iK`bLj^I5GB-#DwsS~5)i zSwb^)_7agviYj%Rr6|>H8baf2q!uk$MwKHbX~gS*G@=k#MrUv&Ps|}Cxu!(IbQBB8 z9<7nZ9z|sQWPNJIRS7e*z!xyq!k7(Df?eI347t>o0YumoPbDQi7^5L@lX5G8m zcD3o&y;(j&P+CM7iZ{!1*bj1xnTG9K4YSz~&_gP{i}#HW-oMLB)&V8nG@qAP(tuK) z=12Ty3S2>{M(-`?V9v%Y{mue_l5=|tl-i8|N-Tg->ShC!de{ObH2(u3Wr&hnupbnp zI4yC=`)UuiFjzol5zews!sc_v{%I<=68D8*)*0h4m`hu%lnE`Xy}x z{MiP>e&L4Dad5u|B^@RO$q9l_)eV{>NJvK03)-BuQ}bq+TF3})!L@uxn$z3bX_Cil z?fHZoz$e_Vmu1_IQ&W8Vy2(-7w2c~$^_wC^7-rKHqWM?(Y~muPM(8K6pL6F!rT5>^ z!U(9=NBb2FpHR1$vduL*PV{>AQbfe`eyyFOLOMD(Yt**EAm{cC2UPj|6K+yyHukiV zlqU$ydw0mLZ1_@C6{I*RL^@GGJF}M)MCw%4d&oaEEVj+eeCGYq)=Y$EeO1;X2RB=Nf*>$_e32~ zPR7;YOB*?oFthcYy5L{-uxyV!@;*zjAKaeB+?Sn&PKM7}lJJco#Mu?Gt8GAm6x8wy zCT@L5G*e=k4z?-6BEwG6-LON5%@pnHm#(e)rhX}gLM;yB%G96wqcj(*U8$OCTd6Us zv4#pv)=rC5J23FrigTUD8;Xr}vN>yuej4IF+f?)6v>BK;e0p<&;} zEVv-haEA#DoMsfW9m67r4Hz@QYia7tmC>UIIQMSVu2*a4?jgnoPROBs=1lS#)4a6j z{D`qWt?D;f-n=DmF-W?M78{d5ujz0kTN$inWXH3G&1|wo7_MOKhY)MwWR$e*ps_tO zskpYqNrjn-!8MYQ&ovImT(gAJj8)+4H0c)Q&F}&v9OinAoT+?1>&NF>ioDtqj_}Q4 z&@BWFR!AuZ=N9;d5U|O1vep_e>OnV+fgm0BUA#D%r4@g+XwhfIavDpET;t)fCQ?qL zQ##U47JDf!{_Vvj!xxW3qE-xiIcmiL4T{_cp%5`EIU5`*w0G#PnmcF}ebdr=k#4J@ zQ(AT%Sf>F($Lm77XO*HPuV_FOmr713q245jzbqnu{`p2$1U=`lA^&i3ocKEKMJ#)j zTjSsyk#H7?W6EcP5}!jR(;TU5RS$7RRez~PX{oRsKe?r)O6Rr1@d>&{fz;G}?eL1K zC+I&;+jPghM0Zds6BQfqmmTM7WCOQ_21nI)fTN%batAV7hD^ki|Eq&-CM)eRVQi~b zUgLYoNs^c0KuE#xCLO&)2C?DtTf?Fzb!_6kW0nxMj=kB--=(=N|Qg=1^#^q!w>e*1*7jRdAfCMhM@?kIhNt7z_nl0JOeXoi_VPO^XKl& zU4QNgI5Xw;f$W2~Lkz3WoYCHqQ};hB4G1WGwx2DNSDpWE=FIQTv$)FMpe!8I+N0Ws z{A38`Dx!+vY~hE#vFX-h-gdAW*c9T3XE?C6Y1-T>g+;~h37mG~k9F(*I1wJSJDx=u ze%N~^?&Gz2AIF_8DIL>s_fKm!SD%fHJX^ha%}={Kjwxk5d$PJWcK?{1{NwKH^8b3t zcQJ`!u+b%>M`GVASiGl zfWy_RNi~`}tyFjvhnsIg(5dk89IjqXit>$A_*4!z-;gj(52gStwSRbT**|(en!i{3DL1WS z*-!g==%+?s_o0+(tiMKo@x4^YzgPQ>?=AaH?^p2mYX9-xvj6mcHGi+tL2iovn(2V| z;urkAN)P_tOb_#WbjtK0Kf)F80E7H{Zxc zEZKzwfGtl1E5WjAFC^k3)9XU>sXM}ui)Qu5iBpTF3eDx~x%&>tAH9|L<+3yb2E9FYkycEJYoR+P zaB9k0@zgd~0uuDhO7N4fHR;{4VcR;LI}WiM6W#BtZ@NzlwHwmWUe~5k``%XayTUNx zVCVK)ZHZOGaWRG}L7W=dpwR)XwtZ(qkl}50F3jRQ)|DwdS$XlC0+$S2#{m`ij&d9> z9-$-(Zdw7fL68sj-=-vXn7blfBgDxBxxk5J^FI6E;0X?+mX2Sx-l~0{p`BUP`-TH{ zj&1sMvG4oZ06XoSXOpteruOlfKR7ME%_#qw>48#7<*uMu-!>il_Uq8rH#Sg_Legop z*od4*2qJ-8K(q(@ZsV?98|5Qd%H)AFD^_H^ zGq)r!BPmm@&KWXaq_ih=^vQ{@d}7WaJ*|EH*=@OhF<$^d1vp40eu%JcGL#Ja`Y{hM zmFjz7lF}V*7j->>R}(rL0l^CbSW|2$EhYG)gQyd9;fZ!52X<@dAnq+W{cQIR(aP|y zeZ$_a@tXnUb}0ZKuSs(Tr4rwjwpp1(J_ z99Jh<(^<*-B=Gh1-34$L8iEETQF2SLNC#?&@2sIUbQ;){>{nP&nJ{b2q-L!Rf4qO$ zajbJk$38R1oVaN)wDnsVv%im%iBa?N1gPnWU*<*n-NSs)`PiL>|{(n{t z8sCsV*}0Q-yRrNx>xvP%cQY|&`@Mw=?`@CSc7Nf*`*9Uf+gRJnms#6w+vEqAFUt?M z9gTW#!-n^wlz-)1-SWRv(0}T03HoL1ubZ?O{S|3a=(}?+s8760*F7?t6!@VSzz!l# zxv@{4?W_>KspyD9HcZ>UxVZ8**cP`VK7Gtal*p~X0!1L(LsZj*=XtaA)hWmA9IS-= ztzRWnoXb!8Y+BeitX_rCGvdR&xI@focm6oHvqQZMcWEjB(;{HHgfNv5Uqx&$xpTHx zn}G0F;4bX9>J17XOI4<(Ez>MfQX0|}#k$n=n+3dS`L7DGB;rnqJdj=6o$v3CriGq# zTAPRgVL{W_3Ku4}1UHx}BbCNjn-(OJR&M<)wj!WlTEeFhAz#Z?6>?AMkhq4b^<~HA zWsUIlJUiH%U92qAdUrG`uev``b$t@UL|x^lyh4!93sS}37Zi#TRXG(fUixg5x0gmK zRL}+EH-s2aY|oJ;;}1|V-G_@ia8aou$vbrjXIG=xhAm$wC4Rlt@Kps1&)@HzGfj@7 z;gbXBzMH+~b~Kv&usAy?aWwG<>J8!TxlwzXE7BwUR(2e?rkfwsG)eIqEivcX+7UCK zYeT`k4t6$Rk}ek0*p^RXR(s{)UEPEFH1HEXH@rK#Uax@cNNI9ytrZX2yiUAbTy_6 z7~JJ6LV`dg7QjE)b95SxXOfM$yb>cPTwip(c(zSN6Ym9Co|&JdqR z@wJ!>toy-(^2hQKq1?tL_2j~_v3^~%nC`+wrqAl?x7d5p$<$G2<^8|>B=0{fya67Q zC{{{OSAx^-Pq`GF>|vMyxQvkE(>ohmf8kQ_BXU?og%t8nJG&9Z#X5PV^10=P2<^h{7Y{ZmP{Mef^2PvjPz8;s4Tef3ajvRFucf@~vgvnL=K4bGg z*7opRF>!pV>;6SIGcw+fM>3He#H-b%(tE_Kb(8tr@Ymes5(4l#G=1%*MhaZQmIZuA zvY%8Yb!3dRAgRvt*CUp!DI7=GD>~rv6^xA77?e18koCB*@LF*cAEC@K8TV3B?q!V0 zq!F^l2pQ%HWj01qj7mMZ$a^tHNdEic1-TL<6gxJiJZ&@|8B$Px(x(9f%w-;GNqZ-* zB0?(?bULV{DpIx`bt*QUYn~N>?VDC3MEU8ajz3T^U{=xil+W|>zerhh`EU8R6<^42 zoHzu0Gw-D?`~AR1X7iuavDuSDvc?2#p6!@Ex&Ok^gX|{GwCymWr^mIwR+jvgo%zew zV!7%{hRd5Q_@`gk__N0d_0#gxHQ~p8%$mDBXwsgAi#{uJ?E0E*n=Mvttw2T_oPKvg zC%RJNJ*|QJ~QSFu1QQ>NJjfk9?c+LyCC1&7k2#54R5g~`OgZ($FEO4zh>p9 zsVN^X_e-BWw)th7sGYZ--96rPm~)R_JBn=1vI##QXRY3yb5y=@eRoOyjgK<3rv-NMlyi+U6h}#SbpZ|IL@?S6L65 zT9LDg5Lw}yp(1iS?gHyd*xDRrj@0^wpE9$VuHpjIXB%6m`FC7?`0gAqC23_#p-||w zUR-bv02cFs4NSPWjE$23dB?%~r1l#dTKRRC*(K#}OZoXQ5EB zJE6Al>QY?*u`=7Lu(ALPDke4^9vi9ag}>TTL_OWZ&WzIut5tIch#f>9H?8$}tN5;A zZy#ZjT(J>a_l>22$-ym}bV&d5fM@a_SL2gDUpFhqW8~`S*{fYgtk!19pUr2T|Nec| zlWj%6We*PO5pw6f;N)SK2cKrv4x%3S90>t=UnHkKC|I~XVo-yTy8Q=MHtgfSd}?^U&)A%) zQ_?3mG+1(Avu;q6;j?zMSkJWk4>D<;|MEiD)rQ+bf5%nn!86`mp896wgsj|wLVv^U z4417d$Afkp6EX!#v}EdWP!BdC6TH0%zMMg&s0F@)<<<&M*TBSGOZg1VJGH_yUs68H zvb=tx37>2R@nEdq0=|;DnBf-vT0^%yQhDr(866Ph{l%V{&Ex$x_3tI`P5peydsBa3 z^4`?%m%KOi|0VBDbfEX9{+jVO(c>lWUq+Ypny=0DB8LU13ywahr+SH6M(!}TR)d-p zKdx|(LQNBuU;M5Hcad{NZSCx2S~p|uLb5z_6W93r$BxK} zPs|&YhNEMT6VJ?=aeVQDe6Ko=`f&$ySKNqkj1Mz!g zw53>Wqg+IyU`Prjp8JKni-OmExpe85>jKk)doFoWw&havn$hi$y*g;+v;j-MSRcN6 zjMwUE({jAVMNbXI(Prj1|zwBF%?0|NU6 z4Db%?9x$wH=ql_y`ua}oHEW&EsHGG8_)HA*9vw&*mvO{6k1kRrm_L4Vgr#;sxRsfd zMuZ6?vhF%GgLm45Fqo*5Vvv0f%VW!D)WDa{DoBK{fU^oe^J_Uxgf*sNCS1rRt}wT# z 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

R*jRJ1?^iQ`xYAuqn>-7iqg^r+ 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

!+-?iHy`H`{?S!=5pudjt1=3|0 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⁣dUi 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

=;034=|=!0qfLoVZ{M)EKH3o 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 literal 0 HcmV?d00001 diff --git a/app/src/test/java/dev/kaizen/app/SettingsViewModelTest.kt b/app/src/test/java/dev/kaizen/app/SettingsViewModelTest.kt index b26a839..6b19457 100644 --- a/app/src/test/java/dev/kaizen/app/SettingsViewModelTest.kt +++ b/app/src/test/java/dev/kaizen/app/SettingsViewModelTest.kt @@ -1,67 +1,55 @@ package dev.kaizen.app import dev.kaizen.app.settings.AppAppearance -import dev.kaizen.app.settings.KaizenThemeId import dev.kaizen.app.settings.SettingsViewModel +import dev.kaizen.app.ui.theme.themes.KaizenThemeId import org.junit.Assert.assertEquals import org.junit.Test -/** - * High-fidelity JVM Unit Test for the SettingsViewModel. - * - * Verifies that state transitions, user inputs, and theme selections are - * correctly and reactively managed inside the view model under clean MVVM. - */ class SettingsViewModelTest { @Test fun testInitialState() { val viewModel = SettingsViewModel() - - // Assert correct default states - assertEquals(KaizenThemeId.Amber, viewModel.selectedTheme.value) - assertEquals(AppAppearance.Dark, viewModel.appearanceMode.value) + assertEquals(KaizenThemeId.AMBER, viewModel.selectedTheme.value) + assertEquals(AppAppearance.System, viewModel.appearanceMode.value) assertEquals("Bruno", viewModel.userName.value) - assertEquals("gemini-2.5-flash", viewModel.defaultModel.value) } @Test fun testSelectTheme() { val viewModel = SettingsViewModel() - - // Transition theme to Aurora - viewModel.selectTheme(KaizenThemeId.Aurora) - - assertEquals(KaizenThemeId.Aurora, viewModel.selectedTheme.value) + viewModel.selectTheme(KaizenThemeId.AURORA) + assertEquals(KaizenThemeId.AURORA, viewModel.selectedTheme.value) + } + + @Test + fun testSelectAllThemes() { + val viewModel = SettingsViewModel() + KaizenThemeId.entries.forEach { id -> + viewModel.selectTheme(id) + assertEquals(id, viewModel.selectedTheme.value) + } } @Test fun testSelectAppearance() { val viewModel = SettingsViewModel() - - // Switch appearance to Light Mode viewModel.selectAppearance(AppAppearance.Light) - assertEquals(AppAppearance.Light, viewModel.appearanceMode.value) } @Test fun testUpdateUserName() { val viewModel = SettingsViewModel() - - // Update user's name - viewModel.updateUserName(" Giuseppe ") // Should be trimmed - + viewModel.updateUserName(" Giuseppe ") assertEquals("Giuseppe", viewModel.userName.value) } @Test fun testUpdateUserNameBlankIgnored() { val viewModel = SettingsViewModel() - - // Attempting to set an empty/blank name should be ignored viewModel.updateUserName(" ") - - assertEquals("Bruno", viewModel.userName.value) // Remains unchanged + assertEquals("Bruno", viewModel.userName.value) } } From 9e4eaf2297236edfdc4bcac044c116bf23794b28 Mon Sep 17 00:00:00 2001 From: Bruno Deanoz Date: Sun, 21 Jun 2026 15:22:28 +0200 Subject: [PATCH 09/12] =?UTF-8?q?feat:=20Kaizen=20orb=20app=20icon=20?= =?UTF-8?q?=E2=80=94=20light/dark=20backgrounds,=20monochrome,=20splash?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adaptive icon with amber orb on warm off-white (light) / Obsidian (dark). Multi-layer radial gradients for the orb: body, depth shadow, specular highlight, warm bounce light, crisp rim. Monochrome layer for Android 13+ themed icons. Splash screen uses orb foreground (API 31+). Removed all old raster WebP icons — vector-only via mipmap-anydpi. --- .../drawable-night/ic_launcher_background.xml | 21 +++ .../res/drawable/ic_launcher_background.xml | 177 ++---------------- .../res/drawable/ic_launcher_foreground.xml | 97 ++++++++-- .../res/drawable/ic_launcher_monochrome.xml | 36 ++++ .../main/res/mipmap-anydpi/ic_launcher.xml | 4 +- .../res/mipmap-anydpi/ic_launcher_round.xml | 4 +- app/src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 1404 -> 0 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 2898 -> 0 bytes app/src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 982 -> 0 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 1772 -> 0 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 1900 -> 0 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 3918 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 2884 -> 0 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 5914 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 3844 -> 0 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 7778 -> 0 bytes app/src/main/res/values/themes.xml | 5 +- 17 files changed, 157 insertions(+), 187 deletions(-) create mode 100644 app/src/main/res/drawable-night/ic_launcher_background.xml create mode 100644 app/src/main/res/drawable/ic_launcher_monochrome.xml delete mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.webp delete mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.webp delete mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.webp delete mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.webp delete mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.webp delete mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp delete mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.webp delete mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp delete mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp delete mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp diff --git a/app/src/main/res/drawable-night/ic_launcher_background.xml b/app/src/main/res/drawable-night/ic_launcher_background.xml new file mode 100644 index 0000000..75bd836 --- /dev/null +++ b/app/src/main/res/drawable-night/ic_launcher_background.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml index 07d5da9..9a5aa6e 100644 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -1,170 +1,21 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml index 2b068d1..3f8dfb4 100644 --- a/app/src/main/res/drawable/ic_launcher_foreground.xml +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -1,30 +1,91 @@ + - + + + - - + android:type="radial" + android:centerX="54" + android:centerY="54" + android:gradientRadius="30"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + android:pathData="M54,54m-20.6,0a20.6,20.6 0,1 1,41.2 0a20.6,20.6 0,1 1,-41.2 0" + android:strokeWidth="0.6" + android:strokeColor="#25FFFFFF" + android:fillColor="#00000000" /> + diff --git a/app/src/main/res/drawable/ic_launcher_monochrome.xml b/app/src/main/res/drawable/ic_launcher_monochrome.xml new file mode 100644 index 0000000..3f54aaa --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_monochrome.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/mipmap-anydpi/ic_launcher.xml b/app/src/main/res/mipmap-anydpi/ic_launcher.xml index 6f3b755..8fde456 100644 --- a/app/src/main/res/mipmap-anydpi/ic_launcher.xml +++ b/app/src/main/res/mipmap-anydpi/ic_launcher.xml @@ -2,5 +2,5 @@ - - \ No newline at end of file + + diff --git a/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml index 6f3b755..8fde456 100644 --- a/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml +++ b/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml @@ -2,5 +2,5 @@ - - \ No newline at end of file + + diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp deleted file mode 100644 index c209e78ecd372343283f4157dcfd918ec5165bb3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1404 zcmV-?1%vuhNk&F=1pok7MM6+kP&il$0000G0000-002h-06|PpNX!5L00Dqw+t%{r zzW2vH!KF=w&cMnnN@{whkTw+#mAh0SV?YL=)3MimFYCWp#fpdtz~8$hD5VPuQgtcN zXl<@<#Cme5f5yr2h%@8TWh?)bSK`O z^Z@d={gn7J{iyxL_y_%J|L>ep{dUxUP8a{byupH&!UNR*OutO~0{*T4q5R6@ApLF! z5{w?Z150gC7#>(VHFJZ-^6O@PYp{t!jH(_Z*nzTK4 zkc{fLE4Q3|mA2`CWQ3{8;gxGizgM!zccbdQoOLZc8hThi-IhN90RFT|zlxh3Ty&VG z?Fe{#9RrRnxzsu|Lg2ddugg7k%>0JeD+{XZ7>Z~{=|M+sh1MF7~ zz>To~`~LVQe1nNoR-gEzkpe{Ak^7{{ZBk2i_<+`Bq<^GB!RYG+z)h;Y3+<{zlMUYd zrd*W4w&jZ0%kBuDZ1EW&KLpyR7r2=}fF2%0VwHM4pUs}ZI2egi#DRMYZPek*^H9YK zay4Iy3WXFG(F14xYsoDA|KXgGc5%2DhmQ1gFCkrgHBm!lXG8I5h*uf{rn48Z!_@ z4Bk6TJAB2CKYqPjiX&mWoW>OPFGd$wqroa($ne7EUK;#3VYkXaew%Kh^3OrMhtjYN?XEoY`tRPQsAkH-DSL^QqyN0>^ zmC>{#F14jz4GeW{pJoRpLFa_*GI{?T93^rX7SPQgT@LbLqpNA}<@2wH;q493)G=1Y z#-sCiRNX~qf3KgiFzB3I>4Z%AfS(3$`-aMIBU+6?gbgDb!)L~A)je+;fR0jWLL-Fu z4)P{c7{B4Hp91&%??2$v9iRSFnuckHUm}or9seH6 z>%NbT+5*@L5(I9j@06@(!{ZI?U0=pKn8uwIg&L{JV14+8s2hnvbRrU|hZCd}IJu7*;;ECgO%8_*W Kmw_-CKmY()leWbG diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp deleted file mode 100644 index b2dfe3d1ba5cf3ee31b3ecc1ced89044a1f3b7a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2898 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 diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp deleted file mode 100644 index 4f0f1d64e58ba64d180ce43ee13bf9a17835fbca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 982 zcmV;{11bDcNk&G_0{{S5MM6+kP&il$0000G0000l001ul06|PpNU8t;00Dqo+t#w^ z^1csucXz7-Qrhzl9HuHB%l>&>1tG2^vb*E&k^T3$FG1eQZ51g$uv4V+kI`0<^1Z@N zk?Jjh$olyC%l>)Xq;7!>{iBj&BjJ`P&$fsCfpve_epJOBkTF?nu-B7D!hO=2ZR}

C%4 zc_9eOXvPbC4kzU8YowIA8cW~Uv|eB&yYwAObSwL2vY~UYI7NXPvf3b+c^?wcs~_t{ ze_m66-0)^{JdOMKPwjpQ@Sna!*?$wTZ~su*tNv7o!gXT!GRgivP}ec?5>l1!7<(rT zds|8x(qGc673zrvYIz;J23FG{9nHMnAuP}NpAED^laz3mAN1sy+NXK)!6v1FxQ;lh zOBLA>$~P3r4b*NcqR;y6pwyhZ3_PiDb|%n1gGjl3ZU}ujInlP{eks-#oA6>rh&g+!f`hv#_%JrgYPu z(U^&XLW^QX7F9Z*SRPpQl{B%x)_AMp^}_v~?j7 zapvHMKxSf*Mtyx8I}-<*UGn3)oHd(nn=)BZ`d$lDBwq_GL($_TPaS{UeevT(AJ`p0 z9%+hQb6z)U9qjbuXjg|dExCLjpS8$VKQ55VsIC%@{N5t{NsW)=hNGI`J=x97_kbz@ E0Of=7!TQj4N+cqN`nQhxvX7dAV-`K|Ub$-q+H-5I?Tx0g9jWxd@A|?POE8`3b8fO$T))xP* z(X?&brZw({`)WU&rdAs1iTa0x6F@PIxJ&&L|dpySV!ID|iUhjCcKz(@mE z!x@~W#3H<)4Ae(4eQJRk`Iz3<1)6^m)0b_4_TRZ+cz#eD3f8V;2r-1fE!F}W zEi0MEkTTx}8i1{`l_6vo0(Vuh0HD$I4SjZ=?^?k82R51bC)2D_{y8mi_?X^=U?2|F{Vr7s!k(AZC$O#ZMyavHhlQ7 zUR~QXuH~#o#>(b$u4?s~HLF*3IcF7023AlwAYudn0FV~|odGH^05AYPEfR)8p`i{n zwg3zPVp{+wOsxKc>)(pMupKF!Y2HoUqQ3|Yu|8lwR=?5zZuhG6J?H`bSNk_wPoM{u zSL{c@pY7+c2kck>`^q1^^gR0QB7Y?KUD{vz-uVX~;V-rW)PDcI)$_UjgVV?S?=oLR zf4}zz{#*R_{LkiJ#0RdQLNC^2Vp%JPEUvG9ra2BVZ92(p9h7Ka@!yf9(lj#}>+|u* z;^_?KWdzkM`6gqPo9;;r6&JEa)}R3X{(CWv?NvgLeOTq$cZXqf7|sPImi-7cS8DCN zGf;DVt3Am`>hH3{4-WzH43Ftx)SofNe^-#|0HdCo<+8Qs!}TZP{HH8~z5n`ExcHuT zDL1m&|DVpIy=xsLO>8k92HcmfSKhflQ0H~9=^-{#!I1g(;+44xw~=* zxvNz35vfsQE)@)Zsp*6_GjYD};Squ83<_?^SbALb{a`j<0Gn%6JY!zhp=Fg}Ga2|8 z52e1WU%^L1}15Ex0fF$e@eCT(()_P zvV?CA%#Sy08_U6VPt4EtmVQraWJX` zh=N|WQ>LgrvF~R&qOfB$!%D3cGv?;Xh_z$z7k&s4N)$WYf*k=|*jCEkO19{h_(%W4 zPuOqbCw`SeAX*R}UUsbVsgtuG?xs(#Ikx9`JZoQFz0n*7ZG@Fv@kZk`gzO$HoA9kN z8U5{-yY zvV{`&WKU2$mZeoBmiJrEdzUZAv1sRxpePdg1)F*X^Y)zp^Y*R;;z~vOv-z&)&G)JQ{m!C9cmziu1^nHA z`#`0c>@PnQ9CJKgC5NjJD8HM3|KC(g5nnCq$n0Gsu_DXk36@ql%npEye|?%RmG)

FJ$wK}0tWNB{uH;AM~i diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp deleted file mode 100644 index 948a3070fe34c611c42c0d3ad3013a0dce358be0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1900 zcmV-y2b1_xNk&Fw2LJ$9MM6+kP&il$0000G0001A003VA06|PpNH75a00DqwTbm-~ zullQTcXxO9ki!OCRx^i?oR|n!<8G0=kI^!JSjFi-LL*`V;ET0H2IXfU0*i>o6o6Gy zRq6Ap5(_{XLdXcL-MzlN`ugSdZY_`jXhcENAu)N_0?GhF))9R;E`!bo9p?g?SRgw_ zEXHhFG$0{qYOqhdX<(wE4N@es3VIo$%il%6xP9gjiBri+2pI6aY4 zJbgh-Ud|V%3O!IcHKQx1FQH(_*TK;1>FQWbt^$K1zNn^cczkBs=QHCYZ8b&l!UV{K z{L0$KCf_&KR^}&2Fe|L&?1I7~pBENnCtCuH3sjcx6$c zwqkNkru);ie``q+_QI;IYLD9OV0ZxkuyBz|5<$1BH|vtey$> z5oto4=l-R-Aaq`Dk0}o9N0VrkqW_#;!u{!bJLDq%0092{Ghe=F;(kn} z+sQ@1=UlX30+2nWjkL$B^b!H2^QYO@iFc0{(-~yXj2TWz?VG{v`Jg zg}WyYnwGgn>{HFaG7E~pt=)sOO}*yd(UU-D(E&x{xKEl6OcU?pl)K%#U$dn1mDF19 zSw@l8G!GNFB3c3VVK0?uyqN&utT-D5%NM4g-3@Sii9tSXKtwce~uF zS&Jn746EW^wV~8zdQ1XC28~kXu8+Yo9p!<8h&(Q({J*4DBglPdpe4M_mD8AguZFn~ ztiuO~{6Bx?SfO~_ZV(GIboeR9~hAym{{fV|VM=77MxDrbW6`ujX z<3HF(>Zr;#*uCvC*bpoSr~C$h?_%nXps@A)=l_;({Fo#6Y1+Zv`!T5HB+)#^-Ud_; zBwftPN=d8Vx)*O1Mj+0oO=mZ+NVH*ptNDC-&zZ7Hwho6UQ#l-yNvc0Cm+2$$6YUk2D2t#vdZX-u3>-Be1u9gtTBiMB^xwWQ_rgvGpZ6(C@e23c!^K=>ai-Rqu zhqT`ZQof;9Bu!AD(i^PCbYV%yha9zuoKMp`U^z;3!+&d@Hud&_iy!O-$b9ZLcSRh? z)R|826w}TU!J#X6P%@Zh=La$I6zXa#h!B;{qfug}O%z@K{EZECu6zl)7CiNi%xti0 zB{OKfAj83~iJvmpTU|&q1^?^cIMn2RQ?jeSB95l}{DrEPTW{_gmU_pqTc)h@4T>~& zluq3)GM=xa(#^VU5}@FNqpc$?#SbVsX!~RH*5p0p@w z;~v{QMX0^bFT1!cXGM8K9FP+=9~-d~#TK#ZE{4umGT=;dfvWi?rYj;^l_Zxywze`W z^Cr{55U@*BalS}K%Czii_80e0#0#Zkhlij4-~I@}`-JFJ7$5{>LnoJSs??J8kWVl6|8A}RCGAu9^rAsfCE=2}tHwl93t0C?#+jMpvr7O3`2=tr{Hg$=HlnjVG^ewm|Js0J*kfPa6*GhtB>`fN!m#9J(sU!?(OSfzY*zS(FJ<-Vb zfAIg+`U)YaXv#sY(c--|X zEB+TVyZ%Ie4L$gi#Fc++`h6%vzsS$pjz9aLt+ZL(g;n$Dzy5=m=_TV(3H8^C{r0xd zp#a%}ht55dOq?yhwYPrtp-m1xXp;4X;)NhxxUpgP%XTLmO zcjaFva^}dP3$&sfFTIR_jC=2pHh9kpI@2(6V*GQo7Ws)`j)hd+tr@P~gR*2gO@+1? zG<`_tB+LJuF|SZ9tIec;h%}}6WClT`L>HSW?E{Hp1h^+mlbf_$9zA>!ug>NALJsO{ mU%z=YwVD?}XMya)Bp;vlyE5&E_6!fzx9pwrdz474!~g(M6R?N? diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp deleted file mode 100644 index 1b9a6956b3acdc11f40ce2bb3f6efbd845cc243f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3918 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�(p-{x$&=IACIfoAR!za)F-^da-t3#0Dycnp zwO~NVXwXCl;jE<}>%@xz|=8fIJAB?>+E{7)|4l${4ngA3G|=r z2Dyv;VVWSgZx9Wj>qUjleGl3Ei9K4>h!(lPS%8VOG>Xu0%6VDz^O=bjJmuP7>DeUv zrbI}MlHB^^d?{zv6d=@_ZD2lg1&G7UjnVN{1}9WkaM3H~btX0GtSzB+tZ^qRgWo4m z!GmimlG$=wgXCnr6j@m<1gAL46#T~5Bnm=2{^@>|t&`9mkEPddj zAvG~@Tv~TAm2i%VW}R-g(Z0)z-Y|szHr@rk>4MAyG*Ma*7Yh#H7(!-5>DZ@8r;_dx z{prSe<>~099F8vsYd2xff7uAS%7{S)f(|@me3t2$iy&NEc7OUEchp@9A|X;;IA>8!oX+y(BKJ$EzV* znR$z;!L$s7uy@{OT~nG#B!NRraT8(X##Ho!0r_o@gg0CA-9H^;-uE&?$2$nHv_00o z%cbuUc-tCx$Uh&EZ4Nf4Zgqv)Y6>usG3>GeQnxx_Z6+PcbX-+ysbt1hQ`K1LDpOE? zrAhIZhSN9yVIAOa22gn577tbc&i3|3V8NWy&!tw##`}9*x}gtI^h1DzZRA>UuaJG) zaZ7j)dq!O}{?#8Y7~7i6fHh4{`pL?>-18|p!S75Y#^DM>-S3)vuZG+Q7l@ek zQP~#cBpWgg#mApc_sPYjpw8odQuRokmTkzcNl`^CcKB7e&;zViV;{Y{o^Y$%7i0m# z62%#1Lq!RC?}lK>%mp}T!3Xv;L*0v*>USLm``N%>w>@fwC+#T&Tx2bN4w(20JB}oU zuSa6v^kXi0xPs?pbaOHnyiqq6By1EZY9OZ^^QA>{q-Hsd&m`pbQ%8121aWG-F5xf zlZ%;B{;C>X19|`^_?dVyCq>n+41w7|!tUS!{9rHlbhX=SZO5CQ^;!Du_E7*`GiR^Q w)2!4MKjfSAeNo!9>IaV6aUZ*?W>} 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

UmY2RIYtNPVDpE$%vda+HD#3m z&VuXJ{BK&Qe+rBa7eq}Q(bq|tn(RrJAk|ztj2(i{d>nmQnM?;HF2k&9sA6up5tmjl z7lySlzMbifH17-m-Lwa_F&e7nOH?ESi3#ckR3tsM+jsck3`oG!uMS}|eAwVXv>}qxwq?QY%QJ0}r@^;fhuUA9W z*BVl>TGo&N004@xSiwDUXUvp51sVmqO3m)=B55aPwf@0=e}cN+$-BdKxY`YrT_4)0 z_d10#i44Q*rFr8MC>*)v$EJvz``(pb{e&*6k+b zsMz%($|1+8hn8c2?P(l@;Rb&CsZeYoCI3?2!LqjbwPXW3z4G$Qfj=cT5Yb%vY0(AX oeb?AaKtwrnc|$|zzw9vfvn^aJJ!zd)XFXqqy0000001=f@-~a#s diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 8881f53..3d28c2f 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -1,10 +1,11 @@ - From 736bb4c206a1432c64492a575959aecec18742be Mon Sep 17 00:00:00 2001 From: Bruno Deanoz Date: Sun, 21 Jun 2026 15:26:14 +0200 Subject: [PATCH 10/12] feat: persistent settings + server sync + language selector Settings now persist across app restarts via SecureStore: - Theme (KaizenThemeId), appearance (Light/Dark/System), username, locale - All loaded on SettingsViewModel init, saved on every change Server sync: fetchMe() returns name + email from /api/v1/me, populates SettingsViewModel on login and each foreground resume. Language selector: System / Deutsch / English pill toggle in Settings. Locale preference stored; runtime switching deferred to next iteration. MeResponse expanded to parse name + email (was defaultModel only). SettingsViewModel tests updated for store-less default state. --- CLAUDE.md | 9 ++++++ .../main/java/dev/kaizen/app/MainActivity.kt | 5 ++-- .../java/dev/kaizen/app/chat/ChatScreen.kt | 4 +++ .../main/java/dev/kaizen/app/net/KaizenApi.kt | 22 ++++++++++++++- .../java/dev/kaizen/app/net/SecureStore.kt | 18 ++++++++++++ .../dev/kaizen/app/settings/SettingsScreen.kt | 10 +++++++ .../kaizen/app/settings/SettingsViewModel.kt | 28 +++++++++++++++---- app/src/main/res/values-en/strings.xml | 5 ++++ app/src/main/res/values/strings.xml | 5 ++++ .../dev/kaizen/app/SettingsViewModelTest.kt | 3 +- 10 files changed, 100 insertions(+), 9 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 61e5181..e1010a8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -94,6 +94,15 @@ Full spec: `DESIGN.md`. Branch: `feature/design-system-v2`. - ChatModels: `Suggestion.labelRes`/`promptRes` and `ChatMode.labelRes` are resource IDs (Int), not hardcoded strings. - `ModePillsRow`: `selected` state is `Int` (resource ID), not `String`. +### Settings persistence + server sync + +- **SettingsViewModel** takes `SecureStore` — theme, appearance, username, locale survive app restart. +- Theme selection persisted as `KaizenThemeId.value` string ("amber"/"blue"/"mono"/"aurora"). +- Appearance persisted as `AppAppearance.name` ("Light"/"Dark"/"System"). +- On login + on each foreground: `KaizenApi.fetchMe()` → `MeResponse(name, email, defaultModel)` populates SettingsViewModel name/email. +- **Language selector** in Settings: System / Deutsch / English. Stored as `locale` in SecureStore. Note: currently only stores the preference; runtime locale switching (AppCompatDelegate.setApplicationLocales) needs wiring in MainActivity on next iteration. +- No server-side theme storage — web uses localStorage, app uses SecureStore. Both are client-local. + ### Offline-first cache layer (Room) — added 2026-06-21 Architecture decision document: `OFFLINE_CACHE_ADD.md`. diff --git a/app/src/main/java/dev/kaizen/app/MainActivity.kt b/app/src/main/java/dev/kaizen/app/MainActivity.kt index 72705c7..8c9cfcc 100644 --- a/app/src/main/java/dev/kaizen/app/MainActivity.kt +++ b/app/src/main/java/dev/kaizen/app/MainActivity.kt @@ -31,8 +31,9 @@ class MainActivity : ComponentActivity() { window.colorMode = ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT } - val settingsViewModel = SettingsViewModel() - val sessionViewModel = SessionViewModel(SecureStore(applicationContext)) + val secureStore = SecureStore(applicationContext) + val settingsViewModel = SettingsViewModel(secureStore) + val sessionViewModel = SessionViewModel(secureStore) val chatViewModel = ChatViewModel(applicationContext) // auto() picks light/dark system-bar icons based on the system theme 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 9146d0f..e3db922 100644 --- a/app/src/main/java/dev/kaizen/app/chat/ChatScreen.kt +++ b/app/src/main/java/dev/kaizen/app/chat/ChatScreen.kt @@ -158,6 +158,10 @@ fun ChatScreen( } is FetchResult.Fail -> errors.add(r.reason) } + KaizenApi.fetchMe(cfg.baseUrl, cfg.token)?.let { me -> + me.name?.let { settingsViewModel.updateUserName(it) } + me.email?.let { settingsViewModel.updateUserEmail(it) } + } chat.conversationRepo.refresh(cfg.baseUrl, cfg.token) if (errors.isNotEmpty()) { loadError = errors.joinToString(" · ") diff --git a/app/src/main/java/dev/kaizen/app/net/KaizenApi.kt b/app/src/main/java/dev/kaizen/app/net/KaizenApi.kt index 8fb1cf3..3af92c4 100644 --- a/app/src/main/java/dev/kaizen/app/net/KaizenApi.kt +++ b/app/src/main/java/dev/kaizen/app/net/KaizenApi.kt @@ -23,7 +23,11 @@ import java.util.concurrent.TimeUnit @Serializable private data class TokenRequest(val email: String, val password: String, val name: String) @Serializable private data class TokenResponse(val token: String) -@Serializable private data class MeResponse(val defaultModel: String? = null) +@Serializable data class MeResponse( + val name: String? = null, + val email: String? = null, + val defaultModel: String? = null, +) @Serializable data class WireMessage(val role: String, val content: String) @Serializable private data class ChatRequest( val model: String, @@ -164,6 +168,22 @@ object KaizenApi { } /** GET /api/v1/me — resolve the user's configured default model (best-effort, null on any failure). */ + suspend fun fetchMe(baseUrl: String, token: String): MeResponse? = + withContext(Dispatchers.IO) { + val req = Request.Builder() + .url("$baseUrl/api/v1/me") + .header("Authorization", "Bearer $token") + .build() + try { + client.newCall(req).execute().use { resp -> + if (!resp.isSuccessful) return@use null + json.decodeFromString(resp.body!!.string()) + } + } catch (e: Exception) { + null + } + } + suspend fun fetchDefaultModel(baseUrl: String, token: String): String? = withContext(Dispatchers.IO) { val req = Request.Builder() diff --git a/app/src/main/java/dev/kaizen/app/net/SecureStore.kt b/app/src/main/java/dev/kaizen/app/net/SecureStore.kt index 66aa942..9d44aa0 100644 --- a/app/src/main/java/dev/kaizen/app/net/SecureStore.kt +++ b/app/src/main/java/dev/kaizen/app/net/SecureStore.kt @@ -77,6 +77,20 @@ class SecureStore(context: Context) { } } + // ── Settings persistence ───────────────────────────────────────────────── + + fun loadThemeId(): String? = prefs.getString(KEY_THEME_ID, null) + fun saveThemeId(id: String) { prefs.edit().putString(KEY_THEME_ID, id).apply() } + + fun loadAppearance(): String? = prefs.getString(KEY_APPEARANCE, null) + fun saveAppearance(mode: String) { prefs.edit().putString(KEY_APPEARANCE, mode).apply() } + + fun loadUserName(): String? = prefs.getString(KEY_USER_NAME, null) + fun saveUserName(name: String) { prefs.edit().putString(KEY_USER_NAME, name).apply() } + + fun loadLocale(): String? = prefs.getString(KEY_LOCALE, null) + fun saveLocale(locale: String) { prefs.edit().putString(KEY_LOCALE, locale).apply() } + fun clear() { prefs.edit().clear().apply() } @@ -89,5 +103,9 @@ class SecureStore(context: Context) { const val KEY_SPEED = "speed" const val KEY_FAVORITES = "favorite_models" const val KEY_MODELS_CACHE = "models_cache" + const val KEY_THEME_ID = "ui_theme" + const val KEY_APPEARANCE = "appearance" + const val KEY_USER_NAME = "user_name" + const val KEY_LOCALE = "locale" } } diff --git a/app/src/main/java/dev/kaizen/app/settings/SettingsScreen.kt b/app/src/main/java/dev/kaizen/app/settings/SettingsScreen.kt index 13942a5..0bc4913 100644 --- a/app/src/main/java/dev/kaizen/app/settings/SettingsScreen.kt +++ b/app/src/main/java/dev/kaizen/app/settings/SettingsScreen.kt @@ -25,6 +25,7 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.rounded.ArrowBack import androidx.compose.material.icons.rounded.AutoAwesome +import androidx.compose.material.icons.rounded.Language import androidx.compose.material.icons.rounded.Palette import androidx.compose.material.icons.rounded.Person import androidx.compose.material.icons.rounded.Settings @@ -66,6 +67,7 @@ fun SettingsScreen( val appearanceMode by viewModel.appearanceMode.collectAsState() val userName by viewModel.userName.collectAsState() val userEmail by viewModel.userEmail.collectAsState() + val locale by viewModel.locale.collectAsState() MeshBackground { Column( @@ -123,6 +125,14 @@ fun SettingsScreen( } } } + Spacer(Modifier.height(12.dp)) + SettingsOptionRow(title = stringResource(R.string.settings_language_title), description = stringResource(R.string.settings_language_desc), icon = Icons.Rounded.Language) { + Row(horizontalArrangement = Arrangement.spacedBy(6.dp), verticalAlignment = Alignment.CenterVertically) { + listOf("system" to R.string.settings_language_system, "de" to R.string.settings_language_de, "en" to R.string.settings_language_en).forEach { (code, labelRes) -> + AppearanceTogglePill(selected = locale == code, label = stringResource(labelRes), onClick = { viewModel.selectLocale(code) }) + } + } + } } Text(stringResource(R.string.settings_section_profile), color = cs.onSurfaceVariant.copy(alpha = 0.6f), fontSize = 12.sp, fontWeight = FontWeight.Bold, modifier = Modifier.padding(start = 8.dp, bottom = 8.dp)) diff --git a/app/src/main/java/dev/kaizen/app/settings/SettingsViewModel.kt b/app/src/main/java/dev/kaizen/app/settings/SettingsViewModel.kt index 11ffff8..403cd6b 100644 --- a/app/src/main/java/dev/kaizen/app/settings/SettingsViewModel.kt +++ b/app/src/main/java/dev/kaizen/app/settings/SettingsViewModel.kt @@ -1,6 +1,7 @@ package dev.kaizen.app.settings import androidx.lifecycle.ViewModel +import dev.kaizen.app.net.SecureStore import dev.kaizen.app.ui.theme.themes.KaizenThemeId import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -8,33 +9,50 @@ import kotlinx.coroutines.flow.asStateFlow enum class AppAppearance { Light, Dark, System } -class SettingsViewModel : ViewModel() { +class SettingsViewModel(private val store: SecureStore? = null) : ViewModel() { - private val _selectedTheme = MutableStateFlow(KaizenThemeId.AMBER) + private val _selectedTheme = MutableStateFlow( + store?.loadThemeId()?.let { KaizenThemeId.fromString(it) } ?: KaizenThemeId.AMBER + ) val selectedTheme: StateFlow = _selectedTheme.asStateFlow() - private val _appearanceMode = MutableStateFlow(AppAppearance.System) + private val _appearanceMode = MutableStateFlow( + store?.loadAppearance()?.let { runCatching { AppAppearance.valueOf(it) }.getOrNull() } ?: AppAppearance.System + ) val appearanceMode: StateFlow = _appearanceMode.asStateFlow() - private val _userName = MutableStateFlow("Bruno") + private val _userName = MutableStateFlow(store?.loadUserName() ?: "") val userName: StateFlow = _userName.asStateFlow() private val _userEmail = MutableStateFlow("") val userEmail: StateFlow = _userEmail.asStateFlow() + private val _locale = MutableStateFlow(store?.loadLocale() ?: "system") + val locale: StateFlow = _locale.asStateFlow() + fun selectTheme(themeId: KaizenThemeId) { _selectedTheme.value = themeId + store?.saveThemeId(themeId.value) } fun selectAppearance(mode: AppAppearance) { _appearanceMode.value = mode + store?.saveAppearance(mode.name) } fun updateUserName(name: String) { - if (name.isNotBlank()) _userName.value = name.trim() + if (name.isNotBlank()) { + _userName.value = name.trim() + store?.saveUserName(name.trim()) + } } fun updateUserEmail(email: String) { _userEmail.value = email } + + fun selectLocale(locale: String) { + _locale.value = locale + store?.saveLocale(locale) + } } diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index 224869a..0e9d70d 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -91,4 +91,9 @@ Light Dark System + Language + Choose the app language + System + Deutsch + English diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b0df167..bd0cc04 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -93,4 +93,9 @@ Hell Dunkel System + Sprache + Wähle die App-Sprache + System + Deutsch + English diff --git a/app/src/test/java/dev/kaizen/app/SettingsViewModelTest.kt b/app/src/test/java/dev/kaizen/app/SettingsViewModelTest.kt index 6b19457..4a63b2c 100644 --- a/app/src/test/java/dev/kaizen/app/SettingsViewModelTest.kt +++ b/app/src/test/java/dev/kaizen/app/SettingsViewModelTest.kt @@ -13,7 +13,7 @@ class SettingsViewModelTest { val viewModel = SettingsViewModel() assertEquals(KaizenThemeId.AMBER, viewModel.selectedTheme.value) assertEquals(AppAppearance.System, viewModel.appearanceMode.value) - assertEquals("Bruno", viewModel.userName.value) + assertEquals("", viewModel.userName.value) } @Test @@ -49,6 +49,7 @@ class SettingsViewModelTest { @Test fun testUpdateUserNameBlankIgnored() { val viewModel = SettingsViewModel() + viewModel.updateUserName("Bruno") viewModel.updateUserName(" ") assertEquals("Bruno", viewModel.userName.value) } From 76ab8bfde9b949d0b3704b67afb3883fa06afffc Mon Sep 17 00:00:00 2001 From: Bruno Deanoz Date: Sun, 21 Jun 2026 15:35:46 +0200 Subject: [PATCH 11/12] feat: reasoning, sources, and tool-call display StreamConsumer.Incremental now returns StreamState (content, reasoning, tools, query, sources) instead of just visible text. All sentinel sections are parsed and structured: - \x01 REASONING: captured as separate string - \x02 SOURCES: parsed as List (title, url, snippet) - \x03 TOOL: parsed as List (type, name, args, result, elapsed) - \x04 QUERY: captured as search query string UI components: - ReasoningBlock: collapsible "Gedankengang" with expand/collapse animation - ToolEventsBlock: shows tool-call steps with status icons (start/end/error) - SourcesBlock: web search sources as compact cards with domain extraction Message model extended with reasoning, tools, query, sources fields. KaizenApi.chat() returns Flow instead of Flow. ChatScreen wires all fields to Message during streaming. Fixed: empty append() on Incremental no longer prematurely ends tool phase. StreamConsumerTest rewritten to verify all parsed sections. --- .../dev/kaizen/app/chat/ChatComponents.kt | 12 + .../java/dev/kaizen/app/chat/ChatModels.kt | 6 + .../java/dev/kaizen/app/chat/ChatScreen.kt | 10 +- .../java/dev/kaizen/app/chat/StreamBlocks.kt | 215 ++++++++++++++++++ .../main/java/dev/kaizen/app/net/KaizenApi.kt | 2 +- .../java/dev/kaizen/app/net/StreamConsumer.kt | 175 +++++++++----- app/src/main/res/values-en/strings.xml | 4 + app/src/main/res/values/strings.xml | 4 + .../java/dev/kaizen/app/StreamConsumerTest.kt | 157 +++++-------- 9 files changed, 423 insertions(+), 162 deletions(-) create mode 100644 app/src/main/java/dev/kaizen/app/chat/StreamBlocks.kt 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 99467f3..7365a2b 100644 --- a/app/src/main/java/dev/kaizen/app/chat/ChatComponents.kt +++ b/app/src/main/java/dev/kaizen/app/chat/ChatComponents.kt @@ -223,12 +223,24 @@ fun MessageRow(message: Message) { Spacer(Modifier.width(10.dp)) Box(Modifier.weight(1f).padding(top = 3.dp)) { Column { + if (message.tools.isNotEmpty()) { + ToolEventsBlock(message.tools, streaming = message.streaming) + Spacer(Modifier.height(8.dp)) + } if (hasAttachments) { AttachmentGrid(message.attachments) if (message.content.isNotBlank() || message.thinking) Spacer(Modifier.height(8.dp)) } if (message.thinking) TypingDots() else MarkdownText(text = message.content, streaming = message.streaming) + if (message.reasoning.isNotBlank()) { + Spacer(Modifier.height(8.dp)) + ReasoningBlock(message.reasoning, streaming = message.streaming) + } + if (message.sources.isNotEmpty()) { + Spacer(Modifier.height(8.dp)) + SourcesBlock(message.sources, query = message.query) + } } } } diff --git a/app/src/main/java/dev/kaizen/app/chat/ChatModels.kt b/app/src/main/java/dev/kaizen/app/chat/ChatModels.kt index 6ad8e15..e20b3c2 100644 --- a/app/src/main/java/dev/kaizen/app/chat/ChatModels.kt +++ b/app/src/main/java/dev/kaizen/app/chat/ChatModels.kt @@ -13,6 +13,8 @@ import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource import dev.kaizen.app.R import dev.kaizen.app.net.Attachment +import dev.kaizen.app.net.SearchSource +import dev.kaizen.app.net.ToolEvent enum class Role { User, Assistant } @@ -24,6 +26,10 @@ data class Message( val thinking: Boolean = false, val wireId: String = java.util.UUID.randomUUID().toString(), val attachments: List = emptyList(), + val reasoning: String = "", + val tools: List = emptyList(), + val query: String = "", + val sources: List = emptyList(), ) data class Suggestion(val labelRes: Int, val promptRes: Int, val icon: ImageVector) 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 e3db922..c5ea12a 100644 --- a/app/src/main/java/dev/kaizen/app/chat/ChatScreen.kt +++ b/app/src/main/java/dev/kaizen/app/chat/ChatScreen.kt @@ -267,16 +267,20 @@ fun ChatScreen( KaizenApi.chat( cfg.baseUrl, cfg.token, cfg.model, history, cfg.speed, attachments = uploadedAtts.takeIf { it.isNotEmpty() }, - ).collect { visible -> + ).collect { state -> val idx = messages.indexOfLast { it.id == assistantId } if (idx < 0) return@collect - if (!sawContent && visible.isNotEmpty()) { + if (!sawContent && state.content.isNotEmpty()) { sawContent = true haptics.responseStart() } messages[idx] = messages[idx].copy( thinking = if (sawContent) false else messages[idx].thinking, - content = visible, + content = state.content, + reasoning = state.reasoning, + tools = state.tools, + query = state.query, + sources = state.sources, ) } val idx = messages.indexOfLast { it.id == assistantId } diff --git a/app/src/main/java/dev/kaizen/app/chat/StreamBlocks.kt b/app/src/main/java/dev/kaizen/app/chat/StreamBlocks.kt new file mode 100644 index 0000000..0764fc5 --- /dev/null +++ b/app/src/main/java/dev/kaizen/app/chat/StreamBlocks.kt @@ -0,0 +1,215 @@ +package dev.kaizen.app.chat + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.expandVertically +import androidx.compose.animation.shrinkVertically +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ExperimentalLayoutApi +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Check +import androidx.compose.material.icons.rounded.Error +import androidx.compose.material.icons.rounded.ExpandLess +import androidx.compose.material.icons.rounded.ExpandMore +import androidx.compose.material.icons.rounded.Language +import androidx.compose.material.icons.rounded.Psychology +import androidx.compose.material.icons.rounded.Build +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import dev.kaizen.app.net.SearchSource +import dev.kaizen.app.net.ToolEvent +import dev.kaizen.app.ui.shape.KaizenShapes +import dev.kaizen.app.ui.theme.Amber + +@Composable +fun ReasoningBlock(reasoning: String, streaming: Boolean = false) { + val cs = MaterialTheme.colorScheme + val isDark = isSystemInDarkTheme() + var expanded by remember { mutableStateOf(streaming) } + + val bg = if (isDark) Color.White.copy(alpha = 0.05f) else Color.Black.copy(alpha = 0.03f) + val borderColor = if (isDark) Color.White.copy(alpha = 0.08f) else Color.Black.copy(alpha = 0.06f) + + Column( + Modifier + .fillMaxWidth() + .clip(KaizenShapes.sm) + .background(bg) + .border(1.dp, borderColor, KaizenShapes.sm) + ) { + Row( + Modifier + .fillMaxWidth() + .clickable { expanded = !expanded } + .padding(horizontal = 12.dp, vertical = 8.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Icon(Icons.Rounded.Psychology, null, tint = Amber, modifier = Modifier.size(16.dp)) + Spacer(Modifier.width(8.dp)) + Text( + "Gedankengang", + color = cs.onSurfaceVariant, + fontSize = 13.sp, + fontWeight = FontWeight.Medium, + modifier = Modifier.weight(1f), + ) + Icon( + if (expanded) Icons.Rounded.ExpandLess else Icons.Rounded.ExpandMore, + null, tint = cs.onSurfaceVariant, modifier = Modifier.size(16.dp), + ) + } + AnimatedVisibility(expanded, enter = expandVertically(), exit = shrinkVertically()) { + Text( + reasoning, + color = cs.onSurfaceVariant.copy(alpha = 0.8f), + fontSize = 13.sp, + lineHeight = 18.sp, + modifier = Modifier.padding(start = 12.dp, end = 12.dp, bottom = 10.dp), + ) + } + } +} + +@Composable +fun ToolEventsBlock(tools: List, streaming: Boolean = false) { + val cs = MaterialTheme.colorScheme + val isDark = isSystemInDarkTheme() + 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) + + Column( + Modifier + .fillMaxWidth() + .clip(KaizenShapes.sm) + .background(bg) + .border(1.dp, borderColor, KaizenShapes.sm) + .padding(horizontal = 12.dp, vertical = 8.dp), + verticalArrangement = Arrangement.spacedBy(4.dp), + ) { + tools.forEach { tool -> + Row(verticalAlignment = Alignment.CenterVertically) { + val icon = when (tool.type) { + "end" -> Icons.Rounded.Check + "error" -> Icons.Rounded.Error + else -> Icons.Rounded.Build + } + val tint = when (tool.type) { + "end" -> Color(0xFF10B981) + "error" -> Color(0xFFEF4444) + else -> Amber + } + Icon(icon, null, tint = tint, modifier = Modifier.size(14.dp)) + Spacer(Modifier.width(8.dp)) + Text( + tool.name.ifEmpty { "Tool" }, + color = cs.onBackground, + fontSize = 13.sp, + fontWeight = FontWeight.Medium, + ) + if (tool.elapsed != null) { + Spacer(Modifier.width(6.dp)) + Text( + "${tool.elapsed}ms", + color = cs.onSurfaceVariant.copy(alpha = 0.5f), + fontSize = 11.sp, + ) + } + if (tool.error != null) { + Spacer(Modifier.width(6.dp)) + Text(tool.error, color = Color(0xFFEF4444), fontSize = 11.sp, maxLines = 1, overflow = TextOverflow.Ellipsis) + } + } + } + } +} + +@OptIn(ExperimentalLayoutApi::class) +@Composable +fun SourcesBlock(sources: List, query: String = "") { + val cs = MaterialTheme.colorScheme + val isDark = isSystemInDarkTheme() + + Column { + if (query.isNotBlank()) { + Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(bottom = 6.dp)) { + Icon(Icons.Rounded.Language, null, tint = cs.onSurfaceVariant, modifier = Modifier.size(14.dp)) + Spacer(Modifier.width(6.dp)) + Text(query, color = cs.onSurfaceVariant, fontSize = 12.sp, fontWeight = FontWeight.Medium) + } + } + FlowRow( + horizontalArrangement = Arrangement.spacedBy(6.dp), + verticalArrangement = Arrangement.spacedBy(6.dp), + ) { + sources.forEach { source -> + SourceChip(source, isDark) + } + } + } +} + +@Composable +private fun SourceChip(source: SearchSource, isDark: Boolean) { + val cs = MaterialTheme.colorScheme + val bg = if (isDark) Color.White.copy(alpha = 0.06f) else Color.Black.copy(alpha = 0.04f) + val borderColor = if (isDark) Color.White.copy(alpha = 0.08f) else Color.Black.copy(alpha = 0.06f) + + val domain = remember(source.url) { + try { + java.net.URI(source.url).host?.removePrefix("www.") ?: source.url + } catch (_: Exception) { source.url } + } + + Column( + Modifier + .width(140.dp) + .clip(KaizenShapes.xs) + .background(bg) + .border(1.dp, borderColor, KaizenShapes.xs) + .padding(horizontal = 10.dp, vertical = 8.dp), + ) { + Text( + source.title.ifEmpty { domain }, + color = cs.onBackground, + fontSize = 12.sp, + fontWeight = FontWeight.Medium, + maxLines = 2, + overflow = TextOverflow.Ellipsis, + ) + Spacer(Modifier.height(2.dp)) + Text( + domain, + color = cs.onSurfaceVariant.copy(alpha = 0.6f), + fontSize = 10.sp, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + } +} diff --git a/app/src/main/java/dev/kaizen/app/net/KaizenApi.kt b/app/src/main/java/dev/kaizen/app/net/KaizenApi.kt index 3af92c4..4a45e7b 100644 --- a/app/src/main/java/dev/kaizen/app/net/KaizenApi.kt +++ b/app/src/main/java/dev/kaizen/app/net/KaizenApi.kt @@ -350,7 +350,7 @@ object KaizenApi { messages: List, speed: ChatSpeed = ChatSpeed.Normal, attachments: List? = null, - ): Flow = flow { + ): Flow = flow { val payload = json.encodeToString( ChatRequest( model = model, diff --git a/app/src/main/java/dev/kaizen/app/net/StreamConsumer.kt b/app/src/main/java/dev/kaizen/app/net/StreamConsumer.kt index 91324b4..8158851 100644 --- a/app/src/main/java/dev/kaizen/app/net/StreamConsumer.kt +++ b/app/src/main/java/dev/kaizen/app/net/StreamConsumer.kt @@ -1,54 +1,54 @@ package dev.kaizen.app.net -/** - * Sentinel code points delimiting control sections in the `/api/v1/chat` stream. - * Shared between the batch parser ([StreamConsumer.visibleText]) and the - * incremental parser ([StreamConsumer.Incremental]). - */ -private val USAGE = 0.toChar() // -private val REASONING = 1.toChar() // -private val SOURCES = 2.toChar() // -private val TOOL = 3.toChar() // -private val QUERY = 4.toChar() // +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json + +private val USAGE = 0.toChar() +private val REASONING = 1.toChar() +private val SOURCES = 2.toChar() +private val TOOL = 3.toChar() +private val QUERY = 4.toChar() + +private val lenientJson = Json { ignoreUnknownKeys = true } + +@Serializable +data class ToolEvent( + val type: String = "", + val name: String = "", + val args: kotlinx.serialization.json.JsonObject? = null, + val result: String? = null, + val error: String? = null, + val elapsed: Long? = null, +) + +@Serializable +data class SearchSource( + val title: String = "", + val url: String = "", + val snippet: String = "", +) + +data class StreamState( + val content: String = "", + val reasoning: String = "", + val tools: List = emptyList(), + val query: String = "", + val sources: List = emptyList(), +) -/** - * Pure parsing layer for the `/api/v1/chat` response stream — a Kotlin port of the - * backend's `lib/chat/stream-consumer.ts`. The provider stream is a flat string - * with control sentinels (code points, see lib/chat/constants.ts): - * - * 0x00 USAGE trailing usage/cost json - * 0x01 REASONING wraps reasoning, toggling content <-> reasoning - * 0x02 SOURCES web-search sources json - * 0x03 TOOL leading newline-framed tool events ("{json}\n") - * 0x04 QUERY web-search query json - * - * Layout: [tool-events] [0x01 reasoning 0x01 content] [0x04 q] [0x02 src] [0x00 usage] - * - * Two parsers are available: - * - [visibleText]: batch — correct but O(N) per call, used for one-shot parsing and tests. - * - [Incremental]: streaming — O(chunk-size) per call, O(N) total. Used during live streaming. - */ object StreamConsumer { - /** - * Batch extraction — parses the full accumulated buffer from scratch. - * Correct but O(N) per call; kept for unit tests and one-shot use. - */ fun visibleText(raw: String): String { val rest = stripLeadingToolEvents(raw) ?: return "" - val segments = rest.split(REASONING) val sb = StringBuilder() for (i in segments.indices) { if (i % 2 == 0) sb.append(segments[i]) } var text = sb.toString() - val cut = listOf(text.indexOf(QUERY), text.indexOf(SOURCES), text.indexOf(USAGE)) - .filter { it != -1 } - .minOrNull() + .filter { it != -1 }.minOrNull() if (cut != null) text = text.substring(0, cut) - return text } @@ -56,38 +56,33 @@ object StreamConsumer { var rest = raw while (rest.isNotEmpty() && rest[0] == TOOL) { val nl = rest.indexOf('\n') - if (nl == -1) return null // incomplete event — wait for more data + if (nl == -1) return null rest = rest.substring(nl + 1) } return rest } - /** - * Incremental parser — O(chunk-size) per [append] instead of O(total-buffer). - * Each character is visited exactly once across all calls, giving O(N) total - * for the entire stream instead of O(N²). - * - * Operates on decoded [Char]s — the caller must use [java.io.InputStreamReader] - * to handle UTF-8 multi-byte boundaries at the byte level. - */ class Incremental { private val content = StringBuilder(256) + private val reasoningBuf = StringBuilder(256) private val toolBuffer = StringBuilder() + private val trailingBuf = StringBuilder() + private val tools = mutableListOf() private var pastToolEvents = false private var inReasoning = false + private var inTrailing = false private var done = false + private var trailingSentinel: Char? = null - /** - * Feed a chunk of decoded characters. Returns the current visible text. - * Safe to call on every network chunk — only the new characters are scanned. - */ - fun append(chars: CharArray, offset: Int, length: Int): String { - if (done) return content.toString() + fun append(chars: CharArray, offset: Int, length: Int): StreamState { + if (done) return buildState() if (!pastToolEvents) { toolBuffer.append(chars, offset, length) + if (toolBuffer.isEmpty()) return buildState() val end = findToolEventsEnd(toolBuffer) - if (end == -1) return "" + if (end == -1) return buildState() + parseToolEvents(toolBuffer, 0, end) pastToolEvents = true processRange(toolBuffer, end, toolBuffer.length) toolBuffer.setLength(0) @@ -96,11 +91,63 @@ object StreamConsumer { processChars(chars, offset, length) } - return content.toString() + return buildState() } - /** Convenience overload for string input (tests). */ - fun append(chunk: String): String = append(chunk.toCharArray(), 0, chunk.length) + fun append(chunk: String): StreamState = append(chunk.toCharArray(), 0, chunk.length) + + fun currentContent(): String = content.toString() + + private fun buildState(): StreamState { + val queryStr = parseTrailingField(QUERY) + val sourcesList = parseTrailingSources() + return StreamState( + content = content.toString(), + reasoning = reasoningBuf.toString(), + tools = tools.toList(), + query = queryStr, + sources = sourcesList, + ) + } + + private fun parseTrailingField(sentinel: Char): String { + val full = trailingBuf.toString() + val idx = full.indexOf(sentinel) + if (idx == -1) return "" + val after = full.substring(idx + 1) + val end = listOf(after.indexOf(SOURCES), after.indexOf(USAGE), after.indexOf(QUERY)) + .filter { it != -1 }.minOrNull() ?: after.length + return after.substring(0, end).trim() + } + + private fun parseTrailingSources(): List { + val full = trailingBuf.toString() + val idx = full.indexOf(SOURCES) + if (idx == -1) return emptyList() + val after = full.substring(idx + 1) + val end = listOf(after.indexOf(USAGE)).filter { it != -1 }.minOrNull() ?: after.length + val json = after.substring(0, end).trim() + if (json.isEmpty()) return emptyList() + return try { + lenientJson.decodeFromString>(json) + } catch (_: Exception) { + emptyList() + } + } + + private fun parseToolEvents(buf: CharSequence, from: Int, to: Int) { + val s = buf.toString() + var pos = from + while (pos < to && s[pos] == TOOL) { + val nl = s.indexOf('\n', pos) + if (nl == -1 || nl >= to) break + val jsonStr = s.substring(pos + 1, nl) + try { + tools.add(lenientJson.decodeFromString(jsonStr)) + } catch (_: Exception) { } + pos = nl + 1 + } + } private fun processRange(buf: CharSequence, from: Int, to: Int) { for (i in from until to) { @@ -118,18 +165,24 @@ object StreamConsumer { } private fun processChar(c: Char) { - when (c) { - REASONING -> inReasoning = !inReasoning - USAGE, SOURCES, QUERY -> done = true - else -> if (!inReasoning) content.append(c) + when { + inTrailing -> trailingBuf.append(c) + c == REASONING -> inReasoning = !inReasoning + c == QUERY || c == SOURCES || c == USAGE -> { + inTrailing = true + trailingBuf.append(c) + } + inReasoning -> reasoningBuf.append(c) + else -> content.append(c) } } companion object { private fun findToolEventsEnd(buf: StringBuilder): Int { var pos = 0 - while (pos < buf.length && buf[pos] == TOOL) { - val nl = buf.indexOf("\n", pos) + val s = buf.toString() + while (pos < s.length && s[pos] == TOOL) { + val nl = s.indexOf('\n', pos) if (nl == -1) return -1 pos = nl + 1 } diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index 0e9d70d..faebf64 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -19,6 +19,10 @@ Error Open menu + + Reasoning + Sources + Session expired. Please sign in again. Credits exhausted. diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bd0cc04..7866a1f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -21,6 +21,10 @@ Fehler Menü öffnen + + Gedankengang + Quellen + Sitzung abgelaufen. Bitte erneut anmelden. Guthaben aufgebraucht. diff --git a/app/src/test/java/dev/kaizen/app/StreamConsumerTest.kt b/app/src/test/java/dev/kaizen/app/StreamConsumerTest.kt index 0de9144..6ab42ba 100644 --- a/app/src/test/java/dev/kaizen/app/StreamConsumerTest.kt +++ b/app/src/test/java/dev/kaizen/app/StreamConsumerTest.kt @@ -2,21 +2,16 @@ package dev.kaizen.app import dev.kaizen.app.net.StreamConsumer import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue import org.junit.Test -/** - * Characterization tests for the sentinel-stripping stream parser — mirrors the - * backend's lib/chat/stream-consumer.ts so the app shows exactly the same visible - * text the web does. Tests both [StreamConsumer.visibleText] (batch) and - * [StreamConsumer.Incremental] (streaming). - */ class StreamConsumerTest { - private val usage = 0.toChar() // - private val reasoning = 1.toChar() // - private val sources = 2.toChar() // - private val tool = 3.toChar() // - private val query = 4.toChar() // + private val usage = 0.toChar() + private val reasoning = 1.toChar() + private val sources = 2.toChar() + private val tool = 3.toChar() + private val query = 4.toChar() // ── Batch parser (visibleText) ────────────────────────────────────────── @@ -27,38 +22,27 @@ class StreamConsumerTest { @Test fun usageSentinel_isClipped() { - val raw = "Antwort.$usage{\"i\":12,\"o\":34}" - assertEquals("Antwort.", StreamConsumer.visibleText(raw)) + assertEquals("Antwort.", StreamConsumer.visibleText("Antwort.$usage{\"i\":12,\"o\":34}")) } @Test fun reasoning_isStripped_contentKept() { - val raw = "${reasoning}denke nach${reasoning}Die Antwort ist 42." - assertEquals("Die Antwort ist 42.", StreamConsumer.visibleText(raw)) + assertEquals("Die Antwort ist 42.", StreamConsumer.visibleText("${reasoning}denke nach${reasoning}Die Antwort ist 42.")) } @Test fun reasoning_thenContent_thenUsage() { - val raw = "${reasoning}grübel${reasoning}Fertig.$usage{\"i\":1,\"o\":2}" - assertEquals("Fertig.", StreamConsumer.visibleText(raw)) + assertEquals("Fertig.", StreamConsumer.visibleText("${reasoning}grübel${reasoning}Fertig.$usage{\"i\":1,\"o\":2}")) } @Test fun searchQueryAndSources_areClipped() { - val raw = "Hier das Wetter.${query}\"wetter\"${sources}[{\"url\":\"x\"}]$usage{\"i\":1,\"o\":2}" - assertEquals("Hier das Wetter.", StreamConsumer.visibleText(raw)) + assertEquals("Hier das Wetter.", StreamConsumer.visibleText("Hier das Wetter.${query}\"wetter\"${sources}[{\"url\":\"x\"}]$usage{\"i\":1,\"o\":2}")) } @Test fun leadingToolEvents_areStripped() { - val raw = "$tool{\"type\":\"thinking\"}\n${tool}{\"type\":\"start\",\"name\":\"x\"}\nDie Antwort." - assertEquals("Die Antwort.", StreamConsumer.visibleText(raw)) - } - - @Test - fun incompleteLeadingToolEvent_showsNothing() { - val raw = "$tool{\"type\":\"thi" - assertEquals("", StreamConsumer.visibleText(raw)) + assertEquals("Die Antwort.", StreamConsumer.visibleText("$tool{\"type\":\"thinking\"}\n${tool}{\"type\":\"start\",\"name\":\"x\"}\nDie Antwort.")) } @Test @@ -66,121 +50,100 @@ class StreamConsumerTest { assertEquals("", StreamConsumer.visibleText("")) } - @Test - fun reasoningOnly_noContentYet_returnsEmpty() { - val raw = "${reasoning}immer noch am denken" - assertEquals("", StreamConsumer.visibleText(raw)) - } - - // ── Incremental parser ───────────────────────────────────────────────── - // Each test feeds the same input in various chunking patterns to verify - // that the incremental result matches the batch result exactly. + // ── Incremental parser — content ─────────────────────────────────────── @Test - fun incremental_plainText_singleChunk() { + fun incremental_plainText() { val inc = StreamConsumer.Incremental() - assertEquals("Hallo Welt", inc.append("Hallo Welt")) + assertEquals("Hallo Welt", inc.append("Hallo Welt").content) } @Test fun incremental_plainText_charByChar() { val inc = StreamConsumer.Incremental() - val input = "Hallo Welt" - var result = "" - for (c in input) result = inc.append(c.toString()) - assertEquals("Hallo Welt", result) + var state = inc.append("") + for (c in "Hallo Welt") state = inc.append(c.toString()) + assertEquals("Hallo Welt", state.content) } @Test fun incremental_usageSentinel_isClipped() { val inc = StreamConsumer.Incremental() - assertEquals("Antwort.", inc.append("Antwort.")) - assertEquals("Antwort.", inc.append("$usage{\"i\":12,\"o\":34}")) + inc.append("Antwort.") + assertEquals("Antwort.", inc.append("$usage{\"i\":12,\"o\":34}").content) } @Test - fun incremental_reasoning_isStripped() { + fun incremental_reasoning_captured() { val inc = StreamConsumer.Incremental() - assertEquals("", inc.append("${reasoning}denke")) - assertEquals("", inc.append(" nach")) - assertEquals("Die ", inc.append("${reasoning}Die ")) - assertEquals("Die Antwort ist 42.", inc.append("Antwort ist 42.")) + inc.append("${reasoning}denke nach") + val state = inc.append("${reasoning}Die Antwort.") + assertEquals("Die Antwort.", state.content) + assertEquals("denke nach", state.reasoning) } @Test fun incremental_reasoning_thenContent_thenUsage() { val inc = StreamConsumer.Incremental() inc.append("${reasoning}grübel${reasoning}") - val result = inc.append("Fertig.$usage{\"i\":1,\"o\":2}") - assertEquals("Fertig.", result) + val state = inc.append("Fertig.$usage{\"i\":1,\"o\":2}") + assertEquals("Fertig.", state.content) + assertEquals("grübel", state.reasoning) } @Test - fun incremental_searchQueryAndSources_areClipped() { + fun incremental_sources_parsed() { val inc = StreamConsumer.Incremental() - inc.append("Hier das Wetter.") - val result = inc.append("${query}\"wetter\"${sources}[{\"url\":\"x\"}]$usage{\"i\":1,\"o\":2}") - assertEquals("Hier das Wetter.", result) + val state = inc.append("Wetter.${query}\"berlin wetter\"${sources}[{\"title\":\"t\",\"url\":\"u\",\"snippet\":\"s\"}]$usage{}") + assertEquals("Wetter.", state.content) + assertEquals("\"berlin wetter\"", state.query) + assertEquals(1, state.sources.size) + assertEquals("t", state.sources[0].title) + assertEquals("u", state.sources[0].url) } @Test - fun incremental_toolEvents_singleChunk() { + fun incremental_toolEvents_parsed() { val inc = StreamConsumer.Incremental() - val raw = "$tool{\"type\":\"thinking\"}\n${tool}{\"type\":\"start\",\"name\":\"x\"}\nDie Antwort." - assertEquals("Die Antwort.", inc.append(raw)) + val state = inc.append("$tool{\"type\":\"start\",\"name\":\"web_search\"}\n${tool}{\"type\":\"end\",\"name\":\"web_search\",\"elapsed\":120}\nAntwort.") + assertEquals("Antwort.", state.content) + assertEquals(2, state.tools.size) + assertEquals("start", state.tools[0].type) + assertEquals("web_search", state.tools[0].name) + assertEquals("end", state.tools[1].type) + assertEquals(120L, state.tools[1].elapsed) } @Test fun incremental_toolEvents_splitAcrossChunks() { val inc = StreamConsumer.Incremental() - assertEquals("", inc.append("$tool{\"type\":\"thin")) - assertEquals("", inc.append("king\"}\n$tool{\"type\":\"sta")) - assertEquals("Die Antwort.", inc.append("rt\"}\nDie Antwort.")) - } - - @Test - fun incremental_incompleteToolEvent_showsNothing() { - val inc = StreamConsumer.Incremental() - assertEquals("", inc.append("$tool{\"type\":\"thi")) - } - - @Test - fun incremental_emptyAppend_returnsEmpty() { - val inc = StreamConsumer.Incremental() - assertEquals("", inc.append("")) - } - - @Test - fun incremental_reasoningOnly_returnsEmpty() { - val inc = StreamConsumer.Incremental() - assertEquals("", inc.append("${reasoning}immer noch am denken")) + inc.append("$tool{\"type\":\"sta") + inc.append("rt\",\"name\":\"x\"}\n") + val state = inc.append("Content.") + assertEquals("Content.", state.content) + assertEquals(1, state.tools.size) } @Test fun incremental_afterDone_ignoresMore() { val inc = StreamConsumer.Incremental() inc.append("Fertig.") - val afterUsage = inc.append("${usage}{\"i\":1}") - assertEquals("Fertig.", afterUsage) - assertEquals("Fertig.", inc.append("ignored trailing garbage")) + inc.append("${usage}{\"i\":1}") + assertEquals("Fertig.", inc.append("ignored").content) } @Test - fun incremental_toolEvents_thenReasoning_thenContent() { + fun incremental_fullStream_allSections() { + val full = "$tool{\"type\":\"start\",\"name\":\"t\"}\n${reasoning}grübel${reasoning}Die Antwort.${query}\"q\"${sources}[{\"title\":\"x\",\"url\":\"y\",\"snippet\":\"z\"}]$usage{}" val inc = StreamConsumer.Incremental() - assertEquals("", inc.append("$tool{\"type\":\"thinking\"}\n")) - assertEquals("", inc.append("${reasoning}deep thought")) - assertEquals("42", inc.append("${reasoning}42")) - } - - @Test - fun incremental_matchesBatch_fullStream() { - val full = "$tool{\"type\":\"thinking\"}\n${reasoning}grübel${reasoning}Die Antwort.${query}q${sources}s$usage{}" - val expected = StreamConsumer.visibleText(full) - - val inc = StreamConsumer.Incremental() - var result = "" - for (c in full) result = inc.append(c.toString()) - assertEquals(expected, result) + var state = inc.append("") + for (c in full) state = inc.append(c.toString()) + assertEquals("Die Antwort.", state.content) + assertEquals("grübel", state.reasoning) + assertEquals(1, state.tools.size) + assertEquals("t", state.tools[0].name) + assertEquals("\"q\"", state.query) + assertEquals(1, state.sources.size) + assertEquals("x", state.sources[0].title) } } From 9f2a7f298435f314a8d87a9c017c4e8365ff752a Mon Sep 17 00:00:00 2001 From: Bruno Deanoz Date: Sun, 21 Jun 2026 15:38:12 +0200 Subject: [PATCH 12/12] =?UTF-8?q?docs:=20CLAUDE.md=20=E2=80=94=20complete?= =?UTF-8?q?=20update=20for=20design=20system=20v2=20session?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added: sentinel parsing section (reasoning/sources/tools/query), app icon section, updated TODO checklist (3 items checked off), removed pre-existing OklabTest failures section (all fixed), updated test descriptions, removed stale branch reference. --- CLAUDE.md | 45 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index e1010a8..8d10647 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -63,7 +63,7 @@ ui/ ### Design System v2 (`ui/`) — added 2026-06-21 -Full spec: `DESIGN.md`. Branch: `feature/design-system-v2`. +Full spec: `DESIGN.md`. **Six pillars** (load-bearing — if any regress, the design regresses): @@ -103,6 +103,33 @@ Full spec: `DESIGN.md`. Branch: `feature/design-system-v2`. - **Language selector** in Settings: System / Deutsch / English. Stored as `locale` in SecureStore. Note: currently only stores the preference; runtime locale switching (AppCompatDelegate.setApplicationLocales) needs wiring in MainActivity on next iteration. - No server-side theme storage — web uses localStorage, app uses SecureStore. Both are client-local. +### Sentinel parsing — reasoning, sources, tools (added 2026-06-21) + +The `/api/v1/chat` stream embeds control sections via sentinel code points (from `lib/chat/constants.ts`): + +| Sentinel | Code | What | App UI | +|----------|------|------|--------| +| `\x00` USAGE | trailing | Usage/cost JSON | Stripped (display TODO) | +| `\x01` REASONING | toggle | Model's chain-of-thought | `ReasoningBlock` — collapsible "Gedankengang" | +| `\x02` SOURCES | trailing | Web search sources JSON | `SourcesBlock` — compact cards with domain | +| `\x03` TOOL | leading | Tool-call events (JSON+newline) | `ToolEventsBlock` — status icons per step | +| `\x04` QUERY | trailing | Search query string | Shown above sources | + +**StreamConsumer.Incremental** (`net/StreamConsumer.kt`) returns `StreamState` (not `String`): +- `content` — visible text (reasoning stripped, tool events stripped) +- `reasoning` — full reasoning text +- `tools` — `List` (type, name, args, result, error, elapsed) +- `query` — search query string +- `sources` — `List` (title, url, snippet) + +**KaizenApi.chat()** returns `Flow`. ChatScreen maps all fields to `Message` during streaming. + +**UI files:** `chat/StreamBlocks.kt` — `ReasoningBlock`, `ToolEventsBlock`, `SourcesBlock`, `SourceChip`. + +### App icon + +Adaptive icon: amber orb with multi-layer radial gradients (body, depth shadow, specular highlight, warm bounce light, crisp rim). Light mode: warm off-white background. Dark mode: Obsidian gradient. Monochrome layer for Android 13+ themed icons. Splash screen uses orb foreground (API 31+). Vector-only — no raster WebPs. + ### Offline-first cache layer (Room) — added 2026-06-21 Architecture decision document: `OFFLINE_CACHE_ADD.md`. @@ -212,9 +239,9 @@ These are what separate "prototype" from "daily-driver": ### 4. Features for parity with the web - [x] **Attachments** — image/file upload, attachment preview in messages, display in loaded conversations (camera capture still TODO) -- [ ] **Reasoning/thinking display** — parse `\x01` sentinel, show collapsible thinking block -- [ ] **Web search sources** — parse `\x02`/`\x04` sentinels, render source cards -- [ ] **Tool call display** — parse `\x03` sentinel, show live tool steps +- [x] **Reasoning/thinking display** — `ReasoningBlock` (collapsible), parses `\x01` sentinel +- [x] **Web search sources** — `SourcesBlock` + `SourceChip`, parses `\x02`/`\x04` sentinels +- [x] **Tool call display** — `ToolEventsBlock`, parses `\x03` sentinel, status icons per step - [ ] **Native passkey login** (WebAuthn/FIDO2 on Android) - [ ] **WebSocket streaming** (replace chunked HTTP for lower latency on mobile) - [ ] **Usage/cost display** @@ -253,9 +280,9 @@ securityCrypto = "1.1.0-alpha06" **Unit tests** (`app/src/test/`): JVM-only, no emulator needed. -- `SettingsViewModelTest` — state transitions, default values, theme selection, name updates -- `StreamConsumerTest` — incremental parser, sentinel stripping, edge cases -- `OklabTest` — 2 pre-existing failures (round-trip color drift > 0.01 tolerance, unrelated to backend wiring, likely too-tight tolerance or headless float precision) +- `SettingsViewModelTest` — state transitions, all 4 themes, appearance modes, name updates with store-less default +- `StreamConsumerTest` — batch + incremental parser, sentinel stripping, reasoning/sources/tools parsing, char-by-char edge cases +- `OklabTest` — round-trip conversion, interpolation midpoint, gradient generation (all green since Double-precision fix) - `MappersTest` — `ConversationSummary` ↔ `ConversationEntity`, `StoredMessage` ↔ `MessageEntity`, round-trip integrity, attachment preservation - `ConvertersTest` — `List` ↔ JSON round-trips, malformed JSON returns empty list, unknown fields tolerance via `ignoreUnknownKeys` - `ColorPipelineTest` — all tokens in DisplayP3, approximate value ranges, no pure black/white in neutrals @@ -263,10 +290,6 @@ securityCrypto = "1.1.0-alpha06" - `ThemeRegistryTest` — 4 themes present, forId lookup, fromString parsing + fallback, distinct blob colors - `ShadowStackTest` — layer counts per level, alpha range validation, blur/alpha progression -## Pre-existing issues (not from this work) - -- `OklabTest` has 2 headless failures (`testColorToOklabAndBack`, `testGradientGeneration` — round-trip color drift > 0.01 tolerance). Unrelated to backend wiring; likely too-tight tolerance or headless float precision. - ## Constraints & gotchas - Local dev Mac has **no RustFS** (storage on server only); upload/storage flows fail locally with `ECONNREFUSED :9000`.