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; GoogleMapsNavigationViewController? _controller; bool get isSessionInitialized => _isSessionInitialized; Future initializeSession() async { if (_isSessionInitialized) { return; } try { await GoogleMapsNavigationViewController.initializeNavigationSession(); _isSessionInitialized = true; } catch (e) { throw NavigationSessionException('Failed to initialize session: $e'); } } Future setController( GoogleMapsNavigationViewController controller, ) async { _controller = controller; } Future 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 = Waypoint( target: destination, ); // Set destinations will trigger route calculation await _controller!.setDestinations( destinations: [waypoint], ); return NavigationRoute( startLocation: origin, endLocation: destination, isCalculated: true, ); } catch (e) { throw NavigationSessionException('Failed to calculate route: $e'); } } Future startNavigation() async { if (!_isSessionInitialized || _controller == null) { throw NavigationSessionException('Navigation not properly initialized'); } try { await _controller!.startGuidance(); } catch (e) { throw NavigationSessionException('Failed to start navigation: $e'); } } Future stopNavigation() async { if (_controller == null) { return; } try { await _controller!.stopGuidance(); } catch (e) { throw NavigationSessionException('Failed to stop navigation: $e'); } } void addLocationListener( Function(LatLng location) onLocationUpdate, ) { if (_controller == null) { throw NavigationSessionException('Controller not set'); } _controller!.addOnLocationUpdatedListener((location) { onLocationUpdate(location); }); } void addArrivalListener(Function(NavInfo info) onArrival) { if (_controller == null) { throw NavigationSessionException('Controller not set'); } _controller!.addOnArrivalListener((info) { onArrival(info); }); } void addRemainingDistanceListener( Function(int distanceMeters) onDistanceChange, ) { if (_controller == null) { throw NavigationSessionException('Controller not set'); } _controller!.addOnRemainingDistanceChangedListener((distance) { onDistanceChange(distance); }); } void clearAllListeners() { if (_controller == null) { return; } _controller!.removeAllListeners(); } Future cleanup() async { try { if (_controller != null) { await stopNavigation(); clearAllListeners(); } _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'; }