import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'dart:math' show cos, pi, max, min, atan2, sin, sqrt; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:geolocator/geolocator.dart'; import 'package:get/get.dart'; import 'package:intaleq_maps/intaleq_maps.dart'; import 'package:location/location.dart'; import 'package:http/http.dart' as http; import '../../../constant/box_name.dart'; import '../../../constant/links.dart'; import '../../../constant/colors.dart'; import '../../../constant/style.dart'; import '../../../constant/table_names.dart'; import '../../../main.dart'; // contains global 'box', 'sql' import '../../../print.dart'; import '../../../services/offline_map_service.dart'; import '../../functions/crud.dart'; import '../points_for_rider_controller.dart'; import '../../../views/home/map_widget.dart/form_serch_multiy_point.dart'; import '../../../views/widgets/error_snakbar.dart'; import 'map_engine_controller.dart'; import '../deep_link_controller.dart'; import 'ride_lifecycle_controller.dart'; import 'ride_state.dart'; import '../../../constant/country_polygons.dart'; import '../../../constant/univeries_polygon.dart'; class LocationSearchController extends GetxController { List> waypoints = []; String passengerLocationStringUnvirsity = 'Not in University'; bool isInUniversity = false; List coordinatesWithoutEmpty = []; LatLng? latestPosition; List polylineCoordinates0 = []; List polylineCoordinates1 = []; List polylineCoordinates2 = []; List polylineCoordinates3 = []; List polylineCoordinates4 = []; late List> polylineCoordinatesPointsAll = [ polylineCoordinates0, polylineCoordinates1, polylineCoordinates2, polylineCoordinates3, polylineCoordinates4, ]; bool isLoading = true; TextEditingController placeDestinationController = TextEditingController(); TextEditingController placeStartController = TextEditingController(); TextEditingController wayPoint0Controller = TextEditingController(); TextEditingController wayPoint1Controller = TextEditingController(); TextEditingController wayPoint2Controller = TextEditingController(); TextEditingController wayPoint3Controller = TextEditingController(); TextEditingController wayPoint4Controller = TextEditingController(); TextEditingController whatsAppLocationText = TextEditingController(); final sosFormKey = GlobalKey(); List bounds = []; List placesStart = []; List allTextEditingPlaces = []; List placesDestination = []; List wayPoint0 = []; List wayPoint1 = []; List wayPoint2 = []; List wayPoint3 = []; List wayPoint4 = []; List> placeListResponseAll = []; List placeListResponse = []; PermissionStatus? permissionGranted; final location = Location(); double speed = 0; late LatLng passengerLocation = const LatLng(32, 34); late LatLng newMyLocation = const LatLng(32.115295, 36.064773); late LatLng newStartPointLocation = const LatLng(32.115295, 36.064773); late LatLng newPointLocation0 = const LatLng(32.115295, 36.064773); late LatLng newPointLocation1 = const LatLng(32.115295, 36.064773); late LatLng newPointLocation2 = const LatLng(32.115295, 36.064773); late LatLng newPointLocation3 = const LatLng(32.115295, 36.064773); late LatLng newPointLocation4 = const LatLng(32.115295, 36.064773); late LatLng myDestination = const LatLng(32, 34); bool startLocationFromMap = false; bool passengerStartLocationFromMap = false; bool workLocationFromMap = false; bool homeLocationFromMap = false; bool isPassengerRideLocationWidget = false; bool startLocationFromMap0 = false; bool startLocationFromMap1 = false; bool startLocationFromMap2 = false; bool startLocationFromMap3 = false; bool startLocationFromMap4 = false; List startLocationFromMapAll = []; bool currentLocationToFormPlaces = false; bool currentLocationToFormPlaces0 = false; bool currentLocationToFormPlaces1 = false; bool currentLocationToFormPlaces2 = false; bool currentLocationToFormPlaces3 = false; bool currentLocationToFormPlaces4 = false; List currentLocationToFormPlacesAll = []; // Multi-Waypoint (max 2 stops) List menuWaypoints = [null, null]; List menuWaypointNames = ['', '']; int activeMenuWaypointCount = 0; bool isPickingWaypoint = false; int pickingWaypointIndex = -1; int wayPointIndex = 0; String hintTextStartPoint = 'Search for your Start point'.tr; String hintTextwayPoint0 = 'Search for waypoint'.tr; String hintTextwayPoint1 = 'Search for waypoint'.tr; String hintTextwayPoint2 = 'Search for waypoint'.tr; String hintTextwayPoint3 = 'Search for waypoint'.tr; String hintTextwayPoint4 = 'Search for waypoint'.tr; String currentLocationString = 'Current Location'.tr; String currentLocationString0 = 'Current Location'.tr; String currentLocationString1 = 'Add Location 1'.tr; String currentLocationString2 = 'Add Location 2'.tr; String currentLocationString3 = 'Add Location 3'.tr; String currentLocationString4 = 'Add Location 4'.tr; String placesCoordinate0 = ''.tr; String placesCoordinate1 = ''.tr; String placesCoordinate2 = ''.tr; String placesCoordinate3 = ''.tr; String placesCoordinate4 = ''.tr; List currentLocationStringAll = []; List hintTextwayPointStringAll = []; var placesCoordinate = []; String hintTextDestinationPoint = 'Select your destination'.tr; late String startNameAddress = ''; late String endNameAddress = ''; List> stopPoints = []; double latitudeWhatsApp = 0; double longitudeWhatsApp = 0; late List recentPlaces = []; Timer? _camThrottle; final DeepLinkController _deepLinkController = Get.isRegistered() ? Get.find() : Get.put(DeepLinkController()); @override void onInit() { super.onInit(); placeListResponse = [ formSearchPlaces(0), formSearchPlaces(1), formSearchPlaces(2), formSearchPlaces(3), ]; readyWayPoints(); getLocation(); } void readyWayPoints() { hintTextwayPointStringAll = [ hintTextwayPoint0, hintTextwayPoint1, hintTextwayPoint2, hintTextwayPoint3, hintTextwayPoint4, ]; allTextEditingPlaces = [ wayPoint0Controller, wayPoint1Controller, wayPoint2Controller, wayPoint3Controller, wayPoint4Controller, ]; currentLocationToFormPlacesAll = [ currentLocationToFormPlaces0, currentLocationToFormPlaces1, currentLocationToFormPlaces2, currentLocationToFormPlaces3, currentLocationToFormPlaces4, ]; placeListResponseAll = [ wayPoint0, wayPoint1, wayPoint2, wayPoint3, wayPoint4 ]; startLocationFromMapAll = [ startLocationFromMap0, startLocationFromMap1, startLocationFromMap2, startLocationFromMap3, startLocationFromMap4, ]; currentLocationStringAll = [ currentLocationString0, currentLocationString1, currentLocationString2, currentLocationString3, currentLocationString4, ]; placesCoordinate = [ placesCoordinate0, placesCoordinate1, placesCoordinate2, placesCoordinate3, placesCoordinate4, ]; update(); } void removeStop(Map stop) { stopPoints.remove(stop); update(); } Future savePlaceToServer( String latitude, String longitude, String name, String rate) async { var data = { 'latitude': latitude, 'longitude': longitude, 'name': name, 'rate': rate, }; try { CRUD().post( link: AppLink.savePlacesServer, payload: data, ); } catch (e) { Log.print('Error: $e'); } } Future getLocation() async { Log.print('๐Ÿ›ฐ๏ธ getLocation() called'); permissionGranted = await location.hasPermission(); if (permissionGranted == PermissionStatus.denied) { permissionGranted = await location.requestPermission(); if (permissionGranted != PermissionStatus.granted) { return; } } // Pre-populate with last known position for instant loading try { Position? lastPosition = await Geolocator.getLastKnownPosition(); if (lastPosition != null) { passengerLocation = LatLng(lastPosition.latitude, lastPosition.longitude); newStartPointLocation = passengerLocation; newMyLocation = passengerLocation; Log.print( '๐Ÿ“ Pre-populated location from last known: $passengerLocation'); } } catch (e) { Log.print('โš ๏ธ Error getting last known position: $e'); } LocationData? _locationData; try { _locationData = await location.getLocation().timeout( const Duration(seconds: 5), onTimeout: () { Log.print("โš ๏ธ Location fetch timed out after 5s."); return LocationData.fromMap({ "latitude": passengerLocation.latitude, "longitude": passengerLocation.longitude, "speed": 0.0 }); }, ); } catch (e) { Log.print("โš ๏ธ Error fetching location: $e"); } if (_locationData == null) { isLoading = false; update(); return; } passengerLocation = (_locationData.latitude != null && _locationData.longitude != null ? LatLng(_locationData.latitude!, _locationData.longitude!) : const LatLng(32, 34)); newStartPointLocation = passengerLocation; newMyLocation = passengerLocation; if (Get.isRegistered()) { final rideLifecycle = Get.find(); rideLifecycle.getLocationArea( passengerLocation.latitude, passengerLocation.longitude); rideLifecycle.resetNoRideSearch(); } try { getReverseGeocoding(passengerLocation).then((address) { currentLocationString = address; update(); }); } catch (e) { Log.print('Error resolving current location: $e'); } OfflineMapService.instance .downloadRegion(passengerLocation, radiusKm: 10.0); try { final mapEngine = Get.find(); if (mapEngine.mapController != null) { mapEngine.mapController!.animateCamera( CameraUpdate.newLatLng(passengerLocation), ); } } catch (e) { Log.print('Error animating camera to passenger location: $e'); } speed = _locationData.speed ?? 0.0; isLoading = false; update(); } void getCurrentLocationFormString() async { currentLocationToFormPlaces = true; currentLocationString = 'Waiting for your location'.tr; await getLocation(); currentLocationString = passengerLocation.toString(); newStartPointLocation = passengerLocation; update(); } Future getPlaces() async { final q = placeDestinationController.text.trim(); if (q.isEmpty || q.length < 3) { placesDestination = []; update(); return; } final lat = passengerLocation.latitude; final lng = passengerLocation.longitude; final country = CountryPolygons.getCountryName(passengerLocation); try { final url = '${AppLink.searchGeocoding}?q=${Uri.encodeComponent(q)}&lat=$lat&lng=$lng&radius=15000&country=$country'; final response = await CRUD().getMapSaas(link: url); if (response != null && response['results'] is List) { List results = List.from(response['results']); final List filteredResults = []; final Set seenPlaces = {}; for (final p in results) { final name = p['name_ar'] ?? p['name'] ?? ''; final district = p['district'] ?? ''; final plat = p['latitude']?.toString() ?? '0'; final plng = p['longitude']?.toString() ?? '0'; final dedupeKey = "${name.trim().toLowerCase()}_${district.trim().toLowerCase()}"; if (!seenPlaces.contains(dedupeKey)) { seenPlaces.add(dedupeKey); p['distanceKm'] = (p['distance'] as num).toDouble() / 1000.0; p['latitude'] = plat; p['longitude'] = plng; p['name'] = name; p['address'] = p['full_address'] ?? (district.isNotEmpty ? "$districtุŒ ${p['governorate'] ?? ''}" : (p['governorate'] ?? '')); filteredResults.add(p); } } placesDestination = filteredResults; update(); } } catch (e) { Log.print('Exception in getPlaces: $e'); } } Future getPlacesStart() async { final q = placeStartController.text.trim(); if (q.isEmpty || q.length < 3) { placesStart = []; update(); return; } final lat = passengerLocation.latitude; final lng = passengerLocation.longitude; final country = CountryPolygons.getCountryName(passengerLocation); try { final url = '${AppLink.searchGeocoding}?q=${Uri.encodeComponent(q)}&lat=$lat&lng=$lng&radius=15000&country=$country'; final response = await CRUD().getMapSaas(link: url); if (response != null && response['results'] is List) { List list = List.from(response['results']); for (final p in list) { p['distanceKm'] = (p['distance'] as num).toDouble() / 1000.0; p['latitude'] = p['latitude'].toString(); p['longitude'] = p['longitude'].toString(); p['name'] = p['name_ar'] ?? p['name'] ?? ''; p['address'] = p['full_address'] ?? (p['district'] != null ? "${p['district']}ุŒ ${p['governorate'] ?? ''}" : (p['governorate'] ?? '')); } placesStart = list; update(); } } catch (e) { Log.print('Exception in getPlacesStart: $e'); } } Future getPlacesListsWayPoint(int index) async { final q = wayPoint0Controller.text.trim(); if (q.length < 3) return; final lat = passengerLocation.latitude; final lng = passengerLocation.longitude; final country = CountryPolygons.getCountryName(passengerLocation); try { final url = '${AppLink.searchGeocoding}?q=${Uri.encodeComponent(q)}&lat=$lat&lng=$lng&radius=15000&country=$country'; final response = await CRUD().getMapSaas(link: url); if (response != null && response['results'] is List) { List list = List.from(response['results']); for (final p in list) { p['distanceKm'] = (p['distance'] as num).toDouble() / 1000.0; p['latitude'] = p['latitude'].toString(); p['longitude'] = p['longitude'].toString(); p['name'] = p['name_ar'] ?? p['name'] ?? ''; p['address'] = p['full_address'] ?? (p['district'] != null ? "${p['district']}ุŒ ${p['governorate'] ?? ''}" : (p['governorate'] ?? '')); } wayPoint0 = list; placeListResponseAll[index] = list; update(); } } catch (e) { Log.print('Error fetching places in WayPoint: $e'); } } Future getReverseGeocoding(LatLng location) async { final lat = location.latitude; final lng = location.longitude; final url = '${AppLink.reverseGeocoding}?lat=$lat&lng=$lng'; try { final response = await CRUD().getMapSaas(link: url); if (response != null && response is List && response.isNotEmpty) { final data = response[0]; String name = data['name_ar'] ?? data['name'] ?? 'Unknown Location'.tr; return name; } return 'Unknown Location'.tr; } catch (e) { Log.print('ReverseGeocoding Exception: $e'); return 'Unknown Location'.tr; } } void updateCurrentLocationFromCamera(LatLng target) { Log.print('๐Ÿ“ updateCurrentLocationFromCamera: $target'); newMyLocation = target; if (startLocationFromMap == true) { Log.print('๐Ÿ“ Updating startLocationFromMap to $target'); newStartPointLocation = target; } else if (passengerStartLocationFromMap == true) { Log.print('๐Ÿ“ Updating passengerStartLocationFromMap to $target'); newStartPointLocation = target; } int waypointsLength = Get.find().wayPoints.length; if (waypointsLength > 0 && wayPointIndex >= 0 && wayPointIndex < placesCoordinate.length) { Log.print('๐Ÿ“ Updating wayPointIndex $wayPointIndex to $target'); placesCoordinate[wayPointIndex] = '${target.latitude},${target.longitude}'; } if (Get.isRegistered()) { final rideLifecycle = Get.find(); rideLifecycle.getLocationArea(target.latitude, target.longitude); rideLifecycle.resetNoRideSearch(); } update(); } void onCameraMoveThrottled(CameraPosition pos) { _camThrottle?.cancel(); _camThrottle = Timer(const Duration(milliseconds: 160), () { Log.print('๐Ÿ“ธ onCameraMoveThrottled: ${pos.target}'); int waypointsLength = Get.find().wayPoints.length; int index = wayPointIndex; if (waypointsLength > 0 && index < placesCoordinate.length) { placesCoordinate[index] = '${pos.target.latitude},${pos.target.longitude}'; } newMyLocation = pos.target; }); } void convertHintTextPlaces(int index, var res) { if (placeListResponseAll[index].isEmpty) { placeListResponseAll[index] = res; hintTextwayPointStringAll[index] = 'Search for your Start point'.tr; update(); } else { hintTextwayPointStringAll[index] = res['name']; currentLocationStringAll[index] = res['name']; placesCoordinate[index] = '${res['geometry']['location']['lat']},${res['geometry']['location']['lng']}'; placeListResponseAll[index] = []; allTextEditingPlaces[index].clear(); update(); Get.back(); } } void convertHintTextDestinationNewPlaces(int index) { if (placesDestination.isEmpty) { hintTextDestinationPoint = 'Search for your destination'.tr; update(); } else { var res = placesDestination[index]; hintTextDestinationPoint = res['displayName']?['text'] ?? res['formattedAddress'] ?? res['name'] ?? 'Unknown Place'; double? lat = res['location']?['latitude'] ?? double.tryParse(res['latitude']?.toString() ?? ''); double? lng = res['location']?['longitude'] ?? double.tryParse(res['longitude']?.toString() ?? ''); if (lat != null && lng != null) { newMyLocation = LatLng(lat, lng); final mapEngine = Get.find(); mapEngine.mapController ?.animateCamera(CameraUpdate.newLatLngZoom(newMyLocation, 16)); } update(); } } void convertHintTextDestinationNewPlacesFromRecent( List recentLocations, int index) { hintTextDestinationPoint = recentLocations[index]['name']; double lat = recentLocations[index]['latitude']; double lng = recentLocations[index]['longitude']; newMyLocation = LatLng(lat, lng); final mapEngine = Get.find(); mapEngine.mapController ?.animateCamera(CameraUpdate.newLatLngZoom(newMyLocation, 16)); update(); } void clearPlacesDestination() { placesDestination = []; hintTextDestinationPoint = 'Search for your destination'.tr; update(); } void clearPlacesStart() { placesStart = []; hintTextStartPoint = 'Search for your Start point'.tr; update(); } void clearPlaces(int index) { placeListResponseAll[index] = []; hintTextwayPointStringAll[index] = 'Search for waypoint'.tr; update(); } Future?> extractCoordinatesFromLinkAsync( String link) async { try { if (link.startsWith('geo:') || link.startsWith('google.navigation:')) { RegExp regex = RegExp(r'(-?\d+\.\d+)[,/~=](-?\d+\.\d+)'); var match = regex.firstMatch(link); if (match != null) { double lat = double.parse(match.group(1)!); double lng = double.parse(match.group(2)!); if (lat > 40 && lat > lng) { double temp = lat; lat = lng; lng = temp; } return {'latitude': lat, 'longitude': lng}; } } int urlStartIndex = link.indexOf(RegExp(r'https?://')); if (urlStartIndex == -1) return null; String cleanLink = link.substring(urlStartIndex).trim(); Uri uri = Uri.parse(cleanLink); String finalUrl = cleanLink; if (cleanLink.contains('goo.gl') || cleanLink.contains('maps.google.com')) { try { var response = await http.get(uri).timeout(const Duration(seconds: 5)); finalUrl = response.request?.url.toString() ?? cleanLink; } catch (e) { Log.print('Redirect logic failed, using original: $e'); } } RegExp regex = RegExp(r'(-?\d+\.\d+)[,/~](-?\d+\.\d+)'); var match = regex.firstMatch(finalUrl); if (match != null) { double lat = double.parse(match.group(1)!); double lng = double.parse(match.group(2)!); if (lat > 40 && lat > lng) { Log.print("โš ๏ธ Detected Swapped Coordinates in Link. Correcting..."); double temp = lat; lat = lng; lng = temp; } return { 'latitude': lat, 'longitude': lng, }; } } catch (e) { Log.print('Error parsing location link: $e'); } return null; } void handleWhatsAppLink(String link) async { Map? coordinates = await extractCoordinatesFromLinkAsync(link); if (coordinates != null) { latitudeWhatsApp = coordinates['latitude']!; longitudeWhatsApp = coordinates['longitude']!; Log.print( 'Extracted coordinates: Lat: $latitudeWhatsApp, Long: $longitudeWhatsApp'); } else { Log.print('Failed to extract coordinates from the link'); } } void goToWhatappLocation() async { if (sosFormKey.currentState!.validate()) { Map? coordinates = await extractCoordinatesFromLinkAsync(whatsAppLocationText.text); if (coordinates != null) { latitudeWhatsApp = coordinates['latitude']!; longitudeWhatsApp = coordinates['longitude']!; Log.print( '๐Ÿ“ Final Coordinates for OSM: Lat: $latitudeWhatsApp, Lng: $longitudeWhatsApp'); final mapEngine = Get.find(); mapEngine.changeIsWhatsAppOrder(true); Get.back(); myDestination = LatLng(latitudeWhatsApp, longitudeWhatsApp); if (passengerLocation != null) { await mapEngine.mapController?.animateCamera(CameraUpdate.newLatLng( LatLng(passengerLocation.latitude, passengerLocation.longitude))); } mapEngine.changeMainBottomMenuMap(); passengerStartLocationFromMap = true; mapEngine.isPickerShown = true; update(); } else { mySnackbarWarning('ู„ู… ู†ุชู…ูƒู† ู…ู† ุงุณุชุฎุฑุงุฌ ุงู„ู…ูˆู‚ุน ู…ู† ุงู„ุฑุงุจุท'); } } } void addMenuWaypoint() { if (activeMenuWaypointCount >= 2) return; activeMenuWaypointCount++; final mapEngine = Get.find(); mapEngine.mainBottomMenuMapHeight = Get.height * .6 + (activeMenuWaypointCount * 56); update(); } void removeMenuWaypoint(int index) { if (index < 0 || index >= 2) return; if (index == 0 && activeMenuWaypointCount == 2) { menuWaypoints[0] = menuWaypoints[1]; menuWaypointNames[0] = menuWaypointNames[1]; } menuWaypoints[activeMenuWaypointCount - 1] = null; menuWaypointNames[activeMenuWaypointCount - 1] = ''; activeMenuWaypointCount--; final mapEngine = Get.find(); mapEngine.mainBottomMenuMapHeight = Get.height * .6 + (activeMenuWaypointCount * 56); update(); } void clearAllMenuWaypoints() { menuWaypoints = [null, null]; menuWaypointNames = ['', '']; activeMenuWaypointCount = 0; isPickingWaypoint = false; pickingWaypointIndex = -1; update(); } void startPickingWaypointOnMap(int index) { pickingWaypointIndex = index; isPickingWaypoint = true; final mapEngine = Get.find(); mapEngine.isPickerShown = true; mapEngine.heightPickerContainer = 150; mapEngine.isMainBottomMenuMap = true; mapEngine.mainBottomMenuMapHeight = Get.height * .22; update(); } void setMenuWaypointFromMap(int index, LatLng position) { Log.print('๐Ÿ“ setMenuWaypointFromMap called: index=$index, pos=$position'); if (index < 0 || index >= 2) return; menuWaypoints[index] = position; menuWaypointNames[index] = '${position.latitude.toStringAsFixed(4)}, ${position.longitude.toStringAsFixed(4)}'; isPickingWaypoint = false; pickingWaypointIndex = -1; final mapEngine = Get.find(); mapEngine.isPickerShown = false; mapEngine.isMainBottomMenuMap = false; mapEngine.mainBottomMenuMapHeight = Get.height * .6 + (activeMenuWaypointCount * 56); update(); } void setMenuWaypointFromSearch(int index, LatLng pos, String name) { if (index < 0 || index >= 2) return; menuWaypoints[index] = pos; menuWaypointNames[index] = name; update(); } String buildOsrmWaypointCoords() { String coords = ''; for (int i = 0; i < activeMenuWaypointCount; i++) { final wp = menuWaypoints[i]; if (wp != null) { coords += ';${wp.longitude},${wp.latitude}'; } } return coords; } void changeHeightPointsPageForRider() { final mapEngine = Get.find(); mapEngine.isPointsPageForRider = !mapEngine.isPointsPageForRider; mapEngine.heightPointsPageForRider = mapEngine.isPointsPageForRider == true ? Get.height : 0; update(); } getCoordinateFromMapWayPoints(int index) { placesCoordinate[index] = newStartPointLocation.toString(); update(); } void addWaypoint(Map placeDetails) { waypoints.add(placeDetails); update(); } void removeWaypoint(int index) { if (index >= 0 && index < waypoints.length) { waypoints.removeAt(index); update(); } } getFavioratePlaces() async { recentPlaces = await sql.getCustomQuery( 'SELECT * FROM ${TableName.recentLocations} ORDER BY createdAt DESC'); update(); } void _listenForDeepLink() { ever(_deepLinkController.rawDeepLink, (String? link) async { if (link != null && link.isNotEmpty) { Log.print('๐Ÿ“ MapPassengerController processing link: $link'); Map? coordinates = await extractCoordinatesFromLinkAsync(link); if (coordinates != null) { double destLat = coordinates['latitude']!; double destLng = coordinates['longitude']!; myDestination = LatLng(destLat, destLng); if (passengerLocation == null || (passengerLocation.latitude == 0 && passengerLocation.longitude == 0)) { Log.print('โณ Waiting for current location to calculate route...'); await getLocation(); } if (passengerLocation != null) { String originStr = '${passengerLocation.latitude},${passengerLocation.longitude}'; String destStr = '$destLat,$destLng'; Log.print( '๐Ÿš€ Drawing route from Deep Link: $originStr to $destStr'); final mapEngine = Get.find(); mapEngine.clearPolyline(); waypoints.clear(); clearAllMenuWaypoints(); final rideLife = Get.find(); await rideLife.getDirectionMap(originStr, destStr); mapEngine.isBottomSheetShown = true; mapEngine.heightBottomSheetShown = 250; update(); Get.snackbar( 'Location Received'.tr, 'Route and prices have been calculated successfully!'.tr, backgroundColor: AppColor.greenColor, colorText: Colors.white, ); } } else { Log.print('โš ๏ธ Could not extract valid coordinates from link: $link'); } _deepLinkController.rawDeepLink.value = null; } }); if (_deepLinkController.rawDeepLink.value != null && _deepLinkController.rawDeepLink.value!.isNotEmpty) { String link = _deepLinkController.rawDeepLink.value!; _deepLinkController.rawDeepLink.value = null; Future.delayed(const Duration(milliseconds: 500), () async { Log.print( '๐Ÿ“ MapPassengerController processing link (Cold Start): $link'); Map? coordinates = await extractCoordinatesFromLinkAsync(link); if (coordinates != null) { double destLat = coordinates['latitude']!; double destLng = coordinates['longitude']!; myDestination = LatLng(destLat, destLng); if (passengerLocation == null || (passengerLocation.latitude == 0 && passengerLocation.longitude == 0)) { await getLocation(); } if (passengerLocation != null) { String originStr = '${passengerLocation.latitude},${passengerLocation.longitude}'; String destStr = '$destLat,$destLng'; final mapEngine = Get.find(); mapEngine.clearPolyline(); waypoints.clear(); clearAllMenuWaypoints(); final rideLife = Get.find(); await rideLife.getDirectionMap(originStr, destStr); mapEngine.isBottomSheetShown = true; mapEngine.heightBottomSheetShown = 250; update(); } } }); } } // --- Polygon Math and University Check Methods --- bool isPointInPolygon(LatLng point, List polygon) { int intersections = 0; for (int i = 0; i < polygon.length; i++) { LatLng vertex1 = polygon[i]; LatLng vertex2 = polygon[(i + 1) % polygon.length]; if (_rayIntersectsSegment(point, vertex1, vertex2)) { intersections++; } } return intersections % 2 != 0; } bool _rayIntersectsSegment(LatLng point, LatLng vertex1, LatLng vertex2) { double px = point.longitude; double py = point.latitude; double v1x = vertex1.longitude; double v1y = vertex1.latitude; double v2x = vertex2.longitude; double v2y = vertex2.latitude; if ((py < v1y && py < v2y) || (py > v1y && py > v2y)) { return false; } double intersectX = v1x + (py - v1y) * (v2x - v1x) / (v2y - v1y); return intersectX > px; } String checkPassengerLocation(LatLng passengerLocation, List> universityPolygons, List universityNames) { for (int i = 0; i < universityPolygons.length; i++) { if (isPointInPolygon(passengerLocation, universityPolygons[i])) { isInUniversity = true; return "Passenger is in ${universityNames[i]}"; } } return "Passenger is not in any university"; } void getPassengerLocationUniversity() { passengerLocationStringUnvirsity = checkPassengerLocation( passengerLocation, UniversitiesPolygons.universityPolygons, UniversitiesPolygons.universityNames, ); Log.print(passengerLocationStringUnvirsity); } void getMapPointsForAllMethods() async { final mapEngine = Get.find(); final rideLife = Get.find(); mapEngine.clearPolyline(); mapEngine.isMarkersShown = false; mapEngine.isWayPointStopsSheetUtilGetMap = false; mapEngine.isWayPointSheet = false; rideLife.durationToRide = 0; rideLife.distanceOfDestination = 0; mapEngine.wayPointSheetHeight = 0; rideLife.remainingTime = 25; rideLife.haveSteps = true; // Filter out empty value coordinatesWithoutEmpty = placesCoordinate.where((coord) => coord.isNotEmpty).toList(); latestPosition = LatLng( double.parse(coordinatesWithoutEmpty.last.split(',')[0]), double.parse(coordinatesWithoutEmpty.last.split(',')[1])); for (var i = 0; i < coordinatesWithoutEmpty.length; i++) { if ((i + 1) < coordinatesWithoutEmpty.length) { await rideLife.getMapPoints( coordinatesWithoutEmpty[i].toString(), coordinatesWithoutEmpty[i + 1].toString(), i, ); if (i == 0) { startNameAddress = rideLife.data[0]['start_address']; } if (i == coordinatesWithoutEmpty.length - 1) { endNameAddress = rideLife.data[0]['end_address']; } } } if (rideLife.haveSteps) { String latestWaypoint = placesCoordinate.lastWhere((coord) => coord.isNotEmpty); update(); } } double _haversineKm(double lat1, double lon1, double lat2, double lon2) { const double r = 6371.0; double dLat = (lat2 - lat1) * pi / 180.0; double dLon = (lon2 - lon1) * pi / 180.0; double a = sin(dLat / 2) * sin(dLat / 2) + cos(lat1 * pi / 180.0) * cos(lat2 * pi / 180.0) * sin(dLon / 2) * sin(dLon / 2); double c = 2 * atan2(sqrt(a), sqrt(1 - a)); return r * c; } double _kmToLatDelta(double km) { return km / 111.0; } double _kmToLngDelta(double km, double lat) { return km / (111.0 * cos(lat * pi / 180.0)); } String _buildOsrmWaypointCoords() { String coords = ''; for (int i = 0; i < activeMenuWaypointCount; i++) { final wp = menuWaypoints[i]; if (wp != null) { coords += ';${wp.longitude},${wp.latitude}'; } } return coords; } @override void onClose() { _camThrottle?.cancel(); super.onClose(); } }