Wear Catppuccin Mocha, and move Usage to where the provider is

Two changes to the app, plus the one they turned up.

**The theme.** Catppuccin Mocha, copied from dev-updater rather than
shared: wg-app-link is the *link* -- the tunnel, the pinned CA, enrollment
-- and a palette is not that. The two apps looking alike is a preference
rather than a contract, and the moment one wants a different accent a
shared version becomes a thing to fight. dev-updater's ActionTone and its
ANSI table did not come across; nothing here draws a log or a destructive
button yet, and copying a vocabulary with no speakers is how a file starts
lying about what the app does.

**Usage is no longer a global button.** It belongs to the provider, and
the session view is the only place a provider is currently named, so that
is where the control sits -- beside the line that names it, rather than
collected with the app-wide controls where its scope had to be guessed. It
carries the session back with it, so Back returns to that session rather
than dumping the reader on the list.

Its real home is that provider's own settings, which do not exist yet.

**And the bit that only running it could find.** I first subtitled the
usage screen with the session's provider, which on an echo session put
"echo" directly above a card reading "claude" -- Claude's account-wide
numbers labelled as echo's, a claim about echo that nothing measured. The
subtitle is gone; each card names the service that answered, which is the
true scope, and the reason is written where the subtitle was so it does
not get re-added.

Looked at on the emulator rather than read: the palette, the session
header, the usage screen, and Back landing on the session it came from.
ktfmt, compile and Lint clean.
This commit is contained in:
iris committed 2026-08-28 20:26:12 -04:00
1 parent 4370c467ca
commit 31135e3f22
6 files changed
+135 -7

No files matched your search

@@ -0,0 +1,100 @@
package com.example.aiapp
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
/**
* Catppuccin Mocha, as published in `catppuccin/palette`.
*
* Named rather than used as literals at the point of need, so the mapping below reads as the
* decision it is -- "a card is Surface 0" -- and so a value can be checked against the upstream
* palette without reading the layout that uses it.
*/
private object Mocha {
val Rosewater = Color(0xFFF5E0DC)
val Mauve = Color(0xFFCBA6F7)
val Red = Color(0xFFF38BA8)
val Peach = Color(0xFFFAB387)
val Yellow = Color(0xFFF9E2AF)
val Green = Color(0xFFA6E3A1)
val Teal = Color(0xFF94E2D5)
val Sky = Color(0xFF89DCEB)
val Blue = Color(0xFF89B4FA)
val Lavender = Color(0xFFB4BEFE)
val Text = Color(0xFFCDD6F4)
val Subtext0 = Color(0xFFA6ADC8)
val Overlay0 = Color(0xFF6C7086)
val Surface2 = Color(0xFF585B70)
val Surface1 = Color(0xFF45475A)
val Surface0 = Color(0xFF313244)
val Base = Color(0xFF1E1E2E)
val Mantle = Color(0xFF181825)
val Crust = Color(0xFF11111B)
}
/**
* The app's colour scheme: Catppuccin Mocha mapped onto Material's roles.
*
* Copied from dev-updater rather than shared, which is a deliberate line: wg-app-link is the *link*
* -- the tunnel, the pinned CA, enrollment -- and a palette is not that. The two apps looking alike
* is a preference, not a contract, and the moment one wants a different accent the shared version
* becomes a thing to fight rather than a thing to use.
*
* The mapping that matters is the surface ladder. Mocha names its darks in order -- Crust, Mantle,
* Base, Surface 0, Surface 1 -- and Material asks for the same thing under different names, so the
* page is Base, a component's outlined card stays Base beside it, and a project's card is Surface
* 0: one visible step up, which is the whole of what the nesting has to say.
*
* Accents on this palette are light, so anything filled with one takes Crust for its text rather
* than the near-white the roles default to.
*/
val AiAppColors =
darkColorScheme(
primary = Mocha.Mauve,
onPrimary = Mocha.Crust,
primaryContainer = Mocha.Surface1,
onPrimaryContainer = Mocha.Mauve,
secondary = Mocha.Lavender,
onSecondary = Mocha.Crust,
secondaryContainer = Mocha.Surface1,
onSecondaryContainer = Mocha.Lavender,
tertiary = Mocha.Rosewater,
onTertiary = Mocha.Crust,
background = Mocha.Base,
onBackground = Mocha.Text,
surface = Mocha.Base,
onSurface = Mocha.Text,
surfaceVariant = Mocha.Surface0,
onSurfaceVariant = Mocha.Subtext0,
surfaceContainerLowest = Mocha.Crust,
surfaceContainerLow = Mocha.Mantle,
surfaceContainer = Mocha.Base,
surfaceContainerHigh = Mocha.Surface0,
surfaceContainerHighest = Mocha.Surface0,
inverseSurface = Mocha.Text,
inverseOnSurface = Mocha.Base,
inversePrimary = Mocha.Mauve,
outline = Mocha.Overlay0,
outlineVariant = Mocha.Surface2,
error = Mocha.Red,
onError = Mocha.Crust,
errorContainer = Mocha.Surface1,
onErrorContainer = Mocha.Red,
scrim = Mocha.Crust,
)
/** "There is something here": a session that is running. */
val runningColor: Color
@Composable get() = Mocha.Green
/**
* "This went wrong on its own": a session that fell over.
*
* The scheme's error colour, and deliberately not "the same red as a destructive button" even
* though it is the same red. They are the same red for different reasons, and a state is not an
* action -- nothing here is a button.
*/
val failedColor: Color
@Composable get() = MaterialTheme.colorScheme.error