Files
hapi/android/app
6ccde08548 feat(android): render settings pickers as expressive choice dialogs (#2227)
* feat(android): anchor the Material type scale on the shared reading tokens

MaterialTheme was built with only a colorScheme, leaving HapiTypography's
body/code/caption tokens an island that never influenced Material
typography. Derive the app-wide Material type scale from those tokens so
Material widgets and direct token consumers share one type system: the
body token drives bodyLarge (the chat reading size) and the caption token
drives bodySmall (the metadata size), while every other slot keeps its
Material platform default so existing MaterialTheme.typography call sites
stay pixel-identical. Only size and leading come from the tokens; weight,
tracking and family stay Material's. HapiTheme now accepts a typography
argument (defaulting to the shared scale) and passes it through, and the
monospace code token stays a direct-consumer token because Material has
no code slot.

Co-Authored-By: Claude Code <noreply@anthropic.com>
via [HAPI](https://hapi.run)
Co-Authored-By: HAPI <noreply@hapi.run>

* feat(android): render settings pickers as expressive choice dialogs

The theme and language pickers were the last bare AlertDialog + radio-row
surfaces in the app: plain stacked radio buttons with no visual anchor for
what each option means, and two focus targets per row (the row and the
RadioButton each carried their own click handler). Give small exclusive
pickers a shared expressive form: each option renders as a full-width
choice card whose selected state is a secondaryContainer fill plus a
trailing check, and options can carry a fixed preview swatch.

The theme modes show two-tone palette chips — follow-system spans the
light and dark palettes, OLED is outlined pure black, dark uses the dark
canvas rather than black so the two stay distinguishable at a glance.
Swatch colors are fixed values depicting the mode they name, not derived
from the active scheme, mirroring how the web color-theme cards hardcode
their previews: a "light" chip must stay light even inside a dark dialog.

Rows keep radio semantics through Modifier.selectable with Role.RadioButton
inside a selectableGroup, so TalkBack still announces the standard
"selected, n of m" picker phrasing while each option becomes a single
focus target. Tapping an option still applies it immediately. Language
options skip the swatch slot; the component stays generic over the value.

Co-Authored-By: Claude Code <noreply@anthropic.com>
via [HAPI](https://hapi.run)
Co-Authored-By: HAPI <noreply@hapi.run>

---------

Co-authored-by: Claude Code <noreply@anthropic.com>
Co-authored-by: HAPI <noreply@hapi.run>
2026-10-29 10:57:55 +08:00
..
2026-10-29 10:13:33 +08:00