V3-16: visual identity (token-level pass)
Direction written before code, per the ticket's own step 1: safety orange stays primary (authentic to the domain, not decorative), a new instrument-blue tertiary is reserved for reference readings (max/average) vs the live figure, ground warmed fractionally, no new font, no motion -- both argued for directly rather than left undecided. Instrument blue reuses RideMap's existing slow-speed gradient color rather than inventing a new one, so 'same colour, same meaning' holds between the map and stat rows. contrastRatio() implements WCAG 2.x directly and is asserted (11 tests, both themes, AA normal/large) rather than eyeballed. Applied to StatRow's new 'reference' flag on record screen and trip detail's Max/Avg speed rows -- a token-level + targeted pass, not an exhaustive re-skin, named as a deliberate scope reduction alongside the two criteria (outdoor sunlight verification, golden tests) this environment genuinely cannot satisfy.
This commit is contained in:
@@ -8,21 +8,31 @@ library;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
// Matches the launcher icon: near-black tarmac with a safety-orange accent.
|
||||
// Matches the launcher icon: near-black tarmac with a safety-orange accent. V3-16
|
||||
// warmed the ground fractionally (asphalt, not a generic dark-mode blue-black) and added
|
||||
// an instrument-blue tertiary reserved for reference readings -- see the ticket's
|
||||
// Direction section for why.
|
||||
const _accent = Color(0xFFFF5722);
|
||||
const _ground = Color(0xFF101418);
|
||||
const _surface = Color(0xFF181D23);
|
||||
const _ground = Color(0xFF120F0D);
|
||||
const _surface = Color(0xFF1C1917);
|
||||
const _ink = Color(0xFFF2F5F8);
|
||||
const _outline = Color(0xFF66727E);
|
||||
const _outline = Color(0xFF6E7681);
|
||||
const _danger = Color(0xFFE53935);
|
||||
|
||||
/// Reference readings only (a max, an average) -- never the live figure, which stays
|
||||
/// [_accent]. The same colour [RideMap] already uses for its slowest speed bucket,
|
||||
/// reused rather than invented, so "instrument blue" means one thing everywhere.
|
||||
const _instrumentBlue = Color(0xFF4FC3F7);
|
||||
|
||||
const ripprColors = ColorScheme.dark(
|
||||
primary: _accent,
|
||||
onPrimary: Color(0xFF100A06),
|
||||
secondary: _outline,
|
||||
tertiary: _instrumentBlue,
|
||||
onTertiary: Color(0xFF042433),
|
||||
surface: _surface,
|
||||
onSurface: _ink,
|
||||
surfaceContainerHighest: Color(0xFF212832),
|
||||
surfaceContainerHighest: Color(0xFF262220),
|
||||
onSurfaceVariant: _ink,
|
||||
outline: _outline,
|
||||
error: _danger,
|
||||
@@ -53,7 +63,7 @@ ThemeData ripprTheme() {
|
||||
foregroundColor: _ink,
|
||||
elevation: 0,
|
||||
),
|
||||
dividerTheme: const DividerThemeData(color: Color(0xFF2A323C), space: 1),
|
||||
dividerTheme: const DividerThemeData(color: Color(0xFF322C28), space: 1),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -64,10 +74,17 @@ const _mountedGround = Color(0xFFF5F3EF);
|
||||
const _mountedInk = Color(0xFF12100D);
|
||||
const _mountedAccent = Color(0xFFD84315);
|
||||
|
||||
// V3-16: the same instrument/reference split as the pocketed theme, darkened enough to
|
||||
// hold WCAG AA against a near-white ground -- the mounted theme's own reason to exist
|
||||
// (sunlight, a visor) is not touched by this, only extended.
|
||||
const _mountedInstrumentBlue = Color(0xFF01579B);
|
||||
|
||||
const ripprMountedColors = ColorScheme.light(
|
||||
primary: _mountedAccent,
|
||||
onPrimary: Color(0xFFFFFFFF),
|
||||
secondary: Color(0xFF4A4034),
|
||||
tertiary: _mountedInstrumentBlue,
|
||||
onTertiary: Color(0xFFFFFFFF),
|
||||
surface: Color(0xFFFFFFFF),
|
||||
onSurface: _mountedInk,
|
||||
surfaceContainerHighest: Color(0xFFE7E2D9),
|
||||
@@ -107,6 +124,18 @@ ThemeData ripprMountedTheme() {
|
||||
);
|
||||
}
|
||||
|
||||
/// WCAG 2.x's contrast ratio: `(L1 + 0.05) / (L2 + 0.05)`, `L1` the lighter of the two
|
||||
/// relative luminances. AA requires 4.5:1 for normal text, 3:1 for large text (18pt, or
|
||||
/// 14pt bold) -- see the tests in `theme_test.dart` for V3-16's acceptance criterion,
|
||||
/// which asserts this directly rather than trusting a palette pick by eye.
|
||||
double contrastRatio(Color a, Color b) {
|
||||
final la = a.computeLuminance();
|
||||
final lb = b.computeLuminance();
|
||||
final lighter = la > lb ? la : lb;
|
||||
final darker = la > lb ? lb : la;
|
||||
return (lighter + 0.05) / (darker + 0.05);
|
||||
}
|
||||
|
||||
/// Monospace for anything numeric.
|
||||
///
|
||||
/// Digits that change every second must not make the layout jitter, which proportional
|
||||
|
||||
Reference in New Issue
Block a user