From 58a523aab20c7dc60edd0b822f08ec076083f4b6 Mon Sep 17 00:00:00 2001 From: Mikkeli Matlock Date: Sun, 8 Feb 2026 03:06:52 +0900 Subject: [PATCH] ui: gps compass widget layout changes - angular direction (0-359) + 16ths compassrose - documented in ui README --- pi/ui/lib/README.md | 1 + pi/ui/lib/widgets/gps_compass.dart | 28 +++++++++++++++++++--------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/pi/ui/lib/README.md b/pi/ui/lib/README.md index 598ccdc..034f33f 100644 --- a/pi/ui/lib/README.md +++ b/pi/ui/lib/README.md @@ -34,6 +34,7 @@ All services use singleton pattern with `ServiceName.instance`. |--------|---------| | `NavigatorWidget` | Animated character with emotion states (images precached at startup) | | `AccelGraph` | Real-time accelerometer visualization with gravity compensation | +| `GpsCompass` | GPS heading compass with rotating navigation icon and degree readout | | `WhiskeyMark` | Gimbal-style horizon indicator using IMU roll/pitch | | `SystemBar` | Top status bar (time, connection, Pi temp) | | `StatBox` | Reusable metric display box | diff --git a/pi/ui/lib/widgets/gps_compass.dart b/pi/ui/lib/widgets/gps_compass.dart index 32d9945..baa83d4 100644 --- a/pi/ui/lib/widgets/gps_compass.dart +++ b/pi/ui/lib/widgets/gps_compass.dart @@ -7,11 +7,21 @@ class GpsCompass extends StatelessWidget { const GpsCompass({super.key, this.heading}); - bool get _hasSignal => heading != null && !heading!.isNaN && heading! >= 0 && heading! < 360; + bool get _hasSignal => heading != null; String get _displayHeading { - if (!_hasSignal) return '—-'; // Intentional double dash - return '${heading!.round()}°'; + if (!_hasSignal) return 'N/A'; // Just make it clear; redundant anyways, this only gets called when _hasSignal + return '${(heading! % 360).round()}'; // No need for the degree symbol + } + + String get _compassDirection { + if (!_hasSignal) return ''; + final directions = [ + 'N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', + 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW' + ]; + final index = ((heading! % 360) / 22.5).round() % 16; + return directions[index]; } @override @@ -19,7 +29,7 @@ class GpsCompass extends StatelessWidget { final theme = AppTheme.of(context); // No signal = subdued color, valid = foreground - final color = _hasSignal ? theme.foreground : theme.subdued; + final iconColour = _hasSignal ? theme.foreground : theme.highlight; // Convert to radians, 0 = no rotation when no signal final angle = _hasSignal ? (heading! * math.pi / 180.0) : 0.0; @@ -35,8 +45,8 @@ class GpsCompass extends StatelessWidget { fit: BoxFit.contain, child: Icon( _hasSignal ? Icons.navigation : Icons.navigation_outlined, - size: 80, - color: color, + size: 120, + color: iconColour, ), ), ), @@ -46,10 +56,10 @@ class GpsCompass extends StatelessWidget { child: FittedBox( fit: BoxFit.contain, child: Text( - _displayHeading, + _hasSignal ? "${_displayHeading} ${_compassDirection}" : "N/A", style: TextStyle( - fontSize: 60, - color: color, + fontSize: 80, + color: theme.subdued, fontFamily: 'DIN1451', ), ),