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:
@@ -8,12 +8,14 @@ class DarkModeMapComponent extends StatefulWidget {
|
||||
final List<Delivery> deliveries;
|
||||
final Delivery? selectedDelivery;
|
||||
final ValueChanged<Delivery?>? 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<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
|
||||
Widget build(BuildContext context) {
|
||||
final initialPosition = widget.selectedDelivery?.deliveryAddress != null &&
|
||||
@@ -283,6 +326,27 @@ class _DarkModeMapComponentState extends State<DarkModeMapComponent> {
|
||||
),
|
||||
),
|
||||
// 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<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({
|
||||
required String label,
|
||||
required IconData icon,
|
||||
|
||||
@@ -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<DeliveryListItem>
|
||||
),
|
||||
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(
|
||||
|
||||
Reference in New Issue
Block a user