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.
This commit is contained in:
@@ -138,6 +138,11 @@ class _ShellNavBar extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => NavigationBar(
|
Widget build(BuildContext context) => NavigationBar(
|
||||||
key: const Key('shell-nav-bar'),
|
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,
|
selectedIndex: currentIndex,
|
||||||
onDestinationSelected: onDestinationSelected,
|
onDestinationSelected: onDestinationSelected,
|
||||||
destinations: const [
|
destinations: const [
|
||||||
|
|||||||
@@ -156,11 +156,21 @@ class _RecordScreenState extends ConsumerState<RecordScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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
|
/// 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
|
/// the same size and a widget's saved fractional position never jumps between ride
|
||||||
/// states.
|
/// states. Mounted mode stays at 96dp (V3-05: not enough at speed, with gloves,
|
||||||
double _controlBarHeight(bool mountedMode) => mountedMode ? 96 : 72;
|
/// 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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -195,8 +205,11 @@ class _RecordScreenState extends ConsumerState<RecordScreen> {
|
|||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
if (!ui.isIdle)
|
if (!ui.isIdle)
|
||||||
Positioned.fill(
|
Positioned(
|
||||||
bottom: _controlBarHeight(mountedMode),
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
height: _hudAreaHeight(mountedMode),
|
||||||
child: HudEditOverlay(
|
child: HudEditOverlay(
|
||||||
metricBuilder: (context, metric) => _HudMetricValue(
|
metricBuilder: (context, metric) => _HudMetricValue(
|
||||||
metric: metric,
|
metric: metric,
|
||||||
@@ -237,6 +250,7 @@ class _RecordScreenState extends ConsumerState<RecordScreen> {
|
|||||||
height: _controlBarHeight(mountedMode),
|
height: _controlBarHeight(mountedMode),
|
||||||
child: _ControlBar(
|
child: _ControlBar(
|
||||||
ui: ui,
|
ui: ui,
|
||||||
|
mountedMode: mountedMode,
|
||||||
onStart: () => _guard(engine.start),
|
onStart: () => _guard(engine.start),
|
||||||
onPause: () => _guard(engine.pause),
|
onPause: () => _guard(engine.pause),
|
||||||
onStop: () => _guard(() async => engine.stop()),
|
onStop: () => _guard(() async => engine.stop()),
|
||||||
@@ -379,6 +393,7 @@ class _ControlBar extends StatelessWidget {
|
|||||||
required this.onPause,
|
required this.onPause,
|
||||||
required this.onStop,
|
required this.onStop,
|
||||||
required this.onDiscard,
|
required this.onDiscard,
|
||||||
|
this.mountedMode = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
final RecordUiState ui;
|
final RecordUiState ui;
|
||||||
@@ -387,6 +402,11 @@ class _ControlBar extends StatelessWidget {
|
|||||||
final VoidCallback onStop;
|
final VoidCallback onStop;
|
||||||
final VoidCallback onDiscard;
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (ui.isIdle) {
|
if (ui.isIdle) {
|
||||||
@@ -397,6 +417,7 @@ class _ControlBar extends StatelessWidget {
|
|||||||
background: Theme.of(context).colorScheme.tertiaryContainer,
|
background: Theme.of(context).colorScheme.tertiaryContainer,
|
||||||
foreground: Theme.of(context).colorScheme.onTertiaryContainer,
|
foreground: Theme.of(context).colorScheme.onTertiaryContainer,
|
||||||
onTap: onStart,
|
onTap: onStart,
|
||||||
|
mountedMode: mountedMode,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,6 +433,7 @@ class _ControlBar extends StatelessWidget {
|
|||||||
foreground: colors.onTertiaryContainer,
|
foreground: colors.onTertiaryContainer,
|
||||||
onTap: onPause,
|
onTap: onPause,
|
||||||
trailingBorder: true,
|
trailingBorder: true,
|
||||||
|
mountedMode: mountedMode,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
@@ -421,6 +443,7 @@ class _ControlBar extends StatelessWidget {
|
|||||||
background: colors.errorContainer,
|
background: colors.errorContainer,
|
||||||
foreground: colors.onErrorContainer,
|
foreground: colors.onErrorContainer,
|
||||||
onTap: onStop,
|
onTap: onStop,
|
||||||
|
mountedMode: mountedMode,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -441,6 +464,7 @@ class _ControlBar extends StatelessWidget {
|
|||||||
foreground: colors.onTertiaryContainer,
|
foreground: colors.onTertiaryContainer,
|
||||||
onTap: onStart,
|
onTap: onStart,
|
||||||
trailingBorder: true,
|
trailingBorder: true,
|
||||||
|
mountedMode: mountedMode,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
@@ -451,6 +475,7 @@ class _ControlBar extends StatelessWidget {
|
|||||||
foreground: colors.onErrorContainer,
|
foreground: colors.onErrorContainer,
|
||||||
onTap: onStop,
|
onTap: onStop,
|
||||||
trailingBorder: true,
|
trailingBorder: true,
|
||||||
|
mountedMode: mountedMode,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
@@ -460,6 +485,7 @@ class _ControlBar extends StatelessWidget {
|
|||||||
background: colors.surfaceContainerHighest,
|
background: colors.surfaceContainerHighest,
|
||||||
foreground: colors.error,
|
foreground: colors.error,
|
||||||
onTap: onDiscard,
|
onTap: onDiscard,
|
||||||
|
mountedMode: mountedMode,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -476,6 +502,7 @@ class _Segment extends StatelessWidget {
|
|||||||
required this.onTap,
|
required this.onTap,
|
||||||
this.label,
|
this.label,
|
||||||
this.trailingBorder = false,
|
this.trailingBorder = false,
|
||||||
|
this.mountedMode = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String keyName;
|
final String keyName;
|
||||||
@@ -485,6 +512,9 @@ class _Segment extends StatelessWidget {
|
|||||||
final VoidCallback onTap;
|
final VoidCallback onTap;
|
||||||
final String? label;
|
final String? label;
|
||||||
final bool trailingBorder;
|
final bool trailingBorder;
|
||||||
|
final bool mountedMode;
|
||||||
|
|
||||||
|
double get _iconSize => mountedMode ? 32 : 24;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Material(
|
Widget build(BuildContext context) => Material(
|
||||||
@@ -505,18 +535,18 @@ class _Segment extends StatelessWidget {
|
|||||||
child: SizedBox.expand(
|
child: SizedBox.expand(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: label == null
|
child: label == null
|
||||||
? Icon(icon, color: foreground, size: 32)
|
? Icon(icon, color: foreground, size: _iconSize)
|
||||||
: Row(
|
: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Icon(icon, color: foreground),
|
Icon(icon, color: foreground, size: _iconSize),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
label!,
|
label!,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: foreground,
|
color: foreground,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 16,
|
fontSize: mountedMode ? 16 : 14,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user