Major package upgrades: - Riverpod 2.x → 3.0.3 (breaking changes) - flutter_appauth 7.0.0 → 11.0.0 - go_router 14.0.0 → 17.0.0 - permission_handler 11.3.0 → 12.0.1 - flutter_lints 5.0.0 → 6.0.0 - animate_do 3.1.2 → 4.2.0 - Plus 41 transitive dependency updates Breaking changes fixed: Riverpod 3.0 migration: - Replace StateProvider with NotifierProvider pattern - Update .valueOrNull to proper async value handling with .future - Create LanguageNotifier and ThemeModeNotifier classes - Fix all provider async value access patterns Google Maps Navigation API updates: - Rename GoogleMapsNavigationViewController to GoogleNavigationViewController - Update Waypoint to NavigationWaypoint.withLatLngTarget - Migrate controller methods to static GoogleMapsNavigator methods - Update event listener types and callbacks Localization system fixes: - Update l10n.yaml synthetic-package configuration - Fix import paths from flutter_gen to package imports - Add errorTitle translation key for both en/fr - Remove unnecessary null-aware operators (AppLocalizations is non-nullable) - Regenerate localization files iOS/macOS configuration: - Update CocoaPods dependencies (AppAuth 1.7.5 → 2.0.0) - Create missing Profile.xcconfig files for both platforms - Sync Podfile.lock files with updated dependencies Code quality: - Fix all analyzer errors (0 errors remaining) - Resolve deprecated API usage warnings - Update async/await patterns for better error handling 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
193 lines
5.0 KiB
Dart
193 lines
5.0 KiB
Dart
import 'package:google_navigation_flutter/google_navigation_flutter.dart';
|
|
|
|
class NavigationSessionService {
|
|
static final NavigationSessionService _instance =
|
|
NavigationSessionService._internal();
|
|
|
|
factory NavigationSessionService() {
|
|
return _instance;
|
|
}
|
|
|
|
NavigationSessionService._internal();
|
|
|
|
bool _isSessionInitialized = false;
|
|
GoogleNavigationViewController? _controller;
|
|
|
|
bool get isSessionInitialized => _isSessionInitialized;
|
|
|
|
Future<void> initializeSession() async {
|
|
if (_isSessionInitialized) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
await GoogleMapsNavigator.initializeNavigationSession();
|
|
_isSessionInitialized = true;
|
|
} catch (e) {
|
|
throw NavigationSessionException('Failed to initialize session: $e');
|
|
}
|
|
}
|
|
|
|
Future<void> setController(
|
|
GoogleNavigationViewController controller,
|
|
) async {
|
|
_controller = controller;
|
|
}
|
|
|
|
Future<NavigationRoute> calculateRoute({
|
|
required double startLatitude,
|
|
required double startLongitude,
|
|
required double destinationLatitude,
|
|
required double destinationLongitude,
|
|
}) async {
|
|
if (!_isSessionInitialized) {
|
|
throw NavigationSessionException('Session not initialized');
|
|
}
|
|
|
|
if (_controller == null) {
|
|
throw NavigationSessionException('Controller not set');
|
|
}
|
|
|
|
try {
|
|
final origin = LatLng(
|
|
latitude: startLatitude,
|
|
longitude: startLongitude,
|
|
);
|
|
|
|
final destination = LatLng(
|
|
latitude: destinationLatitude,
|
|
longitude: destinationLongitude,
|
|
);
|
|
|
|
final waypoint = NavigationWaypoint.withLatLngTarget(
|
|
title: 'Destination',
|
|
target: destination,
|
|
);
|
|
|
|
final destinations = Destinations(
|
|
waypoints: [waypoint],
|
|
displayOptions: NavigationDisplayOptions(showDestinationMarkers: true),
|
|
);
|
|
|
|
// Set destinations will trigger route calculation
|
|
await GoogleMapsNavigator.setDestinations(destinations);
|
|
|
|
return NavigationRoute(
|
|
startLocation: origin,
|
|
endLocation: destination,
|
|
isCalculated: true,
|
|
);
|
|
} catch (e) {
|
|
throw NavigationSessionException('Failed to calculate route: $e');
|
|
}
|
|
}
|
|
|
|
Future<void> startNavigation() async {
|
|
if (!_isSessionInitialized) {
|
|
throw NavigationSessionException('Navigation not properly initialized');
|
|
}
|
|
|
|
try {
|
|
await GoogleMapsNavigator.startGuidance();
|
|
} catch (e) {
|
|
throw NavigationSessionException('Failed to start navigation: $e');
|
|
}
|
|
}
|
|
|
|
Future<void> stopNavigation() async {
|
|
if (!_isSessionInitialized) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
await GoogleMapsNavigator.stopGuidance();
|
|
} catch (e) {
|
|
throw NavigationSessionException('Failed to stop navigation: $e');
|
|
}
|
|
}
|
|
|
|
void addLocationListener(
|
|
Function(RoadSnappedLocationUpdatedEvent event) onLocationUpdate,
|
|
) {
|
|
if (!_isSessionInitialized) {
|
|
throw NavigationSessionException('Navigation not initialized');
|
|
}
|
|
|
|
GoogleMapsNavigator.setRoadSnappedLocationUpdatedListener((event) {
|
|
onLocationUpdate(event);
|
|
});
|
|
}
|
|
|
|
void addArrivalListener(Function(OnArrivalEvent event) onArrival) {
|
|
if (!_isSessionInitialized) {
|
|
throw NavigationSessionException('Navigation not initialized');
|
|
}
|
|
|
|
GoogleMapsNavigator.setOnArrivalListener((event) {
|
|
onArrival(event);
|
|
});
|
|
}
|
|
|
|
// Note: Remaining distance listener API may vary by version
|
|
// This is a placeholder for future implementation
|
|
void addRemainingDistanceListener(
|
|
Function(dynamic event) onDistanceChange,
|
|
) {
|
|
if (!_isSessionInitialized) {
|
|
throw NavigationSessionException('Navigation not initialized');
|
|
}
|
|
// TODO: Implement when correct API is available
|
|
// GoogleMapsNavigator does not expose a public remaining distance listener
|
|
}
|
|
|
|
void clearAllListeners() {
|
|
if (!_isSessionInitialized) {
|
|
return;
|
|
}
|
|
|
|
// Clear listeners by setting them to empty callbacks
|
|
// Note: The API doesn't support null, so we use no-op callbacks
|
|
GoogleMapsNavigator.setRoadSnappedLocationUpdatedListener((_) {});
|
|
GoogleMapsNavigator.setOnArrivalListener((_) {});
|
|
}
|
|
|
|
Future<void> cleanup() async {
|
|
try {
|
|
if (_isSessionInitialized) {
|
|
await stopNavigation();
|
|
clearAllListeners();
|
|
await GoogleMapsNavigator.cleanup();
|
|
}
|
|
_isSessionInitialized = false;
|
|
_controller = null;
|
|
} catch (e) {
|
|
throw NavigationSessionException('Failed to cleanup: $e');
|
|
}
|
|
}
|
|
}
|
|
|
|
class NavigationRoute {
|
|
final LatLng startLocation;
|
|
final LatLng endLocation;
|
|
final bool isCalculated;
|
|
final int? distanceMeters;
|
|
final Duration? estimatedTime;
|
|
|
|
NavigationRoute({
|
|
required this.startLocation,
|
|
required this.endLocation,
|
|
required this.isCalculated,
|
|
this.distanceMeters,
|
|
this.estimatedTime,
|
|
});
|
|
}
|
|
|
|
class NavigationSessionException implements Exception {
|
|
final String message;
|
|
|
|
NavigationSessionException(this.message);
|
|
|
|
@override
|
|
String toString() => 'NavigationSessionException: $message';
|
|
}
|