import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../../core/theme/theme_extensions.dart'; import '../../../services/navigation/navigation_session_service.dart'; /// High-contrast, glanceable turn-by-turn navigation HUD card mounted on the Dashboard. /// /// Disappears when navigation is inactive. When active, displays high-visibility /// maneuver direction, next road, countdown distance in feet/miles, ETA, and /// quick mute/end controls. class NavigationManeuverCard extends ConsumerWidget { const NavigationManeuverCard({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final navState = ref.watch(navigationSessionProvider); if (!navState.isNavigating || navState.currentManeuver == null) { return const SizedBox.shrink(); } final currentManeuver = navState.currentManeuver!; final nextManeuver = navState.nextManeuver; final colors = context.motorColors; return Semantics( label: 'Navigation: ${currentManeuver.instruction}. ${navState.formattedDistanceToNext} to turn. Remaining: ${navState.formattedRemainingDistance}, ETA ${navState.formattedEta}.', child: Card( key: const ValueKey('navigation_maneuver_card'), margin: const EdgeInsets.only(bottom: 12), elevation: 6, color: const Color(0xFF0F172A), // Dark tactical navy/slate for extreme contrast shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), side: BorderSide( color: colors.cyberCyan.withValues(alpha: 0.6), width: 1.5, ), ), child: InkWell( borderRadius: BorderRadius.circular(16), onTap: () { // Tap navigates to live map context.go('/map'); }, child: Padding( padding: const EdgeInsets.all(14), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ // Top Row: Big Turn Icon, Distance, Street & Voice/Exit controls Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ // High-contrast Turn Direction Icon Badge Container( width: 52, height: 52, decoration: BoxDecoration( color: colors.cyberCyan.withValues(alpha: 0.18), borderRadius: BorderRadius.circular(12), border: Border.all( color: colors.cyberCyan, width: 1.8, ), ), alignment: Alignment.center, child: Icon( currentManeuver.type.icon, size: 32, color: colors.cyberCyan, ), ), const SizedBox(width: 14), // Maneuver Distance and Street Name Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ FittedBox( fit: BoxFit.scaleDown, alignment: Alignment.centerLeft, child: Row( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( navState.formattedDistanceToNext, style: const TextStyle( fontFamily: 'JetBrains Mono', fontSize: 22, fontWeight: FontWeight.w900, color: Colors.white, letterSpacing: -0.5, ), ), const SizedBox(width: 8), Container( padding: const EdgeInsets.symmetric( horizontal: 6, vertical: 2, ), decoration: BoxDecoration( color: colors.cyberCyan.withValues(alpha: 0.2), borderRadius: BorderRadius.circular(4), ), child: Text( currentManeuver.type.directionShort, style: TextStyle( fontFamily: 'JetBrains Mono', fontSize: 10, fontWeight: FontWeight.w800, color: colors.cyberCyan, letterSpacing: 0.8, ), ), ), ], ), ), const SizedBox(height: 2), Text( currentManeuver.streetName ?? currentManeuver.instruction, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle( fontFamily: 'Inter', fontSize: 15, fontWeight: FontWeight.bold, color: Colors.white, ), ), ], ), ), // Quick Audio Mute & End Navigation Buttons IconButton( key: const ValueKey('nav_toggle_tts_button'), constraints: const BoxConstraints(minWidth: 36, minHeight: 36), padding: EdgeInsets.zero, icon: Icon( navState.ttsEnabled ? Icons.volume_up : Icons.volume_off, color: navState.ttsEnabled ? colors.cyberCyan : Colors.white54, size: 22, ), tooltip: navState.ttsEnabled ? 'Mute Voice Guidance' : 'Unmute Voice Guidance', onPressed: () { ref.read(navigationSessionProvider.notifier).toggleTts(); }, ), IconButton( key: const ValueKey('nav_stop_button'), constraints: const BoxConstraints(minWidth: 36, minHeight: 36), padding: EdgeInsets.zero, icon: const Icon(Icons.close, color: Colors.white70, size: 22), tooltip: 'Exit Navigation', onPressed: () { ref.read(navigationSessionProvider.notifier).stopNavigation(); }, ), ], ), const SizedBox(height: 10), Divider( height: 1, color: colors.outlineVariant.withValues(alpha: 0.4), ), const SizedBox(height: 8), Wrap( spacing: 12, runSpacing: 4, crossAxisAlignment: WrapCrossAlignment.center, alignment: WrapAlignment.spaceBetween, children: [ Wrap( spacing: 8, runSpacing: 2, crossAxisAlignment: WrapCrossAlignment.center, children: [ Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.schedule, size: 14, color: colors.cyberCyan), const SizedBox(width: 4), Text( '${navState.formattedDurationRemaining} (${navState.formattedEta})', style: TextStyle( fontFamily: 'JetBrains Mono', fontSize: 11, fontWeight: FontWeight.bold, color: colors.cyberCyan, ), ), ], ), Row( mainAxisSize: MainAxisSize.min, children: [ const Icon(Icons.route, size: 14, color: Colors.white70), const SizedBox(width: 4), Text( navState.formattedRemainingDistance, style: const TextStyle( fontFamily: 'JetBrains Mono', fontSize: 11, fontWeight: FontWeight.w600, color: Colors.white70, ), ), ], ), ], ), if (nextManeuver != null) Row( mainAxisSize: MainAxisSize.min, children: [ const Text( 'Then', style: TextStyle( fontSize: 10.5, color: Colors.white54, fontFamily: 'Inter', ), ), const SizedBox(width: 4), Icon( nextManeuver.type.icon, size: 14, color: colors.cyberCyan, ), ], ), ], ), ], ), ), ), ), ); } }