import 'dart:async'; import 'dart:convert'; import 'dart:math' show cos; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:google_polyline_algorithm/google_polyline_algorithm.dart'; import 'package:location/location.dart'; import 'package:ride/constant/box_name.dart'; import 'package:ride/constant/credential.dart'; import 'package:ride/constant/links.dart'; import 'package:ride/controller/firebase/firbase_messge.dart'; import 'package:ride/controller/functions/crud.dart'; import 'package:ride/controller/functions/secure_storage.dart'; import 'package:ride/views/widgets/elevated_btn.dart'; import '../../main.dart'; import '../../models/model/locations.dart'; class MapController extends GetxController { bool isloading = true; TextEditingController placeController = TextEditingController(); List data = []; List bounds = []; List places = []; LatLngBounds? boundsdata; List markers = []; List polylines = []; late LatLng mylocation; late LatLng newMylocation = const LatLng(32.115295, 36.064773); LatLng mydestination = const LatLng(32.115295, 36.064773); final List polylineCoordinates = []; List carsLocationByPassenger = []; BitmapDescriptor markerIcon = BitmapDescriptor.defaultMarker; BitmapDescriptor carIcon = BitmapDescriptor.defaultMarker; double height = 150; final location = Location(); late LocationData currentLocation; double heightMenu = 0; double widthMenu = 0; double heightPickerContainer = 90; double mainBottomMenuMap = Get.height * .2; bool heightMenuBool = false; bool isPickerShown = false; bool isButtomSheetShown = false; bool mapType = false; bool mapTraficON = false; bool isCancelRidePageShown = false; bool isCashConfirmPageShown = false; bool isPaymentMethodPageShown = false; bool rideConfirm = false; bool isMainBottomMenuMap = true; double heightButtomSheetShown = 0; double cashConfirmPageShown = 250; double widthMapTypeAndTrafic = 50; double paymentPageShown = Get.height * .6; late LatLng southwest; late LatLng northeast; List carLocations = []; var dataCarsLocationByPassenger; CarLocation? nearestCar; late Timer markerReloadingTimer; int selectedPassengerCount = 1; void onChangedPassengerCount(int newValue) { selectedPassengerCount = newValue; update(); } // final mainBottomMenuMap = GlobalKey(); void changeButtomSheetShown() { isButtomSheetShown = !isButtomSheetShown; heightButtomSheetShown = isButtomSheetShown == true ? 250 : 0; update(); } void changeCashConfirmPageShown() { isCashConfirmPageShown = !isCashConfirmPageShown; cashConfirmPageShown = isCashConfirmPageShown == true ? 250 : 0; update(); } void changePaymentMethodPageShown() { isPaymentMethodPageShown = !isPaymentMethodPageShown; paymentPageShown = isPaymentMethodPageShown == true ? Get.height * .6 : 0; update(); } void changeMapType() { mapType = !mapType; // heightButtomSheetShown = isButtomSheetShown == true ? 240 : 0; update(); } void changeMapTraffic() { mapTraficON = !mapTraficON; update(); } void changeCancelRidePageShow() { // rideConfirm == true // ? isCancelRidePageShown = !isCancelRidePageShown; // : cancelRide(); update(); } void getDrawerMenu() { heightMenuBool = !heightMenuBool; widthMapTypeAndTrafic = heightMenuBool == true ? 0 : 50; heightMenu = heightMenuBool == true ? 100 : 0; widthMenu = heightMenuBool == true ? 110 : 0; update(); } void clearPlaces() { places = []; update(); } int selectedReason = -1; String? cancelNote; void selectReason(int index, String note) { selectedReason = index; cancelNote = note; update(); } changeConfirmRide() async { rideConfirm = true; print('rideConfirm= $rideConfirm'); await CRUD().post(link: AppLink.addRides, payload: { "start_location": '${data[0]['start_address']}', // '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}', "end_location": '${data[0]['end_address']}', // '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}', "date": DateTime.now().toString(), "time": DateTime.now().toString(), "endtime": durationToAdd.toString(), "price": totalPassenger.toString(), "passenger_id": box.read(BoxName.pasengerID).toString(), "driver_id": dataCarsLocationByPassenger['message'][0]['id'].toString(), "status": "active", "price_for_driver": totalDriver.toString(), "price_for_passenger": totaME.toString(), "distance": distance.toString() }).then((value) { // print(jsonDecode(value)['message']); List body = [ // '${data[0]['start_address']}', // '${data[0]['end_address']}', '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}', '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}', totalPassenger.toString(), totalDriver.toString(), duration.toString(), distance.toString(), dataCarsLocationByPassenger['message'][0]['id'].toString(), box.read(BoxName.pasengerID).toString() ]; FirebasMessagesController().sendNotificationDriverId( 'Order', jsonDecode(value)['message'].toString(), body[0], body[1], body[2], body[3], body[4], body[5], body[6], body[7], box.read(BoxName.tokenFCM).toString(), //TODO change to Driver ); }); update(); } Future cancelRide() async { print(rideConfirm); if (rideConfirm == false) { clearPlaces(); clearpolyline(); data = []; changeCancelRidePageShow(); update(); } else { clearPlaces(); clearpolyline(); data = []; changeCancelRidePageShow(); await CRUD().post(link: AppLink.addCancelRide, payload: { "driverID": "1", // Convert to String "passengerID": box.read(BoxName.pasengerID).toString(), // Convert to String "rideID": "222", // Convert to String "note": cancelNote }); update(); } } void changePickerShown() { isPickerShown = !isPickerShown; heightPickerContainer = isPickerShown == true ? 150 : 90; update(); } void changeMainBottomMenuMap() { isMainBottomMenuMap = !isMainBottomMenuMap; mainBottomMenuMap = isMainBottomMenuMap == true ? Get.height * .2 : Get.height * .66; if (heightMenuBool == true) { getDrawerMenu(); } update(); } changeHeight() { if (places.isEmpty) { height = 0; update(); } height = 150; update(); } hidePlaces() { height = 0; update(); } Future getPlaces() async { var url = // '${AppLink.googleMapsLink}place/nearbysearch/json?location=${mylocation.longitude}&radius=25000&language=ar&keyword=&key=${placeController.text}${AppCredintials.mapAPIKEY}'; '${AppLink.googleMapsLink}place/nearbysearch/json?keyword=${placeController.text}&location=${mylocation.latitude},${mylocation.longitude}&radius=50000&language=ar&key=${AppCredintials.mapAPIKEY}'; var response = await CRUD().getGoogleApi(link: url, payload: {}); places = response['results']; print(places); update(); } LatLng fromString(String location) { List parts = location.split(','); double lat = double.parse(parts[0]); double lng = double.parse(parts[1]); return LatLng(lat, lng); } void clearpolyline() { polylines = []; polylineCoordinates.clear(); update(); } void addCustomPicker() { ImageConfiguration config = const ImageConfiguration( size: Size(20, 20), // scale: 1.0, ); BitmapDescriptor.fromAssetImage(config, 'assets/images/picker.png') .then((value) { markerIcon = value; update(); }); } void addCustomCarIcon() { ImageConfiguration config = const ImageConfiguration( size: Size(50, 50), // scale: 1.0, ); BitmapDescriptor.fromAssetImage(config, 'assets/images/car.png') .then((value) { carIcon = value; update(); }); } Future getLocation() async { isloading = true; update(); bool serviceEnabled; PermissionStatus permissionGranted; // Check if location services are enabled serviceEnabled = await location.serviceEnabled(); if (!serviceEnabled) { serviceEnabled = await location.requestService(); if (!serviceEnabled) { // Location services are still not enabled, handle the error return; } } // Check if the app has permission to access location permissionGranted = await location.hasPermission(); if (permissionGranted == PermissionStatus.denied) { permissionGranted = await location.requestPermission(); if (permissionGranted != PermissionStatus.granted) { // Location permission is still not granted, handle the error return; } } // Configure location accuracy LocationAccuracy desiredAccuracy = LocationAccuracy.high; // Get the current location LocationData _locationData = await location.getLocation(); mylocation = (_locationData.latitude != null && _locationData.longitude != null ? LatLng(_locationData.latitude!, _locationData.longitude!) : null)!; // Print location details print('Accuracy: ${_locationData.accuracy}'); print('Latitude: ${_locationData.latitude}'); print('Longitude: ${_locationData.longitude}'); print('Time: ${_locationData.time}'); isloading = false; update(); } Future getCarsLocationByPassenger() async { carsLocationByPassenger = []; LatLngBounds bounds = calculateBounds(mylocation.latitude, mylocation.longitude, 10); print( 'Southwest: ${bounds.southwest.latitude}, ${bounds.southwest.longitude}'); print( 'Northeast: ${bounds.northeast.latitude}, ${bounds.northeast.longitude}'); var res = await CRUD().get(link: AppLink.getCarsLocationByPassenger, payload: { 'southwestLat': southwest.latitude.toString(), 'southwestLon': southwest.longitude.toString(), 'northeastLat': northeast.latitude.toString(), 'northeastLon': northeast.longitude.toString(), }); if (res == 'failure') { Get.defaultDialog( title: 'No Car in your site.Sorry!', middleText: '', confirm: MyElevatedButton( title: 'Back', onPressed: () { Get.back(); markerReloadingTimer.cancel(); })); } else { dataCarsLocationByPassenger = jsonDecode(res); // print(dataCarsLocationByPassenger); for (var i = 0; i < dataCarsLocationByPassenger['message'].length; i++) { carsLocationByPassenger.add(LatLng( double.parse(dataCarsLocationByPassenger['message'][i]['latitude']), double.parse( dataCarsLocationByPassenger['message'][i]['longitude']))); } update(); } } LatLngBounds calculateBounds( double centerLat, double centerLng, double radius) { double radius = 2000; // 10 km in meters southwest = LatLng( centerLat - (radius / 111000), centerLng - (radius / (111000 * cos(centerLat))), ); northeast = LatLng( centerLat + (radius / 111000), centerLng + (radius / (111000 * cos(centerLat))), ); return LatLngBounds(southwest: southwest, northeast: northeast); } GoogleMapController? mapController; void onMapCreated(GoogleMapController controller) { mapController = controller; controller.getVisibleRegion(); controller.animateCamera( CameraUpdate.newLatLng(mylocation), ); update(); } // void startMarkerReloading() { // markerReloadingTimer = Timer.periodic(const Duration(seconds: 30), (timer) { // print('timer=============================='); // reloadMarkers(); // }); // } late Timer markerReloadingTimer2; late Timer markerReloadingTimer1; late int duration1; void startMarkerReloading() { // Schedule timer 1 to reload markers at a specific time DateTime scheduledTime1 = DateTime.now().add(const Duration(seconds: 30)); markerReloadingTimer1 = Timer(scheduledTime1.difference(DateTime.now()), () { print('timer 1 =============================='); reloadMarkers(); }); // Schedule timer 2 to reload markers at a specific time DateTime scheduledTime2 = DateTime.now().add(const Duration(seconds: 60)); markerReloadingTimer2 = Timer(scheduledTime2.difference(DateTime.now()), () { print('timer 2 =============================='); reloadMarkers(); }); } void reloadMarkers() async { //TODO await getCarsLocationByPassenger(); // Clear existing markers markers.clear(); getNearestDriverByPassengerLocation(); // Add new markers // Example: Add a marker for each item in a list for (var item in carsLocationByPassenger) { final marker = Marker( infoWindow: InfoWindow(title: '${item.latitude} minutes'), markerId: MarkerId(duration1.toString()), position: LatLng(item.latitude, item.longitude), // Other properties for the marker, such as icon, info window, etc. ); markers.add(marker); } // Update the map with the new markers mapController?.animateCamera(CameraUpdate.newLatLng( LatLng(mylocation.latitude, mylocation.longitude))); } String duratioByPassenger = ''; void getNearestDriverByPassengerLocation() async { if (polylines.isEmpty || data.isEmpty) { double nearestDistance = double.infinity; for (var i = 0; i < dataCarsLocationByPassenger['message'].length; i++) { var carLocation = dataCarsLocationByPassenger['message'][i]; // double distance1 = Geolocator.distanceBetween( // mylocation.latitude, // mylocation.longitude, // double.parse(carLocation['latitude']), // double.parse(carLocation['longitude']), // ); // if (distance1 < nearestDistance) { // nearestDistance = distance1; // // nearestCarLocation = carLocation; // nearestCar = CarLocation( // distance: distance1, // id: carLocation['driver_id'], // latitude: double.parse(carLocation['latitude']), // longitude: double.parse(carLocation['longitude']), // ); // } isloading = true; update(); // Make API request to get exact distance and duration String apiUrl = '${AppLink.googleMapsLink}distancematrix/json?destinations=${carLocation['latitude']},${carLocation['longitude']}&origins=${mylocation.latitude},${mylocation.longitude}&units=metric&key=${AppCredintials.mapAPIKEY}'; var response = await CRUD().getGoogleApi(link: apiUrl, payload: {}); if (response['status'] == "OK") { var data = response; // Extract distance and duration from the response and handle accordingly int distance1 = data['rows'][0]['elements'][0]['distance']['value']; duration1 = data['rows'][0]['elements'][0]['duration']['value']; duratioByPassenger = data['rows'][0]['elements'][0]['duration']['text']; if (distance1 < nearestDistance) { nearestDistance = distance1.toDouble(); nearestCar = CarLocation( distance: distance1.toDouble(), duration: duration1.toDouble(), id: carLocation['driver_id'], latitude: double.parse(carLocation['latitude']), longitude: double.parse(carLocation['longitude']), ); isloading = false; update(); } } // Handle the distance and duration as needed else { print( 'Failed to retrieve distance and duration: ${response['status']}'); // Handle the failure case } } } print(nearestCar!.distance); print(nearestCar!.duration); print(nearestCar!.latitude); print(nearestCar!.longitude); print(nearestCar!.id); } late LatLngBounds boundsData; getMap(String origin, destination) async { var origin1 = fromString(origin); var destination1 = fromString(destination); isloading = false; mydestination = destination1; mylocation = origin1; update(); await getCarsLocationByPassenger(); // print(carsLocationByPassenger); var url = ('${AppLink.googleMapsLink}directions/json?&language=en&avoid=tolls|ferries&destination=$destination&origin=$origin&key=${AppCredintials.mapAPIKEY}'); var response = await CRUD().getGoogleApi(link: url, payload: {}); data = response['routes'][0]['legs']; print(data); final points = decodePolyline(response["routes"][0]["overview_polyline"]["points"]); for (int i = 0; i < points.length; i++) { double lat = points[i][0].toDouble(); double lng = points[i][1].toDouble(); polylineCoordinates.add(LatLng(lat, lng)); } // Define the northeast and southwest coordinates final bounds = response["routes"][0]["bounds"]; LatLng northeast = LatLng(bounds['northeast']['lat'], bounds['northeast']['lng']); LatLng southwest = LatLng(bounds['southwest']['lat'], bounds['southwest']['lng']); // Create the LatLngBounds object boundsData = LatLngBounds(northeast: northeast, southwest: southwest); // Calculate the zoom level based on the distance and screen size double distanceOfDestnation = getDistanceFromText(data[0]['distance']['text']); // Animate the camera to the adjusted bounds if (distanceOfDestnation <= 5) { mapController!.animateCamera(CameraUpdate.newLatLngZoom(mylocation, 14)); } else if (distanceOfDestnation > 5 && distanceOfDestnation <= 8) { mapController!.animateCamera(CameraUpdate.newLatLngZoom(mylocation, 13)); } else if (distanceOfDestnation > 8 && distanceOfDestnation < 16) { mapController!.animateCamera(CameraUpdate.newLatLngZoom(mylocation, 12)); } else if (distanceOfDestnation >= 16 && distanceOfDestnation < 30) { mapController!.animateCamera(CameraUpdate.newLatLngZoom(mylocation, 11)); } else if (distanceOfDestnation >= 30 && distanceOfDestnation < 100) { mapController!.animateCamera(CameraUpdate.newLatLngZoom(mylocation, 10)); } else if (distanceOfDestnation >= 100) { mapController!.animateCamera(CameraUpdate.newLatLngZoom(mylocation, 7)); } if (polylines.isNotEmpty) { clearpolyline(); } else { var polyline = Polyline( polylineId: PolylineId(response["routes"][0]["summary"]), points: polylineCoordinates, width: 10, color: Colors.blue, ); polylines.add(polyline); rideConfirm = false; update(); } } showBottomSheet1() async { bottomSheet(); isButtomSheetShown = true; heightButtomSheetShown = 250; update(); } final promo = TextEditingController(); bool promoTaken = false; void applyPromoCodetoPassenger() async { //TAWJIHI CRUD().get(link: AppLink.getPassengersPromo, payload: { 'promo_code': promo.text, }).then((value) { if (value == 'failure') { Get.defaultDialog( title: 'Promo End !'.tr, confirm: MyElevatedButton( title: 'Back', onPressed: () { Get.back(); Get.back(); }, )); } var decod = jsonDecode(value); if (decod["status"] == "success") { print(totalPassenger); var firstElement = decod["message"][0]; totalPassenger = totalPassenger - (totalPassenger * int.parse(firstElement['amount']) / 100); promoTaken = true; update(); print(totalPassenger); Get.back(); } }); } double getDistanceFromText(String distanceText) { // Remove any non-digit characters from the distance text String distanceValue = distanceText.replaceAll(RegExp(r'[^0-9.]+'), ''); // Parse the extracted numerical value as a double double distance = double.parse(distanceValue); return distance; } late double totaME = 0; late double tax = 0; late double totalPassenger = 0; late double totalDriver = 0; late double averageDuration = 0; late double costDuration = 0; late double cost = 0; late double distance = 0; late double duration = 0; DateTime currentTime = DateTime.now(); late Duration durationToAdd; late DateTime newTime = DateTime.now(); Future bottomSheet() async { if (data.isNotEmpty) { String distanceText = await data[0]['distance']['text']; String durationText = await data[0]['duration']['text']; print(data[0]['duration']['text']); print('================================='); distance = getDistanceFromText(distanceText); duration = getDistanceFromText(durationText); durationToAdd = Duration(minutes: duration.toInt()); DateTime currentTime = DateTime.now(); newTime = currentTime.add(durationToAdd); averageDuration = duration / distance; costDuration = duration * averageDuration * 0.016; totalDriver = cost + costDuration; totalPassenger = totalDriver + (totalDriver * .16); tax = totalPassenger * .04; totaME = totalPassenger - totalDriver - tax; update(); if (currentTime.hour >= 21) { if (distanceText.contains('km')) { cost = distance * 0.23; update(); } else { cost = distance * 0.23 / 1000; update(); } } else if (currentTime.hour < 5) { if (distanceText.contains('km')) { cost = distance * 0.25; update(); } else { cost = distance * 0.25 / 1000; update(); } } else if (currentTime.hour >= 13 && currentTime.hour <= 16) { if (averageDuration > 2.5) { if (distanceText.contains('km')) { cost = distance * 0.23; update(); } else { cost = distance * 0.25 / 1000; update(); } } else { if (distanceText.contains('km')) { cost = distance * 0.21; update(); } else { cost = distance * 0.21 / 1000; update(); } } } else { if (distanceText.contains('km')) { cost = distance * 0.21; update(); } else { cost = distance * 0.21 / 1000; update(); } } if (totalPassenger < 1) { totalPassenger = 1; update(); if (totalDriver < .5) { totalDriver = .85; totaME = .11; update(); } else { totalDriver = .95; totaME = .05; update(); } } // buttomSheetMapPage(); changeButtomSheetShown(); } // Get.bottomSheet( // Container( // height: 130, // decoration: const BoxDecoration( // color: AppColor.secondaryColor, // borderRadius: BorderRadius.only( // topLeft: Radius.circular(15), topRight: Radius.circular(15))), // child: data.isEmpty // ? Center( // child: Text( // 'Where are you want to go..', // style: AppStyle.title, // )) // : Center( // child: Column( // children: [ // Row( // mainAxisAlignment: MainAxisAlignment.spaceAround, // children: [ // Text( // 'distance is ${data[0]['distance']['text']}', // style: AppStyle.title, // ), // Text( // 'duration is ${data[0]['duration']['text']}', // style: AppStyle.title, // ), // ], // ), // Row( // mainAxisAlignment: MainAxisAlignment.spaceAround, // children: [ // Text( // 'Cost for .21/km ${cost.toStringAsFixed(2)} ', // style: AppStyle.title, // ), // Text( // 'costDuration ${averageDuration.toStringAsFixed(2)} is ${costDuration.toStringAsFixed(2)} ', // style: AppStyle.title, // ), // ], // ), // Row( // mainAxisAlignment: MainAxisAlignment.spaceAround, // children: [ // Text( // 'Cost for passenger ${totalPassenger.toStringAsFixed(2)} ', // style: AppStyle.title, // ), // Text( // 'totaME ${totaME.toStringAsFixed(2)} ', // style: AppStyle.title, // ), // ], // ), // Text( // 'totalDriver ${totalDriver.toStringAsFixed(2)}', // style: AppStyle.title, // ), // ], // ), // ), // ), // elevation: 6, // enableDrag: true, // isScrollControlled: true, // isDismissible: true, // useRootNavigator: true, // backgroundColor: Colors.transparent, // barrierColor: AppColor.accentColor.withOpacity(.4), // persistent: true, // shape: ShapeBorder.lerp( // RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), // RoundedRectangleBorder(borderRadius: BorderRadius.circular(6)), // 0.5), // ); } List polylineCoordinate = []; String? cardNumber; @override void onInit() async { await getLocation(); await getCarsLocationByPassenger(); getNearestDriverByPassengerLocation(); addCustomPicker(); addCustomCarIcon(); startMarkerReloading(); cardNumber = await SecureStorage().readData(BoxName.cardNumber); super.onInit(); } } class CarLocation { final String id; final double latitude; final double longitude; final double distance; final double duration; CarLocation({ required this.id, required this.latitude, required this.longitude, this.distance = 10000, this.duration = 10000, }); }