UI-08: migrate theme to Modern Professional Dark
Replaces V3-16's safety-orange identity with the palette actually backing every fetched Stitch mockup (confirmed by hex-matching against all three design systems in the Stitch project, not by trusting its declared default). Ground drops to #0a0a0c with a three-level surface/card stack, primary becomes Professional Blue (#4090fe), and reference readings move to a new tertiary orange since blue is no longer free for that role. Re-verified theme_test.dart's AA contrast assertions against the new values (all pass with wide margin) and left mounted mode's separate daylight palette alone, per the ticket's own reasoning. Also resolves the ticket's named risk: RideMap's speed-gradient hardcoded hex literal, which would have washed to a single hue now that primary is blue, now lerps from the theme's own secondary token instead. Inter is not wired in -- no bundled font asset exists to back the family name, and setting one without an asset would silently fall back to Roboto. Documented as a deliberate follow-up rather than a silent gap. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Xki7YAcc2TiN2PRZJ2tXr
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# UI-08 — Theme migration to Modern Professional Dark
|
||||
|
||||
**Depends on** nothing · **Size** S · **Status** Not started
|
||||
**Depends on** nothing · **Size** S · **Status** Done
|
||||
|
||||
## Goal
|
||||
Replace `theme.dart`'s current safety-orange palette with "Modern Professional Dark" —
|
||||
@@ -94,3 +94,67 @@ Full spec: `docs/design/stitch-export/design-system-modern-professional-dark.md`
|
||||
## Out of scope
|
||||
Any screen-specific redesign (UI-05/06/07) — this ticket only changes the token layer
|
||||
those screens then build against.
|
||||
|
||||
## Outcome
|
||||
|
||||
`lib/src/ui/theme.dart`'s `ripprColors` now carries Modern Professional Dark's values:
|
||||
ground `#0a0a0c` (the design system's own `surface-main`, not its plain `background`
|
||||
token — the spec's prose is explicit that `#0a0a0c` is *the* background, with `#131313`
|
||||
one step up and `#16161a` a second step up for cards, a three-level stack the old
|
||||
two-level `_ground`/`_surface` pair didn't have room for). Added `ripprCardColor`
|
||||
(`#16161a`) to carry the third level, since `ColorScheme` has no free surface slot for it
|
||||
once `surfaceContainerHighest` is spent on the selected/highlighted state. Primary is
|
||||
Professional Blue (`#4090fe`); tertiary is a warm orange (`#ffb68c`).
|
||||
|
||||
**Decision recorded per the ticket's own prompt:** the design system doesn't specify a
|
||||
reference-vs-live split itself, so one was chosen and applied everywhere consistently —
|
||||
tertiary orange for `StatRow`'s `reference` values (a max, an average), inverted from
|
||||
V3-16 where blue held that role, because blue is now the *primary* colour and reusing it
|
||||
for reference readings would have made the two indistinguishable. `RideMap`'s speed
|
||||
polyline gradient — flagged explicitly in the ticket's Risks as a hardcoded hex literal —
|
||||
now lerps `colors.secondary` (the theme's own cool slate-blue) to `colors.primary`
|
||||
instead of a hardcoded `0xFF4FC3F7`, for the same reason: the old literal was itself
|
||||
blue, and lerping blue-to-blue under the new primary would have washed the gradient into
|
||||
one hue.
|
||||
|
||||
**Shape:** added `ripprRadiusSmall` (8px) and `ripprRadiusLarge` (16px) constants
|
||||
matching the spec's small-component/large-container split, and a `CardThemeData` using
|
||||
the large radius and `ripprCardColor`. `RideMap`'s card-mode `ClipRRect` (previously a
|
||||
hardcoded 12px) now uses `ripprRadiusLarge`. Deliberately did **not** add a global
|
||||
`ElevatedButtonTheme`/`OutlinedButtonTheme` shape override — `RecordScreen`'s
|
||||
Start/Pause/Stop/Discard buttons rely on Material 3's default `StadiumBorder` for their
|
||||
pill shape, which already matches the Stitch mockups' own pill buttons; forcing an 8px
|
||||
rectangle there would have been an unrequested regression, not a spec application.
|
||||
|
||||
**Inter was not wired in.** The design system calls for it exclusively, but the codebase
|
||||
has no bundled font asset and no existing `bodyFont`/`headlineFont` abstraction to retarget
|
||||
— setting `TextTheme.apply(fontFamily: 'Inter')` with nothing registered under that name
|
||||
would silently fall back to the platform default (Roboto), which is exactly the class of
|
||||
invisible failure `ripprTheme()`'s own `bodyColor`/`displayColor` fix exists to prevent
|
||||
(the "Compose `Surface`" comment in the file). Left as a documented, deliberate follow-up
|
||||
rather than shipping a fontFamily string that resolves to nothing. `monoDigits` is
|
||||
untouched and still applies to every numeric display, as required.
|
||||
|
||||
**Contrast:** re-ran `theme_test.dart`'s `contrastRatio()` assertions against the new
|
||||
palette (no values needed adjusting — primary-on-ground, tertiary-on-ground, and
|
||||
onSurface-on-ground all clear their AA thresholds with considerable margin: roughly
|
||||
6.3:1, 11.6:1, and 15.3:1 respectively, well past the 4.5:1/3:1 bars). Mounted mode
|
||||
(V3-05) was left unchanged — its own separate high-contrast daylight palette isn't
|
||||
covered by the Modern Professional Dark spec, its orange accent isn't a brand clash the
|
||||
way the pocketed theme's safety-orange was, and V3-13's real-ride sunlight-legibility
|
||||
claim depends on the specific values already tuned there. Its existing contrast tests
|
||||
were re-run, unchanged, and still pass.
|
||||
|
||||
**Tests:** `flutter analyze` clean. `flutter test` green at 315 tests, no count change —
|
||||
this ticket touched no test files, only re-pointed `ripprColors`'s literals and reused
|
||||
the same `theme_test.dart`/`ride_map_test.dart` assertions the diff didn't need to alter
|
||||
because they read `ripprTheme().colorScheme` rather than hardcoding old hex values.
|
||||
|
||||
**Android emulator verification** (`Medium_Phone_API_35`): checked Map/Settings/Rides
|
||||
tabs. Buttons, switches, the segmented Metric/Imperial control, section labels, and the
|
||||
`Save`/`Clear` text actions all render in Professional Blue; the reference "Max speed"
|
||||
figure renders in the new tertiary orange, clearly distinct from the live "0" headline
|
||||
figure (unchanged ink) and from the Pause button's blue; the bottom nav's active-tab
|
||||
indicator picked up a blue-tinted pill automatically (Material 3 derives it from the
|
||||
`ColorScheme`, not something this ticket configured directly) rather than the old
|
||||
neutral grey. No leftover orange/old-instrument-blue literals were visible anywhere.
|
||||
|
||||
Reference in New Issue
Block a user