import 'dart:async'; import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:geolocator/geolocator.dart'; import 'package:location/location.dart' as LocationPlugin; import 'package:flutter_polyline_points/flutter_polyline_points.dart'; class Techniciantrackingprovider extends ChangeNotifier { final String _googleApikey = "AIzaSyBGzvgMMKwPBAANTwaoRsAnrCpiWCj8wVs"; GoogleMapController? _mapController; LocationPlugin.LocationData? _currentLocation; bool _isLoading = true; bool _hasPermission = false; final Set _markers = {}; final Set _polylines = {}; final List _polylineCoordinates = []; late PolylinePoints polylinePoints; BitmapDescriptor? customerIcon; BitmapDescriptor? technicianIcon; LatLng get startLocation => const LatLng(17.439112226708446, 78.43292499146135); GoogleMapController? get mapController => _mapController; Set get markers => _markers; Set get polylines => _polylines; LocationPlugin.LocationData? get currentLocation => _currentLocation; bool get isLoading => _isLoading; set mapController(GoogleMapController? controller) { _mapController = controller; notifyListeners(); } Future loadCustomIcons() async { customerIcon ??= await BitmapDescriptor.fromAssetImage( const ImageConfiguration(size: Size(80, 80)), 'assets/images/maps_ic.png', ); technicianIcon ??= await BitmapDescriptor.fromAssetImage( const ImageConfiguration(size: Size(80, 80)), 'assets/images/technician_marker.png', ); notifyListeners(); } Future getLocationPermission(BuildContext context) async { _isLoading = true; notifyListeners(); bool serviceEnabled = await Geolocator.isLocationServiceEnabled(); if (!serviceEnabled) { _isLoading = false; notifyListeners(); return; } LocationPermission permission = await Geolocator.checkPermission(); if (permission == LocationPermission.denied) { permission = await Geolocator.requestPermission(); if (permission == LocationPermission.denied) { _isLoading = false; notifyListeners(); return; } } if (permission == LocationPermission.deniedForever) { _isLoading = false; notifyListeners(); return; } _hasPermission = true; await loadCustomIcons(); final LocationPlugin.Location location = LocationPlugin.Location(); _currentLocation = await location.getLocation(); // Add customer marker if (_currentLocation != null) { _markers.add(Marker( markerId: const MarkerId('customer'), position: LatLng(_currentLocation!.latitude!, _currentLocation!.longitude!), infoWindow: const InfoWindow(title: "You are here"), icon: customerIcon ?? BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueGreen), )); } _isLoading = false; notifyListeners(); } void updateTechnicianLocation(double? lat, double? lng) { if (lat == null || lng == null || lat == 0 || lng == 0) return; final technicianLatLng = LatLng(lat, lng); // Remove old technician marker _markers.removeWhere((m) => m.markerId.value == 'technician'); _polylines.clear(); _polylineCoordinates.clear(); // Add new technician marker _markers.add(Marker( markerId: const MarkerId('technician'), position: technicianLatLng, infoWindow: const InfoWindow(title: "Technician"), icon: technicianIcon ?? BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueBlue), )); // Draw route if customer location exists if (_currentLocation != null) { _drawRoute( LatLng(_currentLocation!.latitude!, _currentLocation!.longitude!), technicianLatLng, ); } // Adjust camera _fitBothMarkers(); setPolylines(lat,lng); notifyListeners(); } void setPolylines(double? lat, double? lng) async { _polylineCoordinates.clear(); _polylines.clear(); PolylineResult result = await polylinePoints.getRouteBetweenCoordinates( // googleApiKey: "AIzaSyAA2ukvrb1kWQZ2dttsNIMynLJqVCYYrhw", request: PolylineRequest( origin: await PointLatLng( lat!, lng!), destination: await PointLatLng( _currentLocation!.latitude!, _currentLocation!.longitude!), mode: TravelMode.driving), // Example LatLng// Example LatLng // Example LatLng ); if (result.points.isNotEmpty) { result.points.forEach((PointLatLng point) { _polylineCoordinates.add(LatLng(point.latitude, point.longitude)); }); _polylines.add(Polyline( width: 1, polylineId: PolylineId("poly"), color: Color(0xFF008CDE), points: _polylineCoordinates, )); notifyListeners(); } } Future _drawRoute(LatLng origin, LatLng destination) async { final polylinePoints = PolylinePoints(apiKey: _googleApikey); try { final result = await polylinePoints.getRouteBetweenCoordinates( request: PolylineRequest( origin: PointLatLng(origin.latitude, origin.longitude), destination: PointLatLng(destination.latitude, destination.longitude), mode: TravelMode.driving, ), ); if (result.points.isNotEmpty) { _polylineCoordinates.clear(); for (var point in result.points) { _polylineCoordinates.add(LatLng(point.latitude, point.longitude)); } _polylines.add(Polyline( polylineId: const PolylineId('route'), color: Colors.blue, width: 5, points: _polylineCoordinates, patterns: [PatternItem.dash(20), PatternItem.gap(10)], )); } } catch (e) { debugPrint("Polyline Error: $e"); } notifyListeners(); } void _fitBothMarkers() { if (_markers.length < 2 || _mapController == null) return; final positions = _markers.map((m) => m.position).toList(); double minLat = positions[0].latitude; double maxLat = positions[0].latitude; double minLng = positions[0].longitude; double maxLng = positions[0].longitude; for (var pos in positions) { if (pos.latitude < minLat) minLat = pos.latitude; if (pos.latitude > maxLat) maxLat = pos.latitude; if (pos.longitude < minLng) minLng = pos.longitude; if (pos.longitude > maxLng) maxLng = pos.longitude; } _mapController!.animateCamera( CameraUpdate.newLatLngBounds( LatLngBounds( southwest: LatLng(minLat, minLng), northeast: LatLng(maxLat, maxLng), ), 100, ), ); } Future setMapStyle(GoogleMapController controller) async { String mapStyle = ''' [ { "featureType": "road", "elementType": "geometry", "stylers": [ { "visibility": "on" } ] }, { "featureType": "road.arterial", "elementType": "geometry", "stylers": [ { "visibility": "on" } ] }, { "featureType": "road.highway", "elementType": "geometry", "stylers": [ { "visibility": "off" } ] }, { "featureType": "road.local", "elementType": "geometry", "stylers": [ { "visibility": "on" } ] }, { "featureType": "poi", "elementType": "labels", "stylers": [ { "visibility": "on" } ] }, { "featureType": "poi.business", "stylers": [ { "visibility": "on" } ] }, { "featureType": "transit", "stylers": [ { "visibility": "on" } ] }, { "featureType": "road.local", "elementType": "labels", "stylers": [ { "visibility": "on" } ] } ] '''; await controller.setMapStyle(mapStyle); } void clearMap() { _markers.clear(); _polylines.clear(); _polylineCoordinates.clear(); notifyListeners(); } }