231 lines
7.0 KiB
Dart
231 lines
7.0 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:google_navigation_flutter/google_navigation_flutter.dart';
|
|
import '../models/delivery.dart';
|
|
|
|
class DeliveryMap extends StatefulWidget {
|
|
final List<Delivery> deliveries;
|
|
final Delivery? selectedDelivery;
|
|
final ValueChanged<Delivery?>? onDeliverySelected;
|
|
|
|
const DeliveryMap({
|
|
super.key,
|
|
required this.deliveries,
|
|
this.selectedDelivery,
|
|
this.onDeliverySelected,
|
|
});
|
|
|
|
@override
|
|
State<DeliveryMap> createState() => _DeliveryMapState();
|
|
}
|
|
|
|
class _DeliveryMapState extends State<DeliveryMap> {
|
|
GoogleNavigationViewController? _navigationController;
|
|
bool _isNavigating = false;
|
|
LatLng? _destinationLocation;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_initializeNavigation();
|
|
}
|
|
|
|
Future<void> _initializeNavigation() async {
|
|
try {
|
|
debugPrint('🗺️ Starting navigation initialization');
|
|
// Check if terms and conditions need to be shown
|
|
final termsAccepted = await GoogleMapsNavigator.areTermsAccepted();
|
|
debugPrint('🗺️ Terms accepted: $termsAccepted');
|
|
|
|
if (!termsAccepted) {
|
|
debugPrint('🗺️ Showing terms and conditions dialog');
|
|
// Show terms and conditions
|
|
await GoogleMapsNavigator.showTermsAndConditionsDialog(
|
|
'Plan B Logistics',
|
|
'com.goutezplanb.planbLogistic',
|
|
);
|
|
}
|
|
|
|
// Initialize navigation session
|
|
debugPrint('🗺️ Initializing navigation session');
|
|
await GoogleMapsNavigator.initializeNavigationSession();
|
|
debugPrint('🗺️ Navigation session initialized successfully');
|
|
} catch (e) {
|
|
debugPrint('❌ Error initializing navigation: $e');
|
|
}
|
|
}
|
|
|
|
@override
|
|
void didUpdateWidget(DeliveryMap 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<void> _navigateToLocation(LatLng location) async {
|
|
if (_navigationController == null) return;
|
|
|
|
try {
|
|
await _navigationController!.animateCamera(
|
|
CameraUpdate.newLatLngZoom(location, 15),
|
|
);
|
|
} catch (e) {
|
|
debugPrint('Error moving camera: $e');
|
|
}
|
|
}
|
|
|
|
Future<void> _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('Error starting navigation: $e');
|
|
if (mounted) {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(content: Text('Error starting navigation: $e')),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<void> _stopNavigation() async {
|
|
try {
|
|
await GoogleMapsNavigator.stopGuidance();
|
|
await GoogleMapsNavigator.clearDestinations();
|
|
|
|
setState(() {
|
|
_isNavigating = false;
|
|
});
|
|
} catch (e) {
|
|
debugPrint('Error stopping navigation: $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); // Default to Montreal
|
|
|
|
return Stack(
|
|
children: [
|
|
GoogleMapsNavigationView(
|
|
onViewCreated: (controller) {
|
|
debugPrint('🗺️ Map view created successfully');
|
|
_navigationController = controller;
|
|
controller.setMyLocationEnabled(true);
|
|
|
|
// Set initial camera position
|
|
controller.animateCamera(
|
|
CameraUpdate.newLatLngZoom(initialPosition, 12),
|
|
);
|
|
debugPrint('🗺️ Initial camera position set to: $initialPosition');
|
|
},
|
|
initialNavigationUIEnabledPreference: NavigationUIEnabledPreference.disabled,
|
|
initialCameraPosition: CameraPosition(
|
|
target: initialPosition,
|
|
zoom: 12,
|
|
),
|
|
),
|
|
if (_destinationLocation != null && !_isNavigating)
|
|
Positioned(
|
|
bottom: 24,
|
|
left: 24,
|
|
right: 24,
|
|
child: ElevatedButton.icon(
|
|
onPressed: _startNavigation,
|
|
icon: const Icon(Icons.navigation),
|
|
label: const Text('Start Navigation'),
|
|
style: ElevatedButton.styleFrom(
|
|
padding: const EdgeInsets.all(16),
|
|
backgroundColor: Theme.of(context).colorScheme.primary,
|
|
foregroundColor: Theme.of(context).colorScheme.onPrimary,
|
|
),
|
|
),
|
|
),
|
|
if (_isNavigating)
|
|
Positioned(
|
|
bottom: 24,
|
|
left: 24,
|
|
right: 24,
|
|
child: ElevatedButton.icon(
|
|
onPressed: _stopNavigation,
|
|
icon: const Icon(Icons.stop),
|
|
label: const Text('Stop Navigation'),
|
|
style: ElevatedButton.styleFrom(
|
|
padding: const EdgeInsets.all(16),
|
|
backgroundColor: Theme.of(context).colorScheme.error,
|
|
foregroundColor: Theme.of(context).colorScheme.onError,
|
|
),
|
|
),
|
|
),
|
|
Positioned(
|
|
top: 16,
|
|
right: 16,
|
|
child: Column(
|
|
children: [
|
|
FloatingActionButton.small(
|
|
heroTag: 'zoom_in',
|
|
onPressed: () {
|
|
_navigationController?.animateCamera(CameraUpdate.zoomIn());
|
|
},
|
|
child: const Icon(Icons.add),
|
|
),
|
|
const SizedBox(height: 8),
|
|
FloatingActionButton.small(
|
|
heroTag: 'zoom_out',
|
|
onPressed: () {
|
|
_navigationController?.animateCamera(CameraUpdate.zoomOut());
|
|
},
|
|
child: const Icon(Icons.remove),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
GoogleMapsNavigator.cleanup();
|
|
super.dispose();
|
|
}
|
|
}
|