5386 lines
191 KiB
Dart
5386 lines
191 KiB
Dart
import 'dart:async';
|
|
import 'dart:convert';
|
|
import 'dart:math' show Random, cos, max, min, pi, pow, sin, sqrt;
|
|
import 'dart:math' as math;
|
|
import 'dart:ui';
|
|
import 'package:SEFER/constant/univeries_polygon.dart';
|
|
import 'package:SEFER/controller/firebase/local_notification.dart';
|
|
import 'package:SEFER/controller/functions/encrypt_decrypt.dart';
|
|
import 'package:flutter/cupertino.dart';
|
|
import 'package:flutter_confetti/flutter_confetti.dart';
|
|
import 'package:vector_math/vector_math.dart' show radians, degrees;
|
|
|
|
import 'package:SEFER/controller/functions/tts.dart';
|
|
import 'package:SEFER/views/home/map_page_passenger.dart';
|
|
import 'package:SEFER/views/widgets/my_textField.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:geolocator/geolocator.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:intl/intl.dart';
|
|
import 'package:location/location.dart';
|
|
import 'package:SEFER/constant/colors.dart';
|
|
import 'package:SEFER/constant/style.dart';
|
|
import 'package:SEFER/controller/home/points_for_rider_controller.dart';
|
|
import 'package:SEFER/views/home/map_widget.dart/form_serch_multiy_point.dart';
|
|
import '../../constant/api_key.dart';
|
|
import '../../constant/box_name.dart';
|
|
import '../../constant/info.dart';
|
|
import '../../constant/links.dart';
|
|
import '../../constant/table_names.dart';
|
|
import '../../main.dart';
|
|
import '../../models/model/locations.dart';
|
|
import '../../models/model/painter_copoun.dart';
|
|
import '../../print.dart';
|
|
import '../../views/home/map_widget.dart/cancel_raide_page.dart';
|
|
import '../../views/home/map_widget.dart/car_details_widget_to_go.dart';
|
|
import '../../views/home/map_widget.dart/select_driver_mishwari.dart';
|
|
import '../../views/widgets/elevated_btn.dart';
|
|
import '../../views/widgets/error_snakbar.dart';
|
|
import '../../views/widgets/mydialoug.dart';
|
|
import '../firebase/firbase_messge.dart';
|
|
import '../functions/audio_record1.dart';
|
|
import '../functions/crud.dart';
|
|
import '../functions/launch.dart';
|
|
import '../functions/secure_storage.dart';
|
|
import '../payment/payment_controller.dart';
|
|
import 'vip_waitting_page.dart';
|
|
|
|
class MapPassengerController extends GetxController {
|
|
bool isLoading = true;
|
|
TextEditingController placeDestinationController = TextEditingController();
|
|
TextEditingController increasFeeFromPassenger = TextEditingController();
|
|
TextEditingController placeStartController = TextEditingController();
|
|
TextEditingController wayPoint0Controller = TextEditingController();
|
|
TextEditingController wayPoint1Controller = TextEditingController();
|
|
TextEditingController wayPoint2Controller = TextEditingController();
|
|
TextEditingController wayPoint3Controller = TextEditingController();
|
|
TextEditingController wayPoint4Controller = TextEditingController();
|
|
TextEditingController sosPhonePassengerProfile = TextEditingController();
|
|
TextEditingController whatsAppLocationText = TextEditingController();
|
|
TextEditingController messageToDriver = TextEditingController();
|
|
final sosFormKey = GlobalKey<FormState>();
|
|
final promoFormKey = GlobalKey<FormState>();
|
|
final messagesFormKey = GlobalKey<FormState>();
|
|
final increaseFeeFormKey = GlobalKey<FormState>();
|
|
List data = [];
|
|
List<LatLng> bounds = [];
|
|
List placesStart = [];
|
|
List<String> driversToken = [];
|
|
LatLng previousLocationOfDrivers = const LatLng(0, 0);
|
|
double angleDegrees = 0;
|
|
LatLng currentLocationOfDrivers = const LatLng(0, 0);
|
|
List<TextEditingController> allTextEditingPlaces = [];
|
|
List placesDestination = [];
|
|
List wayPoint0 = [];
|
|
List wayPoint1 = [];
|
|
List wayPoint2 = [];
|
|
List wayPoint3 = [];
|
|
List wayPoint4 = [];
|
|
|
|
List<List<dynamic>> placeListResponseAll = [];
|
|
|
|
List<Widget> placeListResponse = [
|
|
formSearchPlaces(0),
|
|
formSearchPlaces(1),
|
|
formSearchPlaces(2),
|
|
formSearchPlaces(3),
|
|
];
|
|
LatLngBounds? boundsdata;
|
|
List<Marker> markers = [];
|
|
List<Polyline> polyLines = [];
|
|
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;
|
|
List<LatLng> polylineCoordinates = [];
|
|
List<LatLng> polylineCoordinates0 = [];
|
|
List<LatLng> polylineCoordinates1 = [];
|
|
List<LatLng> polylineCoordinates2 = [];
|
|
List<LatLng> polylineCoordinates3 = [];
|
|
List<LatLng> polylineCoordinates4 = [];
|
|
List<List<LatLng>> polylineCoordinatesPointsAll = [];
|
|
List carsLocationByPassenger = [];
|
|
List<LatLng> driverCarsLocationToPassengerAfterApplied = [];
|
|
BitmapDescriptor markerIcon = BitmapDescriptor.defaultMarker;
|
|
BitmapDescriptor tripIcon = BitmapDescriptor.defaultMarker;
|
|
BitmapDescriptor startIcon = BitmapDescriptor.defaultMarker;
|
|
BitmapDescriptor endIcon = BitmapDescriptor.defaultMarker;
|
|
BitmapDescriptor carIcon = BitmapDescriptor.defaultMarker;
|
|
BitmapDescriptor motoIcon = BitmapDescriptor.defaultMarker;
|
|
BitmapDescriptor ladyIcon = BitmapDescriptor.defaultMarker;
|
|
double height = 150;
|
|
DateTime currentTime = DateTime.now();
|
|
final location = Location();
|
|
late LocationData currentLocation;
|
|
double heightMenu = 0;
|
|
double widthMenu = 0;
|
|
double heightPickerContainer = 90;
|
|
double heightPointsPageForRider = 0;
|
|
double mainBottomMenuMapHeight = Get.height * .2;
|
|
double wayPointSheetHeight = 0;
|
|
String stringRemainingTimeToPassenger = '';
|
|
String stringRemainingTimeDriverWaitPassenger5Minute = '';
|
|
bool isDriverInPassengerWay = false;
|
|
bool isDriverArrivePassenger = false;
|
|
bool startLocationFromMap = false;
|
|
bool isAnotherOreder = false;
|
|
bool isWhatsAppOrder = 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 = [];
|
|
double latePrice = 0;
|
|
double fuelPrice = 0;
|
|
double heavyPrice = 0;
|
|
double naturePrice = 0;
|
|
bool heightMenuBool = false;
|
|
String statusRide = 'wait';
|
|
String statusRideVip = 'wait';
|
|
bool statusRideFromStart = false;
|
|
bool isPickerShown = false;
|
|
bool isPointsPageForRider = false;
|
|
bool isBottomSheetShown = false;
|
|
bool mapType = false;
|
|
bool mapTrafficON = false;
|
|
bool isCancelRidePageShown = false;
|
|
bool isCashConfirmPageShown = false;
|
|
bool isPaymentMethodPageShown = false;
|
|
bool isRideFinished = false;
|
|
bool rideConfirm = false;
|
|
bool isMarkersShown = false;
|
|
bool isMainBottomMenuMap = true;
|
|
late Timer markerReloadingTimer2;
|
|
late Timer markerReloadingTimer1;
|
|
late int durationToPassenger = 0;
|
|
bool isWayPointSheet = false;
|
|
bool isWayPointStopsSheet = false;
|
|
bool isWayPointStopsSheetUtilGetMap = false;
|
|
double heightBottomSheetShown = 0;
|
|
double cashConfirmPageShown = 250;
|
|
late String driverId = '';
|
|
late String gender = '';
|
|
double widthMapTypeAndTraffic = 50;
|
|
double paymentPageShown = Get.height * .6;
|
|
late LatLng southwest;
|
|
late LatLng northeast;
|
|
List<CarLocationModel> carLocationsModels = <CarLocationModel>[];
|
|
var dataCarsLocationByPassenger;
|
|
var datadriverCarsLocationToPassengerAfterApplied;
|
|
CarLocation? nearestCar;
|
|
late Timer markerReloadingTimer;
|
|
bool shouldFetch = true; // Flag to determine if fetch should be executed
|
|
int selectedPassengerCount = 1;
|
|
double progress = 0;
|
|
double progressTimerToPassengerFromDriverAfterApplied = 0;
|
|
double progressTimerDriverWaitPassenger5Minute = 0;
|
|
int durationTimer = 9;
|
|
int durationToRide = 0;
|
|
int remainingTime = 25;
|
|
int remainingTimeToPassengerFromDriverAfterApplied = 60;
|
|
int remainingTimeDriverWaitPassenger5Minute = 60;
|
|
int timeToPassengerFromDriverAfterApplied = 0;
|
|
Timer? timerToPassengerFromDriverAfterApplied;
|
|
bool rideTimerBegin = false;
|
|
double progressTimerRideBegin = 0;
|
|
int remainingTimeTimerRideBegin = 60;
|
|
String stringRemainingTimeRideBegin = '';
|
|
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<String> currentLocationStringAll = [];
|
|
List<String> hintTextwayPointStringAll = [];
|
|
var placesCoordinate = <String>[];
|
|
String hintTextDestinationPoint = 'Select your destination'.tr;
|
|
late String rideId = 'yet';
|
|
bool noCarString = false;
|
|
bool isCashSelectedBeforeConfirmRide = false;
|
|
bool isPassengerChosen = false;
|
|
bool isSearchingWindow = false;
|
|
bool currentLocationToFormPlaces = false;
|
|
bool currentLocationToFormPlaces0 = false;
|
|
bool currentLocationToFormPlaces1 = false;
|
|
bool currentLocationToFormPlaces2 = false;
|
|
bool currentLocationToFormPlaces3 = false;
|
|
bool currentLocationToFormPlaces4 = false;
|
|
List currentLocationToFormPlacesAll = [];
|
|
late String driverToken = '';
|
|
int carsOrder = 0;
|
|
int wayPointIndex = 0;
|
|
late double kazan;
|
|
String? mapAPIKEY;
|
|
late double totalME = 0;
|
|
late double tax = 0;
|
|
late double totalPassenger = 0;
|
|
late double totalCostPassenger = 0;
|
|
late double totalPassengerComfort = 0;
|
|
late double totalPassengerComfortDiscount = 0;
|
|
late double totalPassengerLadyDiscount = 0;
|
|
late double totalPassengerSpeedDiscount = 0;
|
|
late double totalPassengerBalashDiscount = 0;
|
|
late double totalPassengerRaihGaiDiscount = 0;
|
|
late double totalPassengerScooter = 0;
|
|
late double totalDriver = 0;
|
|
late double averageDuration = 0;
|
|
late double costDuration = 0;
|
|
late double costDistance = 0;
|
|
late double distance = 0;
|
|
late double duration = 0;
|
|
|
|
late Duration durationToAdd;
|
|
late DateTime newTime = DateTime.now();
|
|
int hours = 0;
|
|
int minutes = 0;
|
|
void onChangedPassengerCount(int newValue) {
|
|
selectedPassengerCount = newValue;
|
|
update();
|
|
}
|
|
|
|
void onChangedPassengersChoose() {
|
|
isPassengerChosen = true;
|
|
update();
|
|
}
|
|
|
|
void getCurrentLocationFormString() async {
|
|
currentLocationToFormPlaces = true;
|
|
currentLocationString = 'Waiting for your location'.tr;
|
|
await getLocation();
|
|
currentLocationString = passengerLocation.toString();
|
|
newStartPointLocation = passengerLocation;
|
|
update();
|
|
}
|
|
|
|
List<String> coordinatesWithoutEmpty = [];
|
|
void getMapPointsForAllMethods() async {
|
|
clearPolyline();
|
|
isMarkersShown = false;
|
|
isWayPointStopsSheetUtilGetMap = false;
|
|
isWayPointSheet = false;
|
|
durationToRide = 0;
|
|
distanceOfDestination = 0;
|
|
wayPointSheetHeight = 0;
|
|
remainingTime = 25;
|
|
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 getMapPoints(
|
|
coordinatesWithoutEmpty[i].toString(),
|
|
coordinatesWithoutEmpty[i + 1].toString(),
|
|
i,
|
|
);
|
|
if (i == 0) {
|
|
startNameAddress = data[0]['start_address'];
|
|
}
|
|
if (i == coordinatesWithoutEmpty.length) {
|
|
endNameAddress = data[0]['end_address'];
|
|
}
|
|
}
|
|
}
|
|
|
|
// isWayPointStopsSheet = false;
|
|
if (haveSteps) {
|
|
String latestWaypoint =
|
|
placesCoordinate.lastWhere((coord) => coord.isNotEmpty);
|
|
latestPosition = LatLng(
|
|
double.parse(latestWaypoint.split(',')[0]),
|
|
double.parse(latestWaypoint.split(',')[1]),
|
|
);
|
|
}
|
|
updateCameraForDistanceAfterGetMap();
|
|
changeWayPointStopsSheet();
|
|
bottomSheet();
|
|
showBottomSheet1();
|
|
|
|
update();
|
|
}
|
|
|
|
void convertHintTextStartNewPlaces(int index) {
|
|
if (placesStart.isEmpty) {
|
|
hintTextStartPoint = 'Search for your Start point'.tr;
|
|
update();
|
|
} else {
|
|
hintTextStartPoint = placesStart[index]['name'];
|
|
double lat = placesStart[index]['geometry']['location']['lat'];
|
|
double lng = placesStart[index]['geometry']['location']['lng'];
|
|
newStartPointLocation = LatLng(lat, lng);
|
|
update();
|
|
}
|
|
}
|
|
|
|
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();
|
|
// double lat = wayPoint0[index]['geometry']['location']['lat'];
|
|
// double lng = wayPoint0[index]['geometry']['location']['lng'];
|
|
// newPointLocation0 = LatLng(lat, lng);
|
|
update();
|
|
Get.back();
|
|
}
|
|
}
|
|
|
|
increaseFeeByPassengerAndReOrder() async {
|
|
if (increaseFeeFormKey.currentState!.validate()) {
|
|
if (double.parse(increasFeeFromPassenger.text) > totalPassenger) {
|
|
totalPassenger = double.parse(increasFeeFromPassenger.text);
|
|
Get.back();
|
|
if (rideId != 'yet') {
|
|
await CRUD().post(link: AppLink.updateDriverOrder, payload: {
|
|
"order_id": rideId.toString(), // Convert to String
|
|
"status": 'waiting'
|
|
});
|
|
if (AppLink.endPoint != AppLink.seferCairoServer) {
|
|
CRUD().post(
|
|
link: "${AppLink.endPoint}/ride/driver_order/update.php",
|
|
payload: {
|
|
"order_id": rideId.toString(), // Convert to String
|
|
"status": 'waiting'
|
|
});
|
|
}
|
|
await CRUD().post(link: AppLink.updateRides, payload: {
|
|
"id": rideId.toString(), // Convert to String
|
|
"status": 'waiting'
|
|
});
|
|
if (AppLink.endPoint != AppLink.seferCairoServer) {
|
|
CRUD().post(
|
|
link: "${AppLink.endPoint}/ride/rides/update.php",
|
|
payload: {
|
|
"id": rideId.toString(), // Convert to String
|
|
"status": 'waiting'
|
|
});
|
|
}
|
|
CRUD().post(link: AppLink.updateWaitingTrip, payload: {
|
|
"id": rideId.toString(), // Convert to String
|
|
"status": 'wait'
|
|
});
|
|
if (AppLink.endPoint != AppLink.seferCairoServer) {
|
|
CRUD().post(
|
|
link:
|
|
"${AppLink.endPoint}/ride/notificationCaptain/updateWaitingTrip.php",
|
|
payload: {
|
|
"id": rideId.toString(), // Convert to String
|
|
"status": 'wait'
|
|
});
|
|
}
|
|
tick = 0;
|
|
}
|
|
await getCarsLocationByPassengerAndReloadMarker(
|
|
box.read(BoxName.carType), 4000);
|
|
// confirmRideForAllDriverAvailable();
|
|
|
|
increaseForSameRideAndDelay();
|
|
}
|
|
}
|
|
}
|
|
|
|
void convertHintTextPlaces1(int index) {
|
|
if (wayPoint1.isEmpty) {
|
|
hintTextwayPoint1 = 'Search for your Start point'.tr;
|
|
update();
|
|
} else {
|
|
hintTextwayPoint1 = wayPoint1[index]['name'];
|
|
currentLocationString1 = wayPoint1[index]['name'];
|
|
double lat = wayPoint1[index]['geometry']['location']['lat'];
|
|
double lng = wayPoint1[index]['geometry']['location']['lng'];
|
|
newPointLocation1 = LatLng(lat, lng);
|
|
update();
|
|
}
|
|
}
|
|
|
|
void convertHintTextPlaces2(int index) {
|
|
if (wayPoint1.isEmpty) {
|
|
hintTextwayPoint2 = 'Search for your Start point'.tr;
|
|
update();
|
|
} else {
|
|
hintTextwayPoint2 = wayPoint2[index]['name'];
|
|
currentLocationString2 = wayPoint1[index]['name'];
|
|
double lat = wayPoint2[index]['geometry']['location']['lat'];
|
|
double lng = wayPoint2[index]['geometry']['location']['lng'];
|
|
newPointLocation2 = LatLng(lat, lng);
|
|
update();
|
|
}
|
|
}
|
|
|
|
void convertHintTextPlaces3(int index) {
|
|
if (wayPoint1.isEmpty) {
|
|
hintTextwayPoint3 = 'Search for your Start point'.tr;
|
|
update();
|
|
} else {
|
|
hintTextwayPoint3 = wayPoint3[index]['name'];
|
|
currentLocationString3 = wayPoint1[index]['name'];
|
|
double lat = wayPoint3[index]['geometry']['location']['lat'];
|
|
double lng = wayPoint3[index]['geometry']['location']['lng'];
|
|
newPointLocation3 = LatLng(lat, lng);
|
|
update();
|
|
}
|
|
}
|
|
|
|
void convertHintTextPlaces4(int index) {
|
|
if (wayPoint1.isEmpty) {
|
|
hintTextwayPoint4 = 'Search for your Start point'.tr;
|
|
update();
|
|
} else {
|
|
hintTextwayPoint4 = wayPoint4[index]['name'];
|
|
currentLocationString4 = wayPoint1[index]['name'];
|
|
double lat = wayPoint4[index]['geometry']['location']['lat'];
|
|
double lng = wayPoint4[index]['geometry']['location']['lng'];
|
|
newPointLocation4 = LatLng(lat, lng);
|
|
update();
|
|
}
|
|
}
|
|
|
|
void convertHintTextDestinationNewPlaces(int index) {
|
|
if (placesDestination.isEmpty) {
|
|
hintTextDestinationPoint = 'Search for your destination'.tr;
|
|
update();
|
|
} else {
|
|
hintTextDestinationPoint = placesDestination[index]['title'];
|
|
// hintTextDestinationPoint = placesDestination[index]['name'];
|
|
// double lat = placesDestination[index]['geometry']['location']['lat'];
|
|
double lat = placesDestination[index]['position']['lat'];
|
|
double lng = placesDestination[index]['position']['lng'];
|
|
// double lng = placesDestination[index]['geometry']['location']['lng'];
|
|
newMyLocation = LatLng(lat, lng);
|
|
|
|
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);
|
|
|
|
update();
|
|
}
|
|
|
|
// final mainBottomMenuMap = GlobalKey<AnimatedContainer>();
|
|
void changeBottomSheetShown() {
|
|
isBottomSheetShown = !isBottomSheetShown;
|
|
heightBottomSheetShown = isBottomSheetShown == true ? 250 : 0;
|
|
update();
|
|
}
|
|
|
|
void changeCashConfirmPageShown() {
|
|
isCashConfirmPageShown = !isCashConfirmPageShown;
|
|
isCashSelectedBeforeConfirmRide = true;
|
|
cashConfirmPageShown = isCashConfirmPageShown == true ? 250 : 0;
|
|
// to get or sure picker point for origin //todo
|
|
// isPickerShown = true;
|
|
// clickPointPosition();
|
|
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() {
|
|
mapTrafficON = !mapTrafficON;
|
|
update();
|
|
}
|
|
|
|
void changeisAnotherOreder(bool val) {
|
|
isAnotherOreder = val;
|
|
update();
|
|
}
|
|
|
|
void changeIsWhatsAppOrder(bool val) {
|
|
isWhatsAppOrder = val;
|
|
update();
|
|
}
|
|
|
|
void sendSMS(String to) async {
|
|
// Get the driver's phone number.
|
|
String driverPhone = encryptionHelper.decryptData(
|
|
dataCarsLocationByPassenger['message'][carsOrder]['phone'].toString());
|
|
|
|
// Format the message.
|
|
String message =
|
|
'Hi! This is ${encryptionHelper.decryptData(box.read(BoxName.name).toString().split(' ')[0]).toString()}.\n I am using ${box.read(AppInformation.appName)} to ride with $passengerName as the driver. $passengerName \nis driving a $model\n with license plate $licensePlate.\n I am currently located at $passengerLocation.\n If you need to reach me, please contact the driver directly at\n\n $driverPhone.';
|
|
|
|
// Launch the URL to send the SMS.
|
|
launchCommunication('sms', to, message);
|
|
}
|
|
|
|
void sendWhatsapp(String to) async {
|
|
// Get the driver's phone number.
|
|
// String driverPhone = dataCarsLocationByPassenger['message'][carsOrder]['phone'].toString();
|
|
|
|
// Format the message.
|
|
String message =
|
|
'${'${'Hi! This is'.tr} ${encryptionHelper.decryptData(box.read(BoxName.name).toString().split(' ')[0]).toString()}.\n${' I am using'.tr}'} ${AppInformation.appName}${' to ride with'.tr} $passengerName${' as the driver.'.tr} $passengerName \n${'is driving a '.tr}$model\n${' with license plate '.tr}$licensePlate.\n${' I am currently located at '.tr} https://www.google.com/maps/place/${passengerLocation.latitude},${passengerLocation.longitude}.\n${' If you need to reach me, please contact the driver directly at'.tr}\n\n $driverPhone.';
|
|
|
|
// Launch the URL to send the WhatsApp message.
|
|
launchCommunication('whatsapp', to, message);
|
|
}
|
|
|
|
void changeCancelRidePageShow() {
|
|
showCancelRideBottomSheet();
|
|
isCancelRidePageShown = !isCancelRidePageShown;
|
|
// : cancelRide();
|
|
update();
|
|
}
|
|
|
|
void getDrawerMenu() {
|
|
heightMenuBool = !heightMenuBool;
|
|
widthMapTypeAndTraffic = heightMenuBool == true ? 0 : 50;
|
|
heightMenu = heightMenuBool == true ? 80 : 0;
|
|
widthMenu = heightMenuBool == true ? 110 : 0;
|
|
update();
|
|
}
|
|
|
|
calcualateDistsanceInMetet(LatLng prev, current) async {
|
|
double distance2 = Geolocator.distanceBetween(
|
|
prev.latitude,
|
|
prev.longitude,
|
|
current.latitude,
|
|
current.longitude,
|
|
);
|
|
return distance2;
|
|
}
|
|
|
|
// bool isTimerFromDriverToPassengerAfterAppliedRunning = true;
|
|
// int beginRideInterval = 4; // Interval in seconds for getBeginRideFromDriver
|
|
|
|
// void startTimerFromDriverToPassengerAfterApplied() async {
|
|
// int secondsElapsed = 0;
|
|
|
|
// while (secondsElapsed <= timeToPassengerFromDriverAfterApplied &&
|
|
// isTimerFromDriverToPassengerAfterAppliedRunning) {
|
|
// await Future.delayed(const Duration(seconds: 1));
|
|
// secondsElapsed++;
|
|
|
|
// progressTimerToPassengerFromDriverAfterApplied =
|
|
// secondsElapsed / timeToPassengerFromDriverAfterApplied;
|
|
// remainingTimeToPassengerFromDriverAfterApplied =
|
|
// timeToPassengerFromDriverAfterApplied - secondsElapsed;
|
|
|
|
// if (remainingTimeToPassengerFromDriverAfterApplied < 59) {
|
|
// if (rideTimerBegin == false) {
|
|
// rideTimerBegin = true;
|
|
// }
|
|
// }
|
|
|
|
// // Call getBeginRideFromDriver every 4 seconds
|
|
// if (secondsElapsed % beginRideInterval == 0) {
|
|
// getBeginRideFromDriver();
|
|
// uploadPassengerLocation();
|
|
// }
|
|
|
|
// int minutes =
|
|
// (remainingTimeToPassengerFromDriverAfterApplied / 60).floor();
|
|
// int seconds = remainingTimeToPassengerFromDriverAfterApplied % 60;
|
|
// stringRemainingTimeToPassenger =
|
|
// '$minutes:${seconds.toString().padLeft(2, '0')}';
|
|
|
|
// update();
|
|
// }
|
|
// }
|
|
|
|
StreamController<int> _timerStreamController = StreamController<int>();
|
|
Stream<int> get timerStream => _timerStreamController.stream;
|
|
bool isTimerFromDriverToPassengerAfterAppliedRunning = true;
|
|
bool isTimerRunning = false; // Flag to track if the timer is running
|
|
int beginRideInterval = 4; // Interval in seconds for getBeginRideFromDriver
|
|
|
|
void startTimerFromDriverToPassengerAfterApplied() {
|
|
if (isTimerRunning) return; // Prevent duplicate streams
|
|
isTimerRunning = true;
|
|
|
|
int secondsElapsed = 0;
|
|
|
|
// Start the stream
|
|
Timer.periodic(const Duration(seconds: 1), (timer) {
|
|
if (secondsElapsed > timeToPassengerFromDriverAfterApplied ||
|
|
!isTimerFromDriverToPassengerAfterAppliedRunning) {
|
|
timer.cancel();
|
|
isTimerRunning = false;
|
|
_timerStreamController.close(); // Close the stream when done
|
|
return;
|
|
}
|
|
|
|
secondsElapsed++;
|
|
_timerStreamController.add(secondsElapsed); // Emit elapsed time
|
|
|
|
// Calculate progress and remaining time
|
|
progressTimerToPassengerFromDriverAfterApplied =
|
|
secondsElapsed / timeToPassengerFromDriverAfterApplied;
|
|
remainingTimeToPassengerFromDriverAfterApplied =
|
|
timeToPassengerFromDriverAfterApplied - secondsElapsed;
|
|
|
|
// Update remaining time as string
|
|
int minutes =
|
|
(remainingTimeToPassengerFromDriverAfterApplied / 60).floor();
|
|
int seconds = remainingTimeToPassengerFromDriverAfterApplied % 60;
|
|
stringRemainingTimeToPassenger =
|
|
'$minutes:${seconds.toString().padLeft(2, '0')}';
|
|
|
|
if (remainingTimeToPassengerFromDriverAfterApplied < 59 &&
|
|
!rideTimerBegin) {
|
|
rideTimerBegin = true;
|
|
}
|
|
|
|
// Call periodic functions
|
|
if (secondsElapsed % beginRideInterval == 0) {
|
|
getBeginRideFromDriver();
|
|
uploadPassengerLocation();
|
|
}
|
|
|
|
update(); // Notify listeners
|
|
});
|
|
}
|
|
|
|
// void startTimerFromDriverToPassengerAfterApplied() async {
|
|
// if (isTimerRunning) return; // Exit if timer is already running
|
|
// isTimerRunning = true; // Set the flag to true
|
|
|
|
// int secondsElapsed = 0;
|
|
// while (secondsElapsed <= timeToPassengerFromDriverAfterApplied &&
|
|
// isTimerFromDriverToPassengerAfterAppliedRunning) {
|
|
// await Future.delayed(const Duration(seconds: 1));
|
|
// secondsElapsed++;
|
|
|
|
// progressTimerToPassengerFromDriverAfterApplied =
|
|
// secondsElapsed / timeToPassengerFromDriverAfterApplied;
|
|
// remainingTimeToPassengerFromDriverAfterApplied =
|
|
// timeToPassengerFromDriverAfterApplied - secondsElapsed;
|
|
|
|
// if (remainingTimeToPassengerFromDriverAfterApplied < 59) {
|
|
// if (rideTimerBegin == false) {
|
|
// rideTimerBegin = true;
|
|
// }
|
|
// }
|
|
|
|
// // Call getBeginRideFromDriver every 4 seconds
|
|
// if (secondsElapsed % beginRideInterval == 0) {
|
|
// getBeginRideFromDriver();
|
|
// uploadPassengerLocation();
|
|
// }
|
|
|
|
// int minutes =
|
|
// (remainingTimeToPassengerFromDriverAfterApplied / 60).floor();
|
|
// int seconds = remainingTimeToPassengerFromDriverAfterApplied % 60;
|
|
// stringRemainingTimeToPassenger =
|
|
// '$minutes:${seconds.toString().padLeft(2, '0')}';
|
|
|
|
// update();
|
|
// }
|
|
// isTimerRunning = false; // Reset the flag when timer completes
|
|
// }
|
|
// Remove the getBeginRideFromDriverForDuration function as it's no longer needed
|
|
|
|
// Function to stop the timer
|
|
void stopTimerFromDriverToPassengerAfterApplied() {
|
|
isTimerFromDriverToPassengerAfterAppliedRunning = false;
|
|
update();
|
|
}
|
|
|
|
void startTimerDriverWaitPassenger5Minute() async {
|
|
stopTimerFromDriverToPassengerAfterApplied();
|
|
isDriverArrivePassenger = true;
|
|
isDriverInPassengerWay = false;
|
|
timeToPassengerFromDriverAfterApplied = 0;
|
|
update();
|
|
for (int i = 0; i <= 300; i++) {
|
|
await Future.delayed(const Duration(seconds: 1));
|
|
progressTimerDriverWaitPassenger5Minute = i / 300;
|
|
remainingTimeDriverWaitPassenger5Minute = 300 - i;
|
|
|
|
int minutes = (remainingTimeDriverWaitPassenger5Minute / 60).floor();
|
|
int seconds = remainingTimeDriverWaitPassenger5Minute % 60;
|
|
stringRemainingTimeDriverWaitPassenger5Minute =
|
|
'$minutes:${seconds.toString().padLeft(2, '0')}';
|
|
|
|
update();
|
|
}
|
|
}
|
|
|
|
// Create a StreamController to manage the timer values
|
|
final timerController = StreamController<int>();
|
|
|
|
// Start the timer when the ride begins
|
|
void beginRideTimer() {
|
|
// Set up the timer to run every second
|
|
Timer.periodic(const Duration(seconds: 1), (timer) {
|
|
// Update the timer value and notify listeners
|
|
timerController.add(timer.tick);
|
|
update();
|
|
});
|
|
}
|
|
|
|
// Stop the timer when the ride ends
|
|
void stopRideTimer() {
|
|
timerController.close();
|
|
update();
|
|
}
|
|
|
|
late String arrivalTime = '';
|
|
void rideIsBeginPassengerTimer() async {
|
|
// Calculate arrival time considering current time and duration
|
|
DateTime now = DateTime.now();
|
|
DateTime arrivalTime1 = now.add(Duration(seconds: durationToRide));
|
|
arrivalTime = DateFormat('hh:mm').format(arrivalTime1);
|
|
box.write(BoxName.arrivalTime, arrivalTime);
|
|
for (int i = 0; i <= durationToRide; i++) {
|
|
await Future.delayed(const Duration(seconds: 1));
|
|
progressTimerRideBegin = i / durationToRide;
|
|
remainingTimeTimerRideBegin = durationToRide - i;
|
|
if (i == (durationToRide / 4).round() && (statusRide == 'Begin')) {
|
|
NotificationController().showNotification("Record Your Trip".tr,
|
|
"You can call or record audio during this trip.".tr, 'tone1');
|
|
}
|
|
bool sendSOS = false;
|
|
if (speed > 100 && sendSOS == false) {
|
|
NotificationController().showNotification(
|
|
"Warning: Speeding detected!".tr,
|
|
'You can call or record audio of this trip'.tr,
|
|
'tone1');
|
|
Get.defaultDialog(
|
|
barrierDismissible: false,
|
|
title: "Warning: Speeding detected!".tr,
|
|
titleStyle: AppStyle.title,
|
|
content: Text(
|
|
"We noticed the speed is exceeding 100 km/h. Please slow down for your safety. If you feel unsafe, you can share your trip details with a contact or call the police using the red SOS button."
|
|
.tr,
|
|
style: AppStyle.title,
|
|
),
|
|
confirm: MyElevatedButton(
|
|
title: "Share Trip Details".tr,
|
|
onPressed: () {
|
|
Get.back();
|
|
// Implement sharing trip details logic here
|
|
String message = "**Emergency SOS from Passenger:**\n";
|
|
|
|
// Get trip details from GetX or relevant provider
|
|
String origin = passengerLocation.toString();
|
|
String destination = myDestination.toString();
|
|
String driverName = passengerName;
|
|
String driverCarPlate = licensePlate;
|
|
|
|
// Add trip details to the message
|
|
message += "* ${'Origin'.tr}: $origin\n";
|
|
message += "* ${'Destination'.tr}: $destination\n";
|
|
message += "* ${'Driver Name'.tr}: $driverName\n";
|
|
message += "* ${'Driver Car Plate'.tr}: $driverCarPlate\n\n";
|
|
message += "* ${'Driver phone'.tr}:$driverPhone\n\n";
|
|
|
|
// Add any additional information you want to include (optional)
|
|
// - Example: current location (using GetX LocationController)
|
|
message +=
|
|
"${'Current Location'.tr}:https://www.google.com/maps/place/${passengerLocation.latitude},${passengerLocation.longitude} \n";
|
|
|
|
// Append a call to action
|
|
message += "Please help! Contact me as soon as possible.".tr;
|
|
|
|
// Launch WhatsApp communication with the constructed message
|
|
launchCommunication(
|
|
'whatsapp', box.read(BoxName.sosPhonePassenger), message);
|
|
sendSOS = true;
|
|
},
|
|
kolor: AppColor.redColor,
|
|
),
|
|
cancel: MyElevatedButton(
|
|
title: "Cancel".tr,
|
|
onPressed: () {
|
|
Get.back();
|
|
},
|
|
kolor: AppColor.greenColor,
|
|
),
|
|
);
|
|
}
|
|
int minutes = (remainingTimeTimerRideBegin / 60).floor();
|
|
int seconds = remainingTimeTimerRideBegin % 60;
|
|
stringRemainingTimeRideBegin =
|
|
'$minutes:${seconds.toString().padLeft(2, '0')}';
|
|
|
|
update();
|
|
}
|
|
// rideTimerBegin = false;
|
|
// isRideFinished = true;
|
|
// update();
|
|
}
|
|
|
|
int progressTimerRideBeginVip = 0;
|
|
int elapsedTimeInSeconds = 0; // Timer starts from 0
|
|
String stringElapsedTimeRideBegin = '0:00';
|
|
String stringElapsedTimeRideBeginVip = '0:00';
|
|
bool rideInProgress = true; // To control when to stop the timer
|
|
|
|
void rideIsBeginPassengerTimerVIP() async {
|
|
rideInProgress = true; // Start the ride timer
|
|
bool sendSOS = false;
|
|
while (rideInProgress) {
|
|
await Future.delayed(const Duration(seconds: 1));
|
|
|
|
// Increment elapsed time
|
|
elapsedTimeInSeconds++;
|
|
|
|
// Update the time display
|
|
int minutes = (elapsedTimeInSeconds / 60).floor();
|
|
int seconds = elapsedTimeInSeconds % 60;
|
|
stringElapsedTimeRideBeginVip =
|
|
'$minutes:${seconds.toString().padLeft(2, '0')}';
|
|
|
|
// Check for speed and SOS conditions
|
|
if (speed > 100 && !sendSOS) {
|
|
Get.defaultDialog(
|
|
barrierDismissible: false,
|
|
title: "Warning: Speeding detected!".tr,
|
|
titleStyle: AppStyle.title,
|
|
content: Text(
|
|
"We noticed the speed is exceeding 100 km/h. Please slow down for your safety. If you feel unsafe, you can share your trip details with a contact or call the police using the red SOS button."
|
|
.tr,
|
|
style: AppStyle.title,
|
|
),
|
|
confirm: MyElevatedButton(
|
|
title: "Share Trip Details".tr,
|
|
onPressed: () {
|
|
Get.back();
|
|
// Implement sharing trip details logic here
|
|
String message = "**Emergency SOS from Passenger:**\n";
|
|
|
|
// Get trip details from GetX or relevant provider
|
|
String origin = passengerLocation.toString();
|
|
String destination = myDestination.toString();
|
|
String driverName = passengerName;
|
|
String driverCarPlate = licensePlate;
|
|
|
|
// Add trip details to the message
|
|
message += "* ${'Origin'.tr}: $origin\n";
|
|
message += "* ${'Destination'.tr}: $destination\n";
|
|
message += "* ${'Driver Name'.tr}: $driverName\n";
|
|
message += "* ${'Driver Car Plate'.tr}: $driverCarPlate\n\n";
|
|
message += "* ${'Driver Phone'.tr}: $driverPhone\n\n";
|
|
|
|
// Add current location
|
|
message +=
|
|
"${'Current Location'.tr}:https://www.google.com/maps/place/${passengerLocation.latitude},${passengerLocation.longitude} \n";
|
|
|
|
// Append a call to action
|
|
message += "Please help! Contact me as soon as possible.".tr;
|
|
|
|
// Launch WhatsApp communication
|
|
launchCommunication(
|
|
'whatsapp', box.read(BoxName.sosPhonePassenger), message);
|
|
sendSOS = true;
|
|
},
|
|
kolor: AppColor.redColor,
|
|
),
|
|
cancel: MyElevatedButton(
|
|
title: "Cancel".tr,
|
|
onPressed: () {
|
|
Get.back();
|
|
},
|
|
kolor: AppColor.greenColor,
|
|
),
|
|
);
|
|
}
|
|
|
|
// Update the UI
|
|
update();
|
|
}
|
|
}
|
|
|
|
void tripFinishedFromDriver() {
|
|
isRideFinished = true;
|
|
rideTimerBegin = false;
|
|
statusRideVip = 'Finished';
|
|
box.write(BoxName.arrivalTime, '');
|
|
remainingTimeTimerRideBegin = 0;
|
|
box.write(BoxName.passengerWalletTotal, '0');
|
|
update();
|
|
if (box.read(BoxName.parentTripSelected) == true) {
|
|
FirebaseMessagesController().sendNotificationToPassengerToken(
|
|
"Finish Monitor".tr,
|
|
"Finish Monitor".tr,
|
|
box.read(BoxName.tokenParent),
|
|
[],
|
|
'order1.wav',
|
|
);
|
|
box.write(BoxName.parentTripSelected, false);
|
|
box.remove(BoxName.tokenParent);
|
|
}
|
|
}
|
|
|
|
// bool isBeginRideFromDriver = false;
|
|
// void getBeginRideFromDriver() async {
|
|
// try {
|
|
// if (isBeginRideFromDriver) return; // Prevent duplicate streams
|
|
// isBeginRideFromDriver = true;
|
|
// var res = await CRUD()
|
|
// .get(link: AppLink.getRideStatusBegin, payload: {'ride_id': rideId});
|
|
// if (res != 'failure') {
|
|
// var decode = jsonDecode(res);
|
|
|
|
// // if (decode['data']['status'] != 'Apply') {
|
|
// if (decode['data']['status'] == 'Begin') {
|
|
// timeToPassengerFromDriverAfterApplied = 0;
|
|
// remainingTime = 0;
|
|
// remainingTimeToPassengerFromDriverAfterApplied = 0;
|
|
// remainingTimeDriverWaitPassenger5Minute = 0;
|
|
// rideTimerBegin = true;
|
|
// statusRide = 'Begin';
|
|
// isDriverInPassengerWay = false;
|
|
// isDriverArrivePassenger = false;
|
|
// update();
|
|
// // isCancelRidePageShown = true;
|
|
// rideIsBeginPassengerTimer();
|
|
// runWhenRideIsBegin();
|
|
// } else {}
|
|
// }
|
|
// } catch (e) {
|
|
// // Handle the error or perform any necessary actions
|
|
// }
|
|
// }
|
|
|
|
StreamController<String> _beginRideStreamController =
|
|
StreamController<String>.broadcast();
|
|
Stream<String> get beginRideStream => _beginRideStreamController.stream;
|
|
|
|
bool isBeginRideFromDriverRunning = false;
|
|
|
|
void getBeginRideFromDriver() {
|
|
if (isBeginRideFromDriverRunning) return; // Prevent duplicate streams
|
|
isBeginRideFromDriverRunning = true;
|
|
|
|
Timer.periodic(const Duration(seconds: 1), (timer) async {
|
|
try {
|
|
var res = await CRUD().get(
|
|
link: AppLink.getRideStatusBegin, payload: {'ride_id': rideId});
|
|
print(res);
|
|
print('1002');
|
|
if (res != 'failure') {
|
|
var decode = jsonDecode(res);
|
|
_beginRideStreamController
|
|
.add(decode['data']['status']); // Emit the status
|
|
|
|
if (decode['data']['status'] == 'Begin') {
|
|
// Stop the periodic check
|
|
timer.cancel();
|
|
isBeginRideFromDriverRunning = false;
|
|
|
|
timeToPassengerFromDriverAfterApplied = 0;
|
|
remainingTime = 0;
|
|
remainingTimeToPassengerFromDriverAfterApplied = 0;
|
|
remainingTimeDriverWaitPassenger5Minute = 0;
|
|
rideTimerBegin = true;
|
|
statusRide = 'Begin';
|
|
isDriverInPassengerWay = false;
|
|
isDriverArrivePassenger = false;
|
|
update();
|
|
|
|
// Trigger additional actions
|
|
rideIsBeginPassengerTimer();
|
|
runWhenRideIsBegin();
|
|
NotificationController().showNotification(
|
|
'Trip is begin'.tr,
|
|
'The trip has started! Feel free to contact emergency numbers, share your trip, or activate voice recording for the journey'
|
|
.tr,
|
|
'ding');
|
|
}
|
|
}
|
|
} catch (e) {
|
|
// Handle errors
|
|
_beginRideStreamController.addError(e);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Call this method to listen to the stream
|
|
void listenToBeginRideStream() {
|
|
beginRideStream.listen((status) {
|
|
print("Ride status: $status");
|
|
// Perform additional actions based on the status
|
|
}, onError: (error) {
|
|
print("Error in Begin Ride Stream: $error");
|
|
});
|
|
}
|
|
|
|
begiVIPTripFromPassenger() async {
|
|
timeToPassengerFromDriverAfterApplied = 0;
|
|
remainingTime = 0;
|
|
isBottomSheetShown = false;
|
|
remainingTimeToPassengerFromDriverAfterApplied = 0;
|
|
remainingTimeDriverWaitPassenger5Minute = 0;
|
|
rideTimerBegin = true;
|
|
statusRideVip = 'Begin';
|
|
isDriverInPassengerWay = false;
|
|
isDriverArrivePassenger = false;
|
|
update();
|
|
// isCancelRidePageShown = true;
|
|
rideIsBeginPassengerTimerVIP();
|
|
runWhenRideIsBegin();
|
|
}
|
|
|
|
Map rideStatusFromStartApp = {};
|
|
getRideStatusFromStartApp() async {
|
|
try {
|
|
var res = await CRUD().get(
|
|
link: AppLink.getRideStatusFromStartApp,
|
|
payload: {'passenger_id': box.read(BoxName.passengerID)});
|
|
print(res);
|
|
print('1070');
|
|
if (res == 'failure') {
|
|
print(
|
|
"No rides found for the given passenger ID within the last hour.");
|
|
}
|
|
rideStatusFromStartApp = jsonDecode(res);
|
|
if (rideStatusFromStartApp['data']['status'] == 'Begin') {
|
|
statusRide = 'Begin';
|
|
driverId = rideStatusFromStartApp['data']['driver_id'];
|
|
passengerName = rideStatusFromStartApp['data']['driverName'];
|
|
driverRate = rideStatusFromStartApp['data']['rateDriver'].toString();
|
|
statusRideFromStart = true;
|
|
// DateTime endTime =
|
|
// DateTime.parse(rideStatusFromStartApp['data']['endtime']);
|
|
// DateTime rideTimeStart =
|
|
// DateTime.parse(rideStatusFromStartApp['data']['rideTimeStart']);
|
|
//
|
|
// // Calculate the new end time by adding the duration to the rideTimeStart
|
|
// DateTime newEndTime = rideTimeStart.add(
|
|
// Duration(seconds: endTime.difference(rideTimeStart).inSeconds));
|
|
//
|
|
// // Save the new end time in a variable
|
|
// var newEndTimeVariable = newEndTime.toString();
|
|
update();
|
|
|
|
Map<String, dynamic> tripData =
|
|
box.read(BoxName.tripData) as Map<String, dynamic>;
|
|
final points = decodePolyline(
|
|
tripData["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));
|
|
}
|
|
var polyline = Polyline(
|
|
polylineId: const PolylineId('begin trip'),
|
|
points: polylineCoordinates,
|
|
width: 10,
|
|
color: Colors.blue,
|
|
);
|
|
|
|
polyLines.add(polyline);
|
|
timeToPassengerFromDriverAfterApplied = 0;
|
|
remainingTime = 0;
|
|
remainingTimeToPassengerFromDriverAfterApplied = 0;
|
|
remainingTimeDriverWaitPassenger5Minute = 0;
|
|
rideTimerBegin = true;
|
|
isDriverInPassengerWay = false;
|
|
isDriverArrivePassenger = false;
|
|
// update();
|
|
// isCancelRidePageShown = true;
|
|
durationToAdd = tripData['routes'][0]['legs'][0]['duration']['value'];
|
|
rideIsBeginPassengerTimer();
|
|
runWhenRideIsBegin();
|
|
update();
|
|
}
|
|
} catch (e) {
|
|
// Handle the error or perform any necessary actions
|
|
}
|
|
}
|
|
|
|
void driverArrivePassenger() {
|
|
timeToPassengerFromDriverAfterApplied = 0;
|
|
remainingTime = 0;
|
|
// isCancelRidePageShown = true;
|
|
update();
|
|
rideIsBeginPassengerTimer();
|
|
// runWhenRideIsBegin();
|
|
}
|
|
|
|
void cancelTimerToPassengerFromDriverAfterApplied() {
|
|
timerToPassengerFromDriverAfterApplied?.cancel();
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
void clearPlaces1() {
|
|
wayPoint1 = [];
|
|
hintTextwayPoint1 = 'Search for waypoint'.tr;
|
|
update();
|
|
}
|
|
|
|
void clearPlaces2() {
|
|
wayPoint2 = [];
|
|
hintTextwayPoint2 = 'Search for waypoint'.tr;
|
|
update();
|
|
}
|
|
|
|
void clearPlaces3() {
|
|
wayPoint3 = [];
|
|
hintTextwayPoint3 = 'Search for waypoint'.tr;
|
|
update();
|
|
}
|
|
|
|
void clearPlaces4() {
|
|
wayPoint4 = [];
|
|
hintTextwayPoint4 = 'Search for waypoint'.tr;
|
|
update();
|
|
}
|
|
|
|
int selectedReason = -1;
|
|
String? cancelNote;
|
|
void selectReason(int index, String note) {
|
|
selectedReason = index;
|
|
cancelNote = note;
|
|
update();
|
|
}
|
|
|
|
void getDialog(String title, String? midTitle, VoidCallback onPressed) {
|
|
final textToSpeechController = Get.find<TextToSpeechController>();
|
|
Get.defaultDialog(
|
|
title: title,
|
|
titleStyle: AppStyle.title,
|
|
middleTextStyle: AppStyle.title,
|
|
content: Column(
|
|
children: [
|
|
IconButton(
|
|
onPressed: () async {
|
|
await textToSpeechController.speakText(title ?? midTitle!);
|
|
},
|
|
icon: const Icon(Icons.headphones)),
|
|
Text(
|
|
midTitle!,
|
|
style: AppStyle.title,
|
|
)
|
|
],
|
|
),
|
|
confirm: MyElevatedButton(
|
|
title: 'Ok'.tr,
|
|
onPressed: onPressed,
|
|
kolor: AppColor.greenColor,
|
|
),
|
|
cancel: MyElevatedButton(
|
|
title: 'Cancel',
|
|
kolor: AppColor.redColor,
|
|
onPressed: () {
|
|
Get.back();
|
|
}));
|
|
}
|
|
|
|
Map<String, double>? extractCoordinatesFromLink(String link) {
|
|
try {
|
|
// Extract the URL part from the link by finding the first occurrence of "http"
|
|
int urlStartIndex = link.indexOf(RegExp(r'https?://'));
|
|
if (urlStartIndex == -1) {
|
|
throw const FormatException('No URL found in the provided link.');
|
|
}
|
|
|
|
// Extract the URL and clean it
|
|
link = link.substring(urlStartIndex).trim();
|
|
|
|
Uri uri = Uri.parse(link);
|
|
|
|
// Common coordinate query parameters
|
|
List<String> coordinateParams = ['q', 'cp', 'll'];
|
|
|
|
// Try to extract coordinates from query parameters
|
|
for (var param in coordinateParams) {
|
|
String? value = uri.queryParameters[param];
|
|
if (value != null && (value.contains(',') || value.contains('~'))) {
|
|
List<String> coordinates =
|
|
value.contains(',') ? value.split(',') : value.split('~');
|
|
if (coordinates.length == 2) {
|
|
double? latitude = double.tryParse(coordinates[0].trim());
|
|
double? longitude = double.tryParse(coordinates[1].trim());
|
|
if (latitude != null && longitude != null) {
|
|
return {
|
|
'latitude': latitude,
|
|
'longitude': longitude,
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Try to extract coordinates from the path
|
|
List<String> pathSegments = uri.pathSegments;
|
|
for (var segment in pathSegments) {
|
|
if (segment.contains(',')) {
|
|
List<String> coordinates = segment.split(',');
|
|
if (coordinates.length == 2) {
|
|
double? latitude = double.tryParse(coordinates[0].trim());
|
|
double? longitude = double.tryParse(coordinates[1].trim());
|
|
if (latitude != null && longitude != null) {
|
|
return {
|
|
'latitude': latitude,
|
|
'longitude': longitude,
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} catch (e) {
|
|
print('Error parsing location link: $e');
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
double latitudeWhatsApp = 0;
|
|
double longitudeWhatsApp = 0;
|
|
void handleWhatsAppLink(String link) {
|
|
Map<String, double>? coordinates = extractCoordinatesFromLink(link);
|
|
|
|
if (coordinates != null) {
|
|
latitudeWhatsApp = coordinates['latitude']!;
|
|
longitudeWhatsApp = coordinates['longitude']!;
|
|
|
|
print(
|
|
'Extracted coordinates: Lat: $latitudeWhatsApp, Long: $longitudeWhatsApp');
|
|
// Use these coordinates in your app as needed
|
|
} else {
|
|
print('Failed to extract coordinates from the link');
|
|
}
|
|
}
|
|
|
|
void goToWhatappLocation() async {
|
|
if (sosFormKey.currentState!.validate()) {
|
|
changeIsWhatsAppOrder(true);
|
|
Get.back();
|
|
handleWhatsAppLink(whatsAppLocationText.text);
|
|
myDestination = LatLng(latitudeWhatsApp, longitudeWhatsApp);
|
|
await mapController?.animateCamera(CameraUpdate.newLatLng(
|
|
LatLng(passengerLocation.latitude, passengerLocation.longitude)));
|
|
changeMainBottomMenuMap();
|
|
passengerStartLocationFromMap = true;
|
|
isPickerShown = true;
|
|
update();
|
|
}
|
|
}
|
|
|
|
int currentTimeSearchingCaptainWindow = 0;
|
|
late String driverPhone = '';
|
|
late String driverRate = '';
|
|
late String passengerName = '';
|
|
late String carColor = '';
|
|
late String colorHex = '';
|
|
late String carYear = '';
|
|
late String model = '';
|
|
late String make = '';
|
|
late String licensePlate = '';
|
|
|
|
String driverOrderStatus = 'yet';
|
|
bool isDriversTokensSend = false;
|
|
|
|
Set<String> notifiedDrivers = {};
|
|
|
|
addRideToNotificationDriverAvailable() async {
|
|
await CRUD().post(link: AppLink.addWaitingRide, payload: {
|
|
'id': rideId.toString(),
|
|
'start_location':
|
|
'${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
|
|
'end_location':
|
|
'${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}',
|
|
"date": DateTime.now().toString(),
|
|
"time": DateTime.now().toString(),
|
|
"price": totalPassenger.toStringAsFixed(2),
|
|
'passenger_id': box.read(BoxName.passengerID).toString(),
|
|
'status': 'waiting',
|
|
'carType': box.read(BoxName.carType),
|
|
'passengerRate': passengerRate.toStringAsFixed(2),
|
|
'price_for_passenger': totalME.toStringAsFixed(2),
|
|
'distance': distance.toStringAsFixed(1),
|
|
'duration': duration.toStringAsFixed(1),
|
|
});
|
|
|
|
if (AppLink.endPoint != AppLink.seferCairoServer) {
|
|
CRUD().post(
|
|
link: '${AppLink.endPoint}/notificationCaptain/addWaitingRide.php',
|
|
payload: {
|
|
'id': rideId.toString(),
|
|
'start_location':
|
|
'${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
|
|
'end_location':
|
|
'${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}',
|
|
"date": DateTime.now().toString(),
|
|
"time": DateTime.now().toString(),
|
|
"price": totalPassenger.toStringAsFixed(2),
|
|
'passenger_id': box.read(BoxName.passengerID).toString(),
|
|
'status': 'waiting',
|
|
'carType': box.read(BoxName.carType),
|
|
'passengerRate': passengerRate.toStringAsFixed(2),
|
|
'price_for_passenger': totalME.toStringAsFixed(2),
|
|
'distance': distance.toStringAsFixed(1),
|
|
'duration': duration.toStringAsFixed(0),
|
|
});
|
|
}
|
|
}
|
|
|
|
// Future<void> confirmRideForAllDriverAvailable1() async {
|
|
// // Try to fetch car locations up to 4 times with a 2-second delay
|
|
// bool driversFound = false;
|
|
// for (int attempt = 0; attempt < 8; attempt++) {
|
|
// await getCarsLocationByPassengerAndReloadMarker(
|
|
// box.read(BoxName.carType), attempt > 5 ? 4500 : 3000);
|
|
|
|
// // Check if dataCarsLocationByPassenger is valid and contains drivers
|
|
// if (dataCarsLocationByPassenger != 'failure' &&
|
|
// dataCarsLocationByPassenger != null &&
|
|
// dataCarsLocationByPassenger.containsKey('data') &&
|
|
// dataCarsLocationByPassenger['message'] != null) {
|
|
// driversFound = true;
|
|
// break; // Exit loop if drivers are found
|
|
// }
|
|
|
|
// // Wait 2 seconds before next attempt
|
|
// await Future.delayed(const Duration(seconds: 2));
|
|
// }
|
|
|
|
// // If no drivers were found after 4 attempts, show a dialog
|
|
// if (!driversFound) {
|
|
// Get.dialog(
|
|
// BackdropFilter(
|
|
// filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
|
|
// child: CupertinoAlertDialog(
|
|
// title: Text(
|
|
// "No Car or Driver Found in your area.".tr,
|
|
// style: AppStyle.title.copyWith(
|
|
// fontSize: 20,
|
|
// fontWeight: FontWeight.bold,
|
|
// ),
|
|
// ),
|
|
// content: Text(
|
|
// "No Car or Driver Found in your area.".tr,
|
|
// style: AppStyle.title.copyWith(fontSize: 16),
|
|
// ),
|
|
// actions: [
|
|
// CupertinoDialogAction(
|
|
// onPressed: () {
|
|
// Get.back();
|
|
// Get.offAll(() => const MapPagePassenger());
|
|
// },
|
|
// child: Text('OK'.tr,
|
|
// style: const TextStyle(color: AppColor.greenColor)),
|
|
// ),
|
|
// ],
|
|
// ),
|
|
// ),
|
|
// barrierDismissible: false,
|
|
// );
|
|
|
|
// return;
|
|
// }
|
|
|
|
// // Proceed with the rest of the function if drivers are found
|
|
// PaymentController paymentController = Get.find<PaymentController>();
|
|
// rideConfirm = true;
|
|
// shouldFetch = true;
|
|
// isBottomSheetShown = false;
|
|
// timeToPassengerFromDriverAfterApplied = 60;
|
|
|
|
// // Add ride to database
|
|
// await CRUD()
|
|
// .post(link: "${AppLink.seferCairoServer}/ride/rides/add.php", payload: {
|
|
// "start_location":
|
|
// '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
|
|
// "end_location":
|
|
// '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}',
|
|
// "date": DateTime.now().toString(),
|
|
// "time": DateTime.now().toString(),
|
|
// "endtime": durationToAdd.toString(),
|
|
// "price": totalPassenger.toStringAsFixed(2),
|
|
// "passenger_id": box.read(BoxName.passengerID).toString(),
|
|
// "driver_id": dataCarsLocationByPassenger['message'][carsOrder]['driver_id']
|
|
// .toString(),
|
|
// "status": "waiting",
|
|
// 'carType': box.read(BoxName.carType),
|
|
// "price_for_driver": totalPassenger.toString(),
|
|
// "price_for_passenger": totalME.toString(),
|
|
// "distance": distance.toString(),
|
|
// "paymentMethod": paymentController.isWalletChecked.toString(),
|
|
// }).then((value) {
|
|
// if (value is String) {
|
|
// final parsedValue = jsonDecode(value);
|
|
// rideId = parsedValue['message'];
|
|
// } else if (value is Map) {
|
|
// rideId = value['message'];
|
|
// } else {
|
|
// Log.print('Unexpected response type: ${value.runtimeType}');
|
|
// }
|
|
|
|
// // Timer to notify drivers every 2 seconds for 5 iterations
|
|
// int iteration = 0;
|
|
// Timer.periodic(const Duration(seconds: 2), (timer) async {
|
|
// if (iteration >= 5) {
|
|
// timer.cancel();
|
|
// return;
|
|
// }
|
|
// iteration++;
|
|
|
|
// // Reload driver locations and notify available drivers
|
|
// await getCarsLocationByPassengerAndReloadMarker(
|
|
// box.read(BoxName.carType), 3000);
|
|
// if (dataCarsLocationByPassenger != null &&
|
|
// dataCarsLocationByPassenger.containsKey('data') &&
|
|
// dataCarsLocationByPassenger['message'] != null) {
|
|
// for (var driverData in dataCarsLocationByPassenger['message']) {
|
|
// String driverId = driverData['driver_id'].toString();
|
|
// if (!notifiedDrivers.contains(driverId)) {
|
|
// notifiedDrivers.add(driverId);
|
|
// List<String> body = [
|
|
// '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
|
|
// '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}',
|
|
// totalPassenger.toStringAsFixed(2),
|
|
// totalDriver.toStringAsFixed(2),
|
|
// durationToRide.toString(),
|
|
// distance.toStringAsFixed(2),
|
|
// driverId.toString(),
|
|
// box.read(BoxName.passengerID).toString(),
|
|
// box.read(BoxName.name).toString(),
|
|
// box.read(BoxName.tokenFCM).toString(),
|
|
// box.read(BoxName.phone).toString(),
|
|
// durationByPassenger.toString(),
|
|
// distanceByPassenger.toString(),
|
|
// paymentController.isWalletChecked.toString(),
|
|
// driverData['token'].toString(),
|
|
// durationToPassenger.toString(),
|
|
// rideId.toString(),
|
|
// rideTimerBegin.toString(),
|
|
// driverId.toString(),
|
|
// durationToRide.toString(),
|
|
// Get.find<WayPointController>().wayPoints.length > 1
|
|
// ? 'haveSteps'
|
|
// : 'startEnd',
|
|
// placesCoordinate[0],
|
|
// placesCoordinate[1],
|
|
// placesCoordinate[2],
|
|
// placesCoordinate[3],
|
|
// placesCoordinate[4],
|
|
// costForDriver.toStringAsFixed(2),
|
|
// (double.parse(box.read(BoxName.passengerWalletTotal)) < 0
|
|
// ? double.parse(box.read(BoxName.passengerWalletTotal))
|
|
// .toStringAsFixed(2)
|
|
// : '0'),
|
|
// box.read(BoxName.email).toString(),
|
|
// data[0]['start_address'],
|
|
// data[0]['end_address'],
|
|
// box.read(BoxName.carType),
|
|
// kazan.toStringAsFixed(0),
|
|
// passengerRate.toStringAsFixed(2),
|
|
// ];
|
|
// Log.print('body: ${body}');
|
|
// FirebaseMessagesController().sendNotificationToDriverMAP(
|
|
// 'OrderSpeed',
|
|
// rideId,
|
|
// driverData['token'].toString(),
|
|
// body,
|
|
// 'order.wav',
|
|
// );
|
|
// }
|
|
// }
|
|
// }
|
|
// });
|
|
// });
|
|
|
|
// // If an additional endpoint is available, post data there as well
|
|
// if (AppLink.endPoint != AppLink.seferCairoServer) {
|
|
// CRUD().post(link: '${AppLink.endPoint}/ride/rides/add.php', payload: {
|
|
// "start_location":
|
|
// '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
|
|
// "end_location":
|
|
// '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}',
|
|
// "date": DateTime.now().toString(),
|
|
// "time": DateTime.now().toString(),
|
|
// "endtime": durationToAdd.toString(),
|
|
// "price": totalPassenger.toStringAsFixed(2),
|
|
// "passenger_id": box.read(BoxName.passengerID).toString(),
|
|
// "driver_id": dataCarsLocationByPassenger['message'][carsOrder]['driver_id']
|
|
// .toString(),
|
|
// "status": "waiting",
|
|
// 'carType': box.read(BoxName.carType),
|
|
// "price_for_driver": totalPassenger.toString(),
|
|
// "price_for_passenger": totalME.toString(),
|
|
// "distance": distance.toString(),
|
|
// "paymentMethod": paymentController.isWalletChecked.toString(),
|
|
// });
|
|
// }
|
|
// delayAndFetchRideStatusForAllDriverAvailable(rideId);
|
|
// update();
|
|
// }
|
|
|
|
increaseForSameRideAndDelay() async {
|
|
reSearchAfterCanceledFromDriver();
|
|
// bool driversFound = false;
|
|
// for (int attempt = 0; attempt < 8; attempt++) {
|
|
// await getCarsLocationByPassengerAndReloadMarker(
|
|
// box.read(BoxName.carType), 4500);
|
|
|
|
// // Check if dataCarsLocationByPassenger is valid and contains drivers
|
|
// if (dataCarsLocationByPassenger != 'failure' &&
|
|
// dataCarsLocationByPassenger != null &&
|
|
// dataCarsLocationByPassenger.containsKey('message') &&
|
|
// dataCarsLocationByPassenger['message'] != null) {
|
|
// driversFound = true;
|
|
// break; // Exit loop if drivers are found
|
|
// }
|
|
|
|
// // Wait 2 seconds before next attempt
|
|
// await Future.delayed(const Duration(seconds: 2));
|
|
// }
|
|
|
|
// // If no drivers were found after 4 attempts, show a dialog
|
|
// if (!driversFound) {
|
|
// Get.dialog(
|
|
// BackdropFilter(
|
|
// filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
|
|
// child: CupertinoAlertDialog(
|
|
// title: Text(
|
|
// "No Car or Driver Found in your area.".tr,
|
|
// style: AppStyle.title.copyWith(
|
|
// fontSize: 20,
|
|
// fontWeight: FontWeight.bold,
|
|
// ),
|
|
// ),
|
|
// content: Text(
|
|
// "No Car or Driver Found in your area.".tr,
|
|
// style: AppStyle.title.copyWith(fontSize: 16),
|
|
// ),
|
|
// actions: [
|
|
// CupertinoDialogAction(
|
|
// onPressed: () {
|
|
// Get.back();
|
|
// Get.offAll(() => const MapPagePassenger());
|
|
// },
|
|
// child: Text('OK'.tr,
|
|
// style: const TextStyle(color: AppColor.greenColor)),
|
|
// ),
|
|
// ],
|
|
// ),
|
|
// ),
|
|
// barrierDismissible: false,
|
|
// );
|
|
|
|
// return;
|
|
// }
|
|
// PaymentController paymentController = Get.find<PaymentController>();
|
|
// rideConfirm = true;
|
|
// shouldFetch = true;
|
|
// isBottomSheetShown = false;
|
|
// timeToPassengerFromDriverAfterApplied = 60;
|
|
// // confirmRideForAllDriverAvailable();
|
|
// for (var i = 0; i < dataCarsLocationByPassenger['message'].length; i++) {
|
|
// List<String> body = [
|
|
// '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
|
|
// '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}',
|
|
// totalPassenger.toStringAsFixed(2),
|
|
// totalDriver.toStringAsFixed(2),
|
|
// durationToRide.toString(),
|
|
// distance.toStringAsFixed(2),
|
|
// dataCarsLocationByPassenger['message'][i]['driver_id'].toString(),
|
|
// box.read(BoxName.passengerID).toString(),
|
|
// box.read(BoxName.name).toString(),
|
|
// box.read(BoxName.tokenFCM).toString(),
|
|
// box.read(BoxName.phone).toString(),
|
|
// durationByPassenger.toString(),
|
|
// distanceByPassenger.toString(),
|
|
// paymentController.isWalletChecked.toString(),
|
|
// dataCarsLocationByPassenger['message'][i]['token'].toString(),
|
|
// durationToPassenger.toString(),
|
|
// rideId.toString(),
|
|
// rideTimerBegin.toString(),
|
|
// dataCarsLocationByPassenger['message'][i]['driver_id'].toString(),
|
|
// durationToRide.toString(),
|
|
// Get.find<WayPointController>().wayPoints.length > 1
|
|
// ? 'haveSteps'
|
|
// : 'startEnd',
|
|
// placesCoordinate[0],
|
|
// placesCoordinate[1],
|
|
// placesCoordinate[2],
|
|
// placesCoordinate[3],
|
|
// placesCoordinate[4],
|
|
// costForDriver.toStringAsFixed(2),
|
|
// double.parse(box.read(BoxName.passengerWalletTotal)) < 0
|
|
// ? double.parse(box.read(BoxName.passengerWalletTotal))
|
|
// .toStringAsFixed(2)
|
|
// : '0',
|
|
// box.read(BoxName.email).toString(),
|
|
// data[0]['start_address'],
|
|
// data[0]['end_address'],
|
|
// box.read(BoxName.carType),
|
|
// kazan.toStringAsFixed(0),
|
|
// passengerRate.toStringAsFixed(2),
|
|
// ];
|
|
// // Log.print('body: ${body}');
|
|
|
|
// FirebaseMessagesController().sendNotificationToDriverMAP(
|
|
// 'OrderSpeed',
|
|
// rideId.toString(),
|
|
// dataCarsLocationByPassenger['message'][i]['token'].toString(),
|
|
// body,
|
|
// 'order.wav');
|
|
// }
|
|
}
|
|
|
|
int tick = 0; // Move tick outside the function to maintain its state
|
|
|
|
// void delayAndFetchRideStatus(String rideId, carType) {
|
|
// Timer.periodic(const Duration(seconds: 1), (timer) async {
|
|
// if (shouldFetch) {
|
|
// if (remainingTimeToPassengerFromDriverAfterApplied > 0) {
|
|
// String res = await getRideStatus(rideId);
|
|
|
|
// Log.print('tick: $tick');
|
|
// String rideStatusDelayed = res.toString();
|
|
// if ((rideStatusDelayed == 'waiting' ||
|
|
// rideStatusDelayed == 'Refused') &&
|
|
// tick >= 15) {
|
|
// timer.cancel(); // Stop the current timer
|
|
// showAndResearchForCaptain();
|
|
// //TODO add to wait
|
|
// await getCarsLocationByPassengerAndReloadMarker(carType, 3000);
|
|
// // await getNearestDriverByPassengerLocationAPIGOOGLE();
|
|
// // getCarForFirstConfirm(carType);
|
|
// confirmRideForAllDriverAvailable();
|
|
// // delayAndFetchRideStatusForAllDriverAvailable(rideId);
|
|
// } else if (rideStatusDelayed == 'Apply' || statusRide == 'Apply') {
|
|
// Log.print('rideStatusDelayed == Apply: $rideStatusDelayed');
|
|
// // todo play sound
|
|
// Get.find<AudioRecorderController>()
|
|
// .playSoundFromAssets('assets/start.wav');
|
|
// timer.cancel(); // Stop the current timer
|
|
// await getUpdatedRideForDriverApply(rideId);
|
|
// shouldFetch = false; // Stop further fetches
|
|
// statusRide = 'Apply';
|
|
// rideConfirm = false;
|
|
// isSearchingWindow = false;
|
|
// update();
|
|
// startTimerFromDriverToPassengerAfterApplied();
|
|
// if (box.read(BoxName.carType) == 'Speed' ||
|
|
// box.read(BoxName.carType) == 'Awfar Car') {
|
|
// NotificationController().showNotification(
|
|
// 'The captain is responsible for the route.'.tr,
|
|
// 'This price is fixed even if the route changes for the driver.'
|
|
// .tr,
|
|
// 'ding');
|
|
// } else if (box.read(BoxName.carType) == 'Comfort' ||
|
|
// box.read(BoxName.carType) == 'Lady') {
|
|
// NotificationController().showNotification('Attention'.tr,
|
|
// 'The price may increase if the route changes.'.tr, 'ding');
|
|
// }
|
|
// } else if (rideStatusDelayed == 'Refused') {
|
|
// statusRide = 'Refused';
|
|
// if (isDriversTokensSend == false) {
|
|
// confirmRideForAllDriverAvailable();
|
|
// isDriversTokensSend = true;
|
|
// } // Start 15-second timer
|
|
// }
|
|
// //else if (isDriversTokensSend == false) {
|
|
// // No need to recall delayAndFetchRideStatus as Timer.periodic is already running
|
|
// update();
|
|
// // }
|
|
// if (tick < 19) {
|
|
// tick++;
|
|
// } else {
|
|
// timer.cancel();
|
|
// // Stop the timer if remainingTimeToPassengerFromDriverAfterApplied <= 0
|
|
// }
|
|
// } else {
|
|
// timer.cancel();
|
|
// // Stop the timer if remainingTimeToPassengerFromDriverAfterApplied <= 0
|
|
// }
|
|
// } else {
|
|
// timer.cancel(); // Stop the timer if shouldFetch is false
|
|
// }
|
|
// });
|
|
// }
|
|
|
|
showAndResearchForCaptain() {
|
|
Get.snackbar(
|
|
"No Captain Accepted Your Order".tr,
|
|
"We are looking for a captain but the price may increase to let a captain accept"
|
|
.tr,
|
|
duration: const Duration(seconds: 5),
|
|
backgroundColor: AppColor.yellowColor,
|
|
);
|
|
isSearchingWindow == true;
|
|
update();
|
|
}
|
|
|
|
String driversStatusForSearchWindow = '';
|
|
|
|
Future<void> confirmRideForAllDriverAvailable() async {
|
|
bool driversFound = false;
|
|
const maxAttempts = 8;
|
|
const attemptDelay = Duration(seconds: 3);
|
|
|
|
for (int attempt = 0; attempt < maxAttempts; attempt++) {
|
|
final reloadDuration = attempt > 5 ? 4500 : 3000;
|
|
await getCarsLocationByPassengerAndReloadMarker(
|
|
box.read(BoxName.carType), reloadDuration);
|
|
// await getNearestDriverByPassengerLocation();
|
|
driversStatusForSearchWindow = 'We are search for nearst driver'.tr;
|
|
if (isDriversDataValid()) {
|
|
driversFound = true;
|
|
break;
|
|
}
|
|
|
|
await Future.delayed(attemptDelay);
|
|
}
|
|
|
|
if (!driversFound) {
|
|
showNoDriversDialog();
|
|
return;
|
|
}
|
|
driversStatusForSearchWindow = 'Your order is being prepared'.tr;
|
|
Log.print('driversStatusForSearchWindow: $driversStatusForSearchWindow');
|
|
update();
|
|
await postRideDetailsToServer();
|
|
driversStatusForSearchWindow = 'Your order sent to drivers'.tr;
|
|
|
|
await notifyAvailableDrivers();
|
|
|
|
driversStatusForSearchWindow = 'The drivers are reviewing your request'.tr;
|
|
Log.print('driversStatusForSearchWindow: $driversStatusForSearchWindow');
|
|
update();
|
|
delayAndFetchRideStatusForAllDriverAvailable(rideId);
|
|
// update();
|
|
}
|
|
|
|
Future<void> updateConfirmRideForAllDriverAvailable() async {
|
|
bool driversFound = false;
|
|
const maxAttempts = 8;
|
|
const attemptDelay = Duration(seconds: 3);
|
|
|
|
for (int attempt = 0; attempt < maxAttempts; attempt++) {
|
|
final reloadDuration = attempt > 5 ? 4500 : 3000;
|
|
await getCarsLocationByPassengerAndReloadMarker(
|
|
box.read(BoxName.carType), reloadDuration);
|
|
// await getNearestDriverByPassengerLocation();
|
|
|
|
if (isDriversDataValid()) {
|
|
driversFound = true;
|
|
break;
|
|
}
|
|
|
|
await Future.delayed(attemptDelay);
|
|
}
|
|
|
|
if (!driversFound) {
|
|
showNoDriversDialog();
|
|
return;
|
|
}
|
|
|
|
// await postRideDetailsToServer();
|
|
delayAndFetchRideStatusForAllDriverAvailable(rideId);
|
|
// update();
|
|
await notifyAvailableDrivers();
|
|
}
|
|
|
|
bool isDriversDataValid() {
|
|
return dataCarsLocationByPassenger != 'failure' &&
|
|
dataCarsLocationByPassenger != null &&
|
|
dataCarsLocationByPassenger.containsKey('message') &&
|
|
dataCarsLocationByPassenger['message'] != null;
|
|
}
|
|
|
|
void showNoDriversDialog() {
|
|
Get.dialog(
|
|
BackdropFilter(
|
|
filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
|
|
child: CupertinoAlertDialog(
|
|
title: Text("No Car or Driver Found in your area.".tr,
|
|
style: AppStyle.title
|
|
.copyWith(fontSize: 20, fontWeight: FontWeight.bold)),
|
|
content: Text("No Car or Driver Found in your area.".tr,
|
|
style: AppStyle.title.copyWith(fontSize: 16)),
|
|
actions: [
|
|
CupertinoDialogAction(
|
|
onPressed: () {
|
|
Get.back();
|
|
Get.offAll(() => const MapPagePassenger());
|
|
},
|
|
child: Text('OK'.tr,
|
|
style: const TextStyle(color: AppColor.greenColor)),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
barrierDismissible: false,
|
|
);
|
|
}
|
|
|
|
Future<void> postRideDetailsToServer() async {
|
|
final paymentController = Get.find<PaymentController>();
|
|
final payload = constructRidePayload(paymentController);
|
|
|
|
try {
|
|
final response = await CRUD().post(
|
|
link: "${AppLink.seferCairoServer}/ride/rides/add.php",
|
|
payload: payload);
|
|
if (response is String) {
|
|
final parsedValue = jsonDecode(response);
|
|
rideId = parsedValue['message'];
|
|
} else if (response is Map) {
|
|
rideId = response['message'];
|
|
} else {
|
|
Log.print('Unexpected response type: ${response.runtimeType}');
|
|
}
|
|
} catch (e) {
|
|
Log.print('Error posting ride details: $e');
|
|
}
|
|
}
|
|
|
|
Map<String, dynamic> constructRidePayload(
|
|
PaymentController paymentController) {
|
|
final startLocation =
|
|
'${data[0]['start_location']['lat']},${data[0]['start_location']['lng']}';
|
|
final endLocation =
|
|
'${data[0]['end_location']['lat']},${data[0]['end_location']['lng']}';
|
|
|
|
return {
|
|
"start_location": startLocation,
|
|
"end_location": endLocation,
|
|
"date": DateTime.now().toString(),
|
|
"time": DateTime.now().toString(),
|
|
"endtime": durationToAdd.toString(),
|
|
"price": totalPassenger.toStringAsFixed(2),
|
|
"passenger_id": box.read(BoxName.passengerID).toString(),
|
|
"driver_id": dataCarsLocationByPassenger['message'][carsOrder]
|
|
['driver_id']
|
|
.toString(),
|
|
"status": "waiting",
|
|
'carType': box.read(BoxName.carType),
|
|
"price_for_driver": totalPassenger.toString(),
|
|
"price_for_passenger": totalME.toString(),
|
|
"distance": distance.toString(),
|
|
"paymentMethod": paymentController.isWalletChecked.toString(),
|
|
};
|
|
}
|
|
|
|
Future<void> notifyAvailableDrivers() async {
|
|
int iteration = 0;
|
|
const maxIterations = 5;
|
|
const iterationDelay = Duration(seconds: 2);
|
|
|
|
while (iteration < maxIterations) {
|
|
await Future.delayed(iterationDelay);
|
|
await getCarsLocationByPassengerAndReloadMarker(
|
|
box.read(BoxName.carType), 3000);
|
|
|
|
if (dataCarsLocationByPassenger != null &&
|
|
dataCarsLocationByPassenger.containsKey('message') &&
|
|
dataCarsLocationByPassenger['message'] != null) {
|
|
for (var driverData in dataCarsLocationByPassenger['message']) {
|
|
String driverId = driverData['driver_id'].toString();
|
|
if (!notifiedDrivers.contains(driverId)) {
|
|
notifiedDrivers.add(driverId);
|
|
double driverLat = double.parse(driverData['latitude']);
|
|
double driverLng = double.parse(driverData['longitude']);
|
|
double distanceToDriverInMeters = Geolocator.distanceBetween(
|
|
passengerLocation.latitude,
|
|
passengerLocation.longitude,
|
|
driverLat,
|
|
driverLng,
|
|
);
|
|
|
|
double distanceToDriverInKm = distanceToDriverInMeters *
|
|
1.25 / //to approximate to stright distance
|
|
1000;
|
|
double durationToDriverInHours =
|
|
distanceToDriverInKm / 25; // 25 km/h as default speed
|
|
double durationToDriverInSeconds = durationToDriverInHours * 3600;
|
|
durationToPassenger = durationToDriverInSeconds.toInt();
|
|
distanceByPassenger =
|
|
(distanceToDriverInMeters * 1.25).toStringAsFixed(0);
|
|
Future.delayed(const Duration(microseconds: 10));
|
|
final body = constructNotificationBody(driverData);
|
|
// Log.print('body:ww ${body}');
|
|
FirebaseMessagesController().sendNotificationToDriverMAP(
|
|
'Order'.tr,
|
|
endNameAddress,
|
|
encryptionHelper.decryptData(driverData['token'].toString()),
|
|
body,
|
|
'order.wav');
|
|
}
|
|
}
|
|
}
|
|
iteration++;
|
|
}
|
|
}
|
|
|
|
List<String> constructNotificationBody(var driverData) {
|
|
final paymentController = Get.find<PaymentController>();
|
|
return [
|
|
'${data[0]['start_location']['lat']},${data[0]['start_location']['lng']}',
|
|
'${data[0]['end_location']['lat']},${data[0]['end_location']['lng']}',
|
|
totalPassenger.toStringAsFixed(2),
|
|
totalDriver.toStringAsFixed(2),
|
|
durationToRide.toString(),
|
|
distance.toStringAsFixed(2),
|
|
driverData['driver_id'].toString(),
|
|
box.read(BoxName.passengerID).toString(),
|
|
encryptionHelper
|
|
.decryptData(box.read(BoxName.name).toString().split(' ')[0])
|
|
.toString(),
|
|
encryptionHelper.decryptData(box.read(BoxName.tokenFCM).toString()),
|
|
encryptionHelper.decryptData(box.read(BoxName.phone).toString()),
|
|
durationToPassenger.toStringAsFixed(0) ?? '120',
|
|
distanceByPassenger.toString() ?? '2000',
|
|
paymentController.isWalletChecked.toString(),
|
|
encryptionHelper.decryptData(driverData['token'].toString()),
|
|
durationToPassenger.toString(),
|
|
rideId.toString(),
|
|
rideTimerBegin.toString(),
|
|
driverData['driver_id'].toString(),
|
|
durationToRide.toString(),
|
|
Get.find<WayPointController>().wayPoints.length > 1
|
|
? 'haveSteps'
|
|
: 'startEnd',
|
|
placesCoordinate[0],
|
|
placesCoordinate[1],
|
|
placesCoordinate[2],
|
|
placesCoordinate[3],
|
|
placesCoordinate[4],
|
|
costForDriver.toStringAsFixed(2),
|
|
(double.parse(box.read(BoxName.passengerWalletTotal)) < 0
|
|
? double.parse(box.read(BoxName.passengerWalletTotal))
|
|
.toStringAsFixed(2)
|
|
: '0'),
|
|
box.read(BoxName.email).toString(),
|
|
data[0]['start_address'],
|
|
data[0]['end_address'],
|
|
box.read(BoxName.carType),
|
|
kazan.toStringAsFixed(0),
|
|
passengerRate.toStringAsFixed(2),
|
|
];
|
|
}
|
|
|
|
StreamController<String> _rideStatusStreamController =
|
|
StreamController<String>.broadcast();
|
|
Stream<String> get rideStatusStream => _rideStatusStreamController.stream;
|
|
|
|
Future<void> delayAndFetchRideStatusForAllDriverAvailable(
|
|
String rideId) async {
|
|
const int maxAttempts = 15;
|
|
int attemptCounter = 0;
|
|
bool isApplied = false;
|
|
tick = 0;
|
|
await addRideToNotificationDriverAvailable();
|
|
Timer.periodic(const Duration(seconds: 1), (timer) async {
|
|
if (attemptCounter >= maxAttempts || isApplied == true) {
|
|
timer.cancel();
|
|
_rideStatusStreamController.close(); // Close the stream when done
|
|
return;
|
|
}
|
|
|
|
attemptCounter++;
|
|
tick++;
|
|
|
|
try {
|
|
var res = await getRideStatus(rideId);
|
|
Log.print('res:2022 $res');
|
|
String rideStatusDelayed = res.toString();
|
|
Log.print('rideStatusDelayed: $rideStatusDelayed');
|
|
|
|
_rideStatusStreamController
|
|
.add(rideStatusDelayed); // Emit the ride status
|
|
// addRideToNotificationDriverString();
|
|
if (rideStatusDelayed == 'Cancel') {
|
|
timer.cancel();
|
|
NotificationController().showNotification(
|
|
"Order Cancelled".tr, "you canceled order".tr, 'ding');
|
|
_rideStatusStreamController
|
|
.close(); // Close stream after cancellation
|
|
//
|
|
//
|
|
} else if (rideStatusDelayed == 'Apply' ||
|
|
rideStatusDelayed == 'Applied') {
|
|
isApplied = true;
|
|
rideAppliedFromDriver(isApplied);
|
|
timer.cancel();
|
|
// Close stream after applying
|
|
} else if (attemptCounter >= maxAttempts ||
|
|
rideStatusDelayed != 'Cancel') {
|
|
timer.cancel(); //todo
|
|
// addRideToNotificationDriverString();
|
|
// Show dialog to increase fee...
|
|
// MyDialog().getDialog(
|
|
// 'Are you want to wait drivers to accept your order'.tr, '', () {
|
|
// Get.back();
|
|
// addRideToNotificationDriverAvailable();
|
|
// });
|
|
update();
|
|
_rideStatusStreamController
|
|
.close(); // Close stream after max attempts
|
|
}
|
|
} catch (e) {
|
|
_rideStatusStreamController.addError(e); // Handle errors in the stream
|
|
}
|
|
});
|
|
}
|
|
|
|
rideAppliedFromDriver(bool isApplied) async {
|
|
await getUpdatedRideForDriverApply(rideId);
|
|
NotificationController().showNotification(
|
|
'Order Accepted'.tr,
|
|
'$driverName ${'accepted your order at price'.tr} ${totalPassenger.toStringAsFixed(1)} ${'with type'.tr} ${box.read(BoxName.carType)}',
|
|
'ding');
|
|
if (box.read(BoxName.carType) == 'Speed' ||
|
|
box.read(BoxName.carType) == 'Awfar Car') {
|
|
NotificationController().showNotification(
|
|
'The captain is responsible for the route.'.tr,
|
|
'This price is fixed even if the route changes for the driver.'.tr,
|
|
'ding');
|
|
} else if (box.read(BoxName.carType) == 'Comfort' ||
|
|
box.read(BoxName.carType) == 'Lady') {
|
|
NotificationController().showNotification('Attention'.tr,
|
|
'The price may increase if the route changes.'.tr, 'ding');
|
|
}
|
|
isApplied = true;
|
|
statusRide = 'Apply';
|
|
rideConfirm = false;
|
|
isSearchingWindow = false;
|
|
update();
|
|
startTimer();
|
|
// todo stop this because this method in startTimer()
|
|
// startTimerFromDriverToPassengerAfterApplied();
|
|
|
|
// timer.cancel();
|
|
_rideStatusStreamController.close();
|
|
}
|
|
|
|
// Listening to the Stream
|
|
void listenToRideStatusStream() {
|
|
rideStatusStream.listen((rideStatus) {
|
|
print("Ride Status: $rideStatus");
|
|
// Handle updates based on the ride status
|
|
}, onError: (error) {
|
|
print("Error in Ride Status Stream: $error");
|
|
// Handle stream errors
|
|
}, onDone: () {
|
|
print("Ride status stream closed.");
|
|
});
|
|
}
|
|
|
|
reSearchAfterCanceledFromDriver() async {
|
|
shouldFetch = true; // Stop further fetches
|
|
statusRide = 'wait';
|
|
rideConfirm = true;
|
|
isSearchingWindow = true;
|
|
update();
|
|
updateConfirmRideForAllDriverAvailable();
|
|
}
|
|
|
|
void start15SecondTimer(String rideId) {
|
|
Timer(const Duration(seconds: 15), () {
|
|
delayAndFetchRideStatusForAllDriverAvailable(rideId);
|
|
});
|
|
}
|
|
|
|
void startTimer() async {
|
|
for (int i = 0; i <= durationTimer; i++) {
|
|
await Future.delayed(const Duration(seconds: 1));
|
|
progress = i / durationTimer;
|
|
remainingTime = durationTimer - i;
|
|
if (remainingTime == 0) {
|
|
rideConfirm = false;
|
|
|
|
timeToPassengerFromDriverAfterApplied += durationToPassenger;
|
|
|
|
// timeToPassengerFromDriverAfterApplied.toString());
|
|
startTimerFromDriverToPassengerAfterApplied();
|
|
update();
|
|
}
|
|
update();
|
|
}
|
|
timerEnded();
|
|
}
|
|
|
|
void timerEnded() async {
|
|
runEvery30SecondsUntilConditionMet();
|
|
isCancelRidePageShown = false;
|
|
print('isCancelRidePageShown: $isCancelRidePageShown');
|
|
update();
|
|
}
|
|
|
|
Future<String> getRideStatus(String rideId) async {
|
|
final response = await CRUD().get(
|
|
link: "${AppLink.endPoint}/ride/rides/getRideStatus.php",
|
|
payload: {'id': rideId});
|
|
print(response);
|
|
print('2140');
|
|
return jsonDecode(response)['data'];
|
|
}
|
|
|
|
late String driverCarModel,
|
|
driverCarMake,
|
|
driverLicensePlate,
|
|
driverName = '';
|
|
getUpdatedRideForDriverApply(String rideId) async {
|
|
// if (isDriversTokensSend) {
|
|
final res = await CRUD().get(
|
|
link: "${AppLink.endPoint}/ride/rides/getRideOrderID.php",
|
|
payload: {'id': rideId});
|
|
if (res != 'failure') {
|
|
var response = jsonDecode(res);
|
|
Log.print('getUpdatedRideForDriverApply: $response');
|
|
driverId = response['data']['driver_id'];
|
|
driverPhone = encryptionHelper.decryptData(response['data']['phone']);
|
|
driverCarMake = response['data']['make'];
|
|
model = response['data']['model'];
|
|
colorHex = response['data']['color_hex'];
|
|
carColor = response['data']['color'];
|
|
make = response['data']['make'];
|
|
licensePlate =
|
|
encryptionHelper.decryptData(response['data']['car_plate']);
|
|
passengerName =
|
|
encryptionHelper.decryptData(response['data']['passengerName']);
|
|
driverName = encryptionHelper
|
|
.decryptData(response['data']['driverName'].toString());
|
|
driverToken = encryptionHelper.decryptData(response['data']['token']);
|
|
// Log.print('driverToken updated: $driverToken');
|
|
carYear = response['data']['year'];
|
|
driverRate = response['data']['ratingDriver'].toString();
|
|
}
|
|
// driversToken.remove(driverToken);
|
|
// for (var i = 1; i < driversToken.length; i++) {
|
|
FirebaseMessagesController().sendNotificationToDriverMAP(
|
|
'Order Accepted'.tr,
|
|
'$driverName${'Accepted your order'.tr}',
|
|
driverToken.toString(),
|
|
[],
|
|
'start.wav',
|
|
);
|
|
// }
|
|
// }
|
|
}
|
|
|
|
late LatLng currentDriverLocation;
|
|
late double headingList;
|
|
|
|
// Future getCarsLocationByPassengerAndReloadMarker() async {
|
|
// if (statusRide == 'wait') {
|
|
// carsLocationByPassenger = [];
|
|
// LatLngBounds bounds = calculateBounds(
|
|
// passengerLocation.latitude, passengerLocation.longitude, 7000);
|
|
// var res;
|
|
// if (box.read(BoxName.carType) == 'Lady') {
|
|
// res = await CRUD()
|
|
// .get(link: AppLink.getFemalDriverLocationByPassenger, payload: {
|
|
// 'southwestLat': bounds.southwest.latitude.toString(),
|
|
// 'southwestLon': bounds.southwest.longitude.toString(),
|
|
// 'northeastLat': bounds.northeast.latitude.toString(),
|
|
// 'northeastLon': bounds.northeast.longitude.toString(),
|
|
// });
|
|
// } else if (box.read(BoxName.carType) == 'Speed') {
|
|
// res = await CRUD().get(
|
|
// link: AppLink.getCarsLocationByPassengerSpeed,
|
|
// payload: {
|
|
// 'southwestLat': bounds.southwest.latitude.toString(),
|
|
// 'southwestLon': bounds.southwest.longitude.toString(),
|
|
// 'northeastLat': bounds.northeast.latitude.toString(),
|
|
// 'northeastLon': bounds.northeast.longitude.toString(),
|
|
// },
|
|
// );
|
|
// } else if (box.read(BoxName.carType) == 'Delivery') {
|
|
// res = await CRUD().get(
|
|
// link: AppLink.getCarsLocationByPassengerDelivery,
|
|
// payload: {
|
|
// 'southwestLat': bounds.southwest.latitude.toString(),
|
|
// 'southwestLon': bounds.southwest.longitude.toString(),
|
|
// 'northeastLat': bounds.northeast.latitude.toString(),
|
|
// 'northeastLon': bounds.northeast.longitude.toString(),
|
|
// },
|
|
// );
|
|
// } else {
|
|
// res = await CRUD()
|
|
// .get(link: AppLink.getCarsLocationByPassenger, payload: {
|
|
// 'southwestLat': bounds.southwest.latitude.toString(),
|
|
// 'southwestLon': bounds.southwest.longitude.toString(),
|
|
// 'northeastLat': bounds.northeast.latitude.toString(),
|
|
// 'northeastLon': bounds.northeast.longitude.toString(),
|
|
// });
|
|
// }
|
|
// if (res == 'failure') {
|
|
// noCarString = true;
|
|
// dataCarsLocationByPassenger = res;
|
|
// update();
|
|
// } else {
|
|
// // Get.snackbar('no car', 'message');
|
|
// noCarString = false;
|
|
// dataCarsLocationByPassenger = jsonDecode(res);
|
|
// // if (dataCarsLocationByPassenger.length > carsOrder) {
|
|
// driverId = dataCarsLocationByPassenger['message'][carsOrder]
|
|
// ['driver_id']
|
|
// .toString();
|
|
// gender = dataCarsLocationByPassenger['message'][carsOrder]['gender']
|
|
// .toString();
|
|
// // }
|
|
|
|
// carsLocationByPassenger.clear(); // Clear existing markers
|
|
|
|
// // late LatLng lastDriverLocation; // Initialize a variable for last location
|
|
|
|
// for (var i = 0;
|
|
// i < dataCarsLocationByPassenger['message'].length;
|
|
// i++) {
|
|
// var json = dataCarsLocationByPassenger['message'][i];
|
|
// // CarLocationModel model = CarLocationModel.fromJson(json);
|
|
// if (carLocationsModels.length < i + 1) {
|
|
// // carLocationsModels.add(model);
|
|
// markers.add(
|
|
// Marker(
|
|
// markerId: MarkerId(json['latitude']),
|
|
// position: LatLng(
|
|
// double.parse(json['latitude']),
|
|
// double.parse(json['longitude']),
|
|
// ),
|
|
// rotation: double.parse(json['heading']),
|
|
// icon: json['model'].toString().contains('دراجة')
|
|
// ? motoIcon
|
|
// : json['gender'] == 'Male'.tr
|
|
// ? carIcon
|
|
// : ladyIcon,
|
|
// ),
|
|
// );
|
|
// driversToken.add(json['token']);
|
|
// // driversToken = json['token'];
|
|
// } else {
|
|
// // carLocationsModels[i] = model;
|
|
// markers[i] = Marker(
|
|
// markerId: MarkerId(json['latitude']),
|
|
// position: LatLng(
|
|
// double.parse(json['latitude']),
|
|
// double.parse(json['longitude']),
|
|
// ),
|
|
// rotation: double.parse(json['heading']),
|
|
// icon: json['model'].contains('دراجة')
|
|
// ? motoIcon
|
|
// : json['gender'] == 'Male'.tr
|
|
// ? carIcon
|
|
// : ladyIcon,
|
|
// );
|
|
// // driversToken = json['token'];
|
|
// driversToken.add(json['token']);
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// update();
|
|
// }
|
|
// }
|
|
|
|
Map<String, Timer> _animationTimers = {};
|
|
final int updateIntervalMs = 100; // Update every 100ms
|
|
final double minMovementThreshold =
|
|
10; // Minimum movement in meters to trigger update
|
|
Future getCarForFirstConfirm(String carType) async {
|
|
bool foundCars = false;
|
|
int attempt = 0;
|
|
|
|
// Set up the periodic timer
|
|
Timer? timer = Timer.periodic(const Duration(seconds: 4), (Timer t) async {
|
|
// Attempt to get car location
|
|
foundCars = await getCarsLocationByPassengerAndReloadMarker(
|
|
carType, attempt * 2000);
|
|
Log.print('foundCars: $foundCars');
|
|
|
|
if (foundCars) {
|
|
// If cars are found, cancel the timer and exit the search
|
|
t.cancel();
|
|
} else if (attempt >= 4) {
|
|
// After 4 attempts, stop the search
|
|
t.cancel();
|
|
|
|
// No cars found after 4 attempts
|
|
// MyDialog().getDialog(
|
|
// "No Car or Driver Found in your area.".tr,
|
|
// "No Car or Driver Found in your area.".tr,
|
|
// () {
|
|
// Get.back();
|
|
// },
|
|
// );
|
|
if (!foundCars) {
|
|
noCarString = true;
|
|
dataCarsLocationByPassenger = 'failure';
|
|
}
|
|
|
|
update();
|
|
}
|
|
|
|
attempt++; // Increment attempt
|
|
});
|
|
}
|
|
|
|
void startCarLocationSearch(String carType) {
|
|
int searchInterval = 5; // Interval in seconds
|
|
Log.print('searchInterval: $searchInterval');
|
|
int boundIncreaseStep = 2500; // Initial bounds in meters
|
|
Log.print('boundIncreaseStep: $boundIncreaseStep');
|
|
int maxAttempts = 3; // Maximum attempts to increase bounds
|
|
int maxBoundIncreaseStep = 6000; // Maximum bounds increase step
|
|
int attempt = 0; // Current attempt
|
|
Log.print('initial attempt: $attempt');
|
|
|
|
Timer.periodic(Duration(seconds: searchInterval), (Timer timer) async {
|
|
Log.print('Current attempt: $attempt'); // Log current attempt
|
|
bool foundCars = false;
|
|
if (attempt >= maxAttempts) {
|
|
timer.cancel();
|
|
if (foundCars == false) {
|
|
noCarString = true;
|
|
// dataCarsLocationByPassenger = 'failure';
|
|
update();
|
|
}
|
|
|
|
// return;
|
|
} else if (reloadStartApp == true) {
|
|
Log.print('reloadStartApp: $reloadStartApp');
|
|
foundCars = await getCarsLocationByPassengerAndReloadMarker(
|
|
carType, boundIncreaseStep);
|
|
Log.print('foundCars: $foundCars');
|
|
|
|
if (foundCars) {
|
|
timer.cancel();
|
|
} else {
|
|
attempt++;
|
|
if (reloadCount >= 3 || tick > 18 || reloadCount > 15) {
|
|
timer.cancel();
|
|
}
|
|
Log.print(
|
|
'Incrementing attempt to: $attempt'); // Log incremented attempt
|
|
|
|
if (boundIncreaseStep < maxBoundIncreaseStep) {
|
|
boundIncreaseStep += 1500; // Increase bounds
|
|
if (boundIncreaseStep > maxBoundIncreaseStep) {
|
|
boundIncreaseStep =
|
|
maxBoundIncreaseStep; // Ensure it does not exceed the maximum
|
|
}
|
|
Log.print(
|
|
'New boundIncreaseStep: $boundIncreaseStep'); // Log new bounds
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
String getLocationArea(double latitude, double longitude) {
|
|
final locations = box.read(BoxName.locationName) ?? [];
|
|
for (final location in locations) {
|
|
final locationData = location as Map<String, dynamic>;
|
|
|
|
// Debugging: Print location data
|
|
// print('Location Data: $locationData');
|
|
|
|
// Convert string values to double
|
|
final minLatitude =
|
|
double.tryParse(locationData['min_latitude'].toString()) ?? 0.0;
|
|
final maxLatitude =
|
|
double.tryParse(locationData['max_latitude'].toString()) ?? 0.0;
|
|
final minLongitude =
|
|
double.tryParse(locationData['min_longitude'].toString()) ?? 0.0;
|
|
final maxLongitude =
|
|
double.tryParse(locationData['max_longitude'].toString()) ?? 0.0;
|
|
|
|
// Debugging: Print converted values
|
|
print(
|
|
'Converted Values: minLatitude=$minLatitude, maxLatitude=$maxLatitude, minLongitude=$minLongitude, maxLongitude=$maxLongitude');
|
|
|
|
if (latitude >= minLatitude &&
|
|
latitude <= maxLatitude &&
|
|
longitude >= minLongitude &&
|
|
longitude <= maxLongitude) {
|
|
box.write(BoxName.serverChosen,
|
|
encryptionHelper.decryptData(locationData['server_link']));
|
|
// Log.print(
|
|
// 'locationData----server_link: ${encryptionHelper.decryptData(locationData['server_link'])}');
|
|
return locationData['name'];
|
|
}
|
|
}
|
|
|
|
// Default case
|
|
box.write(BoxName.serverChosen, AppLink.seferCairoServer);
|
|
return 'Cairo';
|
|
}
|
|
|
|
// if (latitude >= 29.918901 &&
|
|
// latitude <= 30.198857 &&
|
|
// longitude >= 31.215009 &&
|
|
// longitude <= 31.532186) {
|
|
// box.write(BoxName.serverChosen, AppLink.seferCairoServer);
|
|
|
|
// return 'Cairo';
|
|
// } else if (latitude >= 29.904975 &&
|
|
// latitude <= 30.143372 &&
|
|
// longitude >= 30.787030 &&
|
|
// longitude <= 31.215009) {
|
|
// box.write(BoxName.serverChosen, AppLink.seferGizaServer);
|
|
// return 'Giza';
|
|
// } else if (latitude >= 30.396286 &&
|
|
// latitude <= 31.654458 &&
|
|
// longitude >= 29.041139 &&
|
|
// longitude <= 32.626259) {
|
|
// box.write(BoxName.serverChosen, AppLink.seferAlexandriaServer);
|
|
// return 'Alexandria';
|
|
// } else {
|
|
// box.write(BoxName.serverChosen, AppLink.seferCairoServer);
|
|
// return 'Cairo';
|
|
// }
|
|
// }
|
|
|
|
Future<bool> getCarsLocationByPassengerAndReloadMarker(
|
|
String carType, int boundIncreaseStep) async {
|
|
// if (statusRide == 'wait') {
|
|
carsLocationByPassenger = [];
|
|
LatLngBounds bounds = calculateBounds(passengerLocation.latitude,
|
|
passengerLocation.longitude, boundIncreaseStep.toDouble());
|
|
var res;
|
|
// await getLocation();
|
|
|
|
switch (carType) {
|
|
case 'Lady':
|
|
res = await CRUD()
|
|
.get(link: AppLink.getFemalDriverLocationByPassenger, payload: {
|
|
'southwestLat': bounds.southwest.latitude.toString(),
|
|
'southwestLon': bounds.southwest.longitude.toString(),
|
|
'northeastLat': bounds.northeast.latitude.toString(),
|
|
'northeastLon': bounds.northeast.longitude.toString(),
|
|
});
|
|
break;
|
|
case 'Comfort':
|
|
res = await CRUD()
|
|
.get(link: AppLink.getCarsLocationByPassengerComfort, payload: {
|
|
'southwestLat': bounds.southwest.latitude.toString(),
|
|
'southwestLon': bounds.southwest.longitude.toString(),
|
|
'northeastLat': bounds.northeast.latitude.toString(),
|
|
'northeastLon': bounds.northeast.longitude.toString(),
|
|
});
|
|
break;
|
|
case 'Speed':
|
|
res = await CRUD()
|
|
.get(link: AppLink.getCarsLocationByPassengerSpeed, payload: {
|
|
'southwestLat': bounds.southwest.latitude.toString(),
|
|
'southwestLon': bounds.southwest.longitude.toString(),
|
|
'northeastLat': bounds.northeast.latitude.toString(),
|
|
'northeastLon': bounds.northeast.longitude.toString(),
|
|
});
|
|
break;
|
|
case 'Scooter':
|
|
res = await CRUD()
|
|
.get(link: AppLink.getCarsLocationByPassengerDelivery, payload: {
|
|
'southwestLat': bounds.southwest.latitude.toString(),
|
|
'southwestLon': bounds.southwest.longitude.toString(),
|
|
'northeastLat': bounds.northeast.latitude.toString(),
|
|
'northeastLon': bounds.northeast.longitude.toString(),
|
|
});
|
|
break;
|
|
case 'Awfar Car':
|
|
res = await CRUD()
|
|
.get(link: AppLink.getCarsLocationByPassengerBalash, payload: {
|
|
'southwestLat': bounds.southwest.latitude.toString(),
|
|
'southwestLon': bounds.southwest.longitude.toString(),
|
|
'northeastLat': bounds.northeast.latitude.toString(),
|
|
'northeastLon': bounds.northeast.longitude.toString(),
|
|
});
|
|
break;
|
|
case 'Pink Bike':
|
|
res = await CRUD()
|
|
.get(link: AppLink.getCarsLocationByPassengerPinkBike, payload: {
|
|
'southwestLat': bounds.southwest.latitude.toString(),
|
|
'southwestLon': bounds.southwest.longitude.toString(),
|
|
'northeastLat': bounds.northeast.latitude.toString(),
|
|
'northeastLon': bounds.northeast.longitude.toString(),
|
|
});
|
|
break;
|
|
default:
|
|
res = await CRUD()
|
|
.get(link: AppLink.getCarsLocationByPassenger, payload: {
|
|
'southwestLat': bounds.southwest.latitude.toString(),
|
|
'southwestLon': bounds.southwest.longitude.toString(),
|
|
'northeastLat': bounds.northeast.latitude.toString(),
|
|
'northeastLon': bounds.northeast.longitude.toString(),
|
|
});
|
|
}
|
|
|
|
if (res == 'failure') {
|
|
noCarString = true;
|
|
// dataCarsLocationByPassenger = 'failure';
|
|
update();
|
|
return false;
|
|
} else {
|
|
noCarString = false;
|
|
dataCarsLocationByPassenger = jsonDecode(res);
|
|
Log.print(
|
|
'dataCarsLocationByPassenger:getCarsLocationByPassengerAndReloadMarker $dataCarsLocationByPassenger');
|
|
|
|
// Check if 'message' is present and not null
|
|
if (dataCarsLocationByPassenger != null &&
|
|
dataCarsLocationByPassenger.isNotEmpty) {
|
|
// Check if carsOrder is within bounds
|
|
// if (carsOrder < dataCarsLocationByPassenger['message'].length) {
|
|
// driverId = dataCarsLocationByPassenger['message'][carsOrder]
|
|
// ['driver_id']
|
|
// .toString();
|
|
// gender = dataCarsLocationByPassenger['message'][carsOrder]['gender']
|
|
// .toString();
|
|
// driverToken = dataCarsLocationByPassenger['message'][carsOrder]
|
|
// ['token']
|
|
// .toString();
|
|
// } else {
|
|
print('carsOrder is in of bounds for message array');
|
|
// return false;
|
|
// }
|
|
} else {
|
|
// Get.defaultDialog(title: 'No cars available ');
|
|
print('No cars available or message is null');
|
|
return false;
|
|
}
|
|
|
|
carsLocationByPassenger.clear(); // Clear existing markers
|
|
|
|
for (var i = 0; i < dataCarsLocationByPassenger['message'].length; i++) {
|
|
var json = dataCarsLocationByPassenger['message'][i];
|
|
_updateOrCreateMarker(
|
|
MarkerId(json['latitude']).toString(),
|
|
LatLng(
|
|
double.parse(json['latitude']), double.parse(json['longitude'])),
|
|
double.parse(json['heading']),
|
|
_getIconForCar(json),
|
|
);
|
|
|
|
driversToken.add(encryptionHelper.decryptData(json['token']));
|
|
}
|
|
|
|
// Add fake car markers
|
|
_addFakeCarMarkers(passengerLocation, 1);
|
|
|
|
update();
|
|
return true;
|
|
}
|
|
// }
|
|
// return false;
|
|
}
|
|
|
|
final List<Map<String, dynamic>> fakeCarData = [];
|
|
|
|
void _addFakeCarMarkers(LatLng center, int count) {
|
|
if (fakeCarData.isEmpty) {
|
|
Random random = Random();
|
|
double radiusInKm = 2.5; // 3 km diameter, so 1.5 km radius
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
// Generate a random angle and distance within the circle
|
|
double angle = random.nextDouble() * 2 * pi;
|
|
double distance = sqrt(random.nextDouble()) * radiusInKm;
|
|
|
|
// Convert distance to latitude and longitude offsets
|
|
double latOffset = (distance / 111.32); // 1 degree lat ≈ 111.32 km
|
|
double lonOffset =
|
|
(distance / (111.32 * cos(radians(center.latitude))));
|
|
|
|
// Calculate new position
|
|
double lat = center.latitude + (latOffset * cos(angle));
|
|
double lon = center.longitude + (lonOffset * sin(angle));
|
|
|
|
double heading = random.nextDouble() * 360;
|
|
|
|
fakeCarData.add({
|
|
'id': 'fake_$i',
|
|
'latitude': lat,
|
|
'longitude': lon,
|
|
'heading': heading,
|
|
'gender': 'Male', // Randomize gender
|
|
});
|
|
}
|
|
}
|
|
|
|
for (var carData in fakeCarData) {
|
|
_updateOrCreateMarker(
|
|
MarkerId(carData['id']).toString(),
|
|
LatLng(carData['latitude'], carData['longitude']),
|
|
carData['heading'],
|
|
_getIconForCar(carData),
|
|
);
|
|
}
|
|
}
|
|
|
|
BitmapDescriptor _getIconForCar(Map<String, dynamic> carData) {
|
|
if (carData['model'].toString().contains('دراجة')) {
|
|
return motoIcon;
|
|
} else if (carData['gender'] == 'Female') {
|
|
return ladyIcon;
|
|
} else {
|
|
return carIcon;
|
|
}
|
|
}
|
|
|
|
void _updateOrCreateMarker(String markerId, LatLng newPosition,
|
|
double newHeading, BitmapDescriptor icon) {
|
|
Marker? existingMarker = markers.cast<Marker?>().firstWhere(
|
|
(m) => m?.markerId == MarkerId(markerId),
|
|
orElse: () => null,
|
|
);
|
|
|
|
if (existingMarker == null) {
|
|
markers.add(Marker(
|
|
markerId: MarkerId(markerId),
|
|
position: newPosition,
|
|
rotation: newHeading,
|
|
icon: icon,
|
|
));
|
|
} else {
|
|
double distance =
|
|
_calculateDistance(existingMarker.position, newPosition);
|
|
if (distance >= minMovementThreshold) {
|
|
_smoothlyUpdateMarker(existingMarker, newPosition, newHeading, icon);
|
|
}
|
|
}
|
|
}
|
|
|
|
void _smoothlyUpdateMarker(Marker oldMarker, LatLng newPosition,
|
|
double newHeading, BitmapDescriptor icon) {
|
|
String markerId = oldMarker.markerId.value;
|
|
LatLng startPosition = oldMarker.position;
|
|
double startHeading = oldMarker.rotation ?? 0;
|
|
|
|
_animationTimers[markerId]?.cancel();
|
|
_animationTimers[markerId] =
|
|
Timer.periodic(Duration(milliseconds: updateIntervalMs), (timer) {
|
|
double progress =
|
|
timer.tick / (500 / updateIntervalMs); // 500ms total duration
|
|
if (progress >= 1.0) {
|
|
timer.cancel();
|
|
_animationTimers.remove(markerId);
|
|
progress = 1.0;
|
|
}
|
|
|
|
LatLng intermediatePosition = LatLng(
|
|
startPosition.latitude +
|
|
(newPosition.latitude - startPosition.latitude) * progress,
|
|
startPosition.longitude +
|
|
(newPosition.longitude - startPosition.longitude) * progress);
|
|
double intermediateHeading =
|
|
startHeading + (newHeading - startHeading) * progress;
|
|
|
|
markers.removeWhere((m) => m.markerId == oldMarker.markerId);
|
|
markers.add(Marker(
|
|
markerId: oldMarker.markerId,
|
|
position: intermediatePosition,
|
|
rotation: intermediateHeading,
|
|
icon: icon,
|
|
));
|
|
|
|
update();
|
|
});
|
|
}
|
|
|
|
double _calculateDistance(LatLng start, LatLng end) {
|
|
// Implement distance calculation (e.g., Haversine formula)
|
|
// For simplicity, this is a placeholder. Replace with actual implementation.
|
|
return 1000 *
|
|
sqrt(pow(start.latitude - end.latitude, 2) +
|
|
pow(start.longitude - end.longitude, 2));
|
|
}
|
|
|
|
Future getTokenForParent() async {
|
|
if (box.read(BoxName.sosPhonePassenger) == null) {
|
|
Get.defaultDialog(
|
|
title: 'Add SOS Phone'.tr,
|
|
titleStyle: AppStyle.title,
|
|
content: Form(
|
|
key: sosFormKey,
|
|
child: MyTextForm(
|
|
controller: sosPhonePassengerProfile,
|
|
label: 'insert sos phone'.tr,
|
|
hint: 'insert sos phone'.tr,
|
|
type: TextInputType.phone,
|
|
),
|
|
),
|
|
confirm: MyElevatedButton(
|
|
title: 'Add SOS Phone'.tr,
|
|
onPressed: () async {
|
|
if (sosFormKey.currentState!.validate()) {
|
|
Get.back();
|
|
await CRUD().post(
|
|
link: AppLink.updateprofile,
|
|
payload: {
|
|
'id': box.read(BoxName.passengerID),
|
|
'sosPhone': sosPhonePassengerProfile.text,
|
|
},
|
|
);
|
|
box.write(
|
|
BoxName.sosPhonePassenger, sosPhonePassengerProfile.text);
|
|
}
|
|
}));
|
|
}
|
|
|
|
var res = await CRUD().getTokenParent(
|
|
link: AppLink.getTokenParent,
|
|
payload: {'phone': '+2${box.read(BoxName.sosPhonePassenger)}'});
|
|
|
|
// Check if `res` is already a map
|
|
if (res is Map<String, dynamic>) {
|
|
var res1 = res;
|
|
handleResponse(res1);
|
|
} else {
|
|
// If it's a string, decode it
|
|
var res1 = jsonDecode(res);
|
|
handleResponse(res1);
|
|
}
|
|
}
|
|
|
|
// Function to check if the point is inside the polygon
|
|
bool isPointInPolygon(LatLng point, List<LatLng> polygon) {
|
|
int intersections = 0;
|
|
for (int i = 0; i < polygon.length; i++) {
|
|
LatLng vertex1 = polygon[i];
|
|
LatLng vertex2 =
|
|
polygon[(i + 1) % polygon.length]; // Loop back to the start
|
|
|
|
if (_rayIntersectsSegment(point, vertex1, vertex2)) {
|
|
intersections++;
|
|
}
|
|
}
|
|
|
|
// If the number of intersections is odd, the point is inside
|
|
return intersections % 2 != 0;
|
|
}
|
|
|
|
// Helper function to check if a ray from the point intersects with a polygon segment
|
|
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;
|
|
|
|
// Check if the point is outside the vertical bounds of the segment
|
|
if ((py < v1y && py < v2y) || (py > v1y && py > v2y)) {
|
|
return false;
|
|
}
|
|
|
|
// Calculate the intersection of the ray and the segment
|
|
double intersectX = v1x + (py - v1y) * (v2x - v1x) / (v2y - v1y);
|
|
|
|
// Check if the intersection is to the right of the point
|
|
return intersectX > px;
|
|
}
|
|
|
|
bool isInUniversity = false;
|
|
// Function to check if the passenger is in any university polygon
|
|
// Function to check if the passenger is in any university polygon and return the university name
|
|
String checkPassengerLocation(LatLng passengerLocation,
|
|
List<List<LatLng>> universityPolygons, List<String> 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";
|
|
}
|
|
|
|
String passengerLocationStringUnvirsity = 'unKnown';
|
|
void getPassengerLocationUniversity() {
|
|
// Check if the passenger is inside any of the university polygons and get the university name
|
|
passengerLocationStringUnvirsity = checkPassengerLocation(
|
|
passengerLocation,
|
|
UniversitiesPolygons.universityPolygons,
|
|
UniversitiesPolygons.universityNames,
|
|
);
|
|
if (passengerLocationStringUnvirsity != 'unKnown') {
|
|
// Get.snackbar('you are in $passengerLocationStringUnvirsity', "");
|
|
}
|
|
print(passengerLocationStringUnvirsity);
|
|
}
|
|
|
|
var polygons = <Polygon>{}.obs;
|
|
|
|
// Initialize polygons from UniversitiesPolygons
|
|
void _initializePolygons() {
|
|
List<List<LatLng>> universityPolygons =
|
|
UniversitiesPolygons.universityPolygons;
|
|
List<String> universityNames = UniversitiesPolygons.universityNames;
|
|
|
|
for (int i = 0; i < universityPolygons.length; i++) {
|
|
Polygon polygon = Polygon(
|
|
polygonId: PolygonId(universityNames[i]),
|
|
points: universityPolygons[i],
|
|
strokeColor: Colors.blueAccent,
|
|
fillColor: Colors.blueAccent.withOpacity(0.2),
|
|
strokeWidth: 2,
|
|
);
|
|
polygons.add(polygon); // Add polygon to observable set
|
|
}
|
|
}
|
|
|
|
void handleResponse(Map<String, dynamic> res1) {
|
|
if (res1['message'] == "No passenger found for the given phone number") {
|
|
Get.defaultDialog(
|
|
title: "No user found for the given phone number".tr,
|
|
titleStyle: AppStyle.title,
|
|
content: Column(
|
|
children: [
|
|
Text(
|
|
"No passenger found for the given phone number".tr,
|
|
style: AppStyle.title,
|
|
),
|
|
Text(
|
|
"Send SPEED app to him".tr,
|
|
style: AppStyle.title.copyWith(color: AppColor.greenColor),
|
|
)
|
|
],
|
|
),
|
|
confirm: MyElevatedButton(
|
|
title: 'Ok'.tr,
|
|
onPressed: () {
|
|
Get.back();
|
|
var phone = box.read(BoxName.countryCode) == 'Egypt'
|
|
? '+2${box.read(BoxName.sosPhonePassenger)}'
|
|
: '+962${box.read(BoxName.sosPhonePassenger)}';
|
|
var message = '''Dear ,
|
|
|
|
🚀 I have just started an exciting trip and I would like to share the details of my journey and my current location with you in real-time! Please download the SPEED app. It will allow you to view my trip details and my latest location.
|
|
|
|
👉 Download link:
|
|
Android [https://play.google.com/store/apps/details?id=com.mobileapp.store.ride]
|
|
iOS [https://getapp.cc/app/6458734951]
|
|
|
|
I look forward to keeping you close during my adventure!
|
|
|
|
SPEED ,'''
|
|
.tr;
|
|
launchCommunication('whatsapp', phone, message);
|
|
}),
|
|
cancel: MyElevatedButton(
|
|
title: 'No'.tr,
|
|
onPressed: () {
|
|
Get.back();
|
|
}));
|
|
} else if (res1['status'] == 'success') {
|
|
var tokenParent = encryptionHelper.decryptData(res1['data'][0]['token']);
|
|
Get.snackbar("The invitation was sent successfully".tr, '',
|
|
backgroundColor: AppColor.greenColor);
|
|
FirebaseMessagesController().sendNotificationToPassengerToken(
|
|
"Trip Monitoring".tr,
|
|
"Trip Monitoring".tr,
|
|
tokenParent,
|
|
[rideId, driverId],
|
|
'order1.wav',
|
|
);
|
|
box.write(BoxName.parentTripSelected, true);
|
|
box.write(BoxName.tokenParent, tokenParent);
|
|
}
|
|
}
|
|
|
|
LatLng driverLocationToPassenger = const LatLng(32, 35);
|
|
Future getDriverCarsLocationToPassengerAfterApplied() async {
|
|
driverCarsLocationToPassengerAfterApplied = [];
|
|
|
|
var res = await CRUD().get(
|
|
link: AppLink.getDriverCarsLocationToPassengerAfterApplied,
|
|
payload: {'driver_id': driverId});
|
|
|
|
datadriverCarsLocationToPassengerAfterApplied = jsonDecode(res);
|
|
driverLocationToPassenger = LatLng(
|
|
double.parse(datadriverCarsLocationToPassengerAfterApplied['message'][0]
|
|
['latitude']),
|
|
double.parse(datadriverCarsLocationToPassengerAfterApplied['message'][0]
|
|
['longitude']));
|
|
driverCarsLocationToPassengerAfterApplied.add(LatLng(
|
|
double.parse(datadriverCarsLocationToPassengerAfterApplied['message'][0]
|
|
['latitude']),
|
|
double.parse(datadriverCarsLocationToPassengerAfterApplied['message'][0]
|
|
['longitude'])));
|
|
CarLocationModel model = CarLocationModel.fromJson(
|
|
datadriverCarsLocationToPassengerAfterApplied['message'][0]);
|
|
carLocationsModels.add(model);
|
|
update();
|
|
}
|
|
|
|
Future runEvery30SecondsUntilConditionMet() async {
|
|
// Calculate the duration of the trip in minutes.
|
|
double tripDurationInMinutes = durationToPassenger / 5;
|
|
int loopCount = tripDurationInMinutes.ceil();
|
|
// If the trip duration is less than or equal to 50 minutes, then break the loop.
|
|
for (var i = 0; i < loopCount; i++) {
|
|
// Wait for 50 seconds.
|
|
await Future.delayed(const Duration(seconds: 5));
|
|
if (rideTimerBegin == true || statusRide == 'Apply') {
|
|
await getDriverCarsLocationToPassengerAfterApplied();
|
|
reloadMarkerDriverCarsLocationToPassengerAfterApplied();
|
|
}
|
|
}
|
|
}
|
|
|
|
Future runWhenRideIsBegin() async {
|
|
// Calculate the duration of the trip in minutes.
|
|
double tripDurationInMinutes = durationToRide / 6;
|
|
int loopCount = tripDurationInMinutes.ceil();
|
|
// If the trip duration is less than or equal to 50 minutes, then break the loop.
|
|
clearMarkersExceptStartEnd();
|
|
for (var i = 0; i < loopCount; i++) {
|
|
// Wait for 50 seconds.
|
|
await Future.delayed(const Duration(seconds: 4));
|
|
// if (rideTimerBegin == true && statusRide == 'Apply') {
|
|
await getDriverCarsLocationToPassengerAfterApplied();
|
|
// }
|
|
reloadMarkerDriverCarsLocationToPassengerAfterApplied();
|
|
}
|
|
}
|
|
|
|
Timer? _timer;
|
|
// final int updateIntervalMs = 100; // Update every 100ms
|
|
// final double minMovementThreshold =
|
|
// 1.0; // Minimum movement in meters to trigger update
|
|
|
|
void clearMarkersExceptStartEnd() {
|
|
Set<Marker> markersToRemove = markers
|
|
.where((marker) =>
|
|
marker.markerId != const MarkerId("start") &&
|
|
marker.markerId != const MarkerId("end"))
|
|
.toSet();
|
|
|
|
for (Marker marker in markersToRemove) {
|
|
markers.remove(marker);
|
|
}
|
|
update();
|
|
}
|
|
|
|
void reloadMarkerDriverCarsLocationToPassengerAfterApplied() {
|
|
// clearMarkersExceptStartEnd();
|
|
|
|
LatLng driverPosition = LatLng(
|
|
double.parse(datadriverCarsLocationToPassengerAfterApplied['message'][0]
|
|
['latitude']),
|
|
double.parse(datadriverCarsLocationToPassengerAfterApplied['message'][0]
|
|
['longitude']));
|
|
|
|
double heading = double.parse(
|
|
datadriverCarsLocationToPassengerAfterApplied['message'][0]['heading']
|
|
.toString());
|
|
|
|
BitmapDescriptor icon =
|
|
datadriverCarsLocationToPassengerAfterApplied['message'][0]
|
|
['model']
|
|
.toString()
|
|
.contains('دراجة') ||
|
|
datadriverCarsLocationToPassengerAfterApplied['message'][0]
|
|
['make']
|
|
.toString()
|
|
.contains('دراجة')
|
|
? motoIcon
|
|
: datadriverCarsLocationToPassengerAfterApplied['message'][0]
|
|
['gender'] ==
|
|
'Female'
|
|
? ladyIcon
|
|
: carIcon;
|
|
|
|
_updateMarkerPosition(driverPosition, heading, icon);
|
|
}
|
|
|
|
void _updateMarkerPosition(
|
|
LatLng newPosition, double newHeading, BitmapDescriptor icon) {
|
|
const String markerId = 'driverToPassengers';
|
|
Marker? existingMarker = markers.cast<Marker?>().firstWhere(
|
|
(m) => m?.markerId == const MarkerId(markerId),
|
|
orElse: () => null,
|
|
);
|
|
|
|
if (existingMarker == null) {
|
|
// If the marker doesn't exist, create it at the new position
|
|
markers.add(Marker(
|
|
markerId: const MarkerId(markerId),
|
|
position: newPosition,
|
|
rotation: newHeading,
|
|
icon: icon,
|
|
));
|
|
update();
|
|
} else {
|
|
// If the marker exists, check if the movement is significant enough to update
|
|
double distance =
|
|
_calculateDistance(existingMarker.position, newPosition);
|
|
if (distance >= minMovementThreshold) {
|
|
_smoothlyUpdateMarker(existingMarker, newPosition, newHeading, icon);
|
|
}
|
|
}
|
|
|
|
mapController?.animateCamera(CameraUpdate.newLatLng(newPosition));
|
|
}
|
|
|
|
@override
|
|
void onClose() {
|
|
_timer?.cancel();
|
|
_animationTimers.forEach((_, timer) => timer.cancel());
|
|
_animationTimers.clear();
|
|
super.onClose();
|
|
}
|
|
|
|
restCounter() {
|
|
clearPlacesDestination();
|
|
clearPolyline();
|
|
data = [];
|
|
rideConfirm = false;
|
|
shouldFetch = false;
|
|
timeToPassengerFromDriverAfterApplied = 0;
|
|
update();
|
|
}
|
|
|
|
Future<void> cancelRideAfterRejectFromAll() async {
|
|
clearPlacesDestination();
|
|
clearPolyline();
|
|
data = [];
|
|
await CRUD().post(link: AppLink.updateRides, payload: {
|
|
"id": rideId.toString(), // Convert to String
|
|
"status": 'notApplyFromAnyDriver'
|
|
});
|
|
if (AppLink.endPoint != AppLink.seferCairoServer) {
|
|
CRUD().post(link: "${AppLink.endPoint}/ride/rides/update.php", payload: {
|
|
"id": rideId.toString(), // Convert to String
|
|
"status": 'notApplyFromAnyDriver'
|
|
});
|
|
}
|
|
rideConfirm = false;
|
|
statusRide == 'Cancel';
|
|
isSearchingWindow = false;
|
|
shouldFetch = false;
|
|
isPassengerChosen = false;
|
|
isCashConfirmPageShown = false;
|
|
// totalStepDurations = 0;
|
|
isCashSelectedBeforeConfirmRide = false;
|
|
timeToPassengerFromDriverAfterApplied = 0;
|
|
changeCancelRidePageShow();
|
|
remainingTime = 0;
|
|
|
|
update();
|
|
}
|
|
|
|
Future cancelRide() async {
|
|
// if (rideConfirm == true ||
|
|
// statusRide == 'Apply' ||
|
|
// statusRide == 'Applied' ||
|
|
// statusRide == 'wait' ||
|
|
// statusRide == 'waiting') {
|
|
clearPlacesDestination();
|
|
clearPolyline();
|
|
// clearPolylineAll();
|
|
data = [];
|
|
changeCancelRidePageShow();
|
|
if (rideId != 'yet') {
|
|
Log.print('cancelRide: 1');
|
|
await FirebaseMessagesController().sendNotificationToDriverMAP(
|
|
'Cancel Trip'.tr,
|
|
'Trip Cancelled'.tr,
|
|
driverToken.toString(),
|
|
[],
|
|
'cancel.wav',
|
|
);
|
|
|
|
await Future.wait([
|
|
CRUD().post(link: AppLink.updateRides, payload: {
|
|
"id": rideId.toString(), // Convert to String
|
|
"status": 'Cancel'
|
|
}),
|
|
CRUD().post(link: AppLink.updateDriverOrder, payload: {
|
|
"order_id": rideId.toString(), // Convert to String
|
|
"status": 'Cancel'
|
|
}),
|
|
CRUD().post(link: AppLink.updateWaitingTrip, payload: {
|
|
"id": rideId.toString(), // Convert to String
|
|
"status": 'Cancel'
|
|
}),
|
|
]);
|
|
|
|
if (AppLink.endPoint != AppLink.seferCairoServer) {
|
|
CRUD().post(
|
|
link: "${AppLink.endPoint}/ride/driver_order/update.php",
|
|
payload: {
|
|
"order_id": rideId.toString(), // Convert to String
|
|
"status": 'Cancel'
|
|
});
|
|
CRUD()
|
|
.post(link: "${AppLink.endPoint}/ride/rides/update.php", payload: {
|
|
"id": rideId.toString(), // Convert to String
|
|
"status": 'Cancel'
|
|
});
|
|
CRUD().post(
|
|
link:
|
|
"${AppLink.endPoint}/ride/notificationCaptain/updateWaitingTrip.php",
|
|
payload: {
|
|
"id": rideId.toString(), // Convert to String
|
|
"status": 'Cancel'
|
|
});
|
|
}
|
|
print('Cancel');
|
|
// }
|
|
}
|
|
Future.delayed(const Duration(seconds: 1));
|
|
Get.offAll(() => const MapPagePassenger());
|
|
}
|
|
|
|
void changePickerShown() {
|
|
isPickerShown = !isPickerShown;
|
|
heightPickerContainer = isPickerShown == true ? 150 : 90;
|
|
update();
|
|
}
|
|
|
|
void changeHeightPointsPageForRider() {
|
|
isPointsPageForRider = !isPointsPageForRider;
|
|
heightPointsPageForRider = isPointsPageForRider == true ? Get.height : 0;
|
|
update();
|
|
}
|
|
|
|
getCoordinateFromMapWayPoints(int index) {
|
|
placesCoordinate[index] = newStartPointLocation.toString();
|
|
update();
|
|
}
|
|
|
|
void changeMainBottomMenuMap() {
|
|
if (isWayPointStopsSheetUtilGetMap == true) {
|
|
changeWayPointSheet();
|
|
} else {
|
|
isMainBottomMenuMap = !isMainBottomMenuMap;
|
|
mainBottomMenuMapHeight =
|
|
isMainBottomMenuMap == true ? Get.height * .2 : Get.height * .6;
|
|
isWayPointSheet = false;
|
|
if (heightMenuBool == true) {
|
|
getDrawerMenu();
|
|
}
|
|
initilizeGetStorage();
|
|
update();
|
|
}
|
|
}
|
|
|
|
void downPoints() {
|
|
if (Get.find<WayPointController>().wayPoints.length < 2) {
|
|
isWayPointStopsSheetUtilGetMap = false;
|
|
isWayPointSheet = false;
|
|
wayPointSheetHeight = isWayPointStopsSheet ? Get.height * .45 : 0;
|
|
// changeWayPointStopsSheet();
|
|
update();
|
|
}
|
|
// changeWayPointStopsSheet();
|
|
// isWayPointSheet = false;
|
|
update();
|
|
}
|
|
|
|
void changeWayPointSheet() {
|
|
isWayPointSheet = !isWayPointSheet;
|
|
wayPointSheetHeight = isWayPointSheet == false ? 0 : Get.height * .45;
|
|
// if (heightMenuBool == true) {
|
|
// getDrawerMenu();
|
|
// }
|
|
update();
|
|
}
|
|
|
|
void changeWayPointStopsSheet() {
|
|
// int waypointsLength = Get.find<WayPointController>().wayPoints.length;
|
|
|
|
if (wayPointIndex > -1) {
|
|
isWayPointStopsSheet = true;
|
|
isWayPointStopsSheetUtilGetMap = true;
|
|
}
|
|
isWayPointStopsSheet = !isWayPointStopsSheet;
|
|
wayPointSheetHeight = isWayPointStopsSheet ? Get.height * .45 : 0;
|
|
// if (heightMenuBool == true) {
|
|
// getDrawerMenu();
|
|
// }
|
|
update();
|
|
}
|
|
|
|
changeHeightPlaces() {
|
|
if (placesDestination.isEmpty) {
|
|
height = 0;
|
|
update();
|
|
}
|
|
height = 150;
|
|
update();
|
|
}
|
|
|
|
changeHeightStartPlaces() {
|
|
if (placesStart.isEmpty) {
|
|
height = 0;
|
|
update();
|
|
}
|
|
height = 150;
|
|
update();
|
|
}
|
|
|
|
changeHeightPlacesAll(int index) {
|
|
if (placeListResponseAll[index].isEmpty) {
|
|
height = 0;
|
|
update();
|
|
}
|
|
height = 150;
|
|
update();
|
|
}
|
|
|
|
changeHeightPlaces1() {
|
|
if (wayPoint1.isEmpty) {
|
|
height = 0;
|
|
update();
|
|
}
|
|
height = 150;
|
|
update();
|
|
}
|
|
|
|
changeHeightPlaces2() {
|
|
if (wayPoint2.isEmpty) {
|
|
height = 0;
|
|
update();
|
|
}
|
|
height = 150;
|
|
update();
|
|
}
|
|
|
|
changeHeightPlaces3() {
|
|
if (wayPoint3.isEmpty) {
|
|
height = 0;
|
|
update();
|
|
}
|
|
height = 150;
|
|
update();
|
|
}
|
|
|
|
changeHeightPlaces4() {
|
|
if (wayPoint4.isEmpty) {
|
|
height = 0;
|
|
update();
|
|
}
|
|
height = 150;
|
|
update();
|
|
}
|
|
|
|
hidePlaces() {
|
|
height = 0;
|
|
|
|
update();
|
|
}
|
|
|
|
// Future getPlaces() async {
|
|
// var languageCode;
|
|
|
|
// // Check if `placeDestinationController.text` contains English characters
|
|
// if (RegExp(r'[a-zA-Z]').hasMatch(placeDestinationController.text)) {
|
|
// languageCode = 'en';
|
|
// } else {
|
|
// languageCode = 'ar';
|
|
// }
|
|
// var url =
|
|
// '${AppLink.searcMaps}?q=${placeDestinationController.text}&in=circle:${passengerLocation.latitude},${passengerLocation.longitude};r=250000&countryCode=${box.read(BoxName.countryCode) == 'EGYPT' ? 'EGY' : 'JOR'}&apiKey=${AK.apiKeyHere}';
|
|
// // '${AppLink.googleMapsLink}place/nearbysearch/json?location=${mylocation.longitude}&radius=25000&language=ar&keyword=&key=${placeController.text}${AK.mapAPIKEY}';
|
|
// // '${AppLink.googleMapsLink}place/nearbysearch/json?keyword=${placeDestinationController.text}&location=${passengerLocation.latitude},${passengerLocation.longitude}&radius=250000&language=$languageCode&key=${AK.mapAPIKEY.toString()}';
|
|
// print(url);
|
|
// var response = await CRUD().getGoogleApi(link: url, payload: {});
|
|
// Log.print('response: ${response}');
|
|
|
|
// placesDestination = response['results'];
|
|
// update();
|
|
// }
|
|
getAIKey(String key) async {
|
|
var res =
|
|
await CRUD().get(link: AppLink.getapiKey, payload: {"keyName": key});
|
|
if (res != 'failure') {
|
|
var d = jsonDecode(res)['message'];
|
|
return d[key].toString();
|
|
} else {}
|
|
}
|
|
|
|
Future<void> getPlaces() async {
|
|
var languageCode;
|
|
|
|
// Check if `placeDestinationController.text` contains English characters
|
|
if (RegExp(r'[a-zA-Z]').hasMatch(placeDestinationController.text)) {
|
|
languageCode = 'en';
|
|
} else {
|
|
languageCode = 'ar';
|
|
}
|
|
|
|
// Construct the URL
|
|
var url = Uri.parse(
|
|
'${AppLink.searcMaps}?q=${Uri.encodeQueryComponent(placeDestinationController.text)}&limit=4&in=circle:${passengerLocation.latitude},${passengerLocation.longitude};r=250000&countryCode=${box.read(BoxName.countryCode) == 'EGYPT' ? 'EGY' : 'JOR'}&lang=$languageCode&apiKey=$k',
|
|
);
|
|
|
|
// Log the URL for debugging
|
|
print(url);
|
|
// box.remove(BoxName.placesDestination);
|
|
try {
|
|
// Make the API request
|
|
var response = await CRUD().getHereMap(
|
|
link: url.toString(),
|
|
);
|
|
|
|
// Log the response for debugging
|
|
// Log.print('response: ${response}');
|
|
|
|
// Check if the response is valid
|
|
if (response != null && response['items'] != null) {
|
|
placesDestination = response['items'];
|
|
// Log.print('placesDestination: ${placesDestination}');
|
|
|
|
placesDestination = response['items'];
|
|
// box.write(BoxName.placesDestination, placesDestination);
|
|
for (var i = 0; i < placesDestination.length; i++) {
|
|
var res = placesDestination[i];
|
|
|
|
// Extract fields with null safety
|
|
var title = res['title']?.toString() ?? 'Unknown Place';
|
|
var position = res['position'];
|
|
var address = res['address']?['label'] ?? 'Unknown Address';
|
|
if (position == null) {
|
|
Log.print('Position is null for place: $title');
|
|
continue; // Skip this place and continue with the next one
|
|
}
|
|
|
|
String latitude = position['lat']?.toString() ?? '0.0';
|
|
String longitude = position['lng']?.toString() ?? '0.0';
|
|
|
|
try {
|
|
await savePlaceToServer(latitude, longitude, title, address);
|
|
// Log.print('Place saved successfully: $title');
|
|
} catch (e) {
|
|
// Log.print('Failed to save place: $e');
|
|
}
|
|
} // todo save key in env then get key and use it
|
|
} else {
|
|
placesDestination = [];
|
|
}
|
|
} catch (e) {
|
|
// Handle any errors that occur during the API request
|
|
Log.print('Error fetching places: $e');
|
|
placesDestination = [];
|
|
}
|
|
|
|
// Notify listeners that the state has changed
|
|
update();
|
|
}
|
|
|
|
Future getPlacesStart() async {
|
|
var languageCode = wayPoint0Controller.text;
|
|
|
|
// Regular expression to check for English alphabet characters
|
|
final englishRegex = RegExp(r'[a-zA-Z]');
|
|
|
|
// Check if text contains English characters
|
|
if (englishRegex.hasMatch(languageCode)) {
|
|
languageCode = 'en';
|
|
} else {
|
|
languageCode = 'ar';
|
|
}
|
|
|
|
var url =
|
|
// '${AppLink.googleMapsLink}place/nearbysearch/json?location=${mylocation.longitude}&radius=25000&language=ar&keyword=&key=${placeController.text}${AK.mapAPIKEY}';
|
|
'${AppLink.googleMapsLink}place/nearbysearch/json?keyword=${placeStartController.text}&location=${passengerLocation.latitude},${passengerLocation.longitude}&radius=250000&language=$languageCode&key=${AK.mapAPIKEY.toString()}';
|
|
|
|
var response = await CRUD().getGoogleApi(link: url, payload: {});
|
|
|
|
placesStart = response['results'];
|
|
update();
|
|
}
|
|
|
|
Future getPlacesListsWayPoint(int index) async {
|
|
var languageCode = wayPoint0Controller.text;
|
|
|
|
// Regular expression to check for English alphabet characters
|
|
final englishRegex = RegExp(r'[a-zA-Z]');
|
|
|
|
// Check if text contains English characters
|
|
if (englishRegex.hasMatch(languageCode)) {
|
|
languageCode = 'en';
|
|
} else {
|
|
languageCode = 'ar';
|
|
}
|
|
|
|
var url =
|
|
'${AppLink.googleMapsLink}place/nearbysearch/json?keyword=${wayPoint0Controller.text}&location=${passengerLocation.latitude},${passengerLocation.longitude}&radius=250000&language=$languageCode&key=${AK.mapAPIKEY.toString()}';
|
|
|
|
try {
|
|
var response = await CRUD().getGoogleApi(link: url, payload: {});
|
|
|
|
if (response != null && response['results'] != null) {
|
|
wayPoint0 = response['results'];
|
|
placeListResponseAll[index] = response['results'];
|
|
update();
|
|
} else {
|
|
print('Error: Invalid response from Google Places API');
|
|
}
|
|
} catch (e) {
|
|
print('Error fetching places: $e');
|
|
}
|
|
}
|
|
|
|
Future<void> 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) {
|
|
print('Error: $e');
|
|
}
|
|
}
|
|
// Future getPlacesListsWayPoint(int index) async {
|
|
// var url =
|
|
// '${AppLink.googleMapsLink}place/nearbysearch/json?keyword=${wayPoint0Controller.text}&location=${passengerLocation.latitude},${passengerLocation.longitude}&radius=80000&language=${}&key=${AK.mapAPIKEY.toString()}';
|
|
|
|
// var response = await CRUD().getGoogleApi(link: url, payload: {});
|
|
|
|
// wayPoint0 = response['results'];
|
|
// placeListResponseAll[index] = response['results'];
|
|
// update();
|
|
// }
|
|
|
|
LatLng fromString(String location) {
|
|
List<String> parts = location.split(',');
|
|
double lat = double.parse(parts[0]);
|
|
double lng = double.parse(parts[1]);
|
|
return LatLng(lat, lng);
|
|
}
|
|
|
|
void clearPolyline() {
|
|
polyLines = [];
|
|
polylineCoordinates.clear();
|
|
// polylineCoordinates = [];
|
|
polylineCoordinatesPointsAll[0].clear();
|
|
polylineCoordinatesPointsAll[1].clear();
|
|
polylineCoordinatesPointsAll[2].clear();
|
|
polylineCoordinatesPointsAll[3].clear();
|
|
polylineCoordinatesPointsAll[4].clear();
|
|
isMarkersShown = false;
|
|
update();
|
|
}
|
|
|
|
void addCustomPicker() {
|
|
ImageConfiguration config = ImageConfiguration(
|
|
size: const Size(30, 30), devicePixelRatio: Get.pixelRatio
|
|
// scale: 1.0,
|
|
);
|
|
BitmapDescriptor.asset(
|
|
config,
|
|
'assets/images/picker.png',
|
|
// mipmaps: false,
|
|
).then((value) {
|
|
markerIcon = value;
|
|
update();
|
|
});
|
|
}
|
|
|
|
void addCustomStartIcon() async {
|
|
// Create the marker with the resized image
|
|
|
|
ImageConfiguration config = ImageConfiguration(
|
|
size: const Size(30, 30), devicePixelRatio: Get.pixelRatio);
|
|
BitmapDescriptor.asset(
|
|
config,
|
|
'assets/images/A.png',
|
|
// mipmaps: false,
|
|
).then((value) {
|
|
startIcon = value;
|
|
update();
|
|
});
|
|
}
|
|
|
|
void addCustomEndIcon() {
|
|
ImageConfiguration config = ImageConfiguration(
|
|
size: const Size(30, 30), devicePixelRatio: Get.pixelRatio);
|
|
BitmapDescriptor.asset(
|
|
config,
|
|
'assets/images/b.png',
|
|
// mipmaps: false,
|
|
).then((value) {
|
|
endIcon = value;
|
|
update();
|
|
});
|
|
}
|
|
|
|
void addCustomCarIcon() {
|
|
ImageConfiguration config = ImageConfiguration(
|
|
size: const Size(30, 35), devicePixelRatio: Get.pixelRatio);
|
|
BitmapDescriptor.asset(
|
|
config,
|
|
'assets/images/car.png',
|
|
// mipmaps: false,
|
|
).then((value) {
|
|
carIcon = value;
|
|
update();
|
|
});
|
|
}
|
|
|
|
void addCustomMotoIcon() {
|
|
ImageConfiguration config = ImageConfiguration(
|
|
size: const Size(30, 30), devicePixelRatio: Get.pixelRatio);
|
|
BitmapDescriptor.asset(
|
|
config,
|
|
'assets/images/moto1.png',
|
|
// mipmaps: false,
|
|
).then((value) {
|
|
motoIcon = value;
|
|
update();
|
|
});
|
|
}
|
|
|
|
void addCustomLadyIcon() {
|
|
ImageConfiguration config = ImageConfiguration(
|
|
size: const Size(30, 30), devicePixelRatio: Get.pixelRatio);
|
|
BitmapDescriptor.asset(
|
|
config,
|
|
'assets/images/lady1.png',
|
|
// mipmaps: false,
|
|
).then((value) {
|
|
ladyIcon = value;
|
|
update();
|
|
});
|
|
}
|
|
|
|
void addCustomStepIcon() {
|
|
ImageConfiguration config = ImageConfiguration(
|
|
size: const Size(30, 30), devicePixelRatio: Get.pixelRatio);
|
|
BitmapDescriptor.asset(
|
|
config,
|
|
'assets/images/brand.png',
|
|
// mipmaps: false,
|
|
).then((value) {
|
|
tripIcon = value;
|
|
update();
|
|
});
|
|
}
|
|
|
|
dialoge() {
|
|
Get.defaultDialog(
|
|
title: 'Location '.tr,
|
|
content: Container(
|
|
child: Column(
|
|
children: [
|
|
Text(
|
|
'We use location to get accurate and nearest driver for you'.tr,
|
|
style: AppStyle.title,
|
|
),
|
|
TextButton(
|
|
onPressed: () async {
|
|
// await Permission.location.request();
|
|
Get.back();
|
|
},
|
|
child: Text(
|
|
'Grant'.tr,
|
|
style: AppStyle.title,
|
|
),
|
|
)
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
double speed = 0;
|
|
Future<void> getLocation() async {
|
|
isLoading = true;
|
|
update();
|
|
bool serviceEnabled;
|
|
PermissionStatus permissionGranted;
|
|
// dialoge();
|
|
// 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();
|
|
passengerLocation =
|
|
(_locationData.latitude != null && _locationData.longitude != null
|
|
? LatLng(_locationData.latitude!, _locationData.longitude!)
|
|
: null)!;
|
|
getLocationArea(passengerLocation.latitude, passengerLocation.longitude);
|
|
Log.print('AppLink.endPoint: ${AppLink.endPoint}');
|
|
// Log.print('BoxName.serverChosen: ${box.read(BoxName.serverChosen)}');
|
|
|
|
newStartPointLocation = passengerLocation;
|
|
Log.print('passengerLocation: $passengerLocation');
|
|
speed = _locationData.speed!;
|
|
// //print location details
|
|
isLoading = false;
|
|
update();
|
|
}
|
|
|
|
LatLngBounds calculateBounds(double lat, double lng, double radiusInMeters) {
|
|
const double earthRadius = 6378137.0; // Earth's radius in meters
|
|
|
|
double latDelta = (radiusInMeters / earthRadius) * (180 / pi);
|
|
double lngDelta =
|
|
(radiusInMeters / (earthRadius * cos(pi * lat / 180))) * (180 / pi);
|
|
|
|
double minLat = lat - latDelta;
|
|
double maxLat = lat + latDelta;
|
|
|
|
double minLng = lng - lngDelta;
|
|
double maxLng = lng + lngDelta;
|
|
|
|
// Ensure the latitude is between -90 and 90
|
|
minLat = max(-90.0, minLat);
|
|
maxLat = min(90.0, maxLat);
|
|
|
|
// Ensure the longitude is between -180 and 180
|
|
minLng = (minLng + 180) % 360 - 180;
|
|
maxLng = (maxLng + 180) % 360 - 180;
|
|
|
|
// Ensure the bounds are in the correct order
|
|
if (minLng > maxLng) {
|
|
double temp = minLng;
|
|
minLng = maxLng;
|
|
maxLng = temp;
|
|
}
|
|
|
|
return LatLngBounds(
|
|
southwest: LatLng(minLat, minLng),
|
|
northeast: LatLng(maxLat, maxLng),
|
|
);
|
|
}
|
|
|
|
GoogleMapController? mapController;
|
|
void onMapCreated(GoogleMapController controller) {
|
|
// myLocation = Get.find<LocationController>().location as LatLng;
|
|
// myLocation = myLocation;
|
|
mapController = controller;
|
|
controller.getVisibleRegion();
|
|
controller.animateCamera(
|
|
CameraUpdate.newLatLng(passengerLocation),
|
|
);
|
|
// Future.delayed(const Duration(milliseconds: 500), () {
|
|
// markers.forEach((marker) {
|
|
// controller.showMarkerInfoWindow(marker.markerId);
|
|
// });
|
|
// });
|
|
update();
|
|
}
|
|
|
|
// void startMarkerReloading() {
|
|
// int count = 0;
|
|
// markerReloadingTimer = Timer.periodic(const Duration(seconds: 30), (timer) {
|
|
// reloadMarkers();
|
|
//
|
|
// count++;
|
|
// if (count == 10) {
|
|
// timer.cancel();
|
|
// }
|
|
// });
|
|
// }
|
|
bool reloadStartApp = false;
|
|
int reloadCount = 0;
|
|
startMarkerReloading() async {
|
|
if (reloadStartApp == false) {
|
|
Timer.periodic(const Duration(seconds: 3), (timer) async {
|
|
reloadCount++;
|
|
Log.print('reloadCount: $reloadCount');
|
|
|
|
if (rideConfirm == false) {
|
|
clearMarkersExceptStartEnd();
|
|
// _smoothlyUpdateMarker();
|
|
// startCarLocationSearch(box.read(BoxName.carType));
|
|
await getCarsLocationByPassengerAndReloadMarker(
|
|
box.read(BoxName.carType), 5000);
|
|
await getNearestDriverByPassengerLocation();
|
|
Log.print('reloadMarkers: from startMarkerReloading');
|
|
} else {
|
|
// runWhenRideIsBegin();
|
|
}
|
|
|
|
if (reloadCount >= 6) {
|
|
reloadStartApp = true;
|
|
timer.cancel(); // Stop the timer after 5 reloads
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
String durationByPassenger = '';
|
|
late DateTime newTime1 = DateTime.now();
|
|
late DateTime timeFromDriverToPassenger = DateTime.now();
|
|
String distanceByPassenger = '';
|
|
late Duration durationFromDriverToPassenger;
|
|
double nearestDistance = double.infinity;
|
|
|
|
// Future<CarLocation?> getNearestDriverByPassengerLocation() async {
|
|
// if (polyLines.isEmpty || data.isEmpty) {
|
|
// return null; // Early return if data is empty
|
|
// }
|
|
|
|
// if (!rideConfirm) {
|
|
// if (dataCarsLocationByPassenger != 'failure') {
|
|
// if (dataCarsLocationByPassenger != null) {
|
|
// if (dataCarsLocationByPassenger['message'].length > 0) {
|
|
// double nearestDistance = double
|
|
// .infinity; // Initialize nearest distance to a large number
|
|
// CarLocation? nearestCar;
|
|
|
|
// for (var i = 0;
|
|
// i < dataCarsLocationByPassenger['message'].length;
|
|
// i++) {
|
|
// var carLocation = dataCarsLocationByPassenger['message'][i];
|
|
|
|
// // Calculate the distance between passenger's location and current driver's location
|
|
// final distance = Geolocator.distanceBetween(
|
|
// passengerLocation.latitude,
|
|
// passengerLocation.longitude,
|
|
// double.parse(carLocation['latitude']),
|
|
// double.parse(carLocation['longitude']),
|
|
// );
|
|
|
|
// // Calculate duration assuming an average speed of 25 km/h (adjust as needed)
|
|
// int durationToPassenger =
|
|
// (distance * 25 * (1000 / 3600)).round(); // 25 km/h in m/s
|
|
|
|
// // Update the UI with the distance and duration for each car
|
|
// update();
|
|
|
|
// // If this distance is smaller than the nearest distance found so far, update nearestCar
|
|
// if (distance < nearestDistance) {
|
|
// nearestDistance = distance;
|
|
|
|
// nearestCar = CarLocation(
|
|
// distance: distance,
|
|
// duration: durationToPassenger.toDouble(),
|
|
// id: carLocation['driver_id'],
|
|
// latitude: double.parse(carLocation['latitude']),
|
|
// longitude: double.parse(carLocation['longitude']),
|
|
// );
|
|
|
|
// // Update the UI with the nearest driver
|
|
// update();
|
|
// }
|
|
// }
|
|
|
|
// // Return the nearest car found
|
|
// return nearestCar;
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// // Return null if no drivers are found or if ride is confirmed
|
|
// return null;
|
|
// }
|
|
Future<CarLocation?> getNearestDriverByPassengerLocation() async {
|
|
if (!rideConfirm) {
|
|
if (dataCarsLocationByPassenger != 'failure' &&
|
|
dataCarsLocationByPassenger != null &&
|
|
dataCarsLocationByPassenger['message'] != null &&
|
|
dataCarsLocationByPassenger['message'].length > 0) {
|
|
double nearestDistance = double.infinity; // Initialize nearest distance
|
|
CarLocation? nearestCar;
|
|
|
|
for (var i = 0;
|
|
i < dataCarsLocationByPassenger['message'].length;
|
|
i++) {
|
|
var carLocation = dataCarsLocationByPassenger['message'][i];
|
|
Log.print('carLocation: $carLocation');
|
|
|
|
try {
|
|
// Calculate distance between passenger's location and current driver's location
|
|
final distance = Geolocator.distanceBetween(
|
|
passengerLocation.latitude,
|
|
passengerLocation.longitude,
|
|
double.parse(carLocation['latitude']),
|
|
double.parse(carLocation['longitude']),
|
|
);
|
|
|
|
// Calculate duration assuming an average speed of 25 km/h (adjust as needed)
|
|
int durationToPassenger = (distance / 1000 / 25 * 3600).round();
|
|
Log.print('distance: $distance');
|
|
Log.print('durationToPassenger: $durationToPassenger');
|
|
Log.print('passengerLocation: $passengerLocation');
|
|
Log.print('carLocation: $carLocation');
|
|
Log.print('distance: $distance meters');
|
|
Log.print('durationToPassenger: $durationToPassenger seconds');
|
|
// Update the UI with the distance and duration for each car
|
|
update();
|
|
|
|
// If this distance is smaller than the nearest distance found so far, update nearestCar
|
|
if (distance < nearestDistance) {
|
|
nearestDistance = distance;
|
|
|
|
nearestCar = CarLocation(
|
|
distance: distance,
|
|
duration: durationToPassenger.toDouble(),
|
|
id: carLocation['driver_id'],
|
|
latitude: double.parse(carLocation['latitude']),
|
|
longitude: double.parse(carLocation['longitude']),
|
|
);
|
|
Log.print('nearestCar: $nearestCar');
|
|
// Update the UI with the nearest driver
|
|
update();
|
|
}
|
|
} catch (e) {
|
|
Log.print('Error calculating distance/duration: $e');
|
|
}
|
|
}
|
|
|
|
// Return the nearest car found
|
|
return nearestCar;
|
|
}
|
|
}
|
|
|
|
// Return null if no drivers are found or if ride is confirmed
|
|
return null;
|
|
}
|
|
|
|
getNearestDriverByPassengerLocationAPIGOOGLE() async {
|
|
if (polyLines.isEmpty || data.isEmpty) {
|
|
return null; // Early return if data is empty
|
|
}
|
|
if (!rideConfirm) {
|
|
double nearestDistance = double.infinity;
|
|
if (dataCarsLocationByPassenger != 'failure') {
|
|
if (dataCarsLocationByPassenger['message'].length > 0) {
|
|
for (var i = 0;
|
|
i < dataCarsLocationByPassenger['message'].length;
|
|
i++) {
|
|
var carLocation = dataCarsLocationByPassenger['message'][i];
|
|
|
|
// }
|
|
// isloading = true;
|
|
update();
|
|
// Make API request to get exact distance and duration
|
|
String apiUrl =
|
|
'${AppLink.googleMapsLink}distancematrix/json?destinations=${carLocation['latitude']},${carLocation['longitude']}&origins=${passengerLocation.latitude},${passengerLocation.longitude}&units=metric&key=${AK.mapAPIKEY}';
|
|
var response = await CRUD().getGoogleApi(link: apiUrl, payload: {});
|
|
if (response != null && 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'];
|
|
distanceByPassenger =
|
|
data['rows'][0]['elements'][0]['distance']['text'];
|
|
durationToPassenger =
|
|
data['rows'][0]['elements'][0]['duration']['value'];
|
|
|
|
durationFromDriverToPassenger =
|
|
Duration(seconds: durationToPassenger.toInt());
|
|
newTime1 = currentTime.add(durationFromDriverToPassenger);
|
|
timeFromDriverToPassenger =
|
|
newTime1.add(Duration(minutes: 2.toInt()));
|
|
durationByPassenger =
|
|
data['rows'][0]['elements'][0]['duration']['text'];
|
|
update();
|
|
if (distance1 < nearestDistance) {
|
|
nearestDistance = distance1.toDouble();
|
|
|
|
nearestCar = CarLocation(
|
|
distance: distance1.toDouble(),
|
|
duration: durationToPassenger.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 {
|
|
// 'Failed to retrieve distance and duration: ${response['status']}');
|
|
Log.print('${response['status']}: ${response['status']}}');
|
|
// Handle the failure case
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
calculateDistanceBetweenPassengerAndDriverBeforeCancelRide() async {
|
|
await getDriverCarsLocationToPassengerAfterApplied();
|
|
double distance = Geolocator.distanceBetween(
|
|
passengerLocation.latitude,
|
|
passengerLocation.longitude,
|
|
driverCarsLocationToPassengerAfterApplied.last.latitude,
|
|
driverCarsLocationToPassengerAfterApplied.last.longitude,
|
|
);
|
|
if (distance > 500) {
|
|
isCancelRidePageShown = true;
|
|
update();
|
|
} else {
|
|
Get.defaultDialog(
|
|
barrierDismissible: false,
|
|
title: 'The Driver Will be in your location soon .'.tr,
|
|
middleText: 'The distance less than 500 meter.'.tr,
|
|
confirm: Column(
|
|
children: [
|
|
MyElevatedButton(
|
|
kolor: AppColor.greenColor,
|
|
title: 'Ok'.tr,
|
|
onPressed: () {
|
|
Get.back();
|
|
},
|
|
),
|
|
MyElevatedButton(
|
|
kolor: AppColor.redColor,
|
|
title: 'No, I want to cancel this trip'.tr,
|
|
onPressed: () {
|
|
Get.back();
|
|
MyDialog().getDialog(
|
|
'Attention'.tr,
|
|
'You will be charged for the cost of the driver coming to your location.'
|
|
.tr,
|
|
() async {
|
|
Get.back();
|
|
Get.find<PaymentController>()
|
|
.payToDriverForCancelAfterAppliedAndHeNearYou(rideId);
|
|
// isCancelRidePageShown = true;
|
|
// update();
|
|
},
|
|
);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
);
|
|
// cancel: MyElevatedButton(
|
|
// title: 'No.Iwant Cancel Trip.'.tr, onPressed: () {}));
|
|
}
|
|
}
|
|
|
|
List<double> headingAngles = [];
|
|
double calculateAngleBetweenLocations(LatLng start, LatLng end) {
|
|
double startLat = start.latitude * math.pi / 180;
|
|
double startLon = start.longitude * math.pi / 180;
|
|
double endLat = end.latitude * math.pi / 180;
|
|
double endLon = end.longitude * math.pi / 180;
|
|
|
|
double dLon = endLon - startLon;
|
|
|
|
double y = math.sin(dLon) * cos(endLat);
|
|
double x = cos(startLat) * math.sin(endLat) -
|
|
math.sin(startLat) * cos(endLat) * cos(dLon);
|
|
|
|
double angle = math.atan2(y, x);
|
|
double angleDegrees = angle * 180 / math.pi;
|
|
|
|
return angleDegrees;
|
|
}
|
|
|
|
late LatLngBounds boundsData;
|
|
late String startNameAddress = '';
|
|
late String endNameAddress = '';
|
|
List<Map<String, dynamic>> stopPoints = [];
|
|
void removeStop(Map<String, dynamic> stop) {
|
|
stopPoints.remove(stop);
|
|
update(); // Trigger a rebuild of the UI
|
|
}
|
|
|
|
getDirectionMap(String origin, destination,
|
|
[List<String> waypoints = const []]) async {
|
|
isLoading = true;
|
|
update();
|
|
remainingTime = 25; //to make cancel every call
|
|
// startCarLocationSearch(box.read(BoxName.carType));
|
|
await getCarsLocationByPassengerAndReloadMarker(
|
|
box.read(BoxName.carType), 5000);
|
|
// await getCarsLocationByPassengerAndReloadMarker();
|
|
var coordDestination = destination.split(',');
|
|
double latPassengerDestination = double.parse(coordDestination[0]);
|
|
double lngPassengerDestination = double.parse(coordDestination[1]);
|
|
myDestination = LatLng(latPassengerDestination, lngPassengerDestination);
|
|
if (origin.isEmpty) {
|
|
origin =
|
|
'${passengerLocation.latitude.toString().split(',')[0]},${passengerLocation.longitude.toString().split(',')[1]}'; //todo
|
|
}
|
|
isLoading = false;
|
|
update();
|
|
var url =
|
|
('${AppLink.googleMapsLink}directions/json?&language=${box.read(BoxName.lang) ?? 'ar'}&avoid=tolls|ferries&destination=$destination&origin=$origin&key=${AK.mapAPIKEY}');
|
|
if (waypoints.isNotEmpty) {
|
|
String formattedWaypoints = waypoints.join('|');
|
|
url += '&waypoints=$formattedWaypoints';
|
|
}
|
|
var response = await CRUD().getGoogleApi(link: url, payload: {});
|
|
data = response['routes'][0]['legs'];
|
|
box.remove(BoxName.tripData);
|
|
box.write(BoxName.tripData, response);
|
|
|
|
startNameAddress = shortenAddress(data[0]['start_address']);
|
|
print('data[0][start_address]: ${data[0]['start_address']}');
|
|
endNameAddress = shortenAddress(data[0]['end_address']);
|
|
isLoading = false;
|
|
newStartPointLocation = LatLng(
|
|
data[0]["start_location"]['lat'], data[0]["start_location"]['lng']);
|
|
|
|
durationToRide = data[0]['duration']['value'];
|
|
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
|
|
|
|
// 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
|
|
LatLngBounds boundsData =
|
|
LatLngBounds(northeast: northeast, southwest: southwest);
|
|
|
|
// Fit the camera to the bounds
|
|
var cameraUpdate = CameraUpdate.newLatLngBounds(boundsData, 130);
|
|
mapController!.animateCamera(cameraUpdate);
|
|
|
|
// getDistanceFromText(data[0]['distance']['text']);
|
|
double distanceOfTrip = (data[0]['distance']['value']) / 1000;
|
|
distance = distanceOfTrip;
|
|
durationToAdd = Duration(seconds: durationToRide);
|
|
hours = durationToAdd.inHours;
|
|
minutes = (durationToAdd.inMinutes % 60).round();
|
|
// updateCameraForDistanceAfterGetMap();
|
|
markers.clear();
|
|
update();
|
|
markers.add(
|
|
Marker(
|
|
markerId: const MarkerId('start'),
|
|
position: newStartPointLocation,
|
|
icon: startIcon,
|
|
infoWindow: InfoWindow(
|
|
title: startNameAddress,
|
|
snippet: '',
|
|
),
|
|
),
|
|
);
|
|
|
|
// Add end marker
|
|
markers.add(
|
|
Marker(
|
|
markerId: const MarkerId('end'),
|
|
position: LatLng(
|
|
data[0]["end_location"]['lat'], data[0]["end_location"]['lng']),
|
|
icon: endIcon,
|
|
infoWindow: InfoWindow(
|
|
title: endNameAddress,
|
|
snippet:
|
|
'$distance ${'KM'.tr} ⌛ ${hours > 0 ? '${'Your Ride Duration is '.tr}$hours ${'H and'.tr} $minutes ${'m'.tr}' : '${'Your Ride Duration is '.tr} $minutes ${'m'.tr}'}'),
|
|
),
|
|
);
|
|
// // Show info windows automatically
|
|
// Future.delayed(const Duration(milliseconds: 500), () {
|
|
// mapController?.showMarkerInfoWindow(const MarkerId('start'));
|
|
// });
|
|
Future.delayed(const Duration(milliseconds: 500), () {
|
|
mapController?.showMarkerInfoWindow(const MarkerId('end'));
|
|
});
|
|
update();
|
|
|
|
if (polyLines.isNotEmpty) {
|
|
clearPolyline();
|
|
} else {
|
|
_animatePolyline(polylineCoordinates);
|
|
rideConfirm = false;
|
|
isMarkersShown = true;
|
|
|
|
update();
|
|
}
|
|
}
|
|
|
|
Future<void> _animatePolyline(List<LatLng> coordinates) async {
|
|
const int totalAnimations = 7;
|
|
|
|
Color getAnimationColor(int cycle) {
|
|
switch (cycle) {
|
|
case 0:
|
|
return AppColor.primaryColor;
|
|
case 1:
|
|
return AppColor.writeColor;
|
|
case 2:
|
|
return AppColor.primaryColor;
|
|
default:
|
|
return AppColor.primaryColor;
|
|
}
|
|
}
|
|
|
|
for (int cycle = 0; cycle < totalAnimations; cycle++) {
|
|
polyLines.clear();
|
|
List<LatLng> animatedPoints = [];
|
|
|
|
for (int i = 0; i < coordinates.length; i++) {
|
|
animatedPoints.add(coordinates[i]);
|
|
polyLines.clear();
|
|
polyLines.add(
|
|
Polyline(
|
|
polylineId: const PolylineId('animated_route'),
|
|
points: List<LatLng>.from(animatedPoints),
|
|
width: 4,
|
|
color: getAnimationColor(cycle),
|
|
endCap: Cap.roundCap,
|
|
startCap: Cap.roundCap,
|
|
geodesic: true,
|
|
),
|
|
);
|
|
update();
|
|
await Future.delayed(const Duration(milliseconds: 10));
|
|
}
|
|
|
|
if (cycle < totalAnimations - 1) {
|
|
await Future.delayed(const Duration(milliseconds: 500));
|
|
polyLines.clear();
|
|
update();
|
|
await Future.delayed(const Duration(milliseconds: 200));
|
|
}
|
|
}
|
|
}
|
|
|
|
String shortenAddress(String fullAddress) {
|
|
// Split the address into parts
|
|
List<String> parts = fullAddress.split('،');
|
|
|
|
// Remove any leading or trailing whitespace from each part
|
|
parts = parts.map((part) => part.trim()).toList();
|
|
|
|
// Remove any empty parts
|
|
parts = parts.where((part) => part.isNotEmpty).toList();
|
|
|
|
// Initialize the short address
|
|
String shortAddress = '';
|
|
|
|
if (parts.isNotEmpty) {
|
|
// Add the first part (usually the most specific location)
|
|
shortAddress += parts[0];
|
|
}
|
|
|
|
if (parts.length > 2) {
|
|
// Add the district or area name (usually the third part in Arabic format)
|
|
shortAddress += '، ${parts[2]}';
|
|
} else if (parts.length > 1) {
|
|
// Add the second part for English or shorter addresses
|
|
shortAddress += '، ${parts[1]}';
|
|
}
|
|
|
|
// Add the country (usually the last part)
|
|
if (parts.length > 1) {
|
|
shortAddress += '، ${parts.last}';
|
|
}
|
|
|
|
// Remove any part that's just numbers (like postal codes)
|
|
shortAddress = shortAddress
|
|
.split('،')
|
|
.where((part) => !RegExp(r'^[0-9 ]+$').hasMatch(part.trim()))
|
|
.join('،');
|
|
|
|
// Check if the address is in English
|
|
bool isEnglish =
|
|
RegExp(r'^[a-zA-Z0-9 ]+$').hasMatch(shortAddress.replaceAll('،', ''));
|
|
|
|
if (isEnglish) {
|
|
// Further processing for English addresses
|
|
List<String> englishParts = shortAddress.split('،');
|
|
if (englishParts.length > 2) {
|
|
shortAddress =
|
|
'${englishParts[0]}، ${englishParts[1]}، ${englishParts.last}';
|
|
} else if (englishParts.length > 1) {
|
|
shortAddress = '${englishParts[0]}، ${englishParts.last}';
|
|
}
|
|
}
|
|
|
|
return shortAddress;
|
|
}
|
|
|
|
double distanceOfDestination = 0;
|
|
bool haveSteps = false;
|
|
late LatLng latestPosition;
|
|
// getMapPoints(String originSteps, String destinationSteps, int index) async {
|
|
// isWayPointStopsSheetUtilGetMap = false;
|
|
// haveSteps = true;
|
|
// await getCarsLocationByPassenger();
|
|
// // isLoading = true;
|
|
// update();
|
|
// String url = '${AppLink.googleMapsLink}directions/json'
|
|
// '?origin=${coordinatesWithoutEmpty.first}'
|
|
// '&destination=${coordinatesWithoutEmpty.last}';
|
|
// if (coordinatesWithoutEmpty.length > 2) {
|
|
// String waypoints = "";
|
|
// for (int i = 1; i < coordinatesWithoutEmpty.length - 1; i++) {
|
|
// waypoints += "${coordinatesWithoutEmpty[i]}|";
|
|
// }
|
|
// waypoints = waypoints.substring(0, waypoints.length - 1);
|
|
// url += "&waypoints=$waypoints";
|
|
// }
|
|
// url += '&language=en'
|
|
// '&avoid=tolls|ferries'
|
|
// '&key=${AK.mapAPIKEY}';
|
|
// var response = await CRUD().getGoogleApi(link: url, payload: {});
|
|
// data = response['routes'][0]['legs'];
|
|
// // isLoading = false;
|
|
// int durationToRide0 = data[0]['duration']['value'];
|
|
// durationToRide = durationToRide + durationToRide0;
|
|
// distance = distanceOfDestnation + (data[0]['distance']['value']) / 1000;
|
|
// update();
|
|
// final points =
|
|
// decodePolyline(response["routes"][0]["overview_polyline"]["points"]);
|
|
// for (int i = 0; i < points.length; i++) {
|
|
// if (points[i][0].toString() != '') {
|
|
// double lat = points[i][0].toDouble();
|
|
// double lng = points[i][1].toDouble();
|
|
// polylineCoordinatesPointsAll[index].add(LatLng(lat, lng));
|
|
// }
|
|
// }
|
|
// // Define the northeast and southwest coordinates
|
|
// update();
|
|
// if (polyLines.isNotEmpty) {
|
|
// // clearPolyline();
|
|
// } else {
|
|
// var polyline = Polyline(
|
|
// polylineId: PolylineId(response["routes"][0]["summary"]),
|
|
// points: polylineCoordinatesPointsAll[index],
|
|
// width: 10,
|
|
// color: Colors.blue,
|
|
// );
|
|
// polyLines.add(polyline);
|
|
// rideConfirm = false;
|
|
// // isMarkersShown = true;
|
|
// update();
|
|
// }
|
|
// }
|
|
|
|
getMapPoints(String originSteps, String destinationSteps, int index) async {
|
|
isWayPointStopsSheetUtilGetMap = false;
|
|
// haveSteps = true;
|
|
// startCarLocationSearch(box.read(BoxName.carType));
|
|
await getCarsLocationByPassengerAndReloadMarker(
|
|
box.read(BoxName.carType), 7000);
|
|
// await getCarsLocationByPassengerAndReloadMarker();
|
|
// isLoading = true;
|
|
update();
|
|
var url =
|
|
('${AppLink.googleMapsLink}directions/json?&language=${box.read(BoxName.lang)}&avoid=tolls|ferries&destination=$destinationSteps&origin=$originSteps&key=${AK.mapAPIKEY}');
|
|
var response = await CRUD().getGoogleApi(link: url, payload: {});
|
|
data = response['routes'][0]['legs'];
|
|
// isLoading = false;
|
|
|
|
int durationToRide0 = data[0]['duration']['value'];
|
|
durationToRide = durationToRide + durationToRide0;
|
|
distance = distanceOfDestination + (data[0]['distance']['value']) / 1000;
|
|
|
|
update();
|
|
final points =
|
|
decodePolyline(response["routes"][0]["overview_polyline"]["points"]);
|
|
for (int i = 0; i < points.length; i++) {
|
|
if (points[i][0].toString() != '') {
|
|
double lat = points[i][0].toDouble();
|
|
double lng = points[i][1].toDouble();
|
|
polylineCoordinatesPointsAll[index].add(LatLng(lat, lng));
|
|
}
|
|
}
|
|
// Define the northeast and southwest coordinates
|
|
|
|
if (polyLines.isNotEmpty) {
|
|
// clearPolyline();
|
|
} else {
|
|
var polyline = Polyline(
|
|
polylineId: PolylineId(response["routes"][0]["summary"]),
|
|
points: polylineCoordinatesPointsAll[index],
|
|
width: 10,
|
|
color: Colors.blue,
|
|
);
|
|
|
|
polyLines.add(polyline);
|
|
rideConfirm = false;
|
|
// isMarkersShown = true;
|
|
update();
|
|
}
|
|
}
|
|
|
|
void updateCameraForDistanceAfterGetMap() {
|
|
LatLng coord1 = LatLng(
|
|
double.parse(coordinatesWithoutEmpty.first.split(',')[0]),
|
|
double.parse(coordinatesWithoutEmpty.first.split(',')[1]));
|
|
|
|
LatLng coord2 = LatLng(
|
|
double.parse(coordinatesWithoutEmpty.last.split(',')[0]),
|
|
double.parse(coordinatesWithoutEmpty.last.split(',')[1]));
|
|
|
|
LatLng northeast;
|
|
LatLng southwest;
|
|
|
|
if (coord1.latitude > coord2.latitude) {
|
|
northeast = coord1;
|
|
southwest = coord2;
|
|
} else {
|
|
northeast = coord2;
|
|
southwest = coord1;
|
|
}
|
|
|
|
// Create the LatLngBounds object
|
|
LatLngBounds bounds =
|
|
LatLngBounds(northeast: northeast, southwest: southwest);
|
|
|
|
// Fit the camera to the bounds
|
|
var cameraUpdate = CameraUpdate.newLatLngBounds(bounds, 180);
|
|
mapController!.animateCamera(cameraUpdate);
|
|
update();
|
|
}
|
|
|
|
int selectedIndex = -1; // Initialize with no selection
|
|
void selectCarFromList(int index) {
|
|
selectedIndex = index; // Update selected index
|
|
carTypes.forEach(
|
|
(element) => element.isSelected = false); // Reset selection flags
|
|
carTypes[index].isSelected = true;
|
|
update();
|
|
}
|
|
|
|
showBottomSheet1() async {
|
|
await bottomSheet();
|
|
isBottomSheetShown = true;
|
|
heightBottomSheetShown = 250;
|
|
|
|
update();
|
|
}
|
|
|
|
final promo = TextEditingController();
|
|
bool promoTaken = false;
|
|
applyPromoCodeToPassenger(BuildContext context) async {
|
|
if (promoTaken == false) {
|
|
if (promoFormKey.currentState!.validate()) {
|
|
CRUD().get(link: AppLink.getPassengersPromo, payload: {
|
|
'promo_code': promo.text,
|
|
}).then((value) {
|
|
if (value == 'failure') {
|
|
MyDialog().getDialog(
|
|
'Promo Ended'.tr,
|
|
'The promotion period has ended.'.tr,
|
|
() {
|
|
Get.back();
|
|
},
|
|
);
|
|
} else if (totalPassengerComfort > 30 ||
|
|
totalPassengerLady > 30 ||
|
|
totalPassengerSpeed > 20 ||
|
|
totalPassengerBalash > 20) {
|
|
var decode = jsonDecode(value);
|
|
|
|
if (decode["status"] == "success") {
|
|
Get.snackbar('Promo Code Accepted'.tr, '',
|
|
backgroundColor: AppColor.greenColor);
|
|
var firstElement = decode["message"][0];
|
|
double burc =
|
|
double.parse(box.read(BoxName.passengerWalletTotal));
|
|
if (burc < 0) {
|
|
int discountPercentage = int.parse(firstElement['amount']);
|
|
|
|
// 1. Calculate and apply discount for totalPassengerComfort
|
|
totalPassengerComfortDiscount =
|
|
totalPassengerComfort * discountPercentage / 100;
|
|
Log.print(
|
|
'totalPassengerComfortDiscount: $totalPassengerComfortDiscount');
|
|
|
|
// Apply the formula: totalPassengerComfort + (-1 * burc) - discount
|
|
totalPassengerComfort = totalPassengerComfort +
|
|
(-1 * burc) -
|
|
totalPassengerComfortDiscount;
|
|
|
|
// 2. Calculate and apply discount for totalPassengerLady
|
|
totalPassengerLadyDiscount =
|
|
totalPassengerLady * discountPercentage / 100;
|
|
|
|
// Apply the formula: totalPassengerLady + (-1 * burc) - discount
|
|
totalPassengerLady = totalPassengerLady +
|
|
(-1 * burc) -
|
|
totalPassengerLadyDiscount;
|
|
|
|
// 3. Calculate and apply discount for totalPassengerSpeed
|
|
totalPassengerSpeedDiscount =
|
|
totalPassengerSpeed * discountPercentage / 100;
|
|
|
|
// Apply the formula: totalPassengerSpeed + (-1 * burc) - discount
|
|
totalPassengerSpeed = totalPassengerSpeed +
|
|
(-1 * burc) -
|
|
totalPassengerSpeedDiscount;
|
|
|
|
// 4. Calculate and apply discount for totalPassengerBalash
|
|
totalPassengerBalashDiscount =
|
|
totalPassengerBalash * discountPercentage / 100;
|
|
|
|
// Apply the formula: totalPassengerBalash + (-1 * burc) - discount
|
|
totalPassengerBalash = totalPassengerBalash +
|
|
(-1 * burc) -
|
|
totalPassengerBalashDiscount;
|
|
|
|
// Mark promo as taken
|
|
promoTaken = true;
|
|
|
|
// Update UI
|
|
update();
|
|
} else {
|
|
int discountPercentage = int.parse(firstElement['amount']);
|
|
|
|
// Calculate discounts for each category, ensuring they don't exceed 25
|
|
totalPassengerComfortDiscount =
|
|
totalPassengerComfort * discountPercentage / 100;
|
|
if (totalPassengerComfortDiscount > 25) {
|
|
totalPassengerComfortDiscount =
|
|
25; // Limit the discount to 25
|
|
}
|
|
Log.print(
|
|
'totalPassengerComfortDiscount: $totalPassengerComfortDiscount');
|
|
totalPassengerComfort =
|
|
totalPassengerComfort - totalPassengerComfortDiscount;
|
|
|
|
totalPassengerLadyDiscount =
|
|
totalPassengerLady * discountPercentage / 100;
|
|
if (totalPassengerLadyDiscount > 25) {
|
|
totalPassengerLadyDiscount = 25; // Limit the discount to 25
|
|
}
|
|
totalPassengerLady =
|
|
totalPassengerLady - totalPassengerLadyDiscount;
|
|
|
|
totalPassengerSpeedDiscount =
|
|
totalPassengerSpeed * discountPercentage / 100;
|
|
if (totalPassengerSpeedDiscount > 25) {
|
|
totalPassengerSpeedDiscount = 25; // Limit the discount to 25
|
|
}
|
|
totalPassengerSpeed =
|
|
totalPassengerSpeed - totalPassengerSpeedDiscount;
|
|
|
|
totalPassengerBalashDiscount =
|
|
totalPassengerBalash * discountPercentage / 100;
|
|
if (totalPassengerBalashDiscount > 25) {
|
|
totalPassengerBalashDiscount = 25; // Limit the discount to 25
|
|
}
|
|
totalPassengerBalash =
|
|
totalPassengerBalash - totalPassengerBalashDiscount;
|
|
|
|
// Trigger UI update
|
|
update();
|
|
}
|
|
|
|
totalDriver = totalDriver -
|
|
(totalDriver * int.parse(firstElement['amount']) / 100);
|
|
promoTaken = true;
|
|
|
|
// Launch confetti for success feedback
|
|
Confetti.launch(
|
|
context,
|
|
options: const ConfettiOptions(
|
|
particleCount: 100, spread: 70, y: 0.6),
|
|
);
|
|
|
|
update();
|
|
Get.back();
|
|
Future.delayed(const Duration(microseconds: 111));
|
|
}
|
|
} else {
|
|
Get.snackbar('Lowest Price Achieved'.tr,
|
|
'Cannot apply further discounts.'.tr,
|
|
backgroundColor: AppColor.yellowColor);
|
|
}
|
|
});
|
|
}
|
|
} else {
|
|
MyDialog().getDialog(
|
|
'Promo Already Used'.tr, 'You have already used this promo code.'.tr,
|
|
() {
|
|
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;
|
|
}
|
|
|
|
double costForDriver = 0;
|
|
double totalPassengerSpeed = 0;
|
|
double totalPassengerBalash = 0;
|
|
double totalPassengerLady = 0;
|
|
double totalPassengerRayehGai = 0;
|
|
double totalPassengerRayehGaiComfort = 0;
|
|
double totalPassengerRayehGaiBalash = 0;
|
|
Future bottomSheet() async {
|
|
if (data.isNotEmpty) {
|
|
durationToAdd = Duration(seconds: durationToRide);
|
|
hours = durationToAdd.inHours;
|
|
minutes = (durationToAdd.inMinutes % 60).round();
|
|
DateTime currentTime = DateTime.now();
|
|
newTime = currentTime.add(durationToAdd);
|
|
averageDuration = (durationToRide / 60) / distance;
|
|
// costDuration = (durationToRide / 60) * averageDuration * 0.016;
|
|
costDuration = (durationToRide / 60).floorToDouble();
|
|
'passengerWalletTotal----- ${box.read(BoxName.passengerWalletTotal)}';
|
|
double costComfort,
|
|
costSpeed,
|
|
costDelivery,
|
|
costBalash,
|
|
costLady,
|
|
costRayehGai,
|
|
costRayehGaiBalash,
|
|
costRayehGaiComfort = 0;
|
|
update();
|
|
|
|
if (startNameAddress.toLowerCase().contains('airport') ||
|
|
endNameAddress.toLowerCase().contains('airport') ||
|
|
startNameAddress.contains('مطار') ||
|
|
startNameAddress.contains('المطار') ||
|
|
endNameAddress.contains('مطار') ||
|
|
endNameAddress.contains('المطار')) {
|
|
costComfort =
|
|
(distance * comfortPrice) + (costDuration * latePrice) + 20;
|
|
costSpeed = (distance * speedPrice) + (costDuration * latePrice) + 20;
|
|
costBalash =
|
|
(distance * (speedPrice - 1)) + (costDuration * latePrice) + 20;
|
|
costDelivery =
|
|
(distance * deliveryPrice) + (costDuration * latePrice) + 20;
|
|
costLady =
|
|
(distance * comfortPrice + 2) + (costDuration * latePrice) + 20;
|
|
costRayehGai = (distance * 2 * speedPrice) -
|
|
((distance * 1 * speedPrice) * .4) +
|
|
costDuration * 2 * latePrice +
|
|
20;
|
|
costRayehGaiComfort = (distance * 2 * comfortPrice) -
|
|
((distance * 1 * comfortPrice) * .4) +
|
|
costDuration * 2 * latePrice +
|
|
20;
|
|
costRayehGaiBalash = (distance * 2 * (speedPrice - 1)) -
|
|
((distance * 1 * (speedPrice - 1)) * .4) +
|
|
costDuration * 2 * latePrice +
|
|
20;
|
|
|
|
update();
|
|
} else if (currentTime.hour >= 21 && currentTime.hour < 0) {
|
|
// costDistance = distance * latePrice;
|
|
costComfort = (distance * comfortPrice) + costDuration * latePrice;
|
|
costSpeed = (distance * speedPrice) + costDuration * latePrice;
|
|
costBalash = (distance * (speedPrice - 1)) + costDuration * latePrice;
|
|
costDelivery = (distance * deliveryPrice) + costDuration * latePrice;
|
|
costLady = (distance * comfortPrice + 2) + costDuration * latePrice;
|
|
costRayehGai = (distance * 2 * speedPrice) -
|
|
((distance * 1 * speedPrice) * .4) +
|
|
costDuration * 2 * latePrice;
|
|
costRayehGaiComfort = (distance * 2 * comfortPrice) -
|
|
((distance * 1 * comfortPrice) * .4) +
|
|
costDuration * 2 * latePrice;
|
|
costRayehGaiBalash = (distance * 2 * (speedPrice - 1)) -
|
|
((distance * 1 * (speedPrice - 1)) * .4) +
|
|
costDuration * 2 * latePrice;
|
|
|
|
update();
|
|
} else if (currentTime.hour >= 1 && currentTime.hour < 5) {
|
|
// costDistance = distance * latePrice;
|
|
if (startNameAddress.contains('club') ||
|
|
startNameAddress.contains('nightclub') ||
|
|
startNameAddress.contains('ديسكو') ||
|
|
startNameAddress.contains('ملهى ليلي') ||
|
|
startNameAddress.contains('Night club')) {
|
|
// Your code here
|
|
costComfort =
|
|
(distance * comfortPrice) + costDuration * (latePrice + .5) * 2;
|
|
costSpeed =
|
|
(distance * speedPrice) + costDuration * (latePrice + .5) * 2;
|
|
costBalash = (distance * (speedPrice - 1)) +
|
|
costDuration * (latePrice + .5) * 2;
|
|
costDelivery =
|
|
(distance * deliveryPrice) + costDuration * (latePrice + .5) * 2;
|
|
costLady = (distance * comfortPrice + 2) +
|
|
costDuration * (latePrice + .5) * 2;
|
|
costRayehGai = (distance * 2 * speedPrice) -
|
|
((distance * 1 * speedPrice) * .4) +
|
|
costDuration * 2 * (latePrice + .5) * 2;
|
|
costRayehGaiComfort = (distance * 2 * comfortPrice) -
|
|
((distance * 1 * comfortPrice) * .4) +
|
|
costDuration * 2 * (latePrice + .5) * 2;
|
|
costRayehGaiBalash = (distance * 2 * (speedPrice - 1)) -
|
|
((distance * 1 * (speedPrice - 1)) * .4) +
|
|
costDuration * 2 * (latePrice + .5) * 2;
|
|
|
|
update();
|
|
}
|
|
costComfort =
|
|
(distance * comfortPrice) + costDuration * (latePrice + .5);
|
|
costSpeed = (distance * speedPrice) + costDuration * (latePrice + .5);
|
|
costBalash =
|
|
(distance * (speedPrice - 1)) + costDuration * (latePrice + .5);
|
|
costDelivery =
|
|
(distance * deliveryPrice) + costDuration * (latePrice + .5);
|
|
costLady =
|
|
(distance * comfortPrice + 2) + costDuration * (latePrice + .5);
|
|
costRayehGai = (distance * 2 * speedPrice) -
|
|
((distance * 1 * speedPrice) * .4) +
|
|
costDuration * 2 * latePrice;
|
|
costRayehGaiComfort = (distance * 2 * comfortPrice) -
|
|
((distance * 1 * comfortPrice) * .4) +
|
|
costDuration * 2 * latePrice;
|
|
costRayehGaiBalash = (distance * 2 * (speedPrice - 1)) -
|
|
((distance * 1 * (speedPrice - 1)) * .4) +
|
|
costDuration * 2 * latePrice;
|
|
|
|
update();
|
|
} else if (currentTime.hour >= 14 && currentTime.hour <= 17) {
|
|
// if (averageDuration > 2.5) {
|
|
// costDistance = distance * heavyPrice;
|
|
costComfort = (distance * comfortPrice) + costDuration * heavyPrice;
|
|
costSpeed = (distance * speedPrice) + costDuration * heavyPrice;
|
|
costBalash = (distance * (speedPrice - 1)) + costDuration * heavyPrice;
|
|
costDelivery = (distance * deliveryPrice) + costDuration * heavyPrice;
|
|
costLady = (distance * comfortPrice + 2) + costDuration * heavyPrice;
|
|
costRayehGai = (distance * 2 * speedPrice) -
|
|
((distance * 1 * speedPrice) * .4) +
|
|
costDuration * 2 * heavyPrice;
|
|
costRayehGaiComfort = (distance * 2 * comfortPrice) -
|
|
((distance * 1 * comfortPrice) * .4) +
|
|
costDuration * 2 * heavyPrice;
|
|
costRayehGaiBalash = (distance * 2 * (speedPrice - 1)) -
|
|
((distance * 1 * (speedPrice - 1)) * .4) +
|
|
costDuration * 2 * heavyPrice;
|
|
|
|
update();
|
|
// } /
|
|
} else {
|
|
// costDistance = distance * (naturePrice - .1);
|
|
costComfort = (distance * comfortPrice) + costDuration;
|
|
costSpeed = (distance * speedPrice) + costDuration;
|
|
costBalash = (distance * (speedPrice - 1)) + costDuration;
|
|
costDelivery = (distance * deliveryPrice) + costDuration;
|
|
costLady = (distance * comfortPrice + 2) + costDuration;
|
|
costRayehGai = (distance * 2 * speedPrice) -
|
|
((distance * 1 * speedPrice) * .4) +
|
|
costDuration * 2;
|
|
costRayehGaiComfort = (distance * 2 * comfortPrice) -
|
|
((distance * 1 * comfortPrice) * .4) +
|
|
costDuration * 2;
|
|
costRayehGaiBalash = (distance * 2 * (speedPrice - 1)) -
|
|
((distance * 1 * (speedPrice - 1)) * .4) +
|
|
costDuration * 2;
|
|
update();
|
|
}
|
|
|
|
var totalDriver1 = costDistance + costDuration;
|
|
totalCostPassenger = totalDriver1 + (totalDriver1 * kazan / 100);
|
|
totalPassenger = costSpeed + (costSpeed * kazan / 100);
|
|
if (isInUniversity) {
|
|
Log.print('isInUniversity: $isInUniversity');
|
|
totalPassengerComfort =
|
|
20 + (costComfort + (costComfort * kazan / 100)).ceilToDouble();
|
|
totalPassengerLady =
|
|
20 + (costLady + (costLady * kazan / 100)).ceilToDouble();
|
|
totalPassengerSpeed =
|
|
20 + (costSpeed + (costSpeed * kazan / 100)).ceilToDouble();
|
|
totalPassengerBalash =
|
|
20 + (costBalash + (costBalash * kazan / 100)).ceilToDouble();
|
|
totalPassengerRayehGai =
|
|
(costRayehGai + (costRayehGai * kazan / 100)).ceilToDouble();
|
|
totalPassengerRayehGaiComfort =
|
|
(costRayehGaiComfort + (costRayehGaiComfort * kazan / 100))
|
|
.ceilToDouble();
|
|
totalPassengerRayehGaiBalash =
|
|
(costRayehGaiBalash + (costRayehGaiBalash * kazan / 100))
|
|
.ceilToDouble();
|
|
totalPassengerComfortDiscount =
|
|
totalPassengerComfort + totalPassengerComfort * (kazan - 0) / 100;
|
|
totalPassengerLadyDiscount =
|
|
totalPassengerLady + totalPassengerLady * (kazan - 0) / 100;
|
|
totalPassengerSpeedDiscount =
|
|
totalPassengerSpeed + totalPassengerSpeed * (kazan) / 100;
|
|
totalPassengerBalashDiscount =
|
|
totalPassengerBalash + totalPassengerBalash * (kazan) / 100;
|
|
totalPassengerRaihGaiDiscount =
|
|
totalPassengerRayehGai + totalPassengerRayehGai * (kazan) / 100;
|
|
totalPassengerScooter =
|
|
(costDelivery + (costDelivery * kazan / 100)).ceilToDouble();
|
|
totalPassengerComfort = totalPassengerComfortDiscount -
|
|
(totalPassengerComfortDiscount * kazan / 100);
|
|
totalPassengerSpeed = totalPassengerSpeedDiscount -
|
|
(totalPassengerSpeedDiscount * kazan / 100);
|
|
totalPassengerBalash = totalPassengerBalashDiscount -
|
|
(totalPassengerBalashDiscount * kazan / 100);
|
|
totalPassengerLady = totalPassengerLadyDiscount -
|
|
(totalPassengerLadyDiscount * kazan / 100);
|
|
totalDriver = totalDriver1 + (totalDriver1 * kazan / 100);
|
|
tax = totalCostPassenger * kazan / 100;
|
|
totalME = totalCostPassenger - tax;
|
|
costForDriver = fuelPrice * (20 / 210) * distance;
|
|
} else {
|
|
Log.print('isInUniversity: $isInUniversity');
|
|
totalPassengerComfort =
|
|
(costComfort + (costComfort * kazan / 100)).ceilToDouble();
|
|
totalPassengerLady =
|
|
(costLady + (costLady * kazan / 100)).ceilToDouble();
|
|
totalPassengerSpeed =
|
|
(costSpeed + (costSpeed * kazan / 100)).ceilToDouble();
|
|
totalPassengerBalash =
|
|
(costBalash + (costBalash * kazan / 100)).ceilToDouble();
|
|
totalPassengerRayehGai =
|
|
(costRayehGai + (costRayehGai * kazan / 100)).ceilToDouble();
|
|
totalPassengerRayehGaiComfort =
|
|
(costRayehGaiComfort + (costRayehGaiComfort * kazan / 100))
|
|
.ceilToDouble();
|
|
totalPassengerRayehGaiBalash =
|
|
(costRayehGaiBalash + (costRayehGaiBalash * kazan / 100))
|
|
.ceilToDouble();
|
|
totalPassengerComfortDiscount =
|
|
totalPassengerComfort + totalPassengerComfort * (kazan - 0) / 100;
|
|
totalPassengerLadyDiscount =
|
|
totalPassengerLady + totalPassengerLady * (kazan - 0) / 100;
|
|
totalPassengerSpeedDiscount =
|
|
totalPassengerSpeed + totalPassengerSpeed * (kazan) / 100;
|
|
totalPassengerBalashDiscount =
|
|
totalPassengerBalash + totalPassengerBalash * (kazan) / 100;
|
|
totalPassengerRaihGaiDiscount =
|
|
totalPassengerRayehGai + totalPassengerRayehGai * (kazan) / 100;
|
|
totalPassengerScooter =
|
|
(costDelivery + (costDelivery * kazan / 100)).ceilToDouble();
|
|
totalPassengerComfort = totalPassengerComfortDiscount -
|
|
(totalPassengerComfortDiscount * kazan / 100);
|
|
totalPassengerSpeed = totalPassengerSpeedDiscount -
|
|
(totalPassengerSpeedDiscount * kazan / 100);
|
|
totalPassengerBalash = totalPassengerBalashDiscount -
|
|
(totalPassengerBalashDiscount * kazan / 100);
|
|
totalPassengerLady = totalPassengerLadyDiscount -
|
|
(totalPassengerLadyDiscount * kazan / 100);
|
|
totalDriver = totalDriver1 + (totalDriver1 * kazan / 100);
|
|
tax = totalCostPassenger * kazan / 100;
|
|
totalME = totalCostPassenger - tax;
|
|
costForDriver = fuelPrice * (20 / 210) * distance;
|
|
}
|
|
|
|
if (totalPassengerSpeed < 20) {
|
|
// for eygpt 20 le open ride
|
|
totalCostPassenger = 20;
|
|
totalPassengerSpeed = 20;
|
|
totalPassengerBalash = 20;
|
|
totalPassengerComfort = 30;
|
|
totalPassengerLady = 30;
|
|
totalPassengerScooter = 18;
|
|
} else {
|
|
totalPassenger = totalCostPassenger;
|
|
update();
|
|
}
|
|
if (double.parse(box.read(BoxName.passengerWalletTotal)) < 0) {
|
|
totalPassenger = totalPassenger +
|
|
(-1) * (double.parse(box.read(BoxName.passengerWalletTotal)));
|
|
totalPassengerComfort = totalPassengerComfort +
|
|
(-1) * (double.parse(box.read(BoxName.passengerWalletTotal)));
|
|
totalPassengerLady = totalPassengerLady +
|
|
(-1) * (double.parse(box.read(BoxName.passengerWalletTotal)));
|
|
totalPassengerBalash = totalPassengerBalash +
|
|
(-1) * (double.parse(box.read(BoxName.passengerWalletTotal)));
|
|
totalPassengerScooter = totalPassengerScooter +
|
|
(-1) * (double.parse(box.read(BoxName.passengerWalletTotal)));
|
|
totalPassengerRayehGai = totalPassengerScooter +
|
|
(-1) * (double.parse(box.read(BoxName.passengerWalletTotal)));
|
|
update();
|
|
}
|
|
// }
|
|
|
|
// buttomSheetMapPage();
|
|
changeBottomSheetShown();
|
|
} else {}
|
|
}
|
|
|
|
addToken() async {
|
|
await CRUD()
|
|
.post(link: "${AppLink.server}/ride/firebase/add.php", payload: {
|
|
'token': box.read(BoxName.tokenFCM),
|
|
'passengerID': box.read(BoxName.passengerID).toString()
|
|
});
|
|
CRUD().post(
|
|
link: "${AppLink.seferAlexandriaServer}/ride/firebase/add.php",
|
|
payload: {
|
|
'token': box.read(BoxName.tokenFCM),
|
|
'passengerID': box.read(BoxName.passengerID).toString()
|
|
});
|
|
CRUD().post(
|
|
link: "${AppLink.seferGizaServer}/ride/firebase/add.php",
|
|
payload: {
|
|
'token': box.read(BoxName.tokenFCM),
|
|
'passengerID': box.read(BoxName.passengerID).toString()
|
|
});
|
|
}
|
|
|
|
List<LatLng> polylineCoordinate = [];
|
|
String? cardNumber;
|
|
void readyWayPoints() {
|
|
hintTextwayPointStringAll = [
|
|
hintTextwayPoint0,
|
|
hintTextwayPoint1,
|
|
hintTextwayPoint2,
|
|
hintTextwayPoint3,
|
|
hintTextwayPoint4,
|
|
];
|
|
polylineCoordinatesPointsAll = [
|
|
polylineCoordinates0,
|
|
polylineCoordinates1,
|
|
polylineCoordinates2,
|
|
polylineCoordinates3,
|
|
polylineCoordinates4,
|
|
];
|
|
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();
|
|
}
|
|
|
|
List driversForMishwari = [];
|
|
|
|
Future selectDriverAndCarForMishwariTrip() async {
|
|
// Calculate the bounds for 20km
|
|
double latitudeOffset = 0.1795; // 20km range in latitude
|
|
double longitudeOffset = 0.2074; // 20km range in longitude
|
|
|
|
// Calculate bounding box based on passenger's location
|
|
double southwestLat = passengerLocation.latitude - latitudeOffset;
|
|
double northeastLat = passengerLocation.latitude + latitudeOffset;
|
|
double southwestLon = passengerLocation.longitude - longitudeOffset;
|
|
double northeastLon = passengerLocation.longitude + longitudeOffset;
|
|
|
|
// Create the payload with calculated bounds
|
|
var payload = {
|
|
'southwestLat': southwestLat.toString(),
|
|
'northeastLat': northeastLat.toString(),
|
|
'southwestLon': southwestLon.toString(),
|
|
'northeastLon': northeastLon.toString(),
|
|
};
|
|
|
|
try {
|
|
// Fetch data from the API
|
|
var res = await CRUD().get(
|
|
link: AppLink.selectDriverAndCarForMishwariTrip, payload: payload);
|
|
|
|
if (res != 'failure') {
|
|
// Check if response is valid JSON
|
|
try {
|
|
var d = jsonDecode(res);
|
|
driversForMishwari = d['message'];
|
|
Log.print('driversForMishwari: $driversForMishwari');
|
|
update();
|
|
} catch (e) {
|
|
// Handle invalid JSON format
|
|
print("Error decoding JSON: $e");
|
|
return 'Server returned invalid data. Please try again later.';
|
|
}
|
|
} else {
|
|
return 'No driver available now, try again later. Thanks for using our app.'
|
|
.tr;
|
|
}
|
|
} catch (e) {
|
|
// Handle network or other exceptions
|
|
print("Error fetching data: $e");
|
|
return 'There was an issue connecting to the server. Please try again later.'
|
|
.tr;
|
|
}
|
|
}
|
|
|
|
final Rx<DateTime> selectedDateTime = DateTime.now().obs;
|
|
|
|
void updateDateTime(DateTime newDateTime) {
|
|
selectedDateTime.value = newDateTime;
|
|
}
|
|
|
|
Future mishwariOption() async {
|
|
isLoading = true;
|
|
update();
|
|
// add dialoug for select driver and car
|
|
await selectDriverAndCarForMishwariTrip();
|
|
Future.delayed(Duration.zero);
|
|
isLoading = false;
|
|
update();
|
|
Get.to(() => CupertinoDriverListWidget());
|
|
|
|
// changeCashConfirmPageShown();
|
|
}
|
|
|
|
var driverIdVip = '';
|
|
Future<void> saveTripData(
|
|
Map<String, dynamic> driver, DateTime tripDateTime) async {
|
|
try {
|
|
// Prepare trip data
|
|
Map<String, dynamic> tripData = {
|
|
'id': driver['driver_id'].toString(), // Ensure the id is a string
|
|
'phone': driver['phone'],
|
|
'gender': driver['gender'],
|
|
'name': driver['NAME'],
|
|
'name_english': driver['name_english'],
|
|
'address': driver['address'],
|
|
'religion': driver['religion'] ?? 'UnKnown',
|
|
'age': driver['age'].toString(), // Convert age to String
|
|
'education': driver['education'] ?? 'UnKnown', //startlocationname
|
|
'license_type': driver['license_type'] ?? 'UnKnown',
|
|
'national_number': driver['national_number'] ?? 'UnKnown',
|
|
'car_plate': driver['car_plate'],
|
|
'make': driver['make'],
|
|
'model': driver['model'],
|
|
'year': driver['year'].toString(), // Convert year to String
|
|
'color': driver['color'],
|
|
'color_hex': driver['color_hex'],
|
|
'displacement': driver['displacement'],
|
|
'fuel': driver['fuel'],
|
|
'token': driver['token'],
|
|
'rating': driver['rating'].toString(), // Convert rating to String
|
|
'countRide':
|
|
driver['ride_count'].toString(), // Convert countRide to String
|
|
'passengerId': box.read(BoxName.passengerID),
|
|
'timeSelected': tripDateTime.toIso8601String(),
|
|
'status': 'pending',
|
|
'startNameAddress': startNameAddress.toString(),
|
|
'locationCoordinate':
|
|
'${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
|
|
};
|
|
Log.print('tripData: $tripData');
|
|
|
|
// Send data to server
|
|
var response =
|
|
await CRUD().post(link: AppLink.addMishwari, payload: tripData);
|
|
// Log.print('response: $response');
|
|
|
|
if (response != 'failure') {
|
|
// Trip saved successfully
|
|
// Get.snackbar('Success'.tr, 'Trip booked successfully'.tr);
|
|
var id = response['message']['id'].toString();
|
|
await CRUD().post(
|
|
link: '${AppLink.seferCairoServer}/ride/rides/add.php',
|
|
payload: {
|
|
"start_location":
|
|
'${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
|
|
"end_location":
|
|
'${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
|
|
"date": DateTime.now().toString(),
|
|
"time": DateTime.now().toString(),
|
|
"endtime":
|
|
DateTime.now().add(const Duration(hours: 2)).toString(),
|
|
"price": '50',
|
|
"passenger_id": box.read(BoxName.passengerID).toString(),
|
|
"driver_id": driver['driver_id'].toString(),
|
|
"status": "waiting",
|
|
'carType': 'vip',
|
|
"price_for_driver": '50',
|
|
"price_for_passenger": '50',
|
|
"distance": '20',
|
|
"paymentMethod": 'cash',
|
|
}).then((value) {
|
|
if (value is String) {
|
|
final parsedValue = jsonDecode(value);
|
|
rideId = parsedValue['message'];
|
|
} else if (value is Map) {
|
|
rideId = value['message'];
|
|
} else {
|
|
Log.print('Unexpected response type: ${value.runtimeType}');
|
|
}
|
|
});
|
|
if (AppLink.endPoint != AppLink.seferCairoServer) {
|
|
await CRUD().post(
|
|
link: "${AppLink.endPoint}/ride/mishwari/add.php",
|
|
payload: tripData);
|
|
CRUD().post(link: '${AppLink.endPoint}/ride/rides/add.php', payload: {
|
|
"start_location":
|
|
'${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
|
|
"end_location":
|
|
'${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
|
|
"date": DateTime.now().toString(),
|
|
"time": DateTime.now().toString(),
|
|
"endtime": DateTime.now().add(const Duration(hours: 2)).toString(),
|
|
"price": '50',
|
|
"passenger_id": box.read(BoxName.passengerID).toString(),
|
|
"driver_id": driver['driver_id'].toString(),
|
|
"status": "waiting",
|
|
'carType': 'vip',
|
|
"price_for_driver": '50',
|
|
"price_for_passenger": '50',
|
|
"distance": '20',
|
|
"paymentMethod": 'cash',
|
|
});
|
|
}
|
|
driverIdVip = driver['driver_id'].toString();
|
|
driverId = driver['driver_id'].toString();
|
|
|
|
DateTime timeSelected = DateTime.parse(tripDateTime.toIso8601String());
|
|
Get.find<NotificationController>().scheduleNotificationsForTimeSelected(
|
|
"Your trip is scheduled".tr,
|
|
"Don't forget your ride!".tr,
|
|
"tone1",
|
|
timeSelected);
|
|
// Optionally, set up local notification or send a push notification
|
|
|
|
await FirebaseMessagesController().sendNotificationToDriverMAP(
|
|
'OrderVIP',
|
|
rideId.toString(),
|
|
encryptionHelper.decryptData(driver['token'].toString()),
|
|
[
|
|
id,
|
|
rideId,
|
|
driver['id'],
|
|
passengerLocation.latitude.toString(),
|
|
startNameAddress.toString(),
|
|
passengerLocation.longitude.toString(),
|
|
encryptionHelper
|
|
.decryptData(box.read(BoxName.name).toString().split(' ')[0])
|
|
.toString(),
|
|
box.read(BoxName.passengerID).toString(),
|
|
box.read(BoxName.phone).toString(),
|
|
box.read(BoxName.email).toString(),
|
|
box.read(BoxName.passengerPhotoUrl).toString(),
|
|
box.read(BoxName.tokenFCM).toString(),
|
|
encryptionHelper.decryptData(driver['token'].toString()),
|
|
],
|
|
'order.wav');
|
|
if (response['message'] == "Trip updated successfully") {
|
|
mySnackbarSuccess("Trip updated successfully".tr);
|
|
Log.print(
|
|
'previous_driver_token: ${response['previous_driver_token']}');
|
|
|
|
FirebaseMessagesController().sendNotificationToDriverMAP(
|
|
'Order VIP Canceld'.tr,
|
|
'Passenger cancel order'.tr,
|
|
response['previous_driver_token'].toString(),
|
|
[],
|
|
'cancel.wav',
|
|
);
|
|
}
|
|
// data = [];
|
|
isBottomSheetShown = false;
|
|
update();
|
|
Get.to(() => VipWaittingPage());
|
|
} else {
|
|
throw Exception('Failed to save trip');
|
|
}
|
|
} catch (e) {
|
|
// Show error message with more details for debugging
|
|
Get.snackbar('Error'.tr, 'Failed to book trip: $e'.tr,
|
|
backgroundColor: AppColor.redColor);
|
|
Log.print('Error: $e');
|
|
}
|
|
}
|
|
|
|
cancelVip(String token, tripId) async {
|
|
// FirebaseMessagesController().sendNotificationToDriverMAP(
|
|
// 'Order VIP Canceld'.tr,
|
|
// 'Passenger cancel order'.tr,
|
|
// token,
|
|
// [],
|
|
// 'cancel.wav',
|
|
// );
|
|
var res = await CRUD()
|
|
.post(link: AppLink.cancelMishwari, payload: {'id': tripId});
|
|
if (res != 'failur') {
|
|
Get.back();
|
|
mySnackbarSuccess('You canceled VIP trip'.tr);
|
|
}
|
|
}
|
|
|
|
sendToDriverAgain(String token) {
|
|
FirebaseMessagesController().sendNotificationToDriverMAP(
|
|
'Order VIP Canceld'.tr,
|
|
'Passenger cancel order'.tr,
|
|
token,
|
|
[],
|
|
'cancel.wav',
|
|
);
|
|
}
|
|
|
|
initilizeGetStorage() async {
|
|
if (box.read(BoxName.addWork) == null) {
|
|
box.write(BoxName.addWork, 'addWork');
|
|
}
|
|
if (box.read(BoxName.addHome) == null) {
|
|
box.write(BoxName.addHome, 'addHome');
|
|
}
|
|
}
|
|
|
|
late List recentPlaces = [];
|
|
getFavioratePlaces0() async {
|
|
recentPlaces = await sql.getCustomQuery(
|
|
'SELECT DISTINCT latitude, longitude, name, rate FROM ${TableName.recentLocations}');
|
|
}
|
|
|
|
getFavioratePlaces() async {
|
|
recentPlaces = await sql.getCustomQuery(
|
|
'SELECT * FROM ${TableName.recentLocations} ORDER BY createdAt DESC');
|
|
// Log.print('recentPlaces: ${recentPlaces}');
|
|
}
|
|
|
|
double passengerRate = 5;
|
|
double comfortPrice = 8;
|
|
double speedPrice = 4;
|
|
double mashwariPrice = 4;
|
|
double deliveryPrice = 1.2;
|
|
getKazanPercent() async {
|
|
var res = await CRUD().get(
|
|
link: AppLink.getKazanPercent,
|
|
payload: {'country': box.read(BoxName.countryCode).toString()},
|
|
);
|
|
if (res != 'failure') {
|
|
var json = jsonDecode(res);
|
|
kazan = double.parse(json['message'][0]['kazan']);
|
|
naturePrice = double.parse(json['message'][0]['naturePrice']);
|
|
heavyPrice = double.parse(json['message'][0]['heavyPrice']);
|
|
latePrice = double.parse(json['message'][0]['latePrice']);
|
|
comfortPrice = double.parse(json['message'][0]['comfortPrice']);
|
|
speedPrice = double.parse(json['message'][0]['speedPrice']);
|
|
deliveryPrice = double.parse(json['message'][0]['deliveryPrice']);
|
|
mashwariPrice = double.parse(json['message'][0]['freePrice']);
|
|
fuelPrice = double.parse(json['message'][0]['fuelPrice']);
|
|
}
|
|
}
|
|
|
|
void startFetchingData() {
|
|
Timer.periodic(const Duration(milliseconds: 50), (Timer timer) async {
|
|
await getKazanPercent();
|
|
});
|
|
}
|
|
|
|
getPassengerRate() async {
|
|
var res = await CRUD().get(
|
|
link: AppLink.getPassengerRate,
|
|
payload: {'passenger_id': box.read(BoxName.passengerID)});
|
|
if (res != 'failure') {
|
|
var message = jsonDecode(res)['message'];
|
|
if (message['rating'] == null) {
|
|
passengerRate = 5.0; // Default rating
|
|
} else {
|
|
// Safely parse the rating to double
|
|
var rating = message['rating'];
|
|
if (rating is String) {
|
|
passengerRate =
|
|
double.tryParse(rating) ?? 5.0; // Default if parsing fails
|
|
} else if (rating is num) {
|
|
passengerRate =
|
|
rating.toDouble(); // Already a number, convert to double
|
|
} else {
|
|
passengerRate = 5.0; // Default for unexpected data types
|
|
}
|
|
}
|
|
} else {
|
|
passengerRate = 5.0; // Default rating for failure
|
|
}
|
|
}
|
|
|
|
firstTimeRunToGetCoupon() async {
|
|
// Check if it's the first time and the app is installed and gift token is available
|
|
if (box.read(BoxName.isFirstTime).toString() == '0' &&
|
|
box.read(BoxName.isInstall).toString() == '1' &&
|
|
box.read(BoxName.isGiftToken).toString() == '0') {
|
|
var promo, discount, validity;
|
|
var resPromo = await CRUD().get(link: AppLink.getPromoFirst, payload: {
|
|
"passengerID": box.read(BoxName.passengerID).toString(),
|
|
});
|
|
if (resPromo != 'failure') {
|
|
var d1 = jsonDecode(resPromo);
|
|
promo = d1['message']['promo_code'];
|
|
discount = d1['message']['amount'];
|
|
validity = d1['message']['validity_end_date'];
|
|
}
|
|
box.write(BoxName.isFirstTime, '1');
|
|
|
|
// Show a full-screen modal styled as an ad
|
|
Get.dialog(
|
|
AlertDialog(
|
|
contentPadding:
|
|
EdgeInsets.zero, // Removes the padding around the content
|
|
content: SizedBox(
|
|
width: 300, // Match the width of PromoBanner
|
|
// height: 250, // Match the height of PromoBanner
|
|
child: PromoBanner(
|
|
promoCode: promo,
|
|
discountPercentage: discount,
|
|
validity: validity,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
var k;
|
|
@override
|
|
void onInit() async {
|
|
mapAPIKEY = await storage.read(key: BoxName.mapAPIKEY);
|
|
k = await getAIKey('HERE_API');
|
|
getFavioratePlaces();
|
|
readyWayPoints();
|
|
addCustomPicker();
|
|
addCustomCarIcon();
|
|
addCustomLadyIcon();
|
|
addCustomMotoIcon();
|
|
addCustomStepIcon();
|
|
addCustomStartIcon();
|
|
addCustomEndIcon();
|
|
// addToken();
|
|
await getLocation();
|
|
getPassengerLocationUniversity();
|
|
_initializePolygons();
|
|
// await addToken();
|
|
getKazanPercent();
|
|
getPassengerRate();
|
|
getRideStatusFromStartApp();
|
|
reloadStartApp = false;
|
|
startMarkerReloading();
|
|
Get.put(TextToSpeechController());
|
|
box.write(BoxName.carType, 'yet');
|
|
box.write(BoxName.tipPercentage, '0');
|
|
Get.put(AudioRecorderController());
|
|
// await getNearestDriverByPassengerLocation();
|
|
firstTimeRunToGetCoupon();
|
|
initilizeGetStorage();
|
|
cardNumber = await SecureStorage().readData(BoxName.cardNumber);
|
|
|
|
super.onInit();
|
|
}
|
|
|
|
uploadPassengerLocation() async {
|
|
await CRUD().post(link: AppLink.addpassengerLocation, payload: {
|
|
"passengerId": box.read(BoxName.passengerID),
|
|
"lat": passengerLocation.latitude.toString(),
|
|
"lng": passengerLocation.longitude.toString(),
|
|
"rideId": rideId.toString()
|
|
});
|
|
}
|
|
}
|
|
|
|
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,
|
|
});
|
|
}
|