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 <noreply@anthropic.com>
This commit is contained in:
parent
46af8f55a2
commit
9cb5b51f6d
@ -3,6 +3,9 @@
|
|||||||
android:label="planb_logistic"
|
android:label="planb_logistic"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/ic_launcher">
|
||||||
|
<meta-data
|
||||||
|
android:name="com.google.android.geo.API_KEY"
|
||||||
|
android:value="AIzaSyCuYzbusLkVrHcy10bJ8STF6gyOexQWjuk" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
|
|||||||
@ -114,7 +114,6 @@
|
|||||||
13867C66F1703482B503520B /* Pods-RunnerTests.release.xcconfig */,
|
13867C66F1703482B503520B /* Pods-RunnerTests.release.xcconfig */,
|
||||||
F864EA92C8601181D927DDF4 /* Pods-RunnerTests.profile.xcconfig */,
|
F864EA92C8601181D927DDF4 /* Pods-RunnerTests.profile.xcconfig */,
|
||||||
);
|
);
|
||||||
name = Pods;
|
|
||||||
path = Pods;
|
path = Pods;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@ -489,13 +488,14 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
|
DEVELOPMENT_TEAM = 833P6TSX55;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.goutezplanb.planbLogistic;
|
PRODUCT_BUNDLE_IDENTIFIER = com.local.planbLogistic;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@ -508,6 +508,7 @@
|
|||||||
baseConfigurationReference = 77C9A4AE9C5588D9B699F74C /* Pods-RunnerTests.debug.xcconfig */;
|
baseConfigurationReference = 77C9A4AE9C5588D9B699F74C /* Pods-RunnerTests.debug.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@ -671,13 +672,14 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
|
DEVELOPMENT_TEAM = 833P6TSX55;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.goutezplanb.planbLogistic;
|
PRODUCT_BUNDLE_IDENTIFIER = com.local.planbLogistic;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
@ -693,13 +695,14 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
|
DEVELOPMENT_TEAM = 833P6TSX55;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.goutezplanb.planbLogistic;
|
PRODUCT_BUNDLE_IDENTIFIER = com.local.planbLogistic;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
|
|||||||
@ -8,12 +8,14 @@ class DarkModeMapComponent extends StatefulWidget {
|
|||||||
final List<Delivery> deliveries;
|
final List<Delivery> deliveries;
|
||||||
final Delivery? selectedDelivery;
|
final Delivery? selectedDelivery;
|
||||||
final ValueChanged<Delivery?>? onDeliverySelected;
|
final ValueChanged<Delivery?>? onDeliverySelected;
|
||||||
|
final Function(String)? onAction;
|
||||||
|
|
||||||
const DarkModeMapComponent({
|
const DarkModeMapComponent({
|
||||||
super.key,
|
super.key,
|
||||||
required this.deliveries,
|
required this.deliveries,
|
||||||
this.selectedDelivery,
|
this.selectedDelivery,
|
||||||
this.onDeliverySelected,
|
this.onDeliverySelected,
|
||||||
|
this.onAction,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -256,6 +258,47 @@ class _DarkModeMapComponentState extends State<DarkModeMapComponent> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _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<void> _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<void> _recenterMap() async {
|
||||||
|
if (_navigationController == null || _destinationLocation == null) return;
|
||||||
|
try {
|
||||||
|
await _navigationController!.animateCamera(
|
||||||
|
CameraUpdate.newLatLngZoom(_destinationLocation!, 15),
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('Recenter map error: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final initialPosition = widget.selectedDelivery?.deliveryAddress != null &&
|
final initialPosition = widget.selectedDelivery?.deliveryAddress != null &&
|
||||||
@ -283,6 +326,27 @@ class _DarkModeMapComponentState extends State<DarkModeMapComponent> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
// Custom dark-themed controls overlay
|
// 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(
|
Positioned(
|
||||||
bottom: 16,
|
bottom: 16,
|
||||||
right: 16,
|
right: 16,
|
||||||
@ -388,10 +452,175 @@ class _DarkModeMapComponentState extends State<DarkModeMapComponent> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
// 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({
|
Widget _buildActionButton({
|
||||||
required String label,
|
required String label,
|
||||||
required IconData icon,
|
required IconData icon,
|
||||||
|
|||||||
@ -8,6 +8,7 @@ class DeliveryListItem extends StatefulWidget {
|
|||||||
final bool isSelected;
|
final bool isSelected;
|
||||||
final VoidCallback onTap;
|
final VoidCallback onTap;
|
||||||
final VoidCallback? onCall;
|
final VoidCallback? onCall;
|
||||||
|
final Function(String)? onAction;
|
||||||
final int? animationIndex;
|
final int? animationIndex;
|
||||||
|
|
||||||
const DeliveryListItem({
|
const DeliveryListItem({
|
||||||
@ -16,6 +17,7 @@ class DeliveryListItem extends StatefulWidget {
|
|||||||
required this.isSelected,
|
required this.isSelected,
|
||||||
required this.onTap,
|
required this.onTap,
|
||||||
this.onCall,
|
this.onCall,
|
||||||
|
this.onAction,
|
||||||
this.animationIndex,
|
this.animationIndex,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -112,10 +114,12 @@ class _DeliveryListItemState extends State<DeliveryListItem>
|
|||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
color: _isHovered || widget.isSelected
|
color: widget.delivery.delivered
|
||||||
? Theme.of(context).colorScheme.surfaceContainer
|
? Colors.green.withOpacity(0.15)
|
||||||
: Colors.transparent,
|
: (_isHovered || widget.isSelected
|
||||||
boxShadow: _isHovered || widget.isSelected
|
? Theme.of(context).colorScheme.surfaceContainer
|
||||||
|
: Colors.transparent),
|
||||||
|
boxShadow: (_isHovered || widget.isSelected) && !widget.delivery.delivered
|
||||||
? [
|
? [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: Colors.black.withOpacity(
|
color: Colors.black.withOpacity(
|
||||||
|
|||||||
@ -331,6 +331,114 @@ abstract class AppLocalizations {
|
|||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'{completed}/{total} completed'**
|
/// **'{completed}/{total} completed'**
|
||||||
String completedDeliveries(int completed, int total);
|
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
|
class _AppLocalizationsDelegate
|
||||||
|
|||||||
@ -134,4 +134,64 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
String completedDeliveries(int completed, int total) {
|
String completedDeliveries(int completed, int total) {
|
||||||
return '$completed/$total completed';
|
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...';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -134,4 +134,64 @@ class AppLocalizationsFr extends AppLocalizations {
|
|||||||
String completedDeliveries(int completed, int total) {
|
String completedDeliveries(int completed, int total) {
|
||||||
return '$completed/$total livrs';
|
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...';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,8 +11,6 @@ import '../utils/breakpoints.dart';
|
|||||||
import '../components/map_sidebar_layout.dart';
|
import '../components/map_sidebar_layout.dart';
|
||||||
import '../components/dark_mode_map.dart';
|
import '../components/dark_mode_map.dart';
|
||||||
import '../components/delivery_list_item.dart';
|
import '../components/delivery_list_item.dart';
|
||||||
import '../components/collapsible_routes_sidebar.dart'
|
|
||||||
show CollapsibleRoutesSidebar;
|
|
||||||
|
|
||||||
class DeliveriesPage extends ConsumerStatefulWidget {
|
class DeliveriesPage extends ConsumerStatefulWidget {
|
||||||
final int routeFragmentId;
|
final int routeFragmentId;
|
||||||
@ -29,22 +27,38 @@ class DeliveriesPage extends ConsumerStatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _DeliveriesPageState extends ConsumerState<DeliveriesPage> {
|
class _DeliveriesPageState extends ConsumerState<DeliveriesPage> {
|
||||||
late PageController _pageController;
|
late ScrollController _listScrollController;
|
||||||
int _currentSegment = 0;
|
|
||||||
Delivery? _selectedDelivery;
|
Delivery? _selectedDelivery;
|
||||||
|
int? _lastRouteFragmentId;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_pageController = PageController();
|
_listScrollController = ScrollController();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_pageController.dispose();
|
_listScrollController.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _autoScrollToFirstPending(List<Delivery> 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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final deliveriesData = ref.watch(deliveriesProvider(widget.routeFragmentId));
|
final deliveriesData = ref.watch(deliveriesProvider(widget.routeFragmentId));
|
||||||
@ -58,6 +72,14 @@ class _DeliveriesPageState extends ConsumerState<DeliveriesPage> {
|
|||||||
),
|
),
|
||||||
body: deliveriesData.when(
|
body: deliveriesData.when(
|
||||||
data: (deliveries) {
|
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
|
final todoDeliveries = deliveries
|
||||||
.where((d) => !d.delivered && !d.isSkipped)
|
.where((d) => !d.delivered && !d.isSkipped)
|
||||||
.toList();
|
.toList();
|
||||||
@ -76,27 +98,7 @@ class _DeliveriesPageState extends ConsumerState<DeliveriesPage> {
|
|||||||
currentRoute = routes.isNotEmpty ? routes.first : null;
|
currentRoute = routes.isNotEmpty ? routes.first : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Row(
|
return MapSidebarLayout(
|
||||||
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(
|
|
||||||
mapWidget: DarkModeMapComponent(
|
mapWidget: DarkModeMapComponent(
|
||||||
deliveries: deliveries,
|
deliveries: deliveries,
|
||||||
selectedDelivery: _selectedDelivery,
|
selectedDelivery: _selectedDelivery,
|
||||||
@ -105,75 +107,25 @@ class _DeliveriesPageState extends ConsumerState<DeliveriesPage> {
|
|||||||
_selectedDelivery = delivery;
|
_selectedDelivery = delivery;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
onAction: (action) => _selectedDelivery != null
|
||||||
|
? _handleDeliveryAction(context, _selectedDelivery!, action, token)
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
sidebarWidget: Column(
|
sidebarWidget: UnifiedDeliveryListView(
|
||||||
children: [
|
deliveries: deliveries,
|
||||||
Padding(
|
selectedDelivery: _selectedDelivery,
|
||||||
padding: const EdgeInsets.all(16.0),
|
scrollController: _listScrollController,
|
||||||
child: SegmentedButton<int>(
|
onDeliverySelected: (delivery) {
|
||||||
segments: const [
|
setState(() {
|
||||||
ButtonSegment(
|
_selectedDelivery = delivery;
|
||||||
value: 0,
|
});
|
||||||
label: Text('To Do'),
|
},
|
||||||
),
|
onItemAction: (delivery, action) {
|
||||||
ButtonSegment(
|
_handleDeliveryAction(context, delivery, action, token);
|
||||||
value: 1,
|
_autoScrollToFirstPending(deliveries);
|
||||||
label: Text('Delivered'),
|
},
|
||||||
),
|
|
||||||
],
|
|
||||||
selected: <int>{_currentSegment},
|
|
||||||
onSelectionChanged: (Set<int> 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),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
loading: () => const Center(
|
loading: () => const Center(
|
||||||
child: CircularProgressIndicator(),
|
child: CircularProgressIndicator(),
|
||||||
@ -187,70 +139,23 @@ class _DeliveriesPageState extends ConsumerState<DeliveriesPage> {
|
|||||||
_selectedDelivery = delivery;
|
_selectedDelivery = delivery;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
onAction: (action) => _selectedDelivery != null
|
||||||
|
? _handleDeliveryAction(context, _selectedDelivery!, action, token)
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
sidebarWidget: Column(
|
sidebarWidget: UnifiedDeliveryListView(
|
||||||
children: [
|
deliveries: deliveries,
|
||||||
Padding(
|
selectedDelivery: _selectedDelivery,
|
||||||
padding: const EdgeInsets.all(16.0),
|
scrollController: _listScrollController,
|
||||||
child: SegmentedButton<int>(
|
onDeliverySelected: (delivery) {
|
||||||
segments: const [
|
setState(() {
|
||||||
ButtonSegment(
|
_selectedDelivery = delivery;
|
||||||
value: 0,
|
});
|
||||||
label: Text('To Do'),
|
},
|
||||||
),
|
onItemAction: (delivery, action) {
|
||||||
ButtonSegment(
|
_handleDeliveryAction(context, delivery, action, token);
|
||||||
value: 1,
|
_autoScrollToFirstPending(deliveries);
|
||||||
label: Text('Delivered'),
|
},
|
||||||
),
|
|
||||||
],
|
|
||||||
selected: <int>{_currentSegment},
|
|
||||||
onSelectionChanged: (Set<int> 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),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -291,7 +196,6 @@ class _DeliveriesPageState extends ConsumerState<DeliveriesPage> {
|
|||||||
endpoint: 'completeDelivery',
|
endpoint: 'completeDelivery',
|
||||||
command: CompleteDeliveryCommand(
|
command: CompleteDeliveryCommand(
|
||||||
deliveryId: delivery.id,
|
deliveryId: delivery.id,
|
||||||
deliveredAt: DateTime.now().toIso8601String(),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
result.when(
|
result.when(
|
||||||
@ -351,18 +255,20 @@ class _DeliveriesPageState extends ConsumerState<DeliveriesPage> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DeliveryListView extends StatelessWidget {
|
class UnifiedDeliveryListView extends StatelessWidget {
|
||||||
final List<Delivery> deliveries;
|
final List<Delivery> deliveries;
|
||||||
final Delivery? selectedDelivery;
|
final Delivery? selectedDelivery;
|
||||||
|
final ScrollController scrollController;
|
||||||
final ValueChanged<Delivery> onDeliverySelected;
|
final ValueChanged<Delivery> onDeliverySelected;
|
||||||
final Function(Delivery, String) onAction;
|
final Function(Delivery, String) onItemAction;
|
||||||
|
|
||||||
const DeliveryListView({
|
const UnifiedDeliveryListView({
|
||||||
super.key,
|
super.key,
|
||||||
required this.deliveries,
|
required this.deliveries,
|
||||||
this.selectedDelivery,
|
this.selectedDelivery,
|
||||||
|
required this.scrollController,
|
||||||
required this.onDeliverySelected,
|
required this.onDeliverySelected,
|
||||||
required this.onAction,
|
required this.onItemAction,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -378,6 +284,7 @@ class DeliveryListView extends StatelessWidget {
|
|||||||
// Trigger refresh via provider
|
// Trigger refresh via provider
|
||||||
},
|
},
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
|
controller: scrollController,
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
itemCount: deliveries.length,
|
itemCount: deliveries.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
@ -386,7 +293,8 @@ class DeliveryListView extends StatelessWidget {
|
|||||||
delivery: delivery,
|
delivery: delivery,
|
||||||
isSelected: selectedDelivery?.id == delivery.id,
|
isSelected: selectedDelivery?.id == delivery.id,
|
||||||
onTap: () => onDeliverySelected(delivery),
|
onTap: () => onDeliverySelected(delivery),
|
||||||
onCall: () => onAction(delivery, 'call'),
|
onCall: () => onItemAction(delivery, 'call'),
|
||||||
|
onAction: (action) => onItemAction(delivery, action),
|
||||||
animationIndex: index,
|
animationIndex: index,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@ -52,11 +52,8 @@ class _NavigationPageState extends ConsumerState<NavigationPage> {
|
|||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_hasLocationPermission = true;
|
_hasLocationPermission = true;
|
||||||
|
_isNavigationInitialized = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (mounted) {
|
|
||||||
_initializeNavigationSession();
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
_showErrorDialog('Initialization error: ${e.toString()}');
|
_showErrorDialog('Initialization error: ${e.toString()}');
|
||||||
@ -67,19 +64,10 @@ class _NavigationPageState extends ConsumerState<NavigationPage> {
|
|||||||
Future<void> _initializeNavigationSession() async {
|
Future<void> _initializeNavigationSession() async {
|
||||||
try {
|
try {
|
||||||
await GoogleMapsNavigationViewController.initializeNavigationSession();
|
await GoogleMapsNavigationViewController.initializeNavigationSession();
|
||||||
|
|
||||||
if (mounted) {
|
|
||||||
setState(() {
|
|
||||||
_isNavigationInitialized = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Set destination after session is initialized
|
|
||||||
await _setDestination();
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (mounted) {
|
debugPrint('Navigation session initialization error: $e');
|
||||||
_showErrorDialog('Failed to initialize navigation: ${e.toString()}');
|
// Don't show error dialog, just log it
|
||||||
}
|
// The session might already be initialized
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,8 +251,11 @@ class _NavigationPageState extends ConsumerState<NavigationPage> {
|
|||||||
),
|
),
|
||||||
body: _hasLocationPermission && _isNavigationInitialized
|
body: _hasLocationPermission && _isNavigationInitialized
|
||||||
? GoogleMapsNavigationView(
|
? GoogleMapsNavigationView(
|
||||||
onViewCreated: (controller) {
|
onViewCreated: (controller) async {
|
||||||
_navigationViewController = controller;
|
_navigationViewController = controller;
|
||||||
|
await _initializeNavigationSession();
|
||||||
|
await Future.delayed(const Duration(milliseconds: 500));
|
||||||
|
await _setDestination();
|
||||||
},
|
},
|
||||||
initialCameraPosition: CameraPosition(
|
initialCameraPosition: CameraPosition(
|
||||||
target: LatLng(
|
target: LatLng(
|
||||||
|
|||||||
@ -588,7 +588,7 @@
|
|||||||
338D0CEB231458BD00FA5F75 /* Profile */ = {
|
338D0CEB231458BD00FA5F75 /* Profile */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
};
|
};
|
||||||
name = Profile;
|
name = Profile;
|
||||||
@ -708,7 +708,7 @@
|
|||||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
DEVELOPMENT_TEAM = LD76P8L42W;
|
DEVELOPMENT_TEAM = 833P6TSX55;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@ -744,7 +744,7 @@
|
|||||||
33CC111C2044C6BA0003C045 /* Debug */ = {
|
33CC111C2044C6BA0003C045 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
PRODUCT_NAME = planb_logistic
|
PRODUCT_NAME = planb_logistic
|
||||||
|
|
||||||
// The application's bundle identifier
|
// The application's bundle identifier
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.goutezplanb.planbLogistic
|
PRODUCT_BUNDLE_IDENTIFIER = com.local.planbLogistic
|
||||||
|
|
||||||
// The copyright displayed in application information
|
// The copyright displayed in application information
|
||||||
PRODUCT_COPYRIGHT = Copyright © 2025 com.goutezplanb. All rights reserved.
|
PRODUCT_COPYRIGHT = Copyright © 2025 com.goutezplanb. All rights reserved.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user