From a96a22aabc83bfa5e0a573fa044e23a7da8519ae Mon Sep 17 00:00:00 2001 From: uhryniuk Date: Tue, 25 Aug 2026 13:02:51 -0500 Subject: [PATCH] Shrink HUD stat tiles, control bar buttons, and nav bar Direct feedback: HUD stat tiles filled nearly the whole screen above the map, and the pause/stop/discard control bar and bottom nav bar were both oversized. Caps the HUD grid to a fixed compact band instead of filling down to the control bar, shrinks the handheld control bar from 72dp to 56dp (mounted mode stays 96dp for glove use), shrinks its icons from 32 to 24 outside mounted mode, and trims the nav bar from Material 3's default 80dp to 64dp. --- lib/src/ui/app_shell.dart | 5 +++ lib/src/ui/record/record_screen.dart | 46 +++++++++++++++++++++++----- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/lib/src/ui/app_shell.dart b/lib/src/ui/app_shell.dart index 7ff0f15..678862a 100644 --- a/lib/src/ui/app_shell.dart +++ b/lib/src/ui/app_shell.dart @@ -138,6 +138,11 @@ class _ShellNavBar extends StatelessWidget { @override Widget build(BuildContext context) => NavigationBar( key: const Key('shell-nav-bar'), + // Material 3's own default (80dp) reads as oversized for a 4-item bar with plain + // icon+label destinations -- direct feedback (`docs/FEEDBACK.md`) called this out. + // 64dp keeps every icon/label pair at its default size, just with less surrounding + // padding, and stays comfortably above the 48dp minimum touch target. + height: 64, selectedIndex: currentIndex, onDestinationSelected: onDestinationSelected, destinations: const [ diff --git a/lib/src/ui/record/record_screen.dart b/lib/src/ui/record/record_screen.dart index b5fff2b..3154316 100644 --- a/lib/src/ui/record/record_screen.dart +++ b/lib/src/ui/record/record_screen.dart @@ -156,11 +156,21 @@ class _RecordScreenState extends ConsumerState { } } - /// 72dp normally, 96dp mounted -- one constant height regardless of how many + /// 56dp normally, 96dp mounted -- one constant height regardless of how many /// segments the control bar has (one/two/three), so the HUD area above it is always /// the same size and a widget's saved fractional position never jumps between ride - /// states. - double _controlBarHeight(bool mountedMode) => mountedMode ? 96 : 72; + /// states. Mounted mode stays at 96dp (V3-05: not enough at speed, with gloves, + /// below that); the handheld case only needs a comfortable tap target, not a glove + /// target, and 56dp is still well above the 48dp accessibility floor. + double _controlBarHeight(bool mountedMode) => mountedMode ? 96 : 56; + + /// The HUD stat grid used to fill the entire area down to the control bar, which + /// made even a two-row default layout balloon to take up most of the screen on a + /// tall phone -- direct feedback (`docs/FEEDBACK.md`) called this out explicitly. + /// Capping it to a fixed, compact band keeps every grid cell a sane physical size + /// regardless of screen height, leaving the rest of the screen as pure map. Mounted + /// mode gets a taller band to match its own larger text scale ([mountedTextScale]). + double _hudAreaHeight(bool mountedMode) => mountedMode ? 320 : 260; @override Widget build(BuildContext context) { @@ -195,8 +205,11 @@ class _RecordScreenState extends ConsumerState { child: Stack( children: [ if (!ui.isIdle) - Positioned.fill( - bottom: _controlBarHeight(mountedMode), + Positioned( + top: 0, + left: 0, + right: 0, + height: _hudAreaHeight(mountedMode), child: HudEditOverlay( metricBuilder: (context, metric) => _HudMetricValue( metric: metric, @@ -237,6 +250,7 @@ class _RecordScreenState extends ConsumerState { height: _controlBarHeight(mountedMode), child: _ControlBar( ui: ui, + mountedMode: mountedMode, onStart: () => _guard(engine.start), onPause: () => _guard(engine.pause), onStop: () => _guard(() async => engine.stop()), @@ -379,6 +393,7 @@ class _ControlBar extends StatelessWidget { required this.onPause, required this.onStop, required this.onDiscard, + this.mountedMode = false, }); final RecordUiState ui; @@ -387,6 +402,11 @@ class _ControlBar extends StatelessWidget { final VoidCallback onStop; final VoidCallback onDiscard; + /// V3-05: mounted mode keeps full-size, glove-friendly icons. The handheld case + /// only needs a comfortable tap target, not a glove target, so its icons shrink + /// along with the bar itself (`_controlBarHeight`) -- see [_Segment.iconSize]. + final bool mountedMode; + @override Widget build(BuildContext context) { if (ui.isIdle) { @@ -397,6 +417,7 @@ class _ControlBar extends StatelessWidget { background: Theme.of(context).colorScheme.tertiaryContainer, foreground: Theme.of(context).colorScheme.onTertiaryContainer, onTap: onStart, + mountedMode: mountedMode, ); } @@ -412,6 +433,7 @@ class _ControlBar extends StatelessWidget { foreground: colors.onTertiaryContainer, onTap: onPause, trailingBorder: true, + mountedMode: mountedMode, ), ), Expanded( @@ -421,6 +443,7 @@ class _ControlBar extends StatelessWidget { background: colors.errorContainer, foreground: colors.onErrorContainer, onTap: onStop, + mountedMode: mountedMode, ), ), ], @@ -441,6 +464,7 @@ class _ControlBar extends StatelessWidget { foreground: colors.onTertiaryContainer, onTap: onStart, trailingBorder: true, + mountedMode: mountedMode, ), ), Expanded( @@ -451,6 +475,7 @@ class _ControlBar extends StatelessWidget { foreground: colors.onErrorContainer, onTap: onStop, trailingBorder: true, + mountedMode: mountedMode, ), ), Expanded( @@ -460,6 +485,7 @@ class _ControlBar extends StatelessWidget { background: colors.surfaceContainerHighest, foreground: colors.error, onTap: onDiscard, + mountedMode: mountedMode, ), ), ], @@ -476,6 +502,7 @@ class _Segment extends StatelessWidget { required this.onTap, this.label, this.trailingBorder = false, + this.mountedMode = false, }); final String keyName; @@ -485,6 +512,9 @@ class _Segment extends StatelessWidget { final VoidCallback onTap; final String? label; final bool trailingBorder; + final bool mountedMode; + + double get _iconSize => mountedMode ? 32 : 24; @override Widget build(BuildContext context) => Material( @@ -505,18 +535,18 @@ class _Segment extends StatelessWidget { child: SizedBox.expand( child: Center( child: label == null - ? Icon(icon, color: foreground, size: 32) + ? Icon(icon, color: foreground, size: _iconSize) : Row( mainAxisSize: MainAxisSize.min, children: [ - Icon(icon, color: foreground), + Icon(icon, color: foreground, size: _iconSize), const SizedBox(width: 8), Text( label!, style: TextStyle( color: foreground, fontWeight: FontWeight.bold, - fontSize: 16, + fontSize: mountedMode ? 16 : 14, ), ), ],