import 'package:flutter/material.dart'; import 'package:google_navigation_flutter/google_navigation_flutter.dart'; import '../models/delivery.dart'; import '../theme/color_system.dart'; /// Enhanced dark-mode aware map component with custom styling class DarkModeMapComponent extends StatefulWidget { final List deliveries; final Delivery? selectedDelivery; final ValueChanged? onDeliverySelected; const DarkModeMapComponent({ super.key, required this.deliveries, this.selectedDelivery, this.onDeliverySelected, }); @override State createState() => _DarkModeMapComponentState(); } class _DarkModeMapComponentState extends State { GoogleNavigationViewController? _navigationController; bool _isNavigating = false; LatLng? _destinationLocation; @override void initState() { super.initState(); _initializeNavigation(); } Future _initializeNavigation() async { try { final termsAccepted = await GoogleMapsNavigator.areTermsAccepted(); if (!termsAccepted) { await GoogleMapsNavigator.showTermsAndConditionsDialog( 'Plan B Logistics', 'com.goutezplanb.planbLogistic', ); } await GoogleMapsNavigator.initializeNavigationSession(); } catch (e) { debugPrint('Map initialization error: $e'); } } @override void didUpdateWidget(DarkModeMapComponent oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.selectedDelivery != widget.selectedDelivery) { _updateDestination(); } } void _updateDestination() { if (widget.selectedDelivery != null) { final address = widget.selectedDelivery!.deliveryAddress; if (address?.latitude != null && address?.longitude != null) { setState(() { _destinationLocation = LatLng( latitude: address!.latitude!, longitude: address.longitude!, ); }); _navigateToLocation(_destinationLocation!); } } } Future _navigateToLocation(LatLng location) async { if (_navigationController == null) return; try { await _navigationController!.animateCamera( CameraUpdate.newLatLngZoom(location, 15), ); } catch (e) { debugPrint('Camera navigation error: $e'); } } Future _applyDarkModeStyle() async { if (_navigationController == null) return; try { // Apply dark mode style configuration for Google Maps // This reduces eye strain in low-light environments final isDarkMode = Theme.of(context).brightness == Brightness.dark; if (isDarkMode) { // Dark map style with warm accent colors await _navigationController!.setMapStyle(_getDarkMapStyle()); } } catch (e) { debugPrint('Error applying map style: $e'); } } String _getDarkMapStyle() { // Google Maps style JSON for dark mode with warm accents return '''[ { "elementType": "geometry", "stylers": [{"color": "#212121"}] }, { "elementType": "labels.icon", "stylers": [{"visibility": "off"}] }, { "elementType": "labels.text.fill", "stylers": [{"color": "#757575"}] }, { "elementType": "labels.text.stroke", "stylers": [{"color": "#212121"}] }, { "featureType": "administrative", "elementType": "geometry", "stylers": [{"color": "#757575"}] }, { "featureType": "administrative.country", "elementType": "labels.text.fill", "stylers": [{"color": "#9e9e9e"}] }, { "featureType": "administrative.land_parcel", "stylers": [{"visibility": "off"}] }, { "featureType": "administrative.locality", "elementType": "labels.text.fill", "stylers": [{"color": "#bdbdbd"}] }, { "featureType": "administrative.neighborhood", "stylers": [{"visibility": "off"}] }, { "featureType": "administrative.province", "elementType": "labels.text.fill", "stylers": [{"color": "#9e9e9e"}] }, { "featureType": "landscape", "elementType": "geometry", "stylers": [{"color": "#000000"}] }, { "featureType": "poi", "elementType": "geometry", "stylers": [{"color": "#383838"}] }, { "featureType": "poi", "elementType": "labels.text.fill", "stylers": [{"color": "#9e9e9e"}] }, { "featureType": "poi.park", "elementType": "geometry", "stylers": [{"color": "#181818"}] }, { "featureType": "poi.park", "elementType": "labels.text.fill", "stylers": [{"color": "#616161"}] }, { "featureType": "road", "elementType": "geometry.fill", "stylers": [{"color": "#2c2c2c"}] }, { "featureType": "road", "elementType": "labels.text.fill", "stylers": [{"color": "#8a8a8a"}] }, { "featureType": "road.arterial", "elementType": "geometry", "stylers": [{"color": "#373737"}] }, { "featureType": "road.highway", "elementType": "geometry", "stylers": [{"color": "#3c3c3c"}] }, { "featureType": "road.highway.controlled_access", "elementType": "geometry", "stylers": [{"color": "#4e4e4e"}] }, { "featureType": "road.local", "elementType": "labels.text.fill", "stylers": [{"color": "#616161"}] }, { "featureType": "transit", "elementType": "labels.text.fill", "stylers": [{"color": "#757575"}] }, { "featureType": "water", "elementType": "geometry", "stylers": [{"color": "#0c1221"}] }, { "featureType": "water", "elementType": "labels.text.fill", "stylers": [{"color": "#3d3d3d"}] } ]'''; } Future _startNavigation() async { if (_destinationLocation == null) return; try { final waypoint = NavigationWaypoint.withLatLngTarget( title: widget.selectedDelivery?.name ?? 'Destination', target: _destinationLocation!, ); final destinations = Destinations( waypoints: [waypoint], displayOptions: NavigationDisplayOptions(showDestinationMarkers: true), ); await GoogleMapsNavigator.setDestinations(destinations); await GoogleMapsNavigator.startGuidance(); setState(() { _isNavigating = true; }); } catch (e) { debugPrint('Navigation start error: $e'); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Navigation error: $e')), ); } } } Future _stopNavigation() async { try { await GoogleMapsNavigator.stopGuidance(); await GoogleMapsNavigator.clearDestinations(); setState(() { _isNavigating = false; }); } catch (e) { debugPrint('Navigation stop error: $e'); } } @override Widget build(BuildContext context) { final initialPosition = widget.selectedDelivery?.deliveryAddress != null && widget.selectedDelivery!.deliveryAddress!.latitude != null && widget.selectedDelivery!.deliveryAddress!.longitude != null ? LatLng( latitude: widget.selectedDelivery!.deliveryAddress!.latitude!, longitude: widget.selectedDelivery!.deliveryAddress!.longitude!, ) : const LatLng(latitude: 45.5017, longitude: -73.5673); return Stack( children: [ GoogleMapsNavigationView( onViewCreated: (controller) { _navigationController = controller; _applyDarkModeStyle(); controller.animateCamera( CameraUpdate.newLatLngZoom(initialPosition, 12), ); }, initialCameraPosition: CameraPosition( target: initialPosition, zoom: 12, ), ), // Custom dark-themed controls overlay Positioned( bottom: 16, right: 16, child: Column( mainAxisSize: MainAxisSize.min, children: [ // Start navigation button if (widget.selectedDelivery != null && !_isNavigating) _buildActionButton( label: 'Navigate', icon: Icons.directions, onPressed: _startNavigation, color: SvrntyColors.crimsonRed, ), if (_isNavigating) _buildActionButton( label: 'Stop', icon: Icons.stop, onPressed: _stopNavigation, color: Colors.grey[600]!, ), ], ), ), // Selected delivery info panel (dark themed) if (widget.selectedDelivery != null) Positioned( top: 0, left: 0, right: 0, child: Container( decoration: BoxDecoration( color: Theme.of(context).brightness == Brightness.dark ? const Color(0xFF14161A) : Colors.white, boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.2), blurRadius: 8, offset: const Offset(0, 2), ), ], ), padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 12, ), child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( widget.selectedDelivery!.name, style: Theme.of(context) .textTheme .titleMedium ?.copyWith(fontWeight: FontWeight.w600), maxLines: 1, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 4), Text( widget.selectedDelivery!.deliveryAddress ?.formattedAddress ?? 'No address', style: Theme.of(context) .textTheme .bodySmall ?.copyWith( color: Theme.of(context).brightness == Brightness.dark ? Colors.grey[400] : Colors.grey[600], ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ], ), ), const SizedBox(width: 8), // Status indicator Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 4, ), decoration: BoxDecoration( color: widget.selectedDelivery!.delivered ? SvrntyColors.statusCompleted : SvrntyColors.statusPending, borderRadius: BorderRadius.circular(4), ), child: Text( widget.selectedDelivery!.delivered ? 'Delivered' : 'Pending', style: Theme.of(context) .textTheme .labelSmall ?.copyWith( color: Colors.white, fontWeight: FontWeight.w600, ), ), ), ], ), ), ), ], ); } Widget _buildActionButton({ required String label, required IconData icon, required VoidCallback onPressed, required Color color, }) { return Container( margin: const EdgeInsets.only(bottom: 8), decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.3), blurRadius: 4, offset: const Offset(0, 2), ), ], ), child: Material( color: color, borderRadius: BorderRadius.circular(8), child: InkWell( onTap: onPressed, borderRadius: BorderRadius.circular(8), child: Padding( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 8, ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon( icon, color: Colors.white, size: 18, ), const SizedBox(width: 6), Text( label, style: const TextStyle( color: Colors.white, fontWeight: FontWeight.w500, fontSize: 14, ), ), ], ), ), ), ), ); } }