V3-05: mounted (handlebar) mode

Wake lock via a WakelockController seam (mirrors LocationSource), gated strictly to actual recording and released on stop/discard/navigate-away/dispose. High-contrast ripprMountedTheme() applied only to the record screen. BigStat gained a scale param for the headline figure rather than a blanket TextTheme.apply, which crashes on Material 3's default theme.
This commit is contained in:
2026-08-17 14:55:47 -05:00
parent f3c7e2d6b4
commit fbdb55258c
14 changed files with 401 additions and 19 deletions

View File

@@ -1,7 +1,9 @@
/// Ported from `com.rippr.ui.theme.RipprTheme`.
///
/// Dark-only by design. This is read at a glance in daylight with a visor down, and a
/// light theme would be actively worse for that.
/// Dark-only by design for a pocketed ride -- read at a glance, in a pocket-glance, at
/// night as much as in daylight. V3-05 adds [ripprMountedTheme], a deliberate exception
/// for the one screen that is actually looked at continuously, in direct daylight, behind
/// a visor -- where the dark ground loses to glare instead of helping.
library;
import 'package:flutter/material.dart';
@@ -55,6 +57,56 @@ ThemeData ripprTheme() {
);
}
// V3-05: mounted colours. Near-white ground, near-black ink -- the inverse tradeoff from
// the pocketed theme above. Read against a visor in direct daylight, a dark ground loses
// to glare in a way a dark theme never has to answer for at a pocket glance.
const _mountedGround = Color(0xFFF5F3EF);
const _mountedInk = Color(0xFF12100D);
const _mountedAccent = Color(0xFFD84315);
const ripprMountedColors = ColorScheme.light(
primary: _mountedAccent,
onPrimary: Color(0xFFFFFFFF),
secondary: Color(0xFF4A4034),
surface: Color(0xFFFFFFFF),
onSurface: _mountedInk,
surfaceContainerHighest: Color(0xFFE7E2D9),
onSurfaceVariant: _mountedInk,
outline: Color(0xFF706A5E),
error: Color(0xFFB3261E),
onError: Color(0xFFFFFFFF),
);
const ripprMountedBackground = _mountedGround;
/// Scales body/headline text up for legibility at a glance, at speed, behind a visor.
/// Kept separate from V3-16's visual identity work -- this is a stopgap born of a real
/// constraint, not a design pass.
const double mountedTextScale = 1.25;
/// V3-05's mounted mode: high contrast, larger text. Only applied to the record screen
/// while mounted, not the whole app -- everywhere else is still read at a pocket glance.
ThemeData ripprMountedTheme() {
final base = ThemeData(
colorScheme: ripprMountedColors,
useMaterial3: true,
scaffoldBackgroundColor: _mountedGround,
);
return base.copyWith(
textTheme: base.textTheme.apply(
bodyColor: _mountedInk,
displayColor: _mountedInk,
),
appBarTheme: const AppBarTheme(
backgroundColor: _mountedGround,
foregroundColor: _mountedInk,
elevation: 0,
),
dividerTheme: const DividerThemeData(color: Color(0xFFDAD4C8), space: 1),
);
}
/// Monospace for anything numeric.
///
/// Digits that change every second must not make the layout jitter, which proportional