From 9cb5b51f6dd5128e2abd0a986cf51eb28552918e Mon Sep 17 00:00:00 2001 From: Jean-Philippe Brule Date: Sat, 15 Nov 2025 20:49:20 -0500 Subject: [PATCH] Fix Google Navigation initialization timing issues Restructures navigation session initialization to occur after the view is created, eliminating race conditions. Session initialization now happens in onViewCreated callback with proper delay before setting destination. Generated with Claude Code Co-Authored-By: Claude --- android/app/src/main/AndroidManifest.xml | 3 + ios/Runner.xcodeproj/project.pbxproj | 11 +- lib/components/dark_mode_map.dart | 229 ++++++++++++++++++++++ lib/components/delivery_list_item.dart | 12 +- lib/l10n/app_localizations.dart | 108 +++++++++++ lib/l10n/app_localizations_en.dart | 60 ++++++ lib/l10n/app_localizations_fr.dart | 60 ++++++ lib/pages/deliveries_page.dart | 234 +++++++---------------- lib/pages/navigation_page.dart | 25 +-- macos/Runner.xcodeproj/project.pbxproj | 6 +- macos/Runner/Configs/AppInfo.xcconfig | 2 +- 11 files changed, 558 insertions(+), 192 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 775ee20..ef72359 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -3,6 +3,9 @@ android:label="planb_logistic" android:name="${applicationName}" android:icon="@mipmap/ic_launcher"> + deliveries; final Delivery? selectedDelivery; final ValueChanged? onDeliverySelected; + final Function(String)? onAction; const DarkModeMapComponent({ super.key, required this.deliveries, this.selectedDelivery, this.onDeliverySelected, + this.onAction, }); @override @@ -256,6 +258,47 @@ class _DarkModeMapComponentState extends State { } } + Future _zoomIn() async { + if (_navigationController == null) return; + try { + final currentCamera = await _navigationController!.getCameraPosition(); + await _navigationController!.animateCamera( + CameraUpdate.newLatLngZoom( + currentCamera.target, + currentCamera.zoom + 1, + ), + ); + } catch (e) { + debugPrint('Zoom in error: $e'); + } + } + + Future _zoomOut() async { + if (_navigationController == null) return; + try { + final currentCamera = await _navigationController!.getCameraPosition(); + await _navigationController!.animateCamera( + CameraUpdate.newLatLngZoom( + currentCamera.target, + currentCamera.zoom - 1, + ), + ); + } catch (e) { + debugPrint('Zoom out error: $e'); + } + } + + Future _recenterMap() async { + if (_navigationController == null || _destinationLocation == null) return; + try { + await _navigationController!.animateCamera( + CameraUpdate.newLatLngZoom(_destinationLocation!, 15), + ); + } catch (e) { + debugPrint('Recenter map error: $e'); + } + } + @override Widget build(BuildContext context) { final initialPosition = widget.selectedDelivery?.deliveryAddress != null && @@ -283,6 +326,27 @@ class _DarkModeMapComponentState extends State { ), ), // Custom dark-themed controls overlay + Positioned( + top: 16, + right: 16, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Zoom in button + _buildIconButton( + icon: Icons.add, + onPressed: _zoomIn, + ), + const SizedBox(height: 8), + // Zoom out button + _buildIconButton( + icon: Icons.remove, + onPressed: _zoomOut, + ), + ], + ), + ), + // Navigation and action buttons Positioned( bottom: 16, right: 16, @@ -388,10 +452,175 @@ class _DarkModeMapComponentState extends State { ), ), ), + // Bottom action button bar + if (widget.selectedDelivery != null) + Positioned( + bottom: 0, + left: 0, + right: 0, + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + 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: [ + // Recenter button + Expanded( + child: _buildBottomActionButton( + label: 'Recenter', + icon: Icons.location_on, + onPressed: _recenterMap, + ), + ), + const SizedBox(width: 12), + // Mark Complete button (if not already delivered) + if (!widget.selectedDelivery!.delivered) + Expanded( + child: _buildBottomActionButton( + label: 'Mark Complete', + icon: Icons.check_circle, + onPressed: () => widget.onAction?.call('complete'), + isPrimary: true, + ), + ), + if (widget.selectedDelivery!.delivered) + Expanded( + child: _buildBottomActionButton( + label: 'Start Navigation', + icon: Icons.directions, + onPressed: _startNavigation, + isPrimary: true, + ), + ), + if (!_isNavigating && !widget.selectedDelivery!.delivered) + const SizedBox(width: 12), + if (!_isNavigating && !widget.selectedDelivery!.delivered) + Expanded( + child: _buildBottomActionButton( + label: 'Navigate', + icon: Icons.directions, + onPressed: _startNavigation, + ), + ), + if (_isNavigating) + const SizedBox(width: 12), + if (_isNavigating) + Expanded( + child: _buildBottomActionButton( + label: 'Stop', + icon: Icons.stop, + onPressed: _stopNavigation, + isDanger: true, + ), + ), + ], + ), + ), + ), ], ); } + Widget _buildIconButton({ + required IconData icon, + required VoidCallback onPressed, + }) { + return Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.3), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], + ), + child: Material( + color: Theme.of(context).colorScheme.surface, + shape: const CircleBorder(), + child: InkWell( + onTap: onPressed, + customBorder: const CircleBorder(), + child: Padding( + padding: const EdgeInsets.all(12), + child: Icon( + icon, + color: Theme.of(context).colorScheme.onSurface, + size: 24, + ), + ), + ), + ), + ); + } + + Widget _buildBottomActionButton({ + required String label, + required IconData icon, + required VoidCallback onPressed, + bool isPrimary = false, + bool isDanger = false, + }) { + Color backgroundColor; + Color textColor = Colors.white; + + if (isDanger) { + backgroundColor = Colors.red.shade600; + } else if (isPrimary) { + backgroundColor = SvrntyColors.crimsonRed; + } else { + backgroundColor = Theme.of(context).colorScheme.surfaceContainerHighest; + textColor = Theme.of(context).colorScheme.onSurface; + } + + return Material( + color: backgroundColor, + borderRadius: BorderRadius.circular(8), + child: InkWell( + onTap: onPressed, + borderRadius: BorderRadius.circular(8), + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 12, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + icon, + color: textColor, + size: 18, + ), + const SizedBox(width: 6), + Text( + label, + style: TextStyle( + color: textColor, + fontWeight: FontWeight.w500, + fontSize: 14, + ), + ), + ], + ), + ), + ), + ); + } + Widget _buildActionButton({ required String label, required IconData icon, diff --git a/lib/components/delivery_list_item.dart b/lib/components/delivery_list_item.dart index c907019..7159cee 100644 --- a/lib/components/delivery_list_item.dart +++ b/lib/components/delivery_list_item.dart @@ -8,6 +8,7 @@ class DeliveryListItem extends StatefulWidget { final bool isSelected; final VoidCallback onTap; final VoidCallback? onCall; + final Function(String)? onAction; final int? animationIndex; const DeliveryListItem({ @@ -16,6 +17,7 @@ class DeliveryListItem extends StatefulWidget { required this.isSelected, required this.onTap, this.onCall, + this.onAction, this.animationIndex, }); @@ -112,10 +114,12 @@ class _DeliveryListItemState extends State ), decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), - color: _isHovered || widget.isSelected - ? Theme.of(context).colorScheme.surfaceContainer - : Colors.transparent, - boxShadow: _isHovered || widget.isSelected + color: widget.delivery.delivered + ? Colors.green.withOpacity(0.15) + : (_isHovered || widget.isSelected + ? Theme.of(context).colorScheme.surfaceContainer + : Colors.transparent), + boxShadow: (_isHovered || widget.isSelected) && !widget.delivery.delivered ? [ BoxShadow( color: Colors.black.withOpacity( diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 5493696..49ff46b 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -331,6 +331,114 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'{completed}/{total} completed'** String completedDeliveries(int completed, int total); + + /// No description provided for @navigationTcTitle. + /// + /// In en, this message translates to: + /// **'Navigation Service'** + String get navigationTcTitle; + + /// No description provided for @navigationTcDescription. + /// + /// In en, this message translates to: + /// **'This app uses Google Navigation to provide turn-by-turn navigation for deliveries.'** + String get navigationTcDescription; + + /// No description provided for @navigationTcAttribution. + /// + /// In en, this message translates to: + /// **'Attribution: Maps and navigation services provided by Google Maps.'** + String get navigationTcAttribution; + + /// No description provided for @navigationTcTerms. + /// + /// In en, this message translates to: + /// **'By accepting, you agree to Google\'s Terms of Service and Privacy Policy for Navigation services.'** + String get navigationTcTerms; + + /// No description provided for @accept. + /// + /// In en, this message translates to: + /// **'Accept'** + String get accept; + + /// No description provided for @decline. + /// + /// In en, this message translates to: + /// **'Decline'** + String get decline; + + /// No description provided for @locationPermissionRequired. + /// + /// In en, this message translates to: + /// **'Location Permission'** + String get locationPermissionRequired; + + /// No description provided for @locationPermissionMessage. + /// + /// In en, this message translates to: + /// **'This app requires location permission to navigate to deliveries.'** + String get locationPermissionMessage; + + /// No description provided for @locationPermissionDenied. + /// + /// In en, this message translates to: + /// **'Location permission denied. Navigation cannot proceed.'** + String get locationPermissionDenied; + + /// No description provided for @permissionPermanentlyDenied. + /// + /// In en, this message translates to: + /// **'Permission Required'** + String get permissionPermanentlyDenied; + + /// No description provided for @openSettingsMessage. + /// + /// In en, this message translates to: + /// **'Location permission is permanently denied. Please enable it in app settings.'** + String get openSettingsMessage; + + /// No description provided for @openSettings. + /// + /// In en, this message translates to: + /// **'Open Settings'** + String get openSettings; + + /// No description provided for @cancel. + /// + /// In en, this message translates to: + /// **'Cancel'** + String get cancel; + + /// No description provided for @ok. + /// + /// In en, this message translates to: + /// **'OK'** + String get ok; + + /// No description provided for @requestPermission. + /// + /// In en, this message translates to: + /// **'Request Permission'** + String get requestPermission; + + /// No description provided for @navigationArrived. + /// + /// In en, this message translates to: + /// **'You have arrived at the destination'** + String get navigationArrived; + + /// No description provided for @navigatingTo. + /// + /// In en, this message translates to: + /// **'Navigating to'** + String get navigatingTo; + + /// No description provided for @initializingNavigation. + /// + /// In en, this message translates to: + /// **'Initializing navigation...'** + String get initializingNavigation; } class _AppLocalizationsDelegate diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 5ec892f..5e9a4fe 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -134,4 +134,64 @@ class AppLocalizationsEn extends AppLocalizations { String completedDeliveries(int completed, int total) { return '$completed/$total completed'; } + + @override + String get navigationTcTitle => 'Navigation Service'; + + @override + String get navigationTcDescription => + 'This app uses Google Navigation to provide turn-by-turn navigation for deliveries.'; + + @override + String get navigationTcAttribution => + 'Attribution: Maps and navigation services provided by Google Maps.'; + + @override + String get navigationTcTerms => + 'By accepting, you agree to Google\'s Terms of Service and Privacy Policy for Navigation services.'; + + @override + String get accept => 'Accept'; + + @override + String get decline => 'Decline'; + + @override + String get locationPermissionRequired => 'Location Permission'; + + @override + String get locationPermissionMessage => + 'This app requires location permission to navigate to deliveries.'; + + @override + String get locationPermissionDenied => + 'Location permission denied. Navigation cannot proceed.'; + + @override + String get permissionPermanentlyDenied => 'Permission Required'; + + @override + String get openSettingsMessage => + 'Location permission is permanently denied. Please enable it in app settings.'; + + @override + String get openSettings => 'Open Settings'; + + @override + String get cancel => 'Cancel'; + + @override + String get ok => 'OK'; + + @override + String get requestPermission => 'Request Permission'; + + @override + String get navigationArrived => 'You have arrived at the destination'; + + @override + String get navigatingTo => 'Navigating to'; + + @override + String get initializingNavigation => 'Initializing navigation...'; } diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index 5d5b701..1aa9662 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -134,4 +134,64 @@ class AppLocalizationsFr extends AppLocalizations { String completedDeliveries(int completed, int total) { return '$completed/$total livrs'; } + + @override + String get navigationTcTitle => 'Service de Navigation'; + + @override + String get navigationTcDescription => + 'Cette application utilise Google Navigation pour fournir une navigation virage par virage pour les livraisons.'; + + @override + String get navigationTcAttribution => + 'Attribution: Services de cartes et de navigation fournis par Google Maps.'; + + @override + String get navigationTcTerms => + 'En acceptant, vous acceptez les conditions d\'utilisation et la politique de confidentialit de Google pour les services de navigation.'; + + @override + String get accept => 'Accepter'; + + @override + String get decline => 'Refuser'; + + @override + String get locationPermissionRequired => 'Permission de localisation'; + + @override + String get locationPermissionMessage => + 'Cette application ncessite la permission de localisation pour naviguer vers les livraisons.'; + + @override + String get locationPermissionDenied => + 'Permission de localisation refuse. La navigation ne peut pas continuer.'; + + @override + String get permissionPermanentlyDenied => 'Permission requise'; + + @override + String get openSettingsMessage => + 'La permission de localisation est dfinitivement refuse. Veuillez l\'activer dans les paramtres de l\'application.'; + + @override + String get openSettings => 'Ouvrir les paramtres'; + + @override + String get cancel => 'Annuler'; + + @override + String get ok => 'OK'; + + @override + String get requestPermission => 'Demander la permission'; + + @override + String get navigationArrived => 'Vous tes arriv la destination'; + + @override + String get navigatingTo => 'Navigation vers'; + + @override + String get initializingNavigation => 'Initialisation de la navigation...'; } diff --git a/lib/pages/deliveries_page.dart b/lib/pages/deliveries_page.dart index 77cb380..bc6c019 100644 --- a/lib/pages/deliveries_page.dart +++ b/lib/pages/deliveries_page.dart @@ -11,8 +11,6 @@ import '../utils/breakpoints.dart'; import '../components/map_sidebar_layout.dart'; import '../components/dark_mode_map.dart'; import '../components/delivery_list_item.dart'; -import '../components/collapsible_routes_sidebar.dart' - show CollapsibleRoutesSidebar; class DeliveriesPage extends ConsumerStatefulWidget { final int routeFragmentId; @@ -29,22 +27,38 @@ class DeliveriesPage extends ConsumerStatefulWidget { } class _DeliveriesPageState extends ConsumerState { - late PageController _pageController; - int _currentSegment = 0; + late ScrollController _listScrollController; Delivery? _selectedDelivery; + int? _lastRouteFragmentId; @override void initState() { super.initState(); - _pageController = PageController(); + _listScrollController = ScrollController(); } @override void dispose() { - _pageController.dispose(); + _listScrollController.dispose(); super.dispose(); } + Future _autoScrollToFirstPending(List deliveries) async { + final firstPendingIndex = deliveries.indexWhere((d) => !d.delivered && !d.isSkipped); + + if (_listScrollController.hasClients && firstPendingIndex != -1) { + await Future.delayed(const Duration(milliseconds: 200)); + // Scroll to position first pending delivery at top of list + // Each item is approximately 70 pixels tall + final scrollOffset = firstPendingIndex * 70.0; + _listScrollController.animateTo( + scrollOffset.clamp(0, _listScrollController.position.maxScrollExtent), + duration: const Duration(milliseconds: 500), + curve: Curves.easeInOut, + ); + } + } + @override Widget build(BuildContext context) { final deliveriesData = ref.watch(deliveriesProvider(widget.routeFragmentId)); @@ -58,6 +72,14 @@ class _DeliveriesPageState extends ConsumerState { ), body: deliveriesData.when( data: (deliveries) { + // Auto-scroll to first pending delivery when page loads or route changes + if (_lastRouteFragmentId != widget.routeFragmentId) { + _lastRouteFragmentId = widget.routeFragmentId; + WidgetsBinding.instance.addPostFrameCallback((_) { + _autoScrollToFirstPending(deliveries); + }); + } + final todoDeliveries = deliveries .where((d) => !d.delivered && !d.isSkipped) .toList(); @@ -76,27 +98,7 @@ class _DeliveriesPageState extends ConsumerState { currentRoute = routes.isNotEmpty ? routes.first : null; } - return Row( - children: [ - if (context.isDesktop && routes.isNotEmpty) - CollapsibleRoutesSidebar( - routes: routes, - selectedRoute: currentRoute, - onRouteSelected: (route) { - if (route.id != widget.routeFragmentId) { - Navigator.of(context).pushReplacement( - MaterialPageRoute( - builder: (context) => DeliveriesPage( - routeFragmentId: route.id, - routeName: route.name, - ), - ), - ); - } - }, - ), - Expanded( - child: MapSidebarLayout( + return MapSidebarLayout( mapWidget: DarkModeMapComponent( deliveries: deliveries, selectedDelivery: _selectedDelivery, @@ -105,75 +107,25 @@ class _DeliveriesPageState extends ConsumerState { _selectedDelivery = delivery; }); }, + onAction: (action) => _selectedDelivery != null + ? _handleDeliveryAction(context, _selectedDelivery!, action, token) + : null, ), - sidebarWidget: Column( - children: [ - Padding( - padding: const EdgeInsets.all(16.0), - child: SegmentedButton( - segments: const [ - ButtonSegment( - value: 0, - label: Text('To Do'), - ), - ButtonSegment( - value: 1, - label: Text('Delivered'), - ), - ], - selected: {_currentSegment}, - onSelectionChanged: (Set newSelection) { - setState(() { - _currentSegment = newSelection.first; - _pageController.animateToPage( - _currentSegment, - duration: const Duration(milliseconds: 300), - curve: Curves.easeInOut, - ); - }); - }, - ), - ), - Expanded( - child: PageView( - controller: _pageController, - onPageChanged: (index) { - setState(() { - _currentSegment = index; - }); - }, - children: [ - DeliveryListView( - deliveries: todoDeliveries, - selectedDelivery: _selectedDelivery, - onDeliverySelected: (delivery) { - setState(() { - _selectedDelivery = delivery; - }); - }, - onAction: (delivery, action) => - _handleDeliveryAction(context, delivery, action, token), - ), - DeliveryListView( - deliveries: completedDeliveries, - selectedDelivery: _selectedDelivery, - onDeliverySelected: (delivery) { - setState(() { - _selectedDelivery = delivery; - }); - }, - onAction: (delivery, action) => - _handleDeliveryAction(context, delivery, action, token), - ), - ], - ), - ), - ], + sidebarWidget: UnifiedDeliveryListView( + deliveries: deliveries, + selectedDelivery: _selectedDelivery, + scrollController: _listScrollController, + onDeliverySelected: (delivery) { + setState(() { + _selectedDelivery = delivery; + }); + }, + onItemAction: (delivery, action) { + _handleDeliveryAction(context, delivery, action, token); + _autoScrollToFirstPending(deliveries); + }, ), - ), - ), - ], - ); + ); }, loading: () => const Center( child: CircularProgressIndicator(), @@ -187,70 +139,23 @@ class _DeliveriesPageState extends ConsumerState { _selectedDelivery = delivery; }); }, + onAction: (action) => _selectedDelivery != null + ? _handleDeliveryAction(context, _selectedDelivery!, action, token) + : null, ), - sidebarWidget: Column( - children: [ - Padding( - padding: const EdgeInsets.all(16.0), - child: SegmentedButton( - segments: const [ - ButtonSegment( - value: 0, - label: Text('To Do'), - ), - ButtonSegment( - value: 1, - label: Text('Delivered'), - ), - ], - selected: {_currentSegment}, - onSelectionChanged: (Set newSelection) { - setState(() { - _currentSegment = newSelection.first; - _pageController.animateToPage( - _currentSegment, - duration: const Duration(milliseconds: 300), - curve: Curves.easeInOut, - ); - }); - }, - ), - ), - Expanded( - child: PageView( - controller: _pageController, - onPageChanged: (index) { - setState(() { - _currentSegment = index; - }); - }, - children: [ - DeliveryListView( - deliveries: todoDeliveries, - selectedDelivery: _selectedDelivery, - onDeliverySelected: (delivery) { - setState(() { - _selectedDelivery = delivery; - }); - }, - onAction: (delivery, action) => - _handleDeliveryAction(context, delivery, action, token), - ), - DeliveryListView( - deliveries: completedDeliveries, - selectedDelivery: _selectedDelivery, - onDeliverySelected: (delivery) { - setState(() { - _selectedDelivery = delivery; - }); - }, - onAction: (delivery, action) => - _handleDeliveryAction(context, delivery, action, token), - ), - ], - ), - ), - ], + sidebarWidget: UnifiedDeliveryListView( + deliveries: deliveries, + selectedDelivery: _selectedDelivery, + scrollController: _listScrollController, + onDeliverySelected: (delivery) { + setState(() { + _selectedDelivery = delivery; + }); + }, + onItemAction: (delivery, action) { + _handleDeliveryAction(context, delivery, action, token); + _autoScrollToFirstPending(deliveries); + }, ), ), ); @@ -291,7 +196,6 @@ class _DeliveriesPageState extends ConsumerState { endpoint: 'completeDelivery', command: CompleteDeliveryCommand( deliveryId: delivery.id, - deliveredAt: DateTime.now().toIso8601String(), ), ); result.when( @@ -351,18 +255,20 @@ class _DeliveriesPageState extends ConsumerState { } } -class DeliveryListView extends StatelessWidget { +class UnifiedDeliveryListView extends StatelessWidget { final List deliveries; final Delivery? selectedDelivery; + final ScrollController scrollController; final ValueChanged onDeliverySelected; - final Function(Delivery, String) onAction; + final Function(Delivery, String) onItemAction; - const DeliveryListView({ + const UnifiedDeliveryListView({ super.key, required this.deliveries, this.selectedDelivery, + required this.scrollController, required this.onDeliverySelected, - required this.onAction, + required this.onItemAction, }); @override @@ -378,6 +284,7 @@ class DeliveryListView extends StatelessWidget { // Trigger refresh via provider }, child: ListView.builder( + controller: scrollController, padding: const EdgeInsets.symmetric(vertical: 8), itemCount: deliveries.length, itemBuilder: (context, index) { @@ -386,7 +293,8 @@ class DeliveryListView extends StatelessWidget { delivery: delivery, isSelected: selectedDelivery?.id == delivery.id, onTap: () => onDeliverySelected(delivery), - onCall: () => onAction(delivery, 'call'), + onCall: () => onItemAction(delivery, 'call'), + onAction: (action) => onItemAction(delivery, action), animationIndex: index, ); }, diff --git a/lib/pages/navigation_page.dart b/lib/pages/navigation_page.dart index 446a451..a8f81ec 100644 --- a/lib/pages/navigation_page.dart +++ b/lib/pages/navigation_page.dart @@ -52,11 +52,8 @@ class _NavigationPageState extends ConsumerState { setState(() { _hasLocationPermission = true; + _isNavigationInitialized = true; }); - - if (mounted) { - _initializeNavigationSession(); - } } catch (e) { if (mounted) { _showErrorDialog('Initialization error: ${e.toString()}'); @@ -67,19 +64,10 @@ class _NavigationPageState extends ConsumerState { Future _initializeNavigationSession() async { try { await GoogleMapsNavigationViewController.initializeNavigationSession(); - - if (mounted) { - setState(() { - _isNavigationInitialized = true; - }); - - // Set destination after session is initialized - await _setDestination(); - } } catch (e) { - if (mounted) { - _showErrorDialog('Failed to initialize navigation: ${e.toString()}'); - } + debugPrint('Navigation session initialization error: $e'); + // Don't show error dialog, just log it + // The session might already be initialized } } @@ -263,8 +251,11 @@ class _NavigationPageState extends ConsumerState { ), body: _hasLocationPermission && _isNavigationInitialized ? GoogleMapsNavigationView( - onViewCreated: (controller) { + onViewCreated: (controller) async { _navigationViewController = controller; + await _initializeNavigationSession(); + await Future.delayed(const Duration(milliseconds: 500)); + await _setDestination(); }, initialCameraPosition: CameraPosition( target: LatLng( diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 3260472..79cdf2e 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -588,7 +588,7 @@ 338D0CEB231458BD00FA5F75 /* Profile */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_STYLE = Manual; + CODE_SIGN_STYLE = Automatic; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Profile; @@ -708,7 +708,7 @@ "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - DEVELOPMENT_TEAM = LD76P8L42W; + DEVELOPMENT_TEAM = 833P6TSX55; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -744,7 +744,7 @@ 33CC111C2044C6BA0003C045 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_STYLE = Manual; + CODE_SIGN_STYLE = Automatic; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; diff --git a/macos/Runner/Configs/AppInfo.xcconfig b/macos/Runner/Configs/AppInfo.xcconfig index b11c3b9..5b5b89b 100644 --- a/macos/Runner/Configs/AppInfo.xcconfig +++ b/macos/Runner/Configs/AppInfo.xcconfig @@ -8,7 +8,7 @@ PRODUCT_NAME = planb_logistic // The application's bundle identifier -PRODUCT_BUNDLE_IDENTIFIER = com.goutezplanb.planbLogistic +PRODUCT_BUNDLE_IDENTIFIER = com.local.planbLogistic // The copyright displayed in application information PRODUCT_COPYRIGHT = Copyright © 2025 com.goutezplanb. All rights reserved.