From e0c242bd7758c4ccb72ad6ebdfbc64d5b561eb62 Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Sun, 8 Dec 2024 18:16:31 +0300 Subject: [PATCH] 12/8/1 --- .env | 1 + android/app/build.gradle | 4 +- assets/images/car3.png | Bin 0 -> 110238 bytes ios/Runner/Info.plist | 4 +- lib/constant/api_key.dart | 1 + lib/constant/box_name.dart | 1 + lib/constant/links.dart | 6 + lib/constant/style.dart | 60 +- lib/controller/auth/register_controller.dart | 51 +- lib/controller/firebase/firbase_messge.dart | 9 +- .../firebase/local_notification.dart | 2 +- lib/controller/functions/crud.dart | 20 + lib/controller/functions/sms_controller.dart | 1 + .../home/map_passenger_controller.dart | 1751 +++++++++-------- lib/controller/home/vip_waitting_page.dart | 6 +- lib/controller/local/translations.dart | 32 +- .../payment/payment_controller.dart | 5 +- lib/controller/rate/rate_conroller.dart | 32 +- lib/models/db_sql.dart | 49 +- lib/views/Rate/rate_captain.dart | 2 +- lib/views/auth/login_page.dart | 11 + lib/views/home/HomePage/contact_us.dart | 6 +- lib/views/home/home_page.dart | 195 +- lib/views/home/map_page_passenger.dart | 3 +- .../map_widget.dart/apply_order_widget.dart | 101 +- .../form_search_places_destenation.dart | 214 +- .../map_widget.dart/form_search_start.dart | 4 +- .../form_serch_multiy_point.dart | 2 +- .../map_widget.dart/left_main_menu_icons.dart | 6 +- .../map_widget.dart/main_bottom_Menu_map.dart | 57 +- .../map_widget.dart/ride_begin_passenger.dart | 2 +- .../home/my_wallet/passenger_wallet.dart | 61 +- .../my_wallet/passenger_wallet_dialoge.dart | 146 +- .../home/profile/promos_passenger_page.dart | 376 ++-- 34 files changed, 1876 insertions(+), 1345 deletions(-) create mode 100644 assets/images/car3.png diff --git a/.env b/.env index a5bc609..5443e66 100644 --- a/.env +++ b/.env @@ -5,6 +5,7 @@ accountSIDTwillo=QFx0qy456juj3839xuy2194q629q1fj0y7XrXlBl serverAPI=QQQQobSrrFi:QVQ87xU7zwCvmZzZdaxuS2f23Y4mz7MzyOzr8od2br6KYyeFaTVLG3K3hx5ZaUyx7eYvAYpAVdKk-286NTRi3zs9iSOnXtXRIxswg3KecBmsl3VxJ9wO-vIpwu4Pv7dkHkXniuxMSDgWXrXlBl mapAPIKEY=QOmqZsFsutLDCtZCRIUAZAkB5v6AMkKEPMbJGa3XrXlBl twilloRecoveryCode=CAU79DHPH1BE9PUH4ETXTSXZXrXlBl +apiKeyHere=g_WNUb5L-7-F8oHpUmgIzH7ETeH9xZ8RwGG9_G8zX9A authTokenTwillo=70u98ju0214xx4q0u74028u021u4qu65XrXlBl chatGPTkey=zg-4C26q4SYBKQeHZDqkWowC9XrxgUEfUy9JRw2rm6Q2adb3kjwXrXlBl transactionCloude=Qhcwilomqcoib:QVO_JNYED2XWA26YXKC2TP:YK1DVH6SJB31N3PE1UXrXlBl diff --git a/android/app/build.gradle b/android/app/build.gradle index 2d432ec..de3907d 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -148,8 +148,8 @@ android { // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. minSdk = 23 targetSdk = flutter.targetSdkVersion - versionCode = 99 - versionName = '1.5.99' + versionCode = 106 + versionName = '1.6.106' multiDexEnabled =true // manifestPlaceholders can be specified here if needed diff --git a/assets/images/car3.png b/assets/images/car3.png new file mode 100644 index 0000000000000000000000000000000000000000..41627ae75b5de93880a524e1977ccade4f3cfd9b GIT binary patch literal 110238 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.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

>vRC_x#yV$@VvzJX*&mZ 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 literal 0 HcmV?d00001 diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 3513e88..6a85ad6 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -41,11 +41,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 71 + 77 CFBundleSignature ???? CFBundleVersion - 4.3.71 + 4.3.77 NSHumanReadableCopyright FirebaseAppDelegateProxyEnabled diff --git a/lib/constant/api_key.dart b/lib/constant/api_key.dart index 6433459..f0e2f77 100644 --- a/lib/constant/api_key.dart +++ b/lib/constant/api_key.dart @@ -51,6 +51,7 @@ class AK { X.r(X.r(X.r(Env.payMobApikey, cn), cC), cs); static final String integrationIdPayMobWallet = X.r(X.r(X.r(Env.integrationIdPayMobWallet, cn), cC), cs); + static final String apiKeyHere = Env.apiKeyHere; static final String smsPasswordEgypt = X.r(X.r(X.r(Env.smsPasswordEgypt, cn), cC), cs); static final String ocpApimSubscriptionKey = Env.ocpApimSubscriptionKey; diff --git a/lib/constant/box_name.dart b/lib/constant/box_name.dart index 0113597..e2fbaa7 100644 --- a/lib/constant/box_name.dart +++ b/lib/constant/box_name.dart @@ -24,6 +24,7 @@ class BoxName { static const String agreeTerms = "agreeTerms"; static const String addWork = 'addWork'; static const String addHome = 'addHome'; + static const String placesDestination = 'placesDestination'; static const String tipPercentage = 'tipPercentage'; static const String accountIdStripeConnect = "accountIdStripeConnect"; static const String faceDetectTimes = "faceDetectTimes"; diff --git a/lib/constant/links.dart b/lib/constant/links.dart index d823265..bb2c553 100644 --- a/lib/constant/links.dart +++ b/lib/constant/links.dart @@ -14,6 +14,8 @@ class AppLink { // static final String server = Env.serverPHP; static String googleMapsLink = 'https://maps.googleapis.com/maps/api/'; + static String searcMaps = + 'https://autosuggest.search.hereapi.com/v1/autosuggest'; static String llama = 'https://api.llama-api.com/chat/completions'; static String gemini = 'https://generativelanguage.googleapis.com/v1beta3/models/text-bison-001:generateText'; @@ -185,6 +187,8 @@ class AppLink { // ===================================== static String addRateToPassenger = "$ride/rate/add.php"; + static String savePlacesServer = "$ride/places/add.php"; + static String getapiKey = "$ride/apiKey/get.php"; static String addRateToDriver = "$ride/rate/addRateToDriver.php"; static String getDriverRate = "$ride/rate/getDriverRate.php"; static String getPassengerRate = "$ride/rate/getPassengerRate.php"; @@ -265,6 +269,8 @@ class AppLink { static String getAccount = "$authCaptin/getAccount.php"; static String updatePassengersInvitation = "$server/ride/invitor/updatePassengersInvitation.php"; + static String updateDriverInvitationDirectly = + "$server/ride/invitor/updateDriverInvitationDirectly.php"; //===================Admin Captin============ static String getPassengerDetailsByPassengerID = diff --git a/lib/constant/style.dart b/lib/constant/style.dart index 10975c7..a0993aa 100644 --- a/lib/constant/style.dart +++ b/lib/constant/style.dart @@ -5,35 +5,39 @@ import 'package:google_fonts/google_fonts.dart'; import 'colors.dart'; class AppStyle { - static TextStyle headTitle = TextStyle( - fontWeight: FontWeight.bold, - fontSize: 40, - color: AppColor.accentColor, - fontFamily: box.read(BoxName.lang) == 'ar' - // ?GoogleFonts.notoNaskhArabic().fontFamily - ? GoogleFonts.notoNaskhArabic().fontFamily - : GoogleFonts.roboto().fontFamily); - static TextStyle headTitle2 = TextStyle( - fontWeight: FontWeight.bold, - fontSize: 26, - color: AppColor.writeColor, - fontFamily: box.read(BoxName.lang) == 'ar' - ? GoogleFonts.notoNaskhArabic().fontFamily - : GoogleFonts.roboto().fontFamily); + static TextStyle headTitle = const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 40, + color: AppColor.accentColor, + // fontFamily: box.read(BoxName.lang) == 'ar' + // // ?GoogleFonts.notoNaskhArabic().fontFamily + // ? GoogleFonts.notoNaskhArabic().fontFamily + // : GoogleFonts.roboto().fontFamily, + ); + static TextStyle headTitle2 = const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 22, + color: AppColor.writeColor, + // fontFamily: box.read(BoxName.lang) == 'ar' + // ? GoogleFonts.notoNaskhArabic().fontFamily + // : GoogleFonts.roboto().fontFamily + ); static TextStyle title = TextStyle( - fontWeight: FontWeight.normal, - fontSize: box.read(BoxName.lang) == 'ar' ? 14 : 16, - color: AppColor.writeColor, - fontFamily: box.read(BoxName.lang) == 'ar' - ? GoogleFonts.notoNaskhArabic().fontFamily - : GoogleFonts.roboto().fontFamily); - static TextStyle subtitle = TextStyle( - fontWeight: FontWeight.bold, - fontSize: 13, - color: AppColor.writeColor, - fontFamily: box.read(BoxName.lang) == 'ar' - ? GoogleFonts.notoNaskhArabic().fontFamily - : GoogleFonts.roboto().fontFamily); + fontWeight: FontWeight.normal, + fontSize: box.read(BoxName.lang) == 'ar' ? 14 : 16, + color: AppColor.writeColor, + // fontFamily: box.read(BoxName.lang) == 'ar' + // ? GoogleFonts.notoNaskhArabic().fontFamily + // : GoogleFonts.roboto().fontFamily + ); + static TextStyle subtitle = const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 13, + color: AppColor.writeColor, + // fontFamily: box.read(BoxName.lang) == 'ar' + // ? GoogleFonts.notoNaskhArabic().fontFamily + // : GoogleFonts.roboto().fontFamily + ); static TextStyle number = const TextStyle( fontWeight: FontWeight.bold, fontSize: 14, diff --git a/lib/controller/auth/register_controller.dart b/lib/controller/auth/register_controller.dart index 2cd19d4..d01ceee 100644 --- a/lib/controller/auth/register_controller.dart +++ b/lib/controller/auth/register_controller.dart @@ -166,7 +166,7 @@ class RegisterController extends GetxController { await sendOtp(phoneNumber, randomNumber, isEgyptianNumber, smsEgyptController); } - } else { + } else if (phoneNumber.length > 9) { sendOtp( phoneNumber, randomNumber, isEgyptianNumber, smsEgyptController); } @@ -191,12 +191,57 @@ class RegisterController extends GetxController { SmsEgyptController controller) async { // Trim any leading or trailing whitespace from the phone number phoneNumber = phoneNumber.trim(); - await CRUD().post(link: AppLink.sendVerifyOtpMessage, payload: { + var dd = await CRUD().post(link: AppLink.sendVerifyOtpMessage, payload: { 'phone_number': phoneNumber, 'token': otp.toString(), }); + Log.print('dd: ${dd}'); if (isEgyptian) { - await controller.sendSmsEgypt(phoneNumber, otp.toString()); + await CRUD().post(link: AppLink.updatePhoneInvalidSMSPassenger, payload: { + "phone_number": Get.find().phoneController.text + }); + box.write(BoxName.phoneDriver, phoneController.text); + var nameParts = box.read(BoxName.name).toString().split(' '); + var firstName = nameParts.isNotEmpty ? nameParts[0] : 'unknown'; + var lastName = nameParts.length > 1 ? nameParts[1] : 'unknown'; + + var payload = { + 'id': box.read(BoxName.passengerID), + 'phone': phoneController.text, + 'email': box.read(BoxName.email), + 'password': 'unknown', + 'gender': 'unknown', + 'birthdate': '2002-01-01', + 'site': box.read(BoxName.passengerPhotoUrl) ?? 'unknown', + 'first_name': firstName, + 'last_name': lastName, + }; + + var res1 = await CRUD().post( + link: AppLink.signUp, + payload: payload, + ); + + if (res1 != 'failure') { + await CRUD().post( + link: '${AppLink.seferAlexandriaServer}/auth/signup.php', + payload: payload, + ); + await CRUD().post( + link: '${AppLink.seferGizaServer}/auth/signup.php', + payload: payload, + ); + + box.write(BoxName.isVerified, '1'); + box.write(BoxName.isFirstTime, '0'); + box.write(BoxName.phone, phoneController.text); + + Get.put(LoginController()).loginUsingCredentials( + box.read(BoxName.passengerID).toString(), + box.read(BoxName.email).toString(), + ); + } + // await controller.sendSmsEgypt(phoneNumber, otp.toString()); } else { await CRUD().sendWhatsAppAuth(phoneNumber, otp.toString()); } diff --git a/lib/controller/firebase/firbase_messge.dart b/lib/controller/firebase/firbase_messge.dart index 814766d..334f19c 100644 --- a/lib/controller/firebase/firbase_messge.dart +++ b/lib/controller/firebase/firbase_messge.dart @@ -214,7 +214,7 @@ class FirebaseMessagesController extends GetxController { driverArrivePassengerDialoge(); update(); - } else if (message.notification!.title! == "Cancel Trip from driver".tr) { + } else if (message.notification!.title! == "Cancel Trip from driver") { Get.back(); if (Platform.isAndroid) { notificationController.showNotification("Cancel Trip from driver".tr, @@ -243,7 +243,7 @@ class FirebaseMessagesController extends GetxController { // .searchNewDriverAfterRejectingFromDriver(); ); } else if (message.notification!.title! == 'Driver Finish Trip'.tr) { - var myListString = message.data['passengerList']; + var myListString = message.data['DriverList']; var driverList = jsonDecode(myListString) as List; if (Platform.isAndroid) { notificationController.showNotification( @@ -262,6 +262,11 @@ class FirebaseMessagesController extends GetxController { 'rideId': driverList[1].toString(), 'price': driverList[3].toString() }); + notificationController.showNotification( + 'Don’t forget your personal belongings.'.tr, + 'Please make sure you have all your personal belongings and that any remaining fare, if applicable, has been added to your wallet before leaving. Thank you for choosing the Sefer app' + .tr, + 'ding'); // } } else if (message.notification!.title! == "Finish Monitor".tr) { Get.defaultDialog( diff --git a/lib/controller/firebase/local_notification.dart b/lib/controller/firebase/local_notification.dart index 73ba3ff..44f7b31 100644 --- a/lib/controller/firebase/local_notification.dart +++ b/lib/controller/firebase/local_notification.dart @@ -99,7 +99,7 @@ class NotificationController extends GetxController { for (int day = 0; day < 7; day++) { // Schedule for 8:00 AM await _scheduleNotificationForTime( - day, 8, 0, title, message, details, day * 1000 + 1); // Unique ID + day, 8, 0, title, message, details, day * 1000 + 1); // Schedule for 3:00 PM await _scheduleNotificationForTime( diff --git a/lib/controller/functions/crud.dart b/lib/controller/functions/crud.dart index 96995b0..91f3047 100644 --- a/lib/controller/functions/crud.dart +++ b/lib/controller/functions/crud.dart @@ -509,6 +509,26 @@ class CRUD { return (jsonData['status']); } + Future getHereMap({ + required String link, + }) async { + var url = Uri.parse(link); + try { + var response = await http.get(url); + + if (response.statusCode == 200) { + // Ensure the response body is decoded as UTF-8 + var decodedBody = utf8.decode(response.bodyBytes); + var data = jsonDecode(decodedBody); + return data; + } else { + return null; + } + } catch (e) { + return null; + } + } + Future update({ required String endpoint, required Map data, diff --git a/lib/controller/functions/sms_controller.dart b/lib/controller/functions/sms_controller.dart index 53e3422..09b0b63 100644 --- a/lib/controller/functions/sms_controller.dart +++ b/lib/controller/functions/sms_controller.dart @@ -11,6 +11,7 @@ import 'package:SEFER/views/widgets/elevated_btn.dart'; import 'package:get/get.dart'; import 'package:http/http.dart' as http; +import '../../print.dart'; import '../auth/register_controller.dart'; import 'crud.dart'; diff --git a/lib/controller/home/map_passenger_controller.dart b/lib/controller/home/map_passenger_controller.dart index f786103..3f825d3 100644 --- a/lib/controller/home/map_passenger_controller.dart +++ b/lib/controller/home/map_passenger_controller.dart @@ -403,8 +403,10 @@ class MapPassengerController extends GetxController { } tick = 0; } - await getCarForFirstConfirm(box.read(BoxName.carType)); + await getCarsLocationByPassengerAndReloadMarker( + box.read(BoxName.carType), 4000); // confirmRideForAllDriverAvailable(); + icreaseForSameRideAndDelay(); } } @@ -471,9 +473,12 @@ class MapPassengerController extends GetxController { hintTextDestinationPoint = 'Search for your destination'.tr; update(); } else { - hintTextDestinationPoint = placesDestination[index]['name']; - double lat = placesDestination[index]['geometry']['location']['lat']; - double lng = placesDestination[index]['geometry']['location']['lng']; + 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(); @@ -541,7 +546,7 @@ class MapPassengerController extends GetxController { // Format the message. String message = - 'Hi! This is ${box.read(BoxName.name)}.\n I am using ${box.read(AppInformation.appName)} to ride with $firstName as the driver. $firstName \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.'; + 'Hi! This is ${box.read(BoxName.name)}.\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); @@ -553,7 +558,7 @@ class MapPassengerController extends GetxController { // Format the message. String message = - '${'${'Hi! This is'.tr} ${box.read(BoxName.name)}.\n${' I am using'.tr}'} ${AppInformation.appName}${' to ride with'.tr} $firstName${' as the driver.'.tr} $firstName \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.'; + '${'${'Hi! This is'.tr} ${box.read(BoxName.name)}.\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); @@ -585,44 +590,134 @@ class MapPassengerController extends GetxController { 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 _timerStreamController = StreamController(); + Stream 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() async { + void startTimerFromDriverToPassengerAfterApplied() { + if (isTimerRunning) return; // Prevent duplicate streams + isTimerRunning = true; + int secondsElapsed = 0; - while (secondsElapsed <= timeToPassengerFromDriverAfterApplied && - isTimerFromDriverToPassengerAfterAppliedRunning) { - await Future.delayed(const Duration(seconds: 1)); - secondsElapsed++; + // 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; - if (remainingTimeToPassengerFromDriverAfterApplied < 59) { - if (rideTimerBegin == false) { - rideTimerBegin = true; - } - } - - // Call getBeginRideFromDriver every 4 seconds - if (secondsElapsed % beginRideInterval == 0) { - getBeginRideFromDriver(); - uploadPassengerLocation(); - } - + // Update remaining time as string int minutes = (remainingTimeToPassengerFromDriverAfterApplied / 60).floor(); int seconds = remainingTimeToPassengerFromDriverAfterApplied % 60; stringRemainingTimeToPassenger = '$minutes:${seconds.toString().padLeft(2, '0')}'; - update(); - } + 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 @@ -681,8 +776,16 @@ class MapPassengerController extends GetxController { 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, @@ -702,7 +805,7 @@ class MapPassengerController extends GetxController { // Get trip details from GetX or relevant provider String origin = passengerLocation.toString(); String destination = myDestination.toString(); - String driverName = firstName; + String driverName = passengerName; String driverCarPlate = licensePlate; // Add trip details to the message @@ -790,7 +893,7 @@ class MapPassengerController extends GetxController { // Get trip details from GetX or relevant provider String origin = passengerLocation.toString(); String destination = myDestination.toString(); - String driverName = firstName; + String driverName = passengerName; String driverCarPlate = licensePlate; // Add trip details to the message @@ -850,32 +953,96 @@ class MapPassengerController extends GetxController { update(); } - void getBeginRideFromDriver() async { - try { - var res = await CRUD() - .get(link: AppLink.getRideStatusBegin, payload: {'ride_id': rideId}); - if (res != 'failure') { - var decode = jsonDecode(res); + // 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 {} + // // 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 _beginRideStreamController = + StreamController.broadcast(); + Stream 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}); + 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); } - } catch (e) { - // Handle the error or perform any necessary actions - } + }); + } + +// 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 { @@ -908,7 +1075,7 @@ class MapPassengerController extends GetxController { if (rideStatusFromStartApp['data']['status'] == 'Begin') { statusRide = 'Begin'; driverId = rideStatusFromStartApp['data']['driver_id']; - firstName = rideStatusFromStartApp['data']['driverName']; + passengerName = rideStatusFromStartApp['data']['driverName']; driverRate = rideStatusFromStartApp['data']['rateDriver'].toString(); statusRideFromStart = true; // DateTime endTime = @@ -1150,7 +1317,7 @@ class MapPassengerController extends GetxController { int currentTimeSearchingCaptainWindow = 0; late String driverPhone = ''; late String driverRate = ''; - late String firstName = ''; + late String passengerName = ''; late String carColor = ''; late String colorHex = ''; late String carYear = ''; @@ -1158,500 +1325,249 @@ class MapPassengerController extends GetxController { late String make = ''; late String licensePlate = ''; - confirmRideForFirstDriver() async { - // startCarLocationSearch(box.read(BoxName.carType)); - // await getCarsLocationByPassengerAndReloadMarker( - // box.read(BoxName.carType), 7000); - // var nearestCar = await getNearestDriverByPassengerLocation(); - - // if (nearestCar != null) { - // // Find the corresponding driver data in dataCarsLocationByPassenger - // var nearestDriverData = dataCarsLocationByPassenger['message'].firstWhere( - // (car) => car['driver_id'] == nearestCar.id, - // orElse: () => null, - // ); - - // // if (nearestDriverData != null) { - // driverToken = nearestDriverData['token'].toString(); - // Log.print('driverToken: ${driverToken}'); - // driverPhone = nearestDriverData['phone'].toString(); - // firstName = nearestDriverData['first_name'].toString(); - // carColor = nearestDriverData['color'].toString(); - // driverRate = nearestDriverData['ratingDriver'].toString(); - // carYear = nearestDriverData['year'].toString(); - // model = '${nearestDriverData['model']} - ${nearestDriverData['make']}'; - // licensePlate = nearestDriverData['car_plate'].toString(); - // startCarLocationSearch(box.read(BoxName.carType)); - await getCarsLocationByPassengerAndReloadMarker( - box.read(BoxName.carType), 3000); - // await getCarsLocationByPassengerAndReloadMarker( - // box.read(BoxName.carType), 7000); - // await getNearestDriverByPassengerLocation(); - Log.print('dataCarsLocationByPassenger: $dataCarsLocationByPassenger'); - if (dataCarsLocationByPassenger != 'failure' || - dataCarsLocationByPassenger != null) { - driverToken = - dataCarsLocationByPassenger['data'][carsOrder]['token'].toString(); - driverPhone = - dataCarsLocationByPassenger['data'][carsOrder]['phone'].toString(); - firstName = dataCarsLocationByPassenger['data'][carsOrder] - ['first_name'] // driverName - .toString(); - carColor = - dataCarsLocationByPassenger['data'][carsOrder]['color'].toString(); - colorHex = dataCarsLocationByPassenger['data'][carsOrder]['color_hex'] ?? - '#A52A2A'; - driverRate = dataCarsLocationByPassenger['data'][carsOrder] - ['ratingDriver'] - .toString(); - carYear = - dataCarsLocationByPassenger['data'][carsOrder]['year'].toString(); - model = - '${dataCarsLocationByPassenger['data'][carsOrder]['model']} - ${dataCarsLocationByPassenger['data'][carsOrder]['make']}'; - licensePlate = dataCarsLocationByPassenger['data'][carsOrder]['car_plate'] - .toString(); - PaymentController paymentController = Get.find(); - rideConfirm = true; - shouldFetch = true; - isBottomSheetShown = false; - // timeToPassengerFromDriverAfterApplied = nearestCar.duration.toInt(); - timeToPassengerFromDriverAfterApplied = - durationToPassenger; //60 todo durationToPassenger;/ - isDriversTokensSend = false; - - update(); - await CRUD().post( - link: "${AppLink.seferCairoServer}/ride/rides/add.php", - payload: { - "start_location": //'${data[0]['start_address']}', - '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}', - "end_location": //'${data[0]['end_address']}', - '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}', - "date": DateTime.now().toString(), - "time": DateTime.now().toString(), - "endtime": durationToAdd.toString(), - "price": totalPassenger.toStringAsFixed(2), - "passenger_id": box.read(BoxName.passengerID).toString(), - "driver_id": dataCarsLocationByPassenger['data'][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) { - // List body = [ - rideId = jsonDecode(value)['message']; - List 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['data'][carsOrder]['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['data'][carsOrder]['token'].toString(), - durationToPassenger.toString(), - rideId, - rideTimerBegin.toString(), - dataCarsLocationByPassenger['data'][carsOrder]['driver_id'] - .toString(), - durationToRide.toString(), - Get.find().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('bodyOf order: $body'); - FirebaseMessagesController().sendNotificationToDriverMAP( - 'Order'.tr, - 'from: $startNameAddress\nto: $startNameAddress\ndistanceFromMe: $distanceByPassenger\nDistance :$distance\nPrice ; $totalPassenger', - // jsonDecode(value)['message'].toString(), - driverToken.toString(), - body, - 'order.wav'); - Log.print( - 'dataCarsLocationByPassenger[data]: ${dataCarsLocationByPassenger['data'][carsOrder]['token']}'); - }); - - if (AppLink.endPoint != AppLink.seferCairoServer) { - CRUD().post(link: "${AppLink.endPoint}/ride/rides/add.php", payload: { - "start_location": //'${data[0]['start_address']}', - '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}', - "end_location": //'${data[0]['end_address']}', - '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}', - "date": DateTime.now().toString(), - "time": DateTime.now().toString(), - "endtime": durationToAdd.toString(), - "price": totalPassenger.toStringAsFixed(2), - "passenger_id": box.read(BoxName.passengerID).toString(), - "driver_id": dataCarsLocationByPassenger['data'][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(), - }); - } - delayAndFetchRideStatus(rideId, box.read(BoxName.carType)); - if (shouldFetch == false) { - startTimer(); - update(); - } - update(); - } else { - Get.defaultDialog( - title: 'No Car or Driver Found in your area.'.tr, - titleStyle: AppStyle.title, - middleText: 'Please Try anther time '.tr, - middleTextStyle: AppStyle.title.copyWith(color: AppColor.yellowColor), - confirm: MyElevatedButton( - title: 'Ok'.tr, - onPressed: () { - Get.back(); - isSearchingWindow = false; - cancelRide(); - update(); - })); - } - } - String driverOrderStatus = 'yet'; bool isDriversTokensSend = false; - confirmRideForAllDriverAvailable0() async { - await getCarsLocationByPassengerAndReloadMarker( - box.read(BoxName.carType), 3500); - if (dataCarsLocationByPassenger != 'failure') { - // driversToken.remove(driverToken); - PaymentController paymentController = Get.find(); - rideConfirm = true; - shouldFetch = true; - isBottomSheetShown = false; - timeToPassengerFromDriverAfterApplied = 60; - await CRUD().post( - link: "${AppLink.seferCairoServer}/ride/rides/add.php", - payload: { - "start_location": //'${data[0]['start_address']}', - '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}', - "end_location": //'${data[0]['end_address']}', - '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}', - "date": DateTime.now().toString(), - "time": DateTime.now().toString(), - "endtime": durationToAdd.toString(), - "price": totalPassenger.toStringAsFixed(2), - "passenger_id": box.read(BoxName.passengerID).toString(), - "driver_id": dataCarsLocationByPassenger['data'][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) { - // List body = [ - rideId = jsonDecode(value)['message']; - for (var i = 0; i < dataCarsLocationByPassenger['data'].length; i++) { - List 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['data'][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['data'][i]['token'].toString(), - durationToPassenger.toString(), - rideId, - rideTimerBegin.toString(), - dataCarsLocationByPassenger['data'][i]['driver_id'].toString(), - durationToRide.toString(), - Get.find().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['data'][i]['token'].toString(), - body, - 'order.wav', - ); - driverOrderStatus = 'recive'; - } - }); - (rideId); // - if (AppLink.endPoint != AppLink.seferCairoServer) { - CRUD().post(link: '${AppLink.endPoint}/ride/rides/add.php', payload: { - "start_location": //'${data[0]['start_address']}', - '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}', - "end_location": //'${data[0]['end_address']}', - '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}', - "date": DateTime.now().toString(), - "time": DateTime.now().toString(), - "endtime": durationToAdd.toString(), - "price": totalPassenger.toStringAsFixed(2), - "passenger_id": box.read(BoxName.passengerID).toString(), - "driver_id": dataCarsLocationByPassenger['data'][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(); - } else { - MyDialog().getDialog("No Car or Driver Found in your area.".tr, - "No Car or Driver Found in your area.".tr, () { - Get.back(); - Get.offAll(const MapPagePassenger()); - }); - } - } Set notifiedDrivers = {}; - confirmRideForAllDriverAvailable11() async { - // Fetch car locations - await getCarsLocationByPassengerAndReloadMarker( - box.read(BoxName.carType), 3000); - - // Ensure dataCarsLocationByPassenger is not 'failure' or null - if (dataCarsLocationByPassenger != 'failure' && - dataCarsLocationByPassenger != null) { - // Check if 'data' key exists and is not null - if (dataCarsLocationByPassenger.containsKey('data') && - dataCarsLocationByPassenger['data'] != null) { - PaymentController paymentController = Get.find(); - 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['data'][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}'); - } - // Log.print('value: ${value}'); - // rideId = jsonDecode(value)['message']; - // rideId = jsonDecode(value)['message'].toString(); - - // Timer for 5 iterations, runs every 2 seconds - int iteration = 0; - Timer.periodic(const Duration(seconds: 2), (timer) async { - if (iteration >= 10) { - timer.cancel(); - return; - } - iteration++; - - // Reload driver locations - await getCarsLocationByPassengerAndReloadMarker( - box.read(BoxName.carType), 3000); - - // Ensure dataCarsLocationByPassenger and data key are still valid - if (dataCarsLocationByPassenger != null && - dataCarsLocationByPassenger.containsKey('data') && - dataCarsLocationByPassenger['data'] != null) { - // Notify only new drivers - for (var driverData in dataCarsLocationByPassenger['data']) { - String driverId = driverData['driver_id'].toString(); - if (!notifiedDrivers.contains(driverId)) { - notifiedDrivers.add(driverId); - - // Prepare body payload for notification - List 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, - 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, - rideTimerBegin.toString(), - driverId, - durationToRide.toString(), - Get.find().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), - ]; - - // Send notification to the driver - FirebaseMessagesController().sendNotificationToDriverMAP( - 'OrderSpeed', - rideId, - driverData['token'].toString(), - body, - 'order.wav', - ); - } - } - } - }); - }); - - // Check for additional server endpoint - if (AppLink.endPoint != AppLink.seferCairoServer) { - CRUD().post(link: '${AppLink.endPoint}/ride/rides/add.php', payload: { - "start_location": + addRideToNotificationDriverString() 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, + 'price_for_passenger': totalME.toString(), + 'distance': distance.toString(), + 'duration': duration ?? '10', + }); + 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": + '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['data'][carsOrder] - ['driver_id'] - .toString(), - "status": "waiting", + 'passenger_id': box.read(BoxName.passengerID).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(), + 'passengerRate': passengerRate, + 'price_for_passenger': totalME.toString(), + 'distance': distance.toString(), + 'duration': duration ?? '10', }); - } - delayAndFetchRideStatusForAllDriverAvailable(rideId); - update(); - } else { - // Show dialog if no drivers found in data key - MyDialog().getDialog("No Car or Driver Found in your area.".tr, - "No Car or Driver Found in your area.".tr, () { - Get.back(); - Get.offAll(const MapPagePassenger()); - }); - } - } else { - // Show dialog if dataCarsLocationByPassenger is 'failure' or null - MyDialog().getDialog("No Car or Driver Found in your area.".tr, - "No Car or Driver Found in your area.".tr, () { - Get.back(); - Get.offAll(const MapPagePassenger()); - }); } } - Future confirmRideForAllDriverAvailable() async { - // Try to fetch car locations up to 4 times with a 2-second delay + // Future 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['data'] != 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(); + // 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['data'][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['data'] != null) { + // for (var driverData in dataCarsLocationByPassenger['data']) { + // String driverId = driverData['driver_id'].toString(); + // if (!notifiedDrivers.contains(driverId)) { + // notifiedDrivers.add(driverId); + // List 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().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['data'][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(); + // } + + icreaseForSameRideAndDelay() async { bool driversFound = false; - for (int attempt = 0; attempt < 4; attempt++) { + for (int attempt = 0; attempt < 8; attempt++) { await getCarsLocationByPassengerAndReloadMarker( - box.read(BoxName.carType), 3000); + box.read(BoxName.carType), 4500); // Check if dataCarsLocationByPassenger is valid and contains drivers if (dataCarsLocationByPassenger != 'failure' && @@ -1700,149 +1616,12 @@ class MapPassengerController extends GetxController { return; } - - // Proceed with the rest of the function if drivers are found - PaymentController paymentController = Get.find(); - 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['data'][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['data'] != null) { - for (var driverData in dataCarsLocationByPassenger['data']) { - String driverId = driverData['driver_id'].toString(); - if (!notifiedDrivers.contains(driverId)) { - notifiedDrivers.add(driverId); - List 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, - 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, - rideTimerBegin.toString(), - driverId, - durationToRide.toString(), - Get.find().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), - ]; - 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['data'][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(); - } - - icreaseForSameRideAndDelay() { PaymentController paymentController = Get.find(); rideConfirm = true; shouldFetch = true; isBottomSheetShown = false; timeToPassengerFromDriverAfterApplied = 60; + // confirmRideForAllDriverAvailable(); for (var i = 0; i < dataCarsLocationByPassenger['data'].length; i++) { List body = [ '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}', @@ -1861,7 +1640,7 @@ class MapPassengerController extends GetxController { paymentController.isWalletChecked.toString(), dataCarsLocationByPassenger['data'][i]['token'].toString(), durationToPassenger.toString(), - rideId, + rideId.toString(), rideTimerBegin.toString(), dataCarsLocationByPassenger['data'][i]['driver_id'].toString(), durationToRide.toString(), @@ -1898,64 +1677,76 @@ class MapPassengerController extends GetxController { 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); + // 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() - .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(); - } 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 - } - }); - } + // 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() + // .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( @@ -1969,27 +1760,271 @@ class MapPassengerController extends GetxController { update(); } - void delayAndFetchRideStatusForAllDriverAvailable(String rideId) async { + Future 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(); + + if (isDriversDataValid()) { + driversFound = true; + break; + } + + await Future.delayed(attemptDelay); + } + + if (!driversFound) { + showNoDriversDialog(); + return; + } + + await postRideDetailsToServer(); + await notifyAvailableDrivers(); + delayAndFetchRideStatusForAllDriverAvailable(rideId); + update(); + } + + Future 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(); + await notifyAvailableDrivers(); + delayAndFetchRideStatusForAllDriverAvailable(rideId); + update(); + } + + bool isDriversDataValid() { + return dataCarsLocationByPassenger != 'failure' && + dataCarsLocationByPassenger != null && + dataCarsLocationByPassenger.containsKey('data') && + dataCarsLocationByPassenger['data'] != 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 postRideDetailsToServer() async { + final paymentController = Get.find(); + 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 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['data'][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 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('data') && + dataCarsLocationByPassenger['data'] != null) { + for (var driverData in dataCarsLocationByPassenger['data']) { + 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 / 1000; + double durationToDriverInHours = + distanceToDriverInKm / 25; // 25 km/h as default speed + double durationToDriverInSeconds = durationToDriverInHours * 3600; + durationToPassenger = durationToDriverInSeconds.toInt(); + distanceByPassenger = distanceToDriverInMeters.toStringAsFixed(0); + final body = constructNotificationBody(driverData); + Log.print('body:ww ${body}'); + FirebaseMessagesController().sendNotificationToDriverMAP( + 'OrderSpeed', + rideId, + driverData['token'].toString(), + body, + 'order.wav'); + } + } + } + iteration++; + } + } + + List constructNotificationBody(var driverData) { + final paymentController = Get.find(); + 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(), + box.read(BoxName.name).toString(), + box.read(BoxName.tokenFCM).toString(), + box.read(BoxName.phone).toString(), + durationToPassenger.toString(), + distanceByPassenger.toString(), + paymentController.isWalletChecked.toString(), + driverData['token'].toString(), + durationToPassenger.toString(), + rideId.toString(), + rideTimerBegin.toString(), + driverData['driver_id'].toString(), + durationToRide.toString(), + Get.find().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 _rideStatusStreamController = + StreamController.broadcast(); + Stream get rideStatusStream => _rideStatusStreamController.stream; + + void delayAndFetchRideStatusForAllDriverAvailable(String rideId) { const int maxAttempts = 15; int attemptCounter = 0; bool isApplied = false; tick = 0; - bool shouldContinueSearching = true; // Flag to control searching - void fetchRideStatus() async { - if (attemptCounter < maxAttempts && - !isApplied && - shouldContinueSearching) { - attemptCounter++; - tick++; + Timer.periodic(const Duration(seconds: 1), (timer) async { + if (attemptCounter >= maxAttempts || isApplied) { + timer.cancel(); + _rideStatusStreamController.close(); // Close the stream when done + return; + } + + attemptCounter++; + tick++; + + try { var res = await getRideStatus(rideId); String rideStatusDelayed = res.toString(); - + addRideToNotificationDriverString(); + _rideStatusStreamController + .add(rideStatusDelayed); // Emit the ride status + // addRideToNotificationDriverString(); if (rideStatusDelayed == 'Cancel') { - shouldContinueSearching = false; // Stop searching - attemptCounter = maxAttempts + 1; + timer.cancel(); NotificationController().showNotification( "Order Cancelled".tr, "you canceled order".tr, 'ding'); + _rideStatusStreamController + .close(); // Close stream after cancellation } else if (rideStatusDelayed == 'Apply' || rideStatusDelayed == 'Applied') { await getUpdatedRideForDriverApply(rideId); @@ -1997,8 +2032,19 @@ class MapPassengerController extends GetxController { '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; - shouldFetch = false; statusRide = 'Apply'; rideConfirm = false; isSearchingWindow = false; @@ -2006,26 +2052,42 @@ class MapPassengerController extends GetxController { startTimer(); update(); startTimerFromDriverToPassengerAfterApplied(); - shouldContinueSearching = false; // Stop searching if applied + + timer.cancel(); + _rideStatusStreamController.close(); // Close stream after applying } else if (attemptCounter >= maxAttempts && rideStatusDelayed != 'Cancel') { - shouldContinueSearching = false; // Stop searching + timer.cancel(); + // addRideToNotificationDriverString(); // Show dialog to increase fee... update(); - } else { - Timer(const Duration(seconds: 2), fetchRideStatus); + _rideStatusStreamController + .close(); // Close stream after max attempts } + } catch (e) { + _rideStatusStreamController.addError(e); // Handle errors in the stream } - } + }); + } - fetchRideStatus(); // Initial call to start the process +// 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 { await getCarsLocationByPassengerAndReloadMarker( box.read(BoxName.carType), 3000); - confirmRideForAllDriverAvailable(); + updateConfirmRideForAllDriverAvailable(); shouldFetch = true; // Stop further fetches statusRide = 'wait'; rideConfirm = true; @@ -2089,20 +2151,22 @@ class MapPassengerController extends GetxController { driverPhone = 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 = response['data']['car_plate']; - firstName = response['data']['first_name']; - driverName = response['data']['driverName'].toString().split(' ')[0]; + passengerName = response['data']['passengerName']; + driverName = response['data']['driverName'].toString(); driverToken = response['data']['token']; - Log.print('driverToken updated: $driverToken'); + // 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 Applied'.tr, - '$driverName Apply order\nTake attention in other order'.tr, + 'Order Accepted'.tr, + '$driverName${'Accepted your order'.tr}', driverToken.toString(), [], 'start.wav', @@ -2428,10 +2492,11 @@ class MapPassengerController extends GetxController { } else { noCarString = false; dataCarsLocationByPassenger = jsonDecode(res); + Log.print('dataCarsLocationByPassenger: ${dataCarsLocationByPassenger}'); // Check if 'message' is present and not null - if (dataCarsLocationByPassenger['message'] != null && - dataCarsLocationByPassenger['message'].isNotEmpty) { + if (dataCarsLocationByPassenger['data'] != null && + dataCarsLocationByPassenger['data'].isNotEmpty) { // Check if carsOrder is within bounds // if (carsOrder < dataCarsLocationByPassenger['message'].length) { // driverId = dataCarsLocationByPassenger['message'][carsOrder] @@ -2454,8 +2519,8 @@ class MapPassengerController extends GetxController { carsLocationByPassenger.clear(); // Clear existing markers - for (var i = 0; i < dataCarsLocationByPassenger['message'].length; i++) { - var json = dataCarsLocationByPassenger['message'][i]; + for (var i = 0; i < dataCarsLocationByPassenger['data'].length; i++) { + var json = dataCarsLocationByPassenger['data'][i]; _updateOrCreateMarker( MarkerId(json['latitude']).toString(), LatLng( @@ -3175,23 +3240,101 @@ class MapPassengerController extends GetxController { update(); } - Future getPlaces() async { +// 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 getPlaces() async { var languageCode; -// Check if `placeDestinationController.text` contains English characters + // Check if `placeDestinationController.text` contains English characters if (RegExp(r'[a-zA-Z]').hasMatch(placeDestinationController.text)) { 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=${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']; + // 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(); } @@ -3248,6 +3391,25 @@ class MapPassengerController extends GetxController { print('Error fetching places: $e'); } } + + Future savePlaceToServer( + String latitude, String longitude, String name, String rate) async { + var data = { + 'latitude': latitude, + 'longitude': longitude, + 'name': name, + 'rate': rate, + }; + + try { + CRUD().post( + link: AppLink.savePlacesServer, + payload: data, + ); + } catch (e) { + 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()}'; @@ -3521,7 +3683,7 @@ class MapPassengerController extends GetxController { int reloadCount = 0; startMarkerReloading() async { if (reloadStartApp == false) { - Timer.periodic(const Duration(seconds: 5), (timer) async { + Timer.periodic(const Duration(seconds: 3), (timer) async { reloadCount++; Log.print('reloadCount: $reloadCount'); @@ -3530,7 +3692,7 @@ class MapPassengerController extends GetxController { // _smoothlyUpdateMarker(); // startCarLocationSearch(box.read(BoxName.carType)); await getCarsLocationByPassengerAndReloadMarker( - box.read(BoxName.carType), 6000); + box.read(BoxName.carType), 5000); await getNearestDriverByPassengerLocation(); Log.print('reloadMarkers: from startMarkerReloading'); } else { @@ -3613,26 +3775,19 @@ class MapPassengerController extends GetxController { // return null; // } Future getNearestDriverByPassengerLocation() async { - // if (polyLines.isEmpty && data.isEmpty) { - // return null; // Early return if data is empty - // } - // Log.print('rideConfirm: ${rideConfirm}'); - // Log.print('dataCarsLocationByPassenger: ${dataCarsLocationByPassenger}'); if (!rideConfirm) { - if (dataCarsLocationByPassenger != 'failure') { - if (dataCarsLocationByPassenger != null && - dataCarsLocationByPassenger['message'] != null && - dataCarsLocationByPassenger['message'].length > 0) { - double nearestDistance = - double.infinity; // Initialize nearest distance - CarLocation? nearestCar; + if (dataCarsLocationByPassenger != 'failure' && + dataCarsLocationByPassenger != null && + dataCarsLocationByPassenger['data'] != null && + dataCarsLocationByPassenger['data'].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'); + for (var i = 0; i < dataCarsLocationByPassenger['data'].length; i++) { + var carLocation = dataCarsLocationByPassenger['data'][i]; + Log.print('carLocation: $carLocation'); + try { // Calculate distance between passenger's location and current driver's location final distance = Geolocator.distanceBetween( passengerLocation.latitude, @@ -3642,10 +3797,13 @@ class MapPassengerController extends GetxController { ); // Calculate duration assuming an average speed of 25 km/h (adjust as needed) - int durationToPassenger = (distance * 25 * (1000 / 3600)).round(); + 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(); @@ -3664,11 +3822,13 @@ class MapPassengerController extends GetxController { // 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 the nearest car found + return nearestCar; } } @@ -4728,7 +4888,7 @@ class MapPassengerController extends GetxController { 'address': driver['address'], 'religion': driver['religion'] ?? 'UnKnown', 'age': driver['age'].toString(), // Convert age to String - 'education': driver['education'] ?? 'UnKnown', + 'education': driver['education'] ?? 'UnKnown', //startlocationname 'license_type': driver['license_type'] ?? 'UnKnown', 'national_number': driver['national_number'] ?? 'UnKnown', 'car_plate': driver['car_plate'], @@ -4746,6 +4906,9 @@ class MapPassengerController extends GetxController { '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'); @@ -4828,8 +4991,10 @@ class MapPassengerController extends GetxController { driver['token'].toString(), [ id, + rideId, driver['id'], passengerLocation.latitude.toString(), + startNameAddress.toString(), passengerLocation.longitude.toString(), box.read(BoxName.name).toString(), box.read(BoxName.passengerID).toString(), @@ -4904,11 +5069,17 @@ class MapPassengerController extends GetxController { } late List recentPlaces = []; - getFavioratePlaces() async { + 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; @@ -4990,9 +5161,11 @@ class MapPassengerController extends GetxController { } } + var k; @override void onInit() async { mapAPIKEY = await storage.read(key: BoxName.mapAPIKEY); + k = await getAIKey('HERE_API'); getFavioratePlaces(); readyWayPoints(); addCustomPicker(); diff --git a/lib/controller/home/vip_waitting_page.dart b/lib/controller/home/vip_waitting_page.dart index 9cc1287..7990458 100644 --- a/lib/controller/home/vip_waitting_page.dart +++ b/lib/controller/home/vip_waitting_page.dart @@ -58,15 +58,15 @@ class VipOrderController extends GetxController { tripData.value = decodedResponse['message']; } else { tripData.clear(); // Ensure empty list if no data - mySnackeBarError('No trip data found'); + // mySnackeBarError('No trip data found'); } } else { tripData.clear(); - mySnackeBarError('Failed to fetch trip data'); + // mySnackeBarError('Failed to fetch trip data'); } } catch (e) { tripData.clear(); - mySnackeBarError('An error occurred: $e'); + // mySnackeBarError('An error occurred: $e'); } finally { isLoading.value = false; } diff --git a/lib/controller/local/translations.dart b/lib/controller/local/translations.dart index ba8998e..6bfd249 100644 --- a/lib/controller/local/translations.dart +++ b/lib/controller/local/translations.dart @@ -4,6 +4,13 @@ class MyTranslation extends Translations { @override Map> get keys => { "ar": { + "Home Page": "الصفحة الرئيسية", + "To change Language the App": "لتغيير لغة التطبيق", + "Learn more about our app and mission": + "تعرف على المزيد حول تطبيقنا ورسالتنا", + "Promos For Today": "عروض اليوم", + 'Bonus gift': 'بونص', "Pay": "ادفع", + "Get": "احصل على", "Send to Driver Again": "إرسال إلى السائق مرة أخرى", "Driver Name:": "اسم السائق:", 'No trip data available': "لا توجد بيانات رحلة متاحة", @@ -79,6 +86,7 @@ class MyTranslation extends Translations { "Pick from map destination": "حدد وجهتك على الخريطة", "Pick or Tap to confirm": "حدد أو انقر للتأكيد", "Select Order Type": "حدد نوع الطلب", + 'Accepted your order': "تم قبول طلبك", "Choose who this order is for": "اختر لمن هذا الطلب", "Order Accepted": "تم قبول الطلب", "with type": "مع النوع", "accepted your order at price": "قبل طلبك بالسعر", @@ -473,7 +481,7 @@ iOS [https://getapp.cc/app/6458734951] "Go to this Target": "الانْتِقَال إِلَى هَذَا الهَدَف", "My Profile": "مَلَفِي الشَّخْصِي", "Sign Out": "تَسْجِيل الخُرُوج", - "Home Page": "الصَّفْحَة الرَّئِيسِيَّة", + "Are you want to go to this site": "هَل تَرْغَب فِي الانْتِقَال إِلَى هَذَا المَوْقِع", "MyLocation": "مَوْقِعِي", @@ -550,11 +558,11 @@ iOS [https://getapp.cc/app/6458734951] "Bachelor's Degree": "بَكَالُورِيُوس", "Master's Degree": "مَاجِسْتِير", "Doctoral Degree": "دُكْتُورَاه", - "Promos For today": "الْعُرُوض التَّرْوِيجِيَّة لِلْيَوْم", + "Copy this Promo to use it in your Ride!": "انْسَخْ هَذَا الْعَرْض لِاسْتِخْدَامِهِ فِي رِحْلَتِك!", "To change some Settings": "لِتَغْيِير بَعْض الإِعْدَادَات", - "To change Language the App": "لِتَغْيِير لُغَة التَّطْبِيق", + "Order Request Page": "صَفْحَة طَلَب الطَّلَب", "Rouats of Trip": "طُرُق الرِّحْلَة", "Passenger Name is ": "اسْم الرَّاكِب هُوَ ", @@ -607,6 +615,24 @@ iOS [https://getapp.cc/app/6458734951] "Do you want to pay Tips for this Driver": "هَل تُرِيد دَفْع أُكْرَامِيَّة لِهَذَا السَّائِق؟", "Tip is ": " مَبْلَغ الأُكْرَامِيَّة هُوَ", + "Are you sure to delete this location?": + "هل أنت متأكد من حذف هذا الموقع؟", + "deleted": "تم الحذف", + 'Trip is begin': "الرحلة قد بدأت", + 'This price is fixed even if the route changes for the driver.': + "هذا السعر مثبت حتى لو تغير المسار للسائق", + 'The price may increase if the route changes.': + "احتمالية زيادة السعر عند تغيير المسار", + "The captain is responsible for the route.": + "الكابتن مسؤول عن المسار", + "يمكنك الاتصال أو تسجيل صوت لهذه الرحلة": + "You can call or record audio of this trip", + + 'The trip has started! Feel free to contact emergency numbers, share your trip, or activate voice recording for the journey': + "بدأت الرحلة! لا تتردد في الاتصال بأرقام الطوارئ، مشاركة رحلتك، أو تفعيل التسجيل الصوتي للرحلة", + 'Please make sure you have all your personal belongings and that any remaining fare, if applicable, has been added to your wallet before leaving. Thank you for choosing the Sefer app': + 'الرجاء التأكد من جميع أغراضك الشخصية وأنه تم إضافة باقي الأجرة إن وجد إلى محفظتك قبل النزول. شكرا لاختيارك تطبيق سفر', + 'Don’t forget your personal belongings.': "لا تنسى متعلقاتك الشخصية", "Tip is": " مَبْلَغ الأُكْرَامِيَّة هُوَ", "Camera Access Denied.": "تَمَّ رَفْض الْوُصُول إِلَى الْكَامِيرَا.", "Open Settings": "افْتَحْ الإِعْدَادَات", diff --git a/lib/controller/payment/payment_controller.dart b/lib/controller/payment/payment_controller.dart index 44b1eb7..b4dde90 100644 --- a/lib/controller/payment/payment_controller.dart +++ b/lib/controller/payment/payment_controller.dart @@ -700,8 +700,9 @@ class PaymentController extends GetxController { ); // Log.print('response.message!: ${response!.responseCode!}'); // if (response!.success == true && response.responseCode == '200') { - if (response!.responseCode.toString() == '200' && - response.success == true) { + + if (response!.success == true && + response!.message.toString() == 'Approved') { // Log.print('transactionID wewer: ${response.transactionID}'); Toast.show(context, 'Payment Successful'.tr, AppColor.greenColor); method(); diff --git a/lib/controller/rate/rate_conroller.dart b/lib/controller/rate/rate_conroller.dart index 32f2b90..4d5ef26 100644 --- a/lib/controller/rate/rate_conroller.dart +++ b/lib/controller/rate/rate_conroller.dart @@ -81,34 +81,28 @@ class RateController extends GetxController { } } await CRUD().post( - link: "${AppLink.seferCairoServer}/rate/addRateToDriver.php", + link: "${AppLink.seferCairoServer}/ride/rate/addRateToDriver.php", payload: { 'passenger_id': box.read(BoxName.passengerID).toString(), - 'driver_id': driverId, - 'ride_id': rideId, + 'driver_id': driverId.toString(), + 'ride_id': rideId.toString(), 'rating': selectedRateItemId.toString(), 'comment': comment.text, - }).then((value) { + }); + + if (AppLink.endPoint != AppLink.seferCairoServer) { CRUD().post( - link: "${AppLink.seferAlexandriaServer}/rate/addRateToDriver.php", + link: "${AppLink.endPoint}/ride/rate/addRateToDriver.php", payload: { 'passenger_id': box.read(BoxName.passengerID).toString(), - 'driver_id': driverId, - 'ride_id': rideId, + 'driver_id': driverId.toString(), + 'ride_id': rideId.toString(), 'rating': selectedRateItemId.toString(), 'comment': comment.text, }); - CRUD().post( - link: "${AppLink.seferGizaServer}/rate/addRateToDriver.php", - payload: { - 'passenger_id': box.read(BoxName.passengerID).toString(), - 'driver_id': driverId, - 'ride_id': rideId, - 'rating': selectedRateItemId.toString(), - 'comment': comment.text, - }); - Get.find().restCounter(); - Get.offAll(const MapPagePassenger()); - }); + } + + Get.find().restCounter(); + Get.offAll(const MapPagePassenger()); } } diff --git a/lib/models/db_sql.dart b/lib/models/db_sql.dart index 0caa829..4178e68 100644 --- a/lib/models/db_sql.dart +++ b/lib/models/db_sql.dart @@ -37,18 +37,21 @@ class DbSql { latitude REAL, longitude REAL, name TEXT UNIQUE, - rate TEXT + rate TEXT, + createdAt TEXT ) '''); + await db.execute('DROP TABLE IF EXISTS ${TableName.recentLocations}'); await db.execute(''' - CREATE TABLE IF NOT EXISTS ${TableName.recentLocations}( - id INTEGER PRIMARY KEY AUTOINCREMENT, - latitude REAL, - longitude REAL, - name TEXT , - rate TEXT - ) - '''); + CREATE TABLE ${TableName.recentLocations}( + id INTEGER PRIMARY KEY AUTOINCREMENT, + latitude REAL, + longitude REAL, + name TEXT, + rate TEXT, + createdAt TEXT + ) +'''); await db.execute(''' CREATE TABLE IF NOT EXISTS ${TableName.driverOrdersRefuse}( id INTEGER PRIMARY KEY AUTOINCREMENT, @@ -97,6 +100,34 @@ class DbSql { return await db.insert(table, map); } + Future insertMapLocation(Map map, String table) async { + Database db = await instance.database; + + // Check if the record already exists (based on latitude, longitude, and name) + var existing = await db.query( + table, + where: 'latitude = ? AND longitude = ? AND name = ?', + whereArgs: [map['latitude'], map['longitude'], map['name']], + ); + + if (existing.isNotEmpty) { + // If record exists, update the createdAt field with the current timestamp + var updatedMap = Map.from(map); + updatedMap['createdAt'] = + DateTime.now().toIso8601String(); // Update timestamp + return await db.update( + table, + updatedMap, + where: 'id = ?', + whereArgs: [existing.first['id']], // Update the existing row + ); + } else { + // If record doesn't exist, insert new record with the current timestamp + map['createdAt'] = DateTime.now().toIso8601String(); + return await db.insert(table, map); + } + } + Future updateData(Map map, String table, int id) async { Database db = await instance.database; diff --git a/lib/views/Rate/rate_captain.dart b/lib/views/Rate/rate_captain.dart index b680eb3..e3be4bd 100644 --- a/lib/views/Rate/rate_captain.dart +++ b/lib/views/Rate/rate_captain.dart @@ -40,7 +40,7 @@ class RateDriverFromPassenger extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Text( - '${'Total price to '.tr}${Get.find().firstName}', + '${'Total price to '.tr}${Get.find().driverName}', style: AppStyle.title, ), Row( diff --git a/lib/views/auth/login_page.dart b/lib/views/auth/login_page.dart index b4d6405..8cceb25 100644 --- a/lib/views/auth/login_page.dart +++ b/lib/views/auth/login_page.dart @@ -12,6 +12,7 @@ import 'package:SEFER/constant/style.dart'; import 'package:SEFER/main.dart'; import 'package:SEFER/views/widgets/elevated_btn.dart'; import 'package:SEFER/views/widgets/my_scafold.dart'; +import 'package:permission_handler/permission_handler.dart'; import '../../constant/info.dart'; import '../../controller/auth/apple_signin_controller.dart'; @@ -456,6 +457,16 @@ class LoginPage extends StatelessWidget { textAlign: TextAlign.center, style: AppStyle.title, ), + TextButton( + onPressed: () { + // Optionally, navigate to app settings for manual permission control + openAppSettings(); + }, + child: Text( + "Open Settings".tr, + style: const TextStyle(color: AppColor.blueColor), + ), + ), MyElevatedButton( title: 'Next'.tr, onPressed: () async { diff --git a/lib/views/home/HomePage/contact_us.dart b/lib/views/home/HomePage/contact_us.dart index 58a104c..e7012dc 100644 --- a/lib/views/home/HomePage/contact_us.dart +++ b/lib/views/home/HomePage/contact_us.dart @@ -23,9 +23,9 @@ class ContactUsPage extends StatelessWidget { body: [ Padding( padding: const EdgeInsets.all(8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.spaceBetween, + child: ListView( + // crossAxisAlignment: CrossAxisAlignment.center, + // mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Container( decoration: AppStyle.boxDecoration1, diff --git a/lib/views/home/home_page.dart b/lib/views/home/home_page.dart index 9c58f41..3b9949d 100644 --- a/lib/views/home/home_page.dart +++ b/lib/views/home/home_page.dart @@ -1,10 +1,8 @@ import 'package:SEFER/controller/home/home_page_controller.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:SEFER/constant/colors.dart'; -import 'package:SEFER/constant/style.dart'; import 'package:SEFER/views/lang/languages.dart'; -import 'package:SEFER/views/widgets/my_scafold.dart'; import 'HomePage/about_page.dart'; import 'HomePage/frequentlyQuestionsPage.dart'; @@ -18,121 +16,108 @@ class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { Get.put(HomePageController()); - return MyScafolld( - isleading: true, - title: 'Home Page'.tr, - body: [ - ListView( + return CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar( + middle: Text('Home Page'.tr), + leading: CupertinoButton( + padding: EdgeInsets.zero, + child: const Icon(CupertinoIcons.back), + onPressed: () { + Navigator.pop(context); + }, + ), + ), + child: SafeArea( + child: ListView( children: [ - ListTile( + CupertinoListTile( onTap: () { Get.to(() => const Language()); }, - title: Text( - 'Language'.tr, - style: AppStyle.headTitle2, - ), - subtitle: Text( - 'To change Language the App'.tr, - style: AppStyle.title, - ), - trailing: const Icon( - Icons.arrow_forward_ios, - size: 30, - color: AppColor.primaryColor, - ), - leading: const Icon( - Icons.language_sharp, - color: AppColor.primaryColor, - ), + leading: const Icon(CupertinoIcons.globe, + color: CupertinoColors.activeBlue), + title: Text('Language'.tr), + subtitle: Text('To change Language the App'.tr), + trailing: const CupertinoListTileChevron(), ), - ListTile( - leading: const Icon(Icons.location_city_outlined), - title: Text( - 'Change Country'.tr, - style: AppStyle.headTitle2, - ), - subtitle: Text( - 'You can change the Country to get all features'.tr, - style: AppStyle.title, - ), - onTap: () => Get.to(MyScafolld( - title: 'Change Country'.tr, - body: [CountryPickerFromSetting()], - isleading: true)), - ), - ListTile( - leading: const Icon(Icons.question_answer), - title: Text( - 'Frequently Questions'.tr, - style: AppStyle.headTitle2, - ), - subtitle: Text( - 'You can change the Country to get all features'.tr, - style: AppStyle.title, - ), - onTap: () => Get.to(() => const FrequentlyQuestionsPage()), - ), - ListTile( - leading: const Icon(Icons.vibration), - title: GetBuilder(builder: (controller) { - return SwitchListTile( - title: Text( - 'Vibration'.tr, - style: AppStyle.headTitle2, + CupertinoListTile( + onTap: () { + Get.to(CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar( + middle: Text('Change Country'.tr), ), - value: controller.isVibrate, - onChanged: controller.changeVibrateOption, - activeColor: AppColor.primaryColor, - ); - }), - subtitle: Text( - "You can change the vibration feedback for all buttons".tr, - style: AppStyle.title, - ), - onTap: () => Get.to(() => const FrequentlyQuestionsPage()), + child: SafeArea( + child: CountryPickerFromSetting(), + ), + )); + }, + leading: const Icon(CupertinoIcons.location, + color: CupertinoColors.activeBlue), + title: Text('Change Country'.tr), + subtitle: + Text('You can change the Country to get all features'.tr), + trailing: const CupertinoListTileChevron(), ), - ListTile( - leading: const Icon(Icons.record_voice_over_outlined), - title: Text( - 'Trips recorded'.tr, - style: AppStyle.headTitle2, - ), - subtitle: Text( - 'Here recorded trips audio'.tr, - style: AppStyle.title, - ), - onTap: () async { - Get.to(() => TripsRecordedPage()); - }), - ListTile( - leading: const Icon(Icons.account_balance_outlined), - title: Text( - 'About Us'.tr, - style: AppStyle.headTitle2, - ), - subtitle: Text( - 'You can change the Country to get all features'.tr, - style: AppStyle.title, - ), - onTap: () => Get.to(() => const AboutPage()), + CupertinoListTile( + onTap: () { + Get.to(() => const FrequentlyQuestionsPage()); + }, + leading: const Icon(CupertinoIcons.question, + color: CupertinoColors.activeBlue), + title: Text('Frequently Questions'.tr), + subtitle: Text('Find answers to common questions'.tr), + trailing: const CupertinoListTileChevron(), ), - ListTile( - leading: const Icon(Icons.share), - title: Text( - 'Share App'.tr, - style: AppStyle.headTitle2, + CupertinoListTile( + leading: const Icon(Icons.vibration, + color: CupertinoColors.activeBlue), + title: Text('Vibration'.tr), + trailing: GetBuilder( + builder: (controller) { + return CupertinoSwitch( + value: controller.isVibrate, + onChanged: controller.changeVibrateOption, + ); + }, ), subtitle: Text( - 'You can share the SEFER App with your friends and earn rewards for rides they take using your code' - .tr, - style: AppStyle.title, - ), - onTap: () => Get.to(() => ShareAppPage()), + 'You can change the vibration feedback for all buttons'.tr), + ), + CupertinoListTile( + onTap: () { + Get.to(() => const TripsRecordedPage()); + }, + leading: const Icon(CupertinoIcons.mic_circle, + color: CupertinoColors.activeBlue), + title: Text('Trips recorded'.tr), + subtitle: Text('Here recorded trips audio'.tr), + trailing: const CupertinoListTileChevron(), + ), + CupertinoListTile( + onTap: () { + Get.to(() => const AboutPage()); + }, + leading: const Icon(CupertinoIcons.info_circle, + color: CupertinoColors.activeBlue), + title: Text('About Us'.tr), + subtitle: Text('Learn more about our app and mission'.tr), + trailing: const CupertinoListTileChevron(), + ), + CupertinoListTile( + onTap: () { + Get.to(() => ShareAppPage()); + }, + leading: const Icon(CupertinoIcons.share, + color: CupertinoColors.activeBlue), + title: Text('Share App'.tr), + subtitle: Text( + 'You can share the SEFER App with your friends and earn rewards for rides they take using your code' + .tr), + trailing: const CupertinoListTileChevron(), ), ], ), - ], + ), ); } } diff --git a/lib/views/home/map_page_passenger.dart b/lib/views/home/map_page_passenger.dart index 3c251df..040f669 100644 --- a/lib/views/home/map_page_passenger.dart +++ b/lib/views/home/map_page_passenger.dart @@ -66,6 +66,7 @@ class MapPagePassenger extends StatelessWidget { const RideBeginPassenger(), const VipRideBeginPassenger(), const RideFromStartApp(), + cancelRidePage(), const MenuIconMapPageWidget(), PointsPageForRider() @@ -85,7 +86,7 @@ class CancelRidePageShow extends StatelessWidget { Widget build(BuildContext context) { return GetBuilder( builder: (controller) => - (controller.data.isNotEmpty && controller.remainingTime > 0) + (controller.data.isNotEmpty && controller.statusRide != 'Begin') // || // controller.timeToPassengerFromDriverAfterApplied == 0 ? Positioned( diff --git a/lib/views/home/map_widget.dart/apply_order_widget.dart b/lib/views/home/map_widget.dart/apply_order_widget.dart index 1f61c68..2a974d8 100644 --- a/lib/views/home/map_widget.dart/apply_order_widget.dart +++ b/lib/views/home/map_widget.dart/apply_order_widget.dart @@ -17,6 +17,21 @@ class ApplyOrderWidget extends StatelessWidget { @override Widget build(BuildContext context) { + Color _parseColor(String colorHex) { + if (colorHex.isEmpty) { + return Colors.grey; // Fallback for empty color + } + + // Ensure the string starts with '0xff' for ARGB format + String processedHex = colorHex.replaceFirst('#', '0xff').trim(); + + if (!processedHex.startsWith('0xff')) { + processedHex = '0xff$processedHex'; // Add '0xff' if missing + } + + return Color(int.parse(processedHex)); + } + return GetBuilder(builder: (controller) { if (controller.statusRide == 'Apply' && controller.isSearchingWindow == false) { @@ -108,36 +123,43 @@ class ApplyOrderWidget extends StatelessWidget { ], ), Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ - Image.asset( - box.read(BoxName.carType) == 'Comfort' - ? 'assets/images/blob.png' - : box.read(BoxName.carType) == 'Lady' - ? 'assets/images/lady.png' // Assuming there's an image for Lady - : box.read(BoxName.carType) == 'Speed' - ? 'assets/images/carspeed.png' - : box.read(BoxName.carType) == - 'Scooter' - ? 'assets/images/moto.png' - : box.read(BoxName.carType) == - 'Mishwar Vip' - ? 'assets/images/freeRide.png' - : box.read(BoxName - .carType) == - 'Awfar Car' - ? 'assets/images/balash.png' - : box.read(BoxName - .carType) == - 'Pink Bike' - ? 'assets/images/pinkBike.png' - : box.read(BoxName - .carType) == - 'Rayeh Gai' - ? 'assets/images/roundtrip.png' - : 'assets/images/carspeed.png', // Default image if none of the above - width: 80, - ), + // ColorFiltered( + // colorFilter: ColorFilter.mode( + // _parseColor(controller.colorHex), + // BlendMode.srcIn, + // ), + // child: Image.asset( + // box.read(BoxName.carType) == 'Comfort' + // ? 'assets/images/blob.png' + // : box.read(BoxName.carType) == 'Lady' + // ? 'assets/images/lady.png' // Assuming there's an image for Lady + // : box.read(BoxName.carType) == 'Speed' + // ? 'assets/images/carspeed.png' + // : box.read(BoxName.carType) == + // 'Scooter' + // ? 'assets/images/moto.png' + // : box.read(BoxName.carType) == + // 'Mishwar Vip' + // ? 'assets/images/freeRide.png' + // : box.read(BoxName + // .carType) == + // 'Awfar Car' + // ? 'assets/images/balash.png' + // : box.read(BoxName + // .carType) == + // 'Pink Bike' + // ? 'assets/images/pinkBike.png' + // : box.read(BoxName + // .carType) == + // 'Rayeh Gai' + // ? 'assets/images/roundtrip.png' + // : 'assets/images/carspeed.png', // Default image if none of the above + // width: 80, + // ), + // ), + Column( children: [ Text( @@ -152,14 +174,31 @@ class ApplyOrderWidget extends StatelessWidget { ), ], ), + const SizedBox( + width: 10, + ), Text( // 'Black', - controller.carColor, + controller.carColor.toString(), style: AppStyle.title, ), const SizedBox( width: 10, ), + ColorFiltered( + colorFilter: ColorFilter.mode( + _parseColor(controller.colorHex), + BlendMode.srcIn, + ), + child: Image.asset( + box.read(BoxName.carType) == 'Scooter' || + box.read(BoxName.carType) == + 'Pink Bike' + ? 'assets/images/moto.png' + : 'assets/images/car3.png', + width: 80, + ), + ), ], ), Padding( @@ -218,7 +257,7 @@ class ApplyOrderWidget extends StatelessWidget { children: [ Text( // 'fadi ahmad', - controller.firstName, + controller.driverName, style: AppStyle.title, ), Text( diff --git a/lib/views/home/map_widget.dart/form_search_places_destenation.dart b/lib/views/home/map_widget.dart/form_search_places_destenation.dart index 525e642..83217c3 100644 --- a/lib/views/home/map_widget.dart/form_search_places_destenation.dart +++ b/lib/views/home/map_widget.dart/form_search_places_destenation.dart @@ -242,109 +242,127 @@ GetBuilder formSearchPlacesDestenation() { // ) // : const SizedBox(), Container( - height: controller.placesDestination.isNotEmpty - ? controller.height - : 0, - color: AppColor.secondaryColor, - child: ListView.builder( - itemCount: controller.placesDestination.length, - itemBuilder: (BuildContext context, int index) { - var res = controller.placesDestination[index]; - return InkWell( - onTap: () async { - controller.changeHeightPlaces(); - await sql.insertData({ - 'latitude': res['geometry']['location']['lat'], - 'longitude': res['geometry']['location']['lng'], - 'name': res['name'].toString(), - 'rate': res['rating'].toString(), - }, TableName.recentLocations); + height: controller.placesDestination.isNotEmpty + ? controller.height + : 0, + color: AppColor.secondaryColor, + child: ListView.builder( + itemCount: controller.placesDestination.length, + itemBuilder: (BuildContext context, int index) { + var res = controller.placesDestination[index]; - controller.changeHeightPlaces(); + // Extract fields with null safety + var title = res['title']?.toString() ?? 'Unknown Place'; + var position = res['position']; + var latitude = position?['lat']; + var longitude = position?['lng']; + var address = + res['address']?['label'] ?? 'Unknown Address'; + var categories = res['categories'] ?? []; + var primaryCategory = categories.isNotEmpty + ? categories[0]['name'] + : 'Unknown Category'; - controller.passengerLocation = controller.newMyLocation; - controller.myDestination = LatLng( - double.parse( - res['geometry']['location']['lat'].toString()), - double.parse( - res['geometry']['location']['lng'].toString()), - ); - controller.convertHintTextDestinationNewPlaces(index); + return InkWell( + onTap: () async { + if (latitude != null && longitude != null) { + sql.insertMapLocation({ + 'latitude': latitude, + 'longitude': longitude, + 'name': title, + 'rate': 'N/A', + 'createdAt': DateTime.now().toIso8601String(), + // No rating in this structure, adjust as needed + }, TableName.recentLocations); - controller.placesDestination = []; - controller.placeDestinationController.clear(); - controller.changeMainBottomMenuMap(); - controller.passengerStartLocationFromMap = true; - controller.isPickerShown = true; - }, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 10), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - children: [ - Image.network( - res['icon'], - width: 20, + controller.passengerLocation = + controller.newMyLocation; + controller.myDestination = + LatLng(latitude, longitude); + controller + .convertHintTextDestinationNewPlaces(index); + + controller.placesDestination = []; + controller.placeDestinationController.clear(); + controller.changeMainBottomMenuMap(); + controller.passengerStartLocationFromMap = true; + controller.isPickerShown = true; + } else { + Toast.show( + context, + 'Invalid location data', + AppColor.redColor, + ); + } + }, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: Column( + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Column( + children: [ + const Icon(Icons.place, + size: 20), // Fallback icon for places + IconButton( + onPressed: () async { + if (latitude != null && + longitude != null) { + await sql.insertMapLocation({ + 'latitude': latitude, + 'longitude': longitude, + 'name': title, + 'rate': 'N/A', + }, TableName.placesFavorite); + Toast.show( + context, + '$title ${'Saved Successfully'.tr}', + AppColor.primaryColor, + ); + } else { + Toast.show( + context, + 'Invalid location data', + AppColor.redColor, + ); + } + }, + icon: const Icon(Icons.favorite_border), + ), + ], + ), + Expanded( + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + title, + style: AppStyle.title, + ), + Text( + address, + style: AppStyle.subtitle, + ), + Text( + primaryCategory, + style: AppStyle.subtitle, + ), + ], ), - IconButton( - onPressed: () async { - await sql.insertData({ - 'latitude': res['geometry'] - ['location']['lat'], - 'longitude': res['geometry'] - ['location']['lng'], - 'name': res['name'].toString(), - 'rate': res['rating'].toString(), - }, TableName.placesFavorite); - Toast.show( - context, - '${res['name']} ${'Saved Sucssefully'.tr}', - AppColor.primaryColor); - }, - icon: const Icon(Icons.favorite_border), - ), - ], - ), - Column( - children: [ - Text( - res['name'].toString(), - style: AppStyle.title, - ), - Text( - res['vicinity'].toString(), - style: AppStyle.subtitle, - ), - ], - ), - Column( - children: [ - Text( - 'rate', - style: AppStyle.subtitle, - ), - Text( - res['rating'].toString(), - style: AppStyle.subtitle, - ), - ], - ), - ], - ), - const Divider( - thickness: 1, - ) - ], + ), + ], + ), + const Divider(thickness: 1), + ], + ), ), - ), - ); - }, - ), - ) + ); + }, + )) ], )); } diff --git a/lib/views/home/map_widget.dart/form_search_start.dart b/lib/views/home/map_widget.dart/form_search_start.dart index 171ec03..ac7d2d2 100644 --- a/lib/views/home/map_widget.dart/form_search_start.dart +++ b/lib/views/home/map_widget.dart/form_search_start.dart @@ -103,7 +103,7 @@ GetBuilder formSearchPlacesStart() { // controller.myLocation = // controller.newStartPointLocation; // } - await sql.insertData({ + await sql.insertMapLocation({ 'latitude': res['geometry']['location']['lat'], 'longitude': res['geometry']['location']['lng'], 'name': res['name'].toString(), @@ -130,7 +130,7 @@ GetBuilder formSearchPlacesStart() { ), IconButton( onPressed: () async { - await sql.insertData({ + await sql.insertMapLocation({ 'latitude': res['geometry'] ['location']['lat'], 'longitude': res['geometry'] diff --git a/lib/views/home/map_widget.dart/form_serch_multiy_point.dart b/lib/views/home/map_widget.dart/form_serch_multiy_point.dart index 0347790..fed2274 100644 --- a/lib/views/home/map_widget.dart/form_serch_multiy_point.dart +++ b/lib/views/home/map_widget.dart/form_serch_multiy_point.dart @@ -109,7 +109,7 @@ GetBuilder formSearchPlaces(int index) { ), IconButton( onPressed: () async { - await sql.insertData({ + await sql.insertMapLocation({ 'latitude': res['geometry'] ['location']['lat'], 'longitude': res['geometry'] diff --git a/lib/views/home/map_widget.dart/left_main_menu_icons.dart b/lib/views/home/map_widget.dart/left_main_menu_icons.dart index ff26bb6..09b3346 100644 --- a/lib/views/home/map_widget.dart/left_main_menu_icons.dart +++ b/lib/views/home/map_widget.dart/left_main_menu_icons.dart @@ -8,7 +8,7 @@ import '../../../controller/home/map_passenger_controller.dart'; import '../../../controller/home/vip_waitting_page.dart'; GetBuilder leftMainMenuIcons() { - final textToSpeechController = Get.put(TextToSpeechController()); + Get.put(TextToSpeechController()); return GetBuilder( builder: (controller) => Positioned( top: Get.height * .008, @@ -108,7 +108,9 @@ GetBuilder leftMainMenuIcons() { // borderRadius: BorderRadius.circular(15)), // child: IconButton( // onPressed: () async { - // print(Get.put(MapPassengerController()).data); + // controller.statusRide == 'Apply' && + // controller.isSearchingWindow == false; + // controller.update(); // }, // icon: const Icon( // Octicons diff --git a/lib/views/home/map_widget.dart/main_bottom_Menu_map.dart b/lib/views/home/map_widget.dart/main_bottom_Menu_map.dart index 3acfe04..65591c5 100644 --- a/lib/views/home/map_widget.dart/main_bottom_Menu_map.dart +++ b/lib/views/home/map_widget.dart/main_bottom_Menu_map.dart @@ -1,4 +1,6 @@ +import 'package:SEFER/views/widgets/my_dialog.dart'; import 'package:SEFER/views/widgets/my_textField.dart'; +import 'package:SEFER/views/widgets/mysnakbar.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; @@ -14,6 +16,7 @@ import '../../../constant/colors.dart'; import '../../../constant/table_names.dart'; import '../../../controller/functions/toast.dart'; import '../../../controller/functions/tts.dart'; +import '../../../print.dart'; import 'form_search_start.dart'; class MainBottomMenuMap extends StatelessWidget { @@ -46,24 +49,34 @@ class MainBottomMenuMap extends StatelessWidget { child: Container( width: Get.width * .8, height: Get.height * .1, - decoration: const BoxDecoration( - boxShadow: [ - BoxShadow( - color: Color.fromARGB( - 255, 237, 230, 230), - blurRadius: 5, - offset: Offset(2, 4)), - BoxShadow( - color: Color.fromARGB( - 255, 242, 237, 237), - blurRadius: 5, - offset: Offset(-2, -2)) - ], - color: AppColor.blueColor, - borderRadius: BorderRadius.all( - Radius.elliptical(15, 30), + padding: const EdgeInsets.symmetric( + horizontal: 20, vertical: 10), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + AppColor.blueColor.withOpacity(0.8), + AppColor.blueColor.withOpacity(0.6), + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, ), + boxShadow: const [ + BoxShadow( + color: Color.fromARGB( + 255, 237, 230, 230), + blurRadius: 8, + offset: Offset(4, 8), + ), + BoxShadow( + color: Color.fromARGB( + 255, 242, 237, 237), + blurRadius: 8, + offset: Offset(-4, -4), + ), + ], + borderRadius: BorderRadius.circular(30), ), + // decoration: AppStyle.boxDecoration1, child: DefaultTextStyle( style: AppStyle.title.copyWith( @@ -350,6 +363,18 @@ class MainBottomMenuMap extends StatelessWidget { }, )); }, + onLongPress: () { + MyDialog().getDialog( + "Are you sure to delete this location?".tr, '', () { + sql.deleteData(TableName.recentLocations, + controller.recentPlaces[index]['id']); + + controller.getFavioratePlaces(); + controller.update(); + Get.back(); + mySnackbarSuccess('deleted'.tr); + }); + }, child: Container( decoration: AppStyle.boxDecoration1, child: Padding( diff --git a/lib/views/home/map_widget.dart/ride_begin_passenger.dart b/lib/views/home/map_widget.dart/ride_begin_passenger.dart index 3c71f0e..cf919a1 100644 --- a/lib/views/home/map_widget.dart/ride_begin_passenger.dart +++ b/lib/views/home/map_widget.dart/ride_begin_passenger.dart @@ -53,7 +53,7 @@ class RideBeginPassenger extends StatelessWidget { Container( decoration: AppStyle.boxDecoration, child: Text( - controller.firstName, + controller.driverName, style: AppStyle.title, ), ), diff --git a/lib/views/home/my_wallet/passenger_wallet.dart b/lib/views/home/my_wallet/passenger_wallet.dart index 1bbe5f9..ce13291 100644 --- a/lib/views/home/my_wallet/passenger_wallet.dart +++ b/lib/views/home/my_wallet/passenger_wallet.dart @@ -1,4 +1,3 @@ -import 'package:SEFER/views/widgets/my_dialog.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -12,11 +11,8 @@ import '../../../controller/functions/toast.dart'; import '../../../controller/home/payment/credit_card_controller.dart'; import '../../../controller/payment/payment_controller.dart'; import '../../../main.dart'; -import '../../../models/model/painter_copoun.dart'; -import '../../../print.dart'; import '../../widgets/elevated_btn.dart'; import '../../widgets/my_scafold.dart'; -import '../../widgets/my_textField.dart'; import 'passenger_wallet_dialoge.dart'; class PassengerWallet extends StatelessWidget { @@ -51,33 +47,33 @@ class PassengerWallet extends StatelessWidget { }, ), ), - Padding( - padding: - const EdgeInsets.symmetric(horizontal: 80, vertical: 10), - child: MyElevatedButton( - kolor: AppColor.yellowColor, - title: 'Bounus gift'.tr, - onPressed: () { - 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: box.read(BoxName.promo), - discountPercentage: box.read(BoxName.discount), - validity: box.read(BoxName.validity), - ), - ), - ), - ); - Log.print( - 'box.read(BoxName.isGiftToken).toString(): ${box.read(BoxName.isGiftToken).toString()}'); - }, - ), - ) + // Padding( + // padding: + // const EdgeInsets.symmetric(horizontal: 80, vertical: 10), + // child: MyElevatedButton( + // kolor: AppColor.yellowColor, + // title: 'Bonus gift'.tr, + // onPressed: () { + // 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: box.read(BoxName.promo), + // discountPercentage: box.read(BoxName.discount), + // validity: box.read(BoxName.validity), + // ), + // ), + // ), + // ); + // Log.print( + // 'box.read(BoxName.isGiftToken).toString(): ${box.read(BoxName.isGiftToken).toString()}'); + // }, + // ), + // ) ], ), ), @@ -98,7 +94,8 @@ class PassengerWallet extends StatelessWidget { MyElevatedButton( title: 'Show Promos to Charge'.tr, onPressed: () { - controller.changePromoSheetDialogue(); + // controller.changePromoSheetDialogue(); + showPaymentBottomSheet(context); }, ), const SizedBox( diff --git a/lib/views/home/my_wallet/passenger_wallet_dialoge.dart b/lib/views/home/my_wallet/passenger_wallet_dialoge.dart index 89b9933..af85f94 100644 --- a/lib/views/home/my_wallet/passenger_wallet_dialoge.dart +++ b/lib/views/home/my_wallet/passenger_wallet_dialoge.dart @@ -1,4 +1,6 @@ +import 'package:SEFER/constant/style.dart'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:SEFER/constant/box_name.dart'; import 'package:SEFER/constant/colors.dart'; @@ -89,6 +91,147 @@ class PassengerWalletDialog extends StatelessWidget { ); } } +// class PassengerWalletDialog extends StatelessWidget { +// const PassengerWalletDialog({ +// super.key, +// }); + +// @override +// Widget build(BuildContext context) { +// return GetBuilder( +// builder: (controller) { +// return Positioned( +// top: Get.height * .1, +// right: Get.width * .15, +// left: Get.width * .15, +// bottom: Get.height * .1, +// child: controller.isPromoSheetDialogue +// ? Container() +// : SizedBox +// .shrink(), // If condition is false, return an empty widget +// ); +// }, +// ); +// } +// } +void showPaymentBottomSheet(BuildContext context) { + final controller = Get.find(); + + showModalBottomSheet( + context: context, + isScrollControlled: true, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(15.0)), + ), + builder: (BuildContext context) { + return WillPopScope( + onWillPop: () async { + Get.back(); + return false; + }, + child: Container( + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Text( + 'Select Payment Amount'.tr, + style: AppStyle.headTitle2, + textAlign: TextAlign.center, + ), + const SizedBox(height: 16.0), + + // Payment Options List + _buildPaymentOption( + context: context, + controller: controller, + amount: box.read(BoxName.countryCode) == 'Egypt' ? 100 : 10, + bonusAmount: 0, + currency: box.read(BoxName.countryCode) == 'Egypt' + ? 'LE'.tr + : 'JOD'.tr, + ), + + const SizedBox(height: 8.0), + _buildPaymentOption( + context: context, + controller: controller, + amount: box.read(BoxName.countryCode) == 'Egypt' ? 200 : 20, + bonusAmount: box.read(BoxName.countryCode) == 'Egypt' ? 5 : 1, + currency: box.read(BoxName.countryCode) == 'Egypt' + ? 'LE'.tr + : 'JOD'.tr, + ), + + const SizedBox(height: 8.0), + _buildPaymentOption( + context: context, + controller: controller, + amount: box.read(BoxName.countryCode) == 'Egypt' ? 400 : 40, + bonusAmount: + box.read(BoxName.countryCode) == 'Egypt' ? 15 : 2.5, + currency: box.read(BoxName.countryCode) == 'Egypt' + ? 'LE'.tr + : 'JOD'.tr, + ), + + const SizedBox(height: 8.0), + _buildPaymentOption( + context: context, + controller: controller, + amount: box.read(BoxName.countryCode) == 'Egypt' ? 1000 : 50, + bonusAmount: box.read(BoxName.countryCode) == 'Egypt' ? 100 : 6, + currency: box.read(BoxName.countryCode) == 'Egypt' + ? 'LE'.tr + : 'JOD'.tr, + ), + + const SizedBox(height: 16.0), + TextButton( + onPressed: () => Get.back(), + child: Text('Cancel'.tr), + ), + ], + ), + ), + ); + }, + ); +} + +Widget _buildPaymentOption({ + required BuildContext context, + required PaymentController controller, + required int amount, + required double bonusAmount, + required String currency, +}) { + return Material( + color: Colors.transparent, + child: InkWell( + onTap: () { + controller.updateSelectedAmount(amount); + Get.back(); + showPaymentOptions(context, controller); + }, + child: Container( + padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 16.0), + decoration: BoxDecoration( + border: Border.all(color: Colors.grey[300]!), + borderRadius: BorderRadius.circular(8.0), + ), + child: Text( + bonusAmount > 0 + ? '${'Pay'.tr} $amount $currency, ${'Get'.tr} ${amount + bonusAmount} $currency' + : '$amount $currency', + style: AppStyle.title, + textAlign: TextAlign.center, + ), + ), + ), + ); +} void showPaymentOptions(BuildContext context, PaymentController controller) { showCupertinoModalPopup( @@ -209,7 +352,8 @@ void showPaymentOptions(BuildContext context, PaymentController controller) { cancelButton: CupertinoActionSheetAction( child: Text('Cancel'.tr), onPressed: () { - controller.changePromoSheetDialogue(); + // controller.changePromoSheetDialogue(); + Get.back(); }, ), ), diff --git a/lib/views/home/profile/promos_passenger_page.dart b/lib/views/home/profile/promos_passenger_page.dart index 1d995d4..923478b 100644 --- a/lib/views/home/profile/promos_passenger_page.dart +++ b/lib/views/home/profile/promos_passenger_page.dart @@ -20,211 +20,211 @@ class PromosPassengerPage extends StatelessWidget { Widget build(BuildContext context) { Get.put(PromosController()); return MyScafolld( - title: 'Promos For today'.tr, + title: "Promos For Today".tr, isleading: true, body: [ GetBuilder( builder: (orderHistoryController) => orderHistoryController.isLoading ? const MyCircularProgressIndicator() : ListView.builder( - itemCount: orderHistoryController.promoList.length + - 1, // Adding 1 for the ad + itemCount: orderHistoryController + .promoList.length, // Adding 1 for the ad itemBuilder: (BuildContext context, int index) { - if (index == 0) { - // Ad at the beginning - return Padding( - padding: const EdgeInsets.all(8.0), - child: Container( - height: 120, // Adjust the height of the ad container - decoration: BoxDecoration( - color: - Colors.grey[200], // Background color for the ad - borderRadius: BorderRadius.circular(10), - ), - child: Center( - child: Container( - decoration: AppStyle.boxDecoration, - height: Get.height * .19, - child: ListView( - scrollDirection: Axis.horizontal, - children: [ - PointsCaptain( - kolor: AppColor.greyColor, - pricePoint: - box.read(BoxName.countryCode) == - 'Jordan' - ? 5 - : 100, - countPoint: - box.read(BoxName.countryCode) == - 'Jordan' - ? '300' - : '100', - ), - PointsCaptain( - kolor: AppColor.bronze, - pricePoint: - box.read(BoxName.countryCode) == - 'Jordan' - ? 10 - : 200, - countPoint: - box.read(BoxName.countryCode) == - 'Jordan' - ? '1040' - : '210', - ), - PointsCaptain( - kolor: AppColor.goldenBronze, - pricePoint: - box.read(BoxName.countryCode) == - 'Jordan' - ? 22 - : 400, - countPoint: - box.read(BoxName.countryCode) == - 'Jordan' - ? '2300' - : '450', - ), - PointsCaptain( - kolor: AppColor.gold, - pricePoint: - box.read(BoxName.countryCode) == - 'Jordan' - ? 50 - : 1000, - countPoint: - box.read(BoxName.countryCode) == - 'Jordan' - ? '55000' - : '1200', - ), - ], - )), - ), - ), - ); - } else { - // Promo items - final rides = orderHistoryController.promoList[index - 1]; + // if (index == 0) { + // // Ad at the beginning + // return Padding( + // padding: const EdgeInsets.all(8.0), + // child: Container( + // height: 120, // Adjust the height of the ad container + // decoration: BoxDecoration( + // color: + // Colors.grey[200], // Background color for the ad + // borderRadius: BorderRadius.circular(10), + // ), + // child: Center( + // child: Container( + // decoration: AppStyle.boxDecoration, + // height: Get.height * .19, + // child: ListView( + // scrollDirection: Axis.horizontal, + // children: [ + // PointsCaptain( + // kolor: AppColor.greyColor, + // pricePoint: + // box.read(BoxName.countryCode) == + // 'Jordan' + // ? 5 + // : 100, + // countPoint: + // box.read(BoxName.countryCode) == + // 'Jordan' + // ? '300' + // : '100', + // ), + // PointsCaptain( + // kolor: AppColor.bronze, + // pricePoint: + // box.read(BoxName.countryCode) == + // 'Jordan' + // ? 10 + // : 200, + // countPoint: + // box.read(BoxName.countryCode) == + // 'Jordan' + // ? '1040' + // : '210', + // ), + // PointsCaptain( + // kolor: AppColor.goldenBronze, + // pricePoint: + // box.read(BoxName.countryCode) == + // 'Jordan' + // ? 22 + // : 400, + // countPoint: + // box.read(BoxName.countryCode) == + // 'Jordan' + // ? '2300' + // : '450', + // ), + // PointsCaptain( + // kolor: AppColor.gold, + // pricePoint: + // box.read(BoxName.countryCode) == + // 'Jordan' + // ? 50 + // : 1000, + // countPoint: + // box.read(BoxName.countryCode) == + // 'Jordan' + // ? '55000' + // : '1200', + // ), + // ], + // )), + // ), + // ), + // ); + // } else { + // Promo items + final rides = orderHistoryController.promoList[index]; - return Padding( - padding: const EdgeInsets.all(12.0), - child: Container( - decoration: BoxDecoration( - color: CupertinoColors.systemGrey6, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: - CupertinoColors.systemGrey.withOpacity(0.5), - blurRadius: 8, - offset: Offset(0, 4), - ), - ], - ), - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - GestureDetector( - onTap: () {}, - child: AnimatedTextKit( - animatedTexts: [ - ScaleAnimatedText( - rides['promo_code'], - textStyle: - AppStyle.title.copyWith( - fontSize: - 32, // Increased font size for emphasis - color: CupertinoColors - .activeBlue, - fontWeight: FontWeight.bold, - ), + return Padding( + padding: const EdgeInsets.all(12.0), + child: Container( + decoration: BoxDecoration( + color: CupertinoColors.systemGrey6, + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: + CupertinoColors.systemGrey.withOpacity(0.5), + blurRadius: 8, + offset: Offset(0, 4), + ), + ], + ), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + GestureDetector( + onTap: () {}, + child: AnimatedTextKit( + animatedTexts: [ + ScaleAnimatedText( + rides['promo_code'], + textStyle: + AppStyle.title.copyWith( + fontSize: + 32, // Increased font size for emphasis + color: + CupertinoColors.activeBlue, + fontWeight: FontWeight.bold, ), - WavyAnimatedText( - rides['promo_code'], - textStyle: - AppStyle.title.copyWith( - fontSize: - 32, // Increased font size for emphasis - color: CupertinoColors - .activeBlue, - fontWeight: FontWeight.bold, - ), + ), + WavyAnimatedText( + rides['promo_code'], + textStyle: + AppStyle.title.copyWith( + fontSize: + 32, // Increased font size for emphasis + color: + CupertinoColors.activeBlue, + fontWeight: FontWeight.bold, ), - ], - isRepeatingAnimation: true, - ), + ), + ], + isRepeatingAnimation: true, ), - const SizedBox(height: 8), - // Description Text - Text( - rides['description'], - style: AppStyle.title.copyWith( - fontSize: 22, - color: CupertinoColors.systemGrey, - ), - ), - ], - ), - Column( - children: [ - // Only displaying end date - Text( - '${'Valid Until:'.tr} ${rides['validity_end_date']}', - style: AppStyle.subtitle.copyWith( - fontWeight: FontWeight.bold, - fontSize: 20, - color: CupertinoColors.systemGrey, - ), - ), - ], - ), - ], - ), - // const SizedBox(height: 16), - // Copy Promo Text - Center( - child: GestureDetector( - onTap: () { - Clipboard.setData(ClipboardData( - text: rides['promo_code'])); - Get.snackbar( - 'Promo Copied!'.tr, - 'You have copied the promo code.'.tr, - snackPosition: SnackPosition.BOTTOM, - backgroundColor: - CupertinoColors.systemGrey, - colorText: CupertinoColors.white, - ); - }, - child: Text( - 'Copy Code'.tr, - textAlign: TextAlign.center, - style: AppStyle.headTitle2.copyWith( - color: CupertinoColors.systemBlue, - fontWeight: FontWeight.bold, ), + const SizedBox(height: 8), + // Description Text + Text( + rides['description'], + style: AppStyle.title.copyWith( + fontSize: 22, + color: CupertinoColors.systemGrey, + ), + ), + ], + ), + Column( + children: [ + // Only displaying end date + Text( + '${'Valid Until:'.tr} ${rides['validity_end_date']}', + style: AppStyle.subtitle.copyWith( + fontWeight: FontWeight.bold, + fontSize: 20, + color: CupertinoColors.systemGrey, + ), + ), + ], + ), + ], + ), + // const SizedBox(height: 16), + // Copy Promo Text + Center( + child: GestureDetector( + onTap: () { + Clipboard.setData(ClipboardData( + text: rides['promo_code'])); + Get.snackbar( + 'Promo Copied!'.tr, + 'You have copied the promo code.'.tr, + snackPosition: SnackPosition.BOTTOM, + backgroundColor: + CupertinoColors.systemGrey, + colorText: CupertinoColors.white, + ); + }, + child: Text( + 'Copy Code'.tr, + textAlign: TextAlign.center, + style: AppStyle.headTitle2.copyWith( + color: CupertinoColors.systemBlue, + fontWeight: FontWeight.bold, ), ), ), - ], - ), + ), + ], ), ), - ); - } + ), + ); + // } }, ), )