diff --git a/.env b/.env
index 80f024b..e24b520 100644
--- a/.env
+++ b/.env
@@ -5,6 +5,7 @@ accountSIDTwillo=QFx0qy456juj383n9xuy2194q629q1fj0y7XrXlBl
serverAPI=QQQQobSrrFi:QVQ87xU7zwCvmZzZdaxuS2f23Y4mz7MzyOzr8od2br6KYyeFaTVLG3K3hx5ZaUyx7eYvAYpAVdKk-286NTRi3zs9iSOnXtXRIxswg3KecBmsl3VxJ9wO-vIpwu4Pv7dkHkXniuxMSDgWXrXlBl
# mapAPIKEY=AIzaSyCFsWBqvkXzk1Gb-bCGxwqTwJQKIeHjH64
mapAPIKEY=AIzaSyAPFR_XbRN0XZ5Iz3AYDjNYHGJG2s2QWwM
+mapKeyOsm=maldev@route-dollars
mapAPIKEYIOS=AIzaSyDdqkLMCrqjVrn7XmadIqynyoBa7P27OeM
twilloRecoveryCode=CAU79DHPH1BjE9PUH4ETXTSXZXrXlBl
apiKeyHere=g_WNUb5L-tripz7-F8omHpUmgIzH7ETeH9xZ8RwGG9_G8zX9A
diff --git a/android/app/build.gradle b/android/app/build.gradle
index e7fc4f0..1d656d3 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -45,10 +45,10 @@ android {
applicationId = "com.Intaleq.intaleq"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
- minSdk = 29
+ minSdk = 23
targetSdk = 36
- versionCode = 25
- versionName = '1.0.25'
+ versionCode = 45
+ versionName = '1.0.45'
multiDexEnabled = true
ndk {
abiFilters "armeabi-v7a", "arm64-v8a"
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index e5eeae8..e7b1cbd 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -20,7 +20,7 @@
تحذير أمني
- تم اكتشاف مشكلة أمنية أو تعديل على هذا الجهاز. لا يمكن تشغيل التطبيق على هذا الجهاز.
+ تم اكتشاف مشكلة أمنية أو تعديل على هذا الجهاز. لا يمكن
+ تشغيل التطبيق على هذا الجهاز.
إغلاق التطبيق
الجهاز آمن. الاستمرار بشكل طبيعي.
+ انطلق
\ No newline at end of file
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
index 9152f91..b099bf5 100644
--- a/android/app/src/main/res/values/strings.xml
+++ b/android/app/src/main/res/values/strings.xml
@@ -12,5 +12,5 @@
this device. The app cannot run on this device.
Exit App
Device is secure. Proceeding normally.
-
+ Intaleq
\ No newline at end of file
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 300fb74..296bab4 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -33,11 +33,11 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 12
+ 23
CFBundleSignature
????
CFBundleVersion
- 1.0.12
+ 1.0.23
FirebaseAppDelegateProxyEnabled
NO
GMSApiKey
diff --git a/lib/constant/colors.dart b/lib/constant/colors.dart
index 1ddb393..d10133a 100644
--- a/lib/constant/colors.dart
+++ b/lib/constant/colors.dart
@@ -27,7 +27,7 @@ class AppColor {
/// **Grey Color:** A neutral grey for secondary text, borders, dividers,
/// and disabled states.
- static const Color greyColor = Color(0xFF8E8E93);
+ static const Color grayColor = Color(0xFF8E8E93);
/// **Red Color (Error):** A clear, attention-grabbing red for error messages and alerts.
static const Color redColor = Color(0xFFD32F2F);
diff --git a/lib/constant/country_polygons.dart b/lib/constant/country_polygons.dart
new file mode 100644
index 0000000..be919af
--- /dev/null
+++ b/lib/constant/country_polygons.dart
@@ -0,0 +1,107 @@
+// في ملف: constant/country_polygons.dart
+
+import 'package:google_maps_flutter/google_maps_flutter.dart';
+
+class CountryPolygons {
+ // ==========================================================
+ // 1. الأردن: تغطية الممر الحضري الرئيسي (من إربد شمالاً حتى العقبة جنوباً)
+ // حوالي 12 نقطة
+ // ==========================================================
+ static final List jordanBoundary = [
+ // شمال إربد (قرب الحدود)
+ const LatLng(32.65, 35.80),
+ // شمال شرق المفرق
+ const LatLng(32.35, 37.00),
+ // شرق الزرقاء / الأزرق
+ const LatLng(31.85, 36.80),
+ // جنوب شرق (نهاية الزحف السكاني)
+ const LatLng(31.00, 36.50),
+ // جنوب / معان
+ const LatLng(30.30, 35.75),
+ // العقبة
+ const LatLng(29.50, 35.00),
+ // البحر الأحمر / الحدود الغربية
+ const LatLng(29.50, 34.85),
+ // غرب وادي عربة
+ const LatLng(30.80, 35.25),
+ // منطقة البحر الميت / السلط
+ const LatLng(32.00, 35.50),
+ // العودة عبر وادي الأردن إلى الشمال
+ const LatLng(32.45, 35.60),
+ // العودة لنقطة إربد
+ const LatLng(32.65, 35.80),
+ ];
+
+ // ==========================================================
+ // 2. سوريا: تغطية الممر الغربي والساحلي (درعا، دمشق، حمص، حماة، حلب، الساحل)
+ // حوالي 14 نقطة
+ // ==========================================================
+ static final List syriaBoundary = [
+ // درعا / الجنوب
+ const LatLng(32.65, 35.95),
+ // شرق السويداء (حدود المنطقة المأهولة)
+ const LatLng(32.85, 37.10),
+ // أطراف دمشق الشرقية
+ const LatLng(33.50, 36.65),
+ // تدمر (أقصى امتداد شرقي للمضلع)
+ const LatLng(34.50, 38.30),
+ // الرقة (شمال شرق)
+ const LatLng(35.95, 38.80),
+ // حلب (الشمال)
+ const LatLng(36.45, 37.15),
+ // الحدود الشمالية الغربية (إدلب / تركيا)
+ const LatLng(36.50, 36.50),
+ // اللاذقية (الساحل)
+ const LatLng(35.50, 35.75),
+ // طرطوس (الساحل)
+ const LatLng(34.80, 35.85),
+ // حمص
+ const LatLng(34.70, 36.70),
+ // حماة
+ const LatLng(35.10, 36.70),
+ // العودة إلى منطقة دمشق
+ const LatLng(33.40, 36.30),
+ // العودة إلى درعا
+ const LatLng(32.65, 35.95),
+ ];
+
+ // ==========================================================
+ // 3. مصر: تغطية القاهرة الكبرى، الدلتا، والإسكندرية والإسماعيلية
+ // حوالي 10 نقاط
+ // ==========================================================
+ static final List egyptBoundary = [
+ // جنوب الفيوم (أقصى امتداد جنوبي غربي)
+ const LatLng(29.20, 30.60),
+ // جنوب القاهرة (العياط)
+ const LatLng(29.80, 31.30),
+ // شرق السويس
+ const LatLng(29.95, 32.70),
+ // الإسماعيلية / القناة
+ const LatLng(30.60, 32.25),
+ // بورسعيد / أطراف الدلتا الشمالية الشرقية
+ const LatLng(31.30, 31.80),
+ // دمياط / ساحل الدلتا
+ const LatLng(31.50, 31.25),
+ // الإسكندرية (أقصى الشمال الغربي)
+ const LatLng(31.20, 29.80),
+ // غرب الدلتا
+ const LatLng(30.50, 30.20),
+ // العودة لنقطة البداية
+ const LatLng(29.20, 30.60),
+ ];
+
+ // دالة تُرجع رابط API بناءً على اسم الدولة
+ static String getRoutingApiUrl(String countryName) {
+ switch (countryName) {
+ case 'Jordan':
+ return 'https://routec.intaleq.xyz/route-jo';
+ case 'Syria':
+ return 'https://routec.intaleq.xyz/route';
+ case 'Egypt':
+ return 'https://routec.intaleq.xyz/route-eg';
+ default:
+ // الافتراضي في حالة لم يقع الموقع ضمن أي من المضلعات
+ return 'https://routec.intaleq.xyz/route';
+ }
+ }
+}
diff --git a/lib/constant/links.dart b/lib/constant/links.dart
index b5d2591..b7d9cf9 100644
--- a/lib/constant/links.dart
+++ b/lib/constant/links.dart
@@ -1,33 +1,18 @@
import 'package:Intaleq/constant/box_name.dart';
-import 'package:Intaleq/env/env.dart';
import 'package:Intaleq/main.dart';
class AppLink {
- // static final String seferPaymentServer0 = Env.seferPaymentServer;
- // static final String seferPaymentServer = '${Env.seferPaymentServer}/ride';
- // static final String seferAlexandriaServer = Env.seferAlexandriaServer;
- // static final String seferCairoServer = Env.seferCairoServer;
static String serverPHP = box.read('serverPHP');
- // static String seferCairoServer =
- // box.read(BoxName.locationName)[0]['server_link'];
- // static String seferGizaServer = box.read(BoxName.serverChosen);
- // static String seferAlexandriaServer = box.read(BoxName.serverChosen);
- // static String seferPaymentServer = box.read('seferPaymentServer');
- static String seferPaymentServer =
- // box.read(BoxName.paymentLink);
- 'https://walletintaleq.intaleq.xyz/v1/main';
+ static String paymentServer = 'https://walletintaleq.intaleq.xyz/v1/main';
+ static String location = 'https://api.intaleq.xyz/intaleq/ride/location';
+
static String seferPaymentServer0 = box.read('seferPaymentServer');
- // static const String seferGizaServer = 'https://gizasefer.online/sefer';
- // static final String seferGizaServer = Env.seferGizaServer;
- // static final String endPoint = box.read(BoxName.serverChosen);
- // static final String server = endPoint;
- // static final String server = Env.serverPHP;
- static final String endPoint = 'https://intaleq.xyz/intaleq';
+ static final String endPoint = 'https://api.intaleq.xyz/intaleq';
+ static final String ride = 'https://rides.intaleq.xyz/intaleq';
// box.read(BoxName.serverChosen) ?? box.read(BoxName.basicLink);
- // 'https://server.sefer.click/sefer.click/sefer';
- static final String server = endPoint;
+ static final String server = 'https://api.intaleq.xyz/intaleq';
static String IntaleqSyriaServer = endPoint;
static String IntaleqGizaServer = box.read('Giza');
static String IntaleqAlexandriaServer = box.read('Alexandria');
@@ -44,30 +29,30 @@ class AppLink {
static String getTokens = "$server/ride/firebase/get.php";
static String getTokenParent = "$server/ride/firebase/getTokenParent.php";
static String addTokens = "$server/ride/firebase/add.php";
- static String addFingerPrint = "$seferPaymentServer/ride/firebase/add.php";
+ static String addFingerPrint = "$paymentServer/ride/firebase/add.php";
static String addTokensDriver = "$server/ride/firebase/addDriver.php";
static String packageInfo = "$server/auth/packageInfo.php";
//=======================Wallet===================
- static String wallet = '$seferPaymentServer/ride/passengerWallet';
- static String walletDriver = '$seferPaymentServer/ride/driverWallet';
+ static String wallet = '$paymentServer/ride/passengerWallet';
+ static String walletDriver = '$paymentServer/ride/driverWallet';
static String getAllPassengerTransaction =
"$wallet/getAllPassengerTransaction.php";
static String getWalletByPassenger = "$wallet/getWalletByPassenger.php";
static String getPassengersWallet = "$wallet/get.php";
static String payWithPayMobWalletPasenger =
- '$seferPaymentServer/ride/payMob/wallet/payWithPayMob.php';
+ '$paymentServer/ride/payMob/wallet/payWithPayMob.php';
static String payWithPayMobCardPassenger =
- '$seferPaymentServer/ride/payMob/payWithPayMob.php';
- static String payWithEcash = "$seferPaymentServer/ecash/payWithEcash.php";
+ '$paymentServer/ride/payMob/payWithPayMob.php';
+ static String payWithEcash = "$paymentServer/ecash/payWithEcash.php";
static String paymetVerifyPassenger =
- "$seferPaymentServer/ride/payMob/paymet_verfy.php";
+ "$paymentServer/ride/payMob/paymet_verfy.php";
static String getPassengerWalletArchive =
"$wallet/getPassengerWalletArchive.php";
- static String addDrivePayment = "$seferPaymentServer/ride/payment/add.php";
- static String addSeferWallet = "$seferPaymentServer/ride/seferWallet/add.php";
+ static String addDrivePayment = "$paymentServer/ride/payment/add.php";
+ static String addSeferWallet = "$paymentServer/ride/seferWallet/add.php";
static String addPassengersWallet = "$wallet/add.php";
static String deletePassengersWallet = "$wallet/delete.php";
static String updatePassengersWallet = "$wallet/update.php";
@@ -92,80 +77,79 @@ class AppLink {
static String getPhones = "$server/ride/egyptPhones/get.php";
////=======================cancelRide===================
- static String ride = '$server/ride';
- static String addCancelRideFromPassenger = "$server/ride/cancelRide/add.php";
- static String cancelRide = "$server/ride/cancelRide/get.php";
+ // static String ride = '$server/ride';
+ static String addCancelRideFromPassenger = "$ride/cancelRide/add.php";
+ static String cancelRide = "$ride/cancelRide/get.php";
//-----------------ridessss------------------
- static String addRides = "$ride/rides/add.php";
- static String getRides = "$endPoint/ride/rides/get.php";
- static String getRideOrderID = "$endPoint/ride/rides/getRideOrderID.php";
- static String getRideStatus = "$endPoint/ride/rides/getRideStatus.php";
- static String getRideStatusBegin =
- "$endPoint/ride/rides/getRideStatusBegin.php";
+ static String addRides = "$ride/ride/rides/add.php";
+ static String getRides = "$ride/ride/rides/get.php";
+ static String getRideOrderID = "$ride/ride/rides/getRideOrderID.php";
+ static String getRideStatus = "$ride/ride/rides/getRideStatus.php";
+ static String getRideStatusBegin = "$ride/ride/rides/getRideStatusBegin.php";
static String getRideStatusFromStartApp =
- "$ride/rides/getRideStatusFromStartApp.php";
- static String updateRides = "$server/ride/rides/update.php";
+ "$server/ride/rides/getRideStatusFromStartApp.php";
+ static String updateRides = "$ride/ride/rides/update.php";
static String updateStausFromSpeed =
- "$server/ride/rides/updateStausFromSpeed.php";
- static String deleteRides = "$server/ride/rides/delete.php";
+ "$ride/ride/rides/updateStausFromSpeed.php";
+ static String deleteRides = "$ride/ride/rides/delete.php";
//-----------------DriverPayment------------------
- static String adddriverScam = "$ride/driver_scam/add.php";
- static String getdriverScam = "$ride/driver_scam/get.php";
+ static String adddriverScam = "$server/driver_scam/add.php";
+ static String getdriverScam = "$server/ride/driver_scam/get.php";
/////////---getKazanPercent===////////////
- static String getKazanPercent = "$ride/kazan/get.php";
- static String addKazanPercent = "$ride/kazan/add.php";
+ static String getKazanPercent = "$server/ride/kazan/get.php";
+ static String addKazanPercent = "$server/ride/kazan/add.php";
////-----------------DriverPayment------------------
- static String addDriverpayment = "$seferPaymentServer/ride/payment/add.php";
+ static String addDriverpayment = "$paymentServer/ride/payment/add.php";
static String addDriverPaymentPoints =
- "$seferPaymentServer/ride/driverPayment/add.php";
+ "$paymentServer/ride/driverPayment/add.php";
static String addPaymentTokenPassenger =
- "$seferPaymentServer/ride/passengerWallet/addPaymentTokenPassenger.php";
+ "$paymentServer/ride/passengerWallet/addPaymentTokenPassenger.php";
static String addPaymentTokenDriver =
- "$seferPaymentServer/ride/driverWallet/addPaymentToken.php";
+ "$paymentServer/ride/driverWallet/addPaymentToken.php";
static String getDriverPaymentPoints =
- "$seferPaymentServer/ride/driverWallet/get.php";
+ "$paymentServer/ride/driverWallet/get.php";
static String payWithEcashPassenger =
- "$seferPaymentServer/ride/ecash/passenger/payWithEcash.php";
+ "$paymentServer/ride/ecash/passenger/payWithEcash.php";
static String payWithMTNConfirm =
- "$seferPaymentServer/ride/mtn/passenger/mtn_confirm.php";
+ "$paymentServer/ride/mtn/passenger/mtn_confirm.php";
static String payWithMTNStart =
- "$seferPaymentServer/ride/mtn/passenger/mtn_start.php";
+ "$paymentServer/ride/mtn/passenger/mtn_start.php";
static String payWithSyriatelConfirm =
- "$seferPaymentServer/ride/syriatel/passenger/confirm_payment.php";
+ "$paymentServer/ride/syriatel/passenger/confirm_payment.php";
static String payWithSyriatelStart =
- "$seferPaymentServer/ride/syriatel/passenger/start_payment.php";
- static String getDriverpaymentToday =
- "$seferPaymentServer/ride/payment/get.php";
- static String getCountRide =
- "$seferPaymentServer/ride/payment/getCountRide.php";
+ "$paymentServer/ride/syriatel/passenger/start_payment.php";
+ static String getDriverpaymentToday = "$paymentServer/ride/payment/get.php";
+ static String getCountRide = "$paymentServer/ride/payment/getCountRide.php";
static String getAllPaymentFromRide =
- "$seferPaymentServer/ride/payment/getAllPayment.php";
+ "$paymentServer/ride/payment/getAllPayment.php";
static String getAllPaymentVisa =
- "$seferPaymentServer/ride/payment/getAllPaymentVisa.php";
+ "$paymentServer/ride/payment/getAllPaymentVisa.php";
//-----------------Passenger NotificationCaptain------------------
static String addNotificationPassenger =
- "$ride/notificationPassenger/add.php";
+ "$server/ride/notificationPassenger/add.php";
static String getNotificationPassenger =
- "$ride/notificationPassenger/get.php";
+ "$server/ride/notificationPassenger/get.php";
static String updateNotificationPassenger =
- "$ride/notificationPassenger/update.php";
+ "$server/ride/notificationPassenger/update.php";
//-----------------Driver NotificationCaptain------------------
- static String addNotificationCaptain = "$ride/notificationCaptain/add.php";
+ static String addNotificationCaptain =
+ "$server/ride/notificationCaptain/add.php";
static String addWaitingRide =
"$server/ride/notificationCaptain/addWaitingRide.php";
static String updateWaitingTrip =
"$server/ride/notificationCaptain/updateWaitingTrip.php";
static String getRideWaiting =
"$endPoint/ride/notificationCaptain/getRideWaiting.php";
- static String getNotificationCaptain = "$ride/notificationCaptain/get.php";
+ static String getNotificationCaptain =
+ "$server/ride/notificationCaptain/get.php";
static String updateNotificationCaptain =
- "$ride/notificationCaptain/update.php";
+ "$server/ride/notificationCaptain/update.php";
static String deleteNotificationCaptain =
- "$ride/notificationCaptain/delete.php";
+ "$server/ride/notificationCaptain/delete.php";
//-----------------invitor------------------
static String addInviteDriver = "$server/ride/invitor/add.php";
@@ -178,70 +162,70 @@ class AppLink {
static String updatePassengerGift =
"$server/ride/invitor/updatePassengerGift.php";
//-----------------Api Key------------------
- static String addApiKey = "$ride/apiKey/add.php";
- static String getApiKey = "$ride/apiKey/get.php";
+ static String addApiKey = "$server/ride/apiKey/add.php";
+ static String getApiKey = "$server/ride/apiKey/get.php";
static String getCnMap = "$server/auth/cnMap.php";
- static String updateApiKey = "$ride/apiKey/update.php";
- static String deleteApiKey = "$ride/apiKey/delete.php";
- static String getPlacesSyria = "$ride/places_syria/get.php";
+ static String updateApiKey = "$server/ride/apiKey/update.php";
+ static String deleteApiKey = "$server/ride/apiKey/delete.php";
+ static String getPlacesSyria = "$server/ride/places_syria/get.php";
//-----------------Feed Back------------------
- static String addFeedBack = "$ride/feedBack/add.php";
- static String add_solve_all = "$ride/feedBack/add_solve_all.php";
- static String uploadAudio = "$ride/feedBack/upload_audio.php";
- static String getFeedBack = "$ride/feedBack/get.php";
- static String updateFeedBack = "$ride/feedBack/updateFeedBack.php";
+ static String addFeedBack = "$server/ride/feedBack/add.php";
+ static String add_solve_all = "$server/ride/feedBack/add_solve_all.php";
+ static String uploadAudio = "$server/ride/feedBack/upload_audio.php";
+ static String getFeedBack = "$server/ride/feedBack/get.php";
+ static String updateFeedBack = "$server/ride/feedBack/updateFeedBack.php";
//-----------------Tips------------------
- static String addTips = "$ride/tips/add.php";
- static String getTips = "$ride/tips/get.php";
- static String updateTips = "$ride/tips/update.php";
+ static String addTips = "$server/ride/tips/add.php";
+ static String getTips = "$server/ride/tips/get.php";
+ static String updateTips = "$server/ride/tips/update.php";
//-----------------Help Center------------------
- static String addhelpCenter = "$ride/helpCenter/add.php";
- static String gethelpCenter = "$ride/helpCenter/get.php";
- static String getByIdhelpCenter = "$ride/helpCenter/getById.php";
- static String updatehelpCenter = "$ride/helpCenter/update.php";
- static String deletehelpCenter = "$ride/helpCenter/delete.php";
+ static String addhelpCenter = "$server/ride/helpCenter/add.php";
+ static String gethelpCenter = "$server/ride/helpCenter/get.php";
+ static String getByIdhelpCenter = "$server/ride/helpCenter/getById.php";
+ static String updatehelpCenter = "$server/ride/helpCenter/update.php";
+ static String deletehelpCenter = "$server/ride/helpCenter/delete.php";
//-----------------license------------------
- static String addLicense = "$ride/license/add.php";
- static String getLicense = "$ride/license/get.php";
- static String updateLicense = "$ride/license/updateFeedBack.php";
+ static String addLicense = "$server/ride/license/add.php";
+ static String getLicense = "$server/ride/license/get.php";
+ static String updateLicense = "$server/ride/license/updateFeedBack.php";
//-----------------RegisrationCar------------------
- static String addRegisrationCar = "$ride/RegisrationCar/add.php";
+ static String addRegisrationCar = "$server/ride/RegisrationCar/add.php";
static String getRegisrationCar =
- "${box.read(BoxName.serverChosen)}/ride/RegisrationCar/get.php";
+ "${box.read(BoxName.serverChosen)}/server/ride/RegisrationCar/get.php";
static String selectDriverAndCarForMishwariTrip =
- "$ride/RegisrationCar/selectDriverAndCarForMishwariTrip.php";
- static String updateRegisrationCar = "$ride/RegisrationCar/update.php";
+ "$server/ride/RegisrationCar/selectDriverAndCarForMishwariTrip.php";
+ static String updateRegisrationCar = "$server/ride/RegisrationCar/update.php";
//-----------------mishwari------------------
- static String addMishwari = "$ride/mishwari/add.php";
- static String cancelMishwari = "$ride/mishwari/cancel.php";
- static String getMishwari = "$ride/mishwari/get.php";
+ static String addMishwari = "$server/ride/mishwari/add.php";
+ static String cancelMishwari = "$server/ride/mishwari/cancel.php";
+ static String getMishwari = "$server/ride/mishwari/get.php";
//-----------------DriverOrder------------------
- static String addDriverOrder = "$ride/driver_order/add.php";
- static String getDriverOrder = "$ride/driver_order/get.php";
+ static String addDriverOrder = "$server/ride/driver_order/add.php";
+ static String getDriverOrder = "$server/ride/driver_order/get.php";
static String getOrderCancelStatus =
- "$ride/driver_order/getOrderCancelStatus.php";
- static String updateDriverOrder = "$ride/driver_order/update.php";
- static String deleteDriverOrder = "$ride/driver_order/delete.php";
+ "$server/ride/driver_order/getOrderCancelStatus.php";
+ static String updateDriverOrder = "$server/ride/driver_order/update.php";
+ static String deleteDriverOrder = "$server/ride/driver_order/delete.php";
// =====================================
- 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";
+ static String addRateToPassenger = "$server/ride/rate/add.php";
+ static String savePlacesServer = "$server/ride/places/add.php";
+ static String getapiKey = "$server/ride/apiKey/get.php";
+ static String addRateToDriver = "$server/ride/rate/addRateToDriver.php";
+ static String getDriverRate = "$server/ride/rate/getDriverRate.php";
+ static String getPassengerRate = "$server/ride/rate/getPassengerRate.php";
////////////////emails ============//
static String sendEmailToPassengerForTripDetails =
- "$ride/rides/emailToPassengerTripDetail.php";
+ "$server/ride/rides/emailToPassengerTripDetail.php";
// ===========================================
static String pathImage = "$server/upload/types/";
@@ -255,11 +239,11 @@ class AppLink {
static String uploadEgypt = "$server/uploadEgypt.php";
//==================certifcate==========
- static String location = '${box.read(BoxName.serverChosen)}/ride/location';
+ // static String location = '${box.read(BoxName.serverChosen)}/ride/location';
static String getCarsLocationByPassenger = "$location/get.php";
static String getLocationAreaLinks =
- '$ride/location/get_location_area_links.php';
+ '$server/ride/location/get_location_area_links.php';
static String addpassengerLocation = "$location/addpassengerLocation.php";
static String getCarsLocationByPassengerSpeed = "$location/getSpeed.php";
static String getCarsLocationByPassengerComfort = "$location/getComfort.php";
@@ -268,6 +252,8 @@ class AppLink {
"$location/getElectric.php";
static String getCarsLocationByPassengerPinkBike =
"$location/getPinkBike.php";
+ static String getCarsLocationByPassengerVan =
+ "$location/getCarsLocationByPassengerVan.php";
static String getCarsLocationByPassengerDelivery =
"$location/getDelivery.php";
static String getLocationParents = "$location/getLocationParents.php";
@@ -275,12 +261,12 @@ class AppLink {
"$location/getFemalDriver.php";
static String getDriverCarsLocationToPassengerAfterApplied =
"$location/getDriverCarsLocationToPassengerAfterApplied.php";
- static String addCarsLocationByPassenger = "$location/add.php";
- static String deleteCarsLocationByPassenger = "$location/delete.php";
- static String updateCarsLocationByPassenger = "$location/update.php";
- static String getTotalDriverDuration = "$location/getTotalDriverDuration.php";
- static String getTotalDriverDurationToday =
- "$location/getTotalDriverDurationToday.php";
+// static String addCarsLocationByPassenger = "$location/add.php";
+// static String deleteCarsLocationByPassenger = "$location/delete.php";
+// static String updateCarsLocationByPassenger = "$location/update.php";
+// static String getTotalDriverDuration = "$location/getTotalDriverDuration.php";
+// static String getTotalDriverDurationToday =
+ // "$location/getTotalDriverDurationToday.php";
//==================Blog=============
static String profile = '$server/ride/profile';
@@ -295,7 +281,7 @@ class AppLink {
static String auth = '$server/auth';
static String login = "$auth/login.php";
static String loginJwtRider = "$server/login.php";
- static String loginJwtWalletRider = "$seferPaymentServer/loginWallet.php";
+ static String loginJwtWalletRider = "$server/loginWallet.php";
static String loginFirstTime = "$server/loginFirstTime.php";
static String getTesterApp = "$auth/Tester/getTesterApp.php";
static String updateTesterApp = "$auth/Tester/updateTesterApp.php";
diff --git a/lib/controller/auth/login_controller.dart b/lib/controller/auth/login_controller.dart
index c2847e6..68f1585 100644
--- a/lib/controller/auth/login_controller.dart
+++ b/lib/controller/auth/login_controller.dart
@@ -87,34 +87,70 @@ class LoginController extends GetxController {
update();
}
- getJwtWallet() async {
- final random = Random();
+ Future getJwtWallet() async {
+ try {
+ final random = Random();
- if (random.nextBool()) {
- await SecurityHelper.performSecurityChecks();
- } else {
- await SecurityChecks.isDeviceRootedFromNative(Get.context!);
+ // Perform security check randomly
+ if (random.nextBool()) {
+ await SecurityHelper.performSecurityChecks();
+ } else {
+ await SecurityChecks.isDeviceRootedFromNative(Get.context!);
+ }
+
+ String fingerPrint = await DeviceHelper.getDeviceFingerprint();
+ final dev = GetPlatform.isAndroid ? 'android' : 'ios';
+
+ var payload = {
+ 'id': box.read(BoxName.passengerID),
+ 'password': AK.passnpassenger,
+ 'aud': '${AK.allowed}$dev',
+ 'fingerPrint': fingerPrint,
+ };
+
+ var response = await http.post(
+ Uri.parse(AppLink.loginJwtWalletRider),
+ body: payload,
+ );
+
+ // Handle bad responses
+ if (response.statusCode != 200) {
+ _showJwtErrorDialog(
+ "حدث خطأ أثناء الاتصال بالخادم. يرجى المحاولة مرة أخرى.");
+ throw Exception("JWT request failed");
+ }
+
+ var data = jsonDecode(response.body);
+
+ // Validate JWT response structure
+ if (!data.containsKey('jwt') || !data.containsKey('hmac')) {
+ _showJwtErrorDialog("تعذّر التحقق من الأمان. يرجى إعادة المحاولة.");
+ throw Exception("Invalid JWT response format");
+ }
+
+ // Save HMAC locally
+ await box.write(BoxName.hmac, data['hmac']);
+
+ return data['jwt'].toString();
+ } catch (e) {
+ _showJwtErrorDialog("حدث خلل غير متوقع. يرجى المحاولة مرة أخرى.");
+ rethrow;
}
+ }
- String fingerPrint = await DeviceHelper.getDeviceFingerprint();
- // print('fingerPrint: ${fingerPrint}');
- dev = Platform.isAndroid ? 'android' : 'ios';
- var payload = {
- 'id': box.read(BoxName.passengerID),
- 'password': AK.passnpassenger,
- 'aud': '${AK.allowed}$dev',
- 'fingerPrint': fingerPrint
- };
- var response1 = await http.post(
- Uri.parse(AppLink.loginJwtWalletRider),
- body: payload,
+ void _showJwtErrorDialog(String message) {
+ if (Get.context == null) return;
+
+ Get.defaultDialog(
+ title: "خطأ في الاتصال",
+ middleText: message,
+ textConfirm: "إعادة المحاولة",
+ confirmTextColor: Colors.white,
+ onConfirm: () {
+ Get.back();
+ getJwtWallet();
+ },
);
- await box.write(BoxName.hmac, jsonDecode(response1.body)['hmac']);
- // Log.print('jsonDecoeded[hmac]: ${jsonDecoeded['hmac']}');
- // Log.print('req: ${response1.request}');
- // Log.print('response: ${response1.body}');
- // Log.print('payload: ${payload}');
- return jsonDecode(response1.body)['jwt'].toString();
}
getJWT() async {
diff --git a/lib/controller/auth/otp_controller.dart b/lib/controller/auth/otp_controller.dart
index 185b2a5..6e6b06f 100644
--- a/lib/controller/auth/otp_controller.dart
+++ b/lib/controller/auth/otp_controller.dart
@@ -19,21 +19,78 @@ class PhoneAuthHelper {
static final String _verifyOtpUrl = '${_baseUrl}verifyOtp.php';
static final String _registerUrl = '${_baseUrl}register_passenger.php';
+ static String formatSyrianPhone(String phone) {
+ // Remove spaces, symbols, +, -, ()
+ phone = phone.replaceAll(RegExp(r'[ \-\(\)\+]'), '').trim();
+
+ // Normalize 00963 → 963
+ if (phone.startsWith('00963')) {
+ phone = phone.replaceFirst('00963', '963');
+ }
+
+ // Normalize 0963 → 963
+ if (phone.startsWith('0963')) {
+ phone = phone.replaceFirst('0963', '963');
+ }
+
+ // NEW: Fix 96309xxxx → 9639xxxx
+ if (phone.startsWith('96309')) {
+ phone = '9639' + phone.substring(5); // remove the "0" after 963
+ }
+
+ // If starts with 9630 → correct to 9639
+ if (phone.startsWith('9630')) {
+ phone = '9639' + phone.substring(4);
+ }
+
+ // If already in correct format: 9639xxxxxxxx
+ if (phone.startsWith('9639') && phone.length == 12) {
+ return phone;
+ }
+
+ // If starts with 963 but missing the 9
+ if (phone.startsWith('963') && phone.length > 3) {
+ // Ensure it begins with 9639
+ if (!phone.startsWith('9639')) {
+ phone = '9639' + phone.substring(3);
+ }
+ return phone;
+ }
+
+ // If starts with 09xxxxxxxx → 9639xxxxxxxx
+ if (phone.startsWith('09')) {
+ return '963' + phone.substring(1);
+ }
+
+ // If 9xxxxxxxx (9 digits)
+ if (phone.startsWith('9') && phone.length == 9) {
+ return '963' + phone;
+ }
+
+ // If starts with incorrect 0xxxxxxx → assume Syrian and fix
+ if (phone.startsWith('0') && phone.length == 10) {
+ return '963' + phone.substring(1);
+ }
+
+ return phone;
+ }
+
/// Sends an OTP to the provided phone number.
static Future sendOtp(String phoneNumber) async {
try {
- // Log.print('_sendOtpUrl: ${_sendOtpUrl}');
- // Log.print('phoneNumber: ${phoneNumber}');
+ // إصلاح الرقم قبل الإرسال
+ final fixedPhone = formatSyrianPhone(phoneNumber);
final response = await CRUD().post(
link: _sendOtpUrl,
- payload: {'receiver': phoneNumber},
+ payload: {'receiver': fixedPhone}, // ← ← استخدام الرقم المُعدّل
);
- // Log.print('response: ${response}');
+
if (response != 'failure') {
- final data = (response);
+ final data = response;
+
if (data['status'] == 'success') {
- mySnackbarSuccess('An OTP has been sent to your WhatsApp number.'.tr);
+ mySnackbarSuccess('An OTP has been sent to your number.'.tr);
return true;
} else {
mySnackeBarError(data['message'] ?? 'Failed to send OTP.');
@@ -44,19 +101,20 @@ class PhoneAuthHelper {
return false;
}
} catch (e) {
- // Log.print('e: ${e}');
- // mySnackeBarError('An error occurred: $e');
return false;
}
}
/// Verifies the OTP and logs the user in.
- static Future verifyOtp(String phoneNumber, String otp) async {
+ static Future verifyOtp(String phoneNumber) async {
try {
+ final fixedPhone = formatSyrianPhone(phoneNumber);
final response = await CRUD().post(
link: _verifyOtpUrl,
- payload: {'phone_number': phoneNumber, 'otp': otp},
+ payload: {
+ 'phone_number': fixedPhone,
+ },
);
if (response != 'failure') {
@@ -96,13 +154,12 @@ class PhoneAuthHelper {
'passengerID': box.read(BoxName.passengerID).toString(),
"fingerPrint": fingerPrint
});
- await CRUD().post(
- link: "${AppLink.seferPaymentServer}/ride/firebase/add.php",
- payload: {
- 'token': (box.read(BoxName.tokenFCM.toString())),
- 'passengerID': box.read(BoxName.passengerID).toString(),
- "fingerPrint": fingerPrint
- });
+ await CRUD()
+ .post(link: "${AppLink.paymentServer}/ride/firebase/add.php", payload: {
+ 'token': (box.read(BoxName.tokenFCM.toString())),
+ 'passengerID': box.read(BoxName.passengerID).toString(),
+ "fingerPrint": fingerPrint
+ });
}
static Future registerUser({
diff --git a/lib/controller/auth/register_controller.dart b/lib/controller/auth/register_controller.dart
index e39b077..f86eab1 100644
--- a/lib/controller/auth/register_controller.dart
+++ b/lib/controller/auth/register_controller.dart
@@ -222,19 +222,19 @@ class RegisterController extends GetxController {
if (res1 != 'failure') {
//Multi-server signup (moved inside the successful registration check)
- if (AppLink.IntaleqAlexandriaServer != AppLink.IntaleqSyriaServer) {
- List signUp = [
- CRUD().post(
- link: '${AppLink.IntaleqAlexandriaServer}/auth/signup.php',
- payload: payload,
- ),
- CRUD().post(
- link: '${AppLink.IntaleqGizaServer}/auth/signup.php',
- payload: payload,
- )
- ];
- await Future.wait(signUp); // Wait for both sign-ups to complete.
- }
+ // if (AppLink.IntaleqAlexandriaServer != AppLink.IntaleqSyriaServer) {
+ // List signUp = [
+ // CRUD().post(
+ // link: '${AppLink.IntaleqAlexandriaServer}/auth/signup.php',
+ // payload: payload,
+ // ),
+ // CRUD().post(
+ // link: '${AppLink.IntaleqGizaServer}/auth/signup.php',
+ // payload: payload,
+ // )
+ // ];
+ // await Future.wait(signUp); // Wait for both sign-ups to complete.
+ // }
box.write(BoxName.isVerified, '1');
box.write(
@@ -297,19 +297,19 @@ class RegisterController extends GetxController {
);
if (res1 != 'failure') {
- if (AppLink.IntaleqAlexandriaServer != AppLink.IntaleqSyriaServer) {
- List signUp = [
- CRUD().post(
- link: '${AppLink.IntaleqAlexandriaServer}/auth/signup.php',
- payload: payload,
- ),
- CRUD().post(
- link: '${AppLink.IntaleqGizaServer}/auth/signup.php',
- payload: payload,
- )
- ];
- await Future.wait(signUp);
- }
+ // if (AppLink.IntaleqAlexandriaServer != AppLink.IntaleqSyriaServer) {
+ // List signUp = [
+ // CRUD().post(
+ // link: '${AppLink.IntaleqAlexandriaServer}/auth/signup.php',
+ // payload: payload,
+ // ),
+ // CRUD().post(
+ // link: '${AppLink.IntaleqGizaServer}/auth/signup.php',
+ // payload: payload,
+ // )
+ // ];
+ // await Future.wait(signUp);
+ // }
box.write(BoxName.isVerified, '1');
box.write(BoxName.isFirstTime, '0');
diff --git a/lib/controller/auth/token_otp_change_controller.dart b/lib/controller/auth/token_otp_change_controller.dart
index dd2634c..3aa0ec2 100644
--- a/lib/controller/auth/token_otp_change_controller.dart
+++ b/lib/controller/auth/token_otp_change_controller.dart
@@ -91,18 +91,8 @@ class OtpVerificationController extends GetxController {
);
if (response != 'failure' && response['status'] == 'success') {
- final fcm = Get.isRegistered()
- ? Get.find()
- : Get.put(FirebaseMessagesController());
-
- // await fcm.sendNotificationToDriverMAP(
- // 'token change',
- // 'change device'.tr,
- // ptoken.toString(),
- // [],
- // 'cancel',
- // );
await NotificationService.sendNotification(
+ category: 'token change',
target: ptoken.toString(),
title: 'token change'.tr,
body: 'change device'.tr,
@@ -110,21 +100,7 @@ class OtpVerificationController extends GetxController {
tone: 'cancel',
driverList: [],
);
- await CRUD().post(
- link: "${AppLink.seferPaymentServer}/ride/firebase/add.php",
- payload: {
- 'token': (box.read(BoxName.tokenFCM.toString())),
- 'passengerID': box.read(BoxName.passengerID).toString(),
- "fingerPrint": fingerPrint.toString(),
- });
- // CRUD().post(
- // link:
- // '${AppLink.seferPaymentServer}/auth/token/update_passenger_token.php',
- // payload: {
- // 'token': box.read(BoxName.tokenFCM).toString(),
- // 'fingerPrint': fingerPrint.toString(),
- // 'passengerID': box.read(BoxName.passengerID).toString(),
- // });
+
Get.offAll(() => const MapPagePassenger());
} else {
Get.snackbar('Verification Failed', 'OTP is incorrect or expired');
diff --git a/lib/controller/firebase/firbase_messge.dart b/lib/controller/firebase/firbase_messge.dart
index 126d940..6f27a5d 100644
--- a/lib/controller/firebase/firbase_messge.dart
+++ b/lib/controller/firebase/firbase_messge.dart
@@ -1,20 +1,15 @@
import 'dart:convert';
import 'dart:io';
-import 'package:Intaleq/controller/functions/encrypt_decrypt.dart';
+import 'package:Intaleq/views/home/HomePage/trip_monitor/trip_link_monitor.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
-import 'package:http/http.dart' as http;
import 'package:Intaleq/controller/functions/toast.dart';
import 'package:Intaleq/views/widgets/elevated_btn.dart';
-import '../../constant/api_key.dart';
import '../../constant/box_name.dart';
import '../../constant/colors.dart';
-import '../../constant/links.dart';
import '../../constant/style.dart';
-import '../../constant/table_names.dart';
-import '../../env/env.dart';
import '../../main.dart';
import '../../print.dart';
import '../../views/Rate/rate_captain.dart';
@@ -23,9 +18,7 @@ import '../../views/home/profile/promos_passenger_page.dart';
import '../auth/google_sign.dart';
import '../functions/audio_record1.dart';
import '../home/map_passenger_controller.dart';
-import 'access_token.dart';
import 'local_notification.dart';
-import 'notification_service.dart';
class FirebaseMessagesController extends GetxController {
final fcmToken = FirebaseMessaging.instance;
@@ -76,9 +69,13 @@ class FirebaseMessagesController extends GetxController {
Future getToken() async {
fcmToken.getToken().then((token) {
- // Log.print('fcmToken: ${token}');
+ Log.print('fcmToken: ${token}');
box.write(BoxName.tokenFCM, (token.toString()));
});
+ // 🔹 الاشتراك في topic
+ await fcmToken
+ .subscribeToTopic("passengers"); // أو "users" حسب نوع المستخدم
+ print("Subscribed to 'passengers' topic ✅");
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
// If the app is in the background or terminated, show a system tray message
@@ -104,115 +101,106 @@ class FirebaseMessagesController extends GetxController {
}
Future fireBaseTitles(RemoteMessage message) async {
- if (message.notification!.title! == 'Order'.tr) {
+ // [!! تعديل !!]
+ // اقرأ "النوع" من حمولة البيانات، وليس من العنوان
+ String category = message.data['category'] ?? '';
+
+ // اقرأ العنوان (للعرض)
+ String title = message.notification?.title ?? '';
+ String body = message.notification?.body ?? '';
+
+ if (category == 'ORDER') {
+ // <-- مثال: كان 'Order'.tr
Log.print('message: ${message}');
if (Platform.isAndroid) {
- notificationController.showNotification(
- 'Order'.tr, message.notification!.body!, 'Order');
+ notificationController.showNotification(title, body, 'Order');
}
- } else if (message.notification!.title! == 'Accepted Ride') {
- if (Platform.isAndroid) {
- notificationController.showNotification(
- 'Accepted Ride'.tr, 'Driver Accepted the Ride for You'.tr, 'ding');
+ }
+
+ // ... داخل معالج الإشعارات في تطبيق الراكب ...
+ else if (category == 'Accepted Ride') {
+ // <-- كان 'Accepted Ride'
+ var driverListJson = message.data['driverList'];
+ if (driverListJson != null) {
+ var myList = jsonDecode(driverListJson) as List;
+ final controller = Get.find();
+ // controller.currentRideState.value = RideState.driverApplied;
+ await controller.processRideAcceptance(
+ driverIdFromFCM: myList[0].toString(),
+ rideIdFromFCM: myList[3].toString());
+ } else {
+ Log.print('❌ خطأ: RIDE_ACCEPTED وصل بدون driverList');
}
- var passengerList = message.data['passengerList'];
-
- var myList = jsonDecode(passengerList) as List;
- Log.print('myList: ${myList}');
- final controller = Get.find();
- controller.driverId = myList[0].toString();
- // assume rideId lives at index 2 in your list:
- controller.rideId = myList[3].toString();
-
- controller
- ..statusRide = 'Apply'
- ..isSearchingWindow = false
- ..update();
- await controller.rideAppliedFromDriver(true);
-
- // driverAppliedTripSnakBar();
- } else if (message.notification!.title! == 'Promo'.tr) {
+ } else if (category == 'Promo') {
+ // <-- كان 'Promo'.tr
if (Platform.isAndroid) {
- notificationController.showNotification(
- 'Promo', 'Show latest promo'.tr, 'promo');
+ notificationController.showNotification(title, body, 'promo');
}
Get.to(const PromosPassengerPage());
- } else if (message.notification!.title! == 'Trip Monitoring'.tr) {
+ } else if (category == 'Trip Monitoring') {
+ // <-- كان 'Trip Monitoring'.tr
if (Platform.isAndroid) {
- notificationController.showNotification(
- 'Trip Monitoring'.tr, '', 'iphone_ringtone');
+ notificationController.showNotification(title, body, 'iphone_ringtone');
}
var myListString = message.data['DriverList'];
var myList = jsonDecode(myListString) as List;
- Get.toNamed('/tripmonitor', arguments: {
+ Get.to(() => TripMonitor(), arguments: {
'rideId': myList[0].toString(),
'driverId': myList[1].toString(),
});
- } else if (message.notification!.title! == 'token change'.tr) {
+ } else if (category == 'token change') {
+ // <-- كان 'token change'.tr
if (Platform.isAndroid) {
- notificationController.showNotification(
- 'token change'.tr, 'token change'.tr, 'cancel');
+ notificationController.showNotification(title, body, 'cancel');
}
GoogleSignInHelper.signOut();
- } else if (message.notification!.title! ==
- 'Driver Is Going To Passenger'.tr) {
+ } else if (category == 'Driver Is Going To Passenger') {
+ // <-- كان 'Driver Is Going To Passenger'
Get.find().isDriverInPassengerWay = true;
Get.find().update();
if (Platform.isAndroid) {
- notificationController.showNotification('Driver is Going To You'.tr,
- 'Please stay on the picked point.'.tr, 'tone1');
+ notificationController.showNotification(title, body, 'tone1');
}
- // Get.snackbar('Driver is Going To Passenger', '',
- // backgroundColor: AppColor.greenColor);
- } else if (message.notification!.title! == 'message From passenger') {
+ } else if (category == 'message From passenger') {
+ // <-- كان 'message From passenger'
if (Platform.isAndroid) {
- notificationController.showNotification(
- 'message From passenger'.tr, ''.tr, 'ding');
+ notificationController.showNotification(title, body, 'ding');
}
- passengerDialog(message.notification!.body!);
-
+ passengerDialog(body);
update();
- } else if (message.notification!.title! == 'message From Driver') {
+ } else if (category == 'message From Driver') {
+ // <-- كان 'message From Driver'
if (Platform.isAndroid) {
- notificationController.showNotification(
- 'message From Driver'.tr, ''.tr, 'ding');
+ notificationController.showNotification(title, body, 'ding');
}
- passengerDialog(message.notification!.body!);
-
+ passengerDialog(body);
update();
- } else if (message.notification!.title! == 'Trip is Begin') {
+ } else if (category == 'Trip is Begin') {
+ // <-- كان 'Trip is Begin'
+ Log.print('[FCM] استقبل إشعار "TRIP_BEGUN".');
+ final controller = Get.find();
+ controller.processRideBegin();
+ } else if (category == 'Hi ,I will go now') {
+ // <-- كان 'Hi ,I will go now'.tr
if (Platform.isAndroid) {
- notificationController.showNotification(
- 'Trip is Begin'.tr, ''.tr, 'start');
- }
- Get.find().getBeginRideFromDriver();
- // Get.snackbar('RideIsBegin', '', backgroundColor: AppColor.greenColor);
- box.write(BoxName.passengerWalletTotal, '0');
- update();
- } else if (message.notification!.title! == 'Hi ,I will go now'.tr) {
- // Get.snackbar('Hi ,I will go now', '',
- // backgroundColor: AppColor.greenColor);
- if (Platform.isAndroid) {
- notificationController.showNotification(
- 'Passenger come to you'.tr, 'Hi ,I will go now'.tr, 'ding');
+ notificationController.showNotification(title, body, 'ding');
}
update();
- } else if (message.notification!.title! == 'Hi ,I Arrive your site'.tr) {
- if (Platform.isAndroid) {
- notificationController.showNotification(
- 'Hi ,I Arrive your site'.tr, ''.tr, 'ding');
- }
- driverArrivePassengerDialoge();
-
- update();
- } else if (message.notification!.title! == "Cancel Trip from driver") {
+ } else if (category == 'Hi ,I Arrive your site') {
+ // <-- كان 'Hi ,I Arrive your site'.tr
+ final controller = Get.find();
+ // if (controller.currentRideState.value == RideState.driverApplied) {
+ Log.print('[FCM] السائق وصل. تغيير الحالة إلى driverArrived');
+ controller.currentRideState.value = RideState.driverArrived;
+ // }
+ } else if (category == 'Cancel Trip from driver') {
+ // <-- كان "Cancel Trip from driver"
Get.back();
if (Platform.isAndroid) {
- notificationController.showNotification("Cancel Trip from driver".tr,
- "We will look for a new driver.\nPlease wait.".tr, 'cancel');
+ notificationController.showNotification(title, body, 'cancel');
}
Get.defaultDialog(
- title: "The driver canceled your ride.".tr,
+ title: "The driver canceled your ride.".tr, // العنوان المترجم للعرض
middleText: "We will look for a new driver.\nPlease wait.".tr,
confirm: MyElevatedButton(
kolor: AppColor.greenColor,
@@ -229,66 +217,42 @@ class FirebaseMessagesController extends GetxController {
onPressed: () {
Get.offAll(() => const MapPagePassenger());
},
- )
- // Get.find()
- // .searchNewDriverAfterRejectingFromDriver();
- );
- } else if (message.notification!.title! == 'Driver Finish Trip'.tr) {
- // الخطوة 1: استقبل البيانات وتحقق من وجودها
+ ));
+ } else if (category == 'Driver Finish Trip') {
+ // <-- كان 'Driver Finish Trip'.tr
final rawData = message.data['DriverList'];
- List driverList = []; // ابدأ بقائمة فارغة كإجراء وقائي
-
- // الخطوة 2: قم بفك تشفير البيانات بأمان
+ List driverList = [];
if (rawData != null && rawData is String) {
try {
driverList = jsonDecode(rawData);
- Log.print('Successfully decoded DriverList: $driverList');
} catch (e) {
Log.print('Error decoding DriverList JSON: $e');
- // اترك القائمة فارغة في حالة حدوث خطأ
}
} else {
Log.print('Error: DriverList data is null or not a String.');
}
- // الخطوة 3: استخدم البيانات فقط إذا كانت القائمة تحتوي على العناصر المطلوبة
- // هذا يمنع خطأ "RangeError" إذا كانت القائمة أقصر من المتوقع
- if (driverList.length >= 4) {
+ if (driverList.length >= 3) {
if (Platform.isAndroid) {
notificationController.showNotification(
- "Driver Finish Trip".tr,
- '${'you will pay to Driver'.tr} ${driverList[3].toString()} \$', // تم تحسين طريقة عرض النص
+ title,
+ '${'you will pay to Driver'.tr} ${driverList[3].toString()} \$',
'tone1');
}
-
Get.find().stopRecording();
-
- if ((double.tryParse(
- box.read(BoxName.passengerWalletTotal).toString()) ??
- 0) <
- 0) {
- box.write(BoxName.passengerWalletTotal, 0);
- }
-
+ // ... (باقي كود المحفظة) ...
Get.find().tripFinishedFromDriver();
-
- 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 Intaleq app'
- .tr,
- 'ding');
-
+ // ... (إشعار "لا تنسى متعلقاتك") ...
Get.to(() => RateDriverFromPassenger(), arguments: {
'driverId': driverList[0].toString(),
'rideId': driverList[1].toString(),
'price': driverList[3].toString()
});
} else {
- Log.print(
- 'Error: Decoded driverList does not have enough elements. Received: $driverList');
- // هنا يمكنك عرض رسالة خطأ للمستخدم إذا لزم الأمر
+ Log.print('Error: TRIP_FINISHED decoded list error.');
}
- } else if (message.notification!.title! == "Finish Monitor".tr) {
+ } else if (category == 'Finish Monitor') {
+ // <-- كان "Finish Monitor".tr
Get.defaultDialog(
titleStyle: AppStyle.title,
title: 'Trip finished '.tr,
@@ -298,69 +262,7 @@ class FirebaseMessagesController extends GetxController {
onPressed: () {
Get.offAll(() => const MapPagePassenger());
}));
- }
- // else if (message.notification!.title! == "Trip Monitoring".tr) {
- // Get.to(() => const TripMonitor());
- // }
- else if (message.notification!.title! == 'Call Income') {
- try {
- var myListString = message.data['DriverList'];
- var driverList = jsonDecode(myListString) as List;
- // if (Platform.isAndroid) {
- if (Platform.isAndroid) {
- notificationController.showNotification(
- 'Call Income'.tr,
- message.notification!.body!,
- 'iphone_ringtone',
- );
- }
- // }
- // Assuming GetMaterialApp is initialized and context is valid for navigation
- // Get.to(() => PassengerCallPage(
- // channelName: driverList[1].toString(),
- // token: driverList[0].toString(),
- // remoteID: driverList[2].toString(),
- // ));
- } catch (e) {}
- } else if (message.notification!.title! == 'Call Income from Driver'.tr) {
- try {
- var myListString = message.data['DriverList'];
- var driverList = jsonDecode(myListString) as List;
- // if (Platform.isAndroid) {
- if (Platform.isAndroid) {
- notificationController.showNotification(
- 'Call Income'.tr,
- message.notification!.body!,
- 'iphone_ringtone',
- );
- }
- // Assuming GetMaterialApp is initialized and context is valid for navigation
- // Get.to(() => PassengerCallPage(
- // channelName: driverList[1].toString(),
- // token: driverList[0].toString(),
- // remoteID: driverList[2].toString(),
- // ));
- } catch (e) {}
- } else if (message.notification!.title! == 'Call End'.tr) {
- try {
- var myListString = message.data['DriverList'];
- var driverList = jsonDecode(myListString) as List;
- if (Platform.isAndroid) {
- notificationController.showNotification(
- 'Call End'.tr,
- message.notification!.body!,
- 'ding',
- );
- }
- // Assuming GetMaterialApp is initialized and context is valid for navigation
- // Get.off(const CallPage());
- } catch (e) {}
- } else if (message.notification!.title! == 'Driver Cancelled Your Trip') {
- // Get.snackbar(
- // 'You will be pay the cost to driver or we will get it from you on next trip'
- // .tr,
- // 'message',
- // backgroundColor: AppColor.redColor);
+ } else if (category == 'Driver Cancelled Your Trip') {
if (Platform.isAndroid) {
notificationController.showNotification(
'Driver Cancelled Your Trip'.tr,
@@ -374,18 +276,10 @@ class FirebaseMessagesController extends GetxController {
Get.find().restCounter();
Get.offAll(() => const MapPagePassenger());
}
- // else if (message.notification!.title! == 'Order Applied') {
- // Get.snackbar(
- // "The order has been accepted by another driver."
- // .tr, // Corrected grammar
- // "Be more mindful next time to avoid dropping orders."
- // .tr, // Improved sentence structure
- // backgroundColor: AppColor.yellowColor,
- // snackPosition: SnackPosition.BOTTOM,
- // );
- // }
+ // ... (باقي الحالات مثل Call Income, Call End, إلخ) ...
+ // ... بنفس الطريقة ...
- else if (message.notification!.title! == 'Order Applied'.tr) {
+ else if (category == 'Order Applied') {
if (Platform.isAndroid) {
notificationController.showNotification(
'The order Accepted by another Driver'.tr,
@@ -395,6 +289,308 @@ class FirebaseMessagesController extends GetxController {
}
}
}
+ // Future fireBaseTitles(RemoteMessage message) async {
+ // if (message.notification!.title! == 'Order'.tr) {
+ // Log.print('message: ${message}');
+ // if (Platform.isAndroid) {
+ // notificationController.showNotification(
+ // 'Order'.tr, message.notification!.body!, 'Order');
+ // }
+ // } else // ... داخل معالج الإشعارات في تطبيق الراكب ...
+
+ // if (message.notification!.title! == 'Accepted Ride') {
+ // // ...
+
+ // // انظر هنا: قمنا بتغيير "passengerList" إلى "driverList"
+ // var driverListJson = message.data['driverList'];
+
+ // // تأكد من أن البيانات ليست null قبل المتابعة
+ // if (driverListJson != null) {
+ // var myList = jsonDecode(driverListJson) as List;
+ // Log.print('myList: ${myList}');
+
+ // final controller = Get.find();
+
+ // // استدعاء الدالة الموحدة الجديدة التي أنشأناها
+ // await controller.processRideAcceptance(
+ // driverIdFromFCM: myList[0].toString(),
+ // rideIdFromFCM: myList[3].toString());
+ // } else {
+ // Log.print(
+ // '❌ خطأ فادح: إشعار "Accepted Ride" وصل بدون بيانات (driverList is null)');
+ // }
+ // } else if (message.notification!.title! == 'Promo'.tr) {
+ // if (Platform.isAndroid) {
+ // notificationController.showNotification(
+ // 'Promo', 'Show latest promo'.tr, 'promo');
+ // }
+ // Get.to(const PromosPassengerPage());
+ // } else if (message.notification!.title! == 'Trip Monitoring'.tr) {
+ // if (Platform.isAndroid) {
+ // notificationController.showNotification(
+ // 'Trip Monitoring'.tr, '', 'iphone_ringtone');
+ // }
+ // var myListString = message.data['DriverList'];
+ // var myList = jsonDecode(myListString) as List;
+ // Get.toNamed('/tripmonitor', arguments: {
+ // 'rideId': myList[0].toString(),
+ // 'driverId': myList[1].toString(),
+ // });
+ // } else if (message.notification!.title! == 'token change'.tr) {
+ // if (Platform.isAndroid) {
+ // notificationController.showNotification(
+ // 'token change'.tr, 'token change'.tr, 'cancel');
+ // }
+ // GoogleSignInHelper.signOut();
+ // } else if (message.notification!.title! == 'Driver Is Going To Passenger') {
+ // Get.find().isDriverInPassengerWay = true;
+ // Get.find().update();
+ // if (Platform.isAndroid) {
+ // notificationController.showNotification('Driver is Going To You'.tr,
+ // 'Please stay on the picked point.'.tr, 'tone1');
+ // }
+ // // Get.snackbar('Driver is Going To Passenger', '',
+ // // backgroundColor: AppColor.greenColor);
+ // } else if (message.notification!.title! == 'message From passenger') {
+ // if (Platform.isAndroid) {
+ // notificationController.showNotification(
+ // 'message From passenger'.tr, ''.tr, 'ding');
+ // }
+ // passengerDialog(message.notification!.body!);
+
+ // update();
+ // } else if (message.notification!.title! == 'message From Driver') {
+ // if (Platform.isAndroid) {
+ // notificationController.showNotification(
+ // 'message From Driver'.tr, ''.tr, 'ding');
+ // }
+ // passengerDialog(message.notification!.body!);
+
+ // update();
+ // } else // (هذا الكود في معالج الإشعارات لديك)
+ // if (message.notification!.title! == 'Trip is Begin') {
+ // Log.print('[FCM] استقبل إشعار "Trip is Begin".');
+
+ // // (تم حذف الإشعار المحلي من هنا، نُقل إلى الدالة الموحدة)
+
+ // final controller = Get.find();
+
+ // // استدعاء حارس البوابة الجديد والآمن
+ // controller.processRideBegin();
+
+ // // (تم حذف كل الأوامر التالية من هنا)
+ // // Get.find().getBeginRideFromDriver();
+ // // box.write(BoxName.passengerWalletTotal, '0');
+ // // update();
+ // } else if (message.notification!.title! == 'Hi ,I will go now'.tr) {
+ // // Get.snackbar('Hi ,I will go now', '',
+ // // backgroundColor: AppColor.greenColor);
+ // if (Platform.isAndroid) {
+ // notificationController.showNotification(
+ // 'Passenger come to you'.tr, 'Hi ,I will go now'.tr, 'ding');
+ // }
+ // update();
+ // } // ... داخل معالج الإشعارات (FCM Handler) ...
+ // if (message.notification!.title! == 'Hi ,I Arrive your site'.tr) {
+ // final controller = Get.find();
+
+ // // 1. التأكد أننا في الحالة الصحيحة (السائق كان في الطريق)
+ // if (controller.currentRideState.value == RideState.driverApplied) {
+ // Log.print('[FCM] السائق وصل. تغيير الحالة إلى driverArrived');
+
+ // // 2. تغيير الحالة فقط!
+ // controller.currentRideState.value = RideState.driverArrived;
+ // }
+ // } else if (message.notification!.title! == "Cancel Trip from driver") {
+ // Get.back();
+ // if (Platform.isAndroid) {
+ // notificationController.showNotification("Cancel Trip from driver".tr,
+ // "We will look for a new driver.\nPlease wait.".tr, 'cancel');
+ // }
+ // Get.defaultDialog(
+ // title: "The driver canceled your ride.".tr,
+ // middleText: "We will look for a new driver.\nPlease wait.".tr,
+ // confirm: MyElevatedButton(
+ // kolor: AppColor.greenColor,
+ // title: 'Ok'.tr,
+ // onPressed: () async {
+ // Get.back();
+ // await Get.find()
+ // .reSearchAfterCanceledFromDriver();
+ // },
+ // ),
+ // cancel: MyElevatedButton(
+ // title: 'Cancel'.tr,
+ // kolor: AppColor.redColor,
+ // onPressed: () {
+ // Get.offAll(() => const MapPagePassenger());
+ // },
+ // )
+ // // Get.find()
+ // // .searchNewDriverAfterRejectingFromDriver();
+ // );
+ // } else if (message.notification!.title! == 'Driver Finish Trip'.tr) {
+ // // الخطوة 1: استقبل البيانات وتحقق من وجودها
+ // final rawData = message.data['DriverList'];
+ // List driverList = []; // ابدأ بقائمة فارغة كإجراء وقائي
+
+ // // الخطوة 2: قم بفك تشفير البيانات بأمان
+ // if (rawData != null && rawData is String) {
+ // try {
+ // driverList = jsonDecode(rawData);
+ // Log.print('Successfully decoded DriverList: $driverList');
+ // } catch (e) {
+ // Log.print('Error decoding DriverList JSON: $e');
+ // // اترك القائمة فارغة في حالة حدوث خطأ
+ // }
+ // } else {
+ // Log.print('Error: DriverList data is null or not a String.');
+ // }
+
+ // // الخطوة 3: استخدم البيانات فقط إذا كانت القائمة تحتوي على العناصر المطلوبة
+ // // هذا يمنع خطأ "RangeError" إذا كانت القائمة أقصر من المتوقع
+ // if (driverList.length >= 4) {
+ // if (Platform.isAndroid) {
+ // notificationController.showNotification(
+ // "Driver Finish Trip".tr,
+ // '${'you will pay to Driver'.tr} ${driverList[3].toString()} \$', // تم تحسين طريقة عرض النص
+ // 'tone1');
+ // }
+
+ // Get.find().stopRecording();
+
+ // if ((double.tryParse(
+ // box.read(BoxName.passengerWalletTotal).toString()) ??
+ // 0) <
+ // 0) {
+ // box.write(BoxName.passengerWalletTotal, 0);
+ // }
+
+ // Get.find().tripFinishedFromDriver();
+
+ // 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 Intaleq app'
+ // .tr,
+ // 'ding');
+
+ // Get.to(() => RateDriverFromPassenger(), arguments: {
+ // 'driverId': driverList[0].toString(),
+ // 'rideId': driverList[1].toString(),
+ // 'price': driverList[3].toString()
+ // });
+ // } else {
+ // Log.print(
+ // 'Error: Decoded driverList does not have enough elements. Received: $driverList');
+ // // هنا يمكنك عرض رسالة خطأ للمستخدم إذا لزم الأمر
+ // }
+ // } else if (message.notification!.title! == "Finish Monitor".tr) {
+ // Get.defaultDialog(
+ // titleStyle: AppStyle.title,
+ // title: 'Trip finished '.tr,
+ // middleText: '',
+ // confirm: MyElevatedButton(
+ // title: 'Ok'.tr,
+ // onPressed: () {
+ // Get.offAll(() => const MapPagePassenger());
+ // }));
+ // }
+ // // else if (message.notification!.title! == "Trip Monitoring".tr) {
+ // // Get.to(() => const TripMonitor());
+ // // }
+ // else if (message.notification!.title! == 'Call Income') {
+ // try {
+ // var myListString = message.data['DriverList'];
+ // var driverList = jsonDecode(myListString) as List;
+ // // if (Platform.isAndroid) {
+ // if (Platform.isAndroid) {
+ // notificationController.showNotification(
+ // 'Call Income'.tr,
+ // message.notification!.body!,
+ // 'iphone_ringtone',
+ // );
+ // }
+ // // }
+ // // Assuming GetMaterialApp is initialized and context is valid for navigation
+ // // Get.to(() => PassengerCallPage(
+ // // channelName: driverList[1].toString(),
+ // // token: driverList[0].toString(),
+ // // remoteID: driverList[2].toString(),
+ // // ));
+ // } catch (e) {}
+ // } else if (message.notification!.title! == 'Call Income from Driver'.tr) {
+ // try {
+ // var myListString = message.data['DriverList'];
+ // var driverList = jsonDecode(myListString) as List;
+ // // if (Platform.isAndroid) {
+ // if (Platform.isAndroid) {
+ // notificationController.showNotification(
+ // 'Call Income'.tr,
+ // message.notification!.body!,
+ // 'iphone_ringtone',
+ // );
+ // }
+ // // Assuming GetMaterialApp is initialized and context is valid for navigation
+ // // Get.to(() => PassengerCallPage(
+ // // channelName: driverList[1].toString(),
+ // // token: driverList[0].toString(),
+ // // remoteID: driverList[2].toString(),
+ // // ));
+ // } catch (e) {}
+ // } else if (message.notification!.title! == 'Call End'.tr) {
+ // try {
+ // var myListString = message.data['DriverList'];
+ // var driverList = jsonDecode(myListString) as List;
+ // if (Platform.isAndroid) {
+ // notificationController.showNotification(
+ // 'Call End'.tr,
+ // message.notification!.body!,
+ // 'ding',
+ // );
+ // }
+ // // Assuming GetMaterialApp is initialized and context is valid for navigation
+ // // Get.off(const CallPage());
+ // } catch (e) {}
+ // } else if (message.notification!.title! == 'Driver Cancelled Your Trip') {
+ // // Get.snackbar(
+ // // 'You will be pay the cost to driver or we will get it from you on next trip'
+ // // .tr,
+ // // 'message',
+ // // backgroundColor: AppColor.redColor);
+ // if (Platform.isAndroid) {
+ // notificationController.showNotification(
+ // 'Driver Cancelled Your Trip'.tr,
+ // 'you will pay to Driver you will be pay the cost of driver time look to your Intaleq Wallet'
+ // .tr,
+ // 'cancel');
+ // }
+ // box.write(BoxName.parentTripSelected, false);
+ // box.remove(BoxName.tokenParent);
+
+ // Get.find().restCounter();
+ // Get.offAll(() => const MapPagePassenger());
+ // }
+ // // else if (message.notification!.title! == 'Order Applied') {
+ // // Get.snackbar(
+ // // "The order has been accepted by another driver."
+ // // .tr, // Corrected grammar
+ // // "Be more mindful next time to avoid dropping orders."
+ // // .tr, // Improved sentence structure
+ // // backgroundColor: AppColor.yellowColor,
+ // // snackPosition: SnackPosition.BOTTOM,
+ // // );
+ // // }
+
+ // else if (message.notification!.title! == 'Order Applied'.tr) {
+ // if (Platform.isAndroid) {
+ // notificationController.showNotification(
+ // 'The order Accepted by another Driver'.tr,
+ // 'We regret to inform you that another driver has accepted this order.'
+ // .tr,
+ // 'order');
+ // }
+ // }
+ // }
SnackbarController driverAppliedTripSnakBar() {
return Get.snackbar(
@@ -418,40 +614,6 @@ class FirebaseMessagesController extends GetxController {
);
}
- Future driverArrivePassengerDialoge() {
- return Get.defaultDialog(
- barrierDismissible: false,
- title: 'Hi ,I Arrive your site'.tr,
- titleStyle: AppStyle.title,
- middleText: 'Please go to Car Driver'.tr,
- middleTextStyle: AppStyle.title,
- confirm: MyElevatedButton(
- title: 'Ok I will go now.'.tr,
- onPressed: () {
- // sendNotificationToPassengerToken(
- // 'Hi ,I will go now',
- // 'I will go now'.tr,
- // Get.find().driverToken,
- // [],
- // 'ding');
- NotificationService.sendNotification(
- target:
- Get.find().driverToken.toString(),
- title: 'Hi ,I will go now'.tr,
- body: 'I will go now'.tr,
- isTopic: false, // Important: this is a token
- tone: 'ding',
- driverList: [],
- );
- Get.find()
- .startTimerDriverWaitPassenger5Minute();
-
- Get.back();
- Get.find().remainingTime = 0;
- Get.find().update();
- }));
- }
-
Future passengerDialog(String message) {
return Get.defaultDialog(
barrierDismissible: false,
@@ -500,246 +662,6 @@ class FirebaseMessagesController extends GetxController {
kolor: AppColor.redColor,
));
}
-
- // void sendNotificationAll(String title, body, tone) async {
- // // Get the token you want to subtract.
- // String token = box.read(BoxName.tokenFCM);
- // tokens = box.read(BoxName.tokens);
- // // Subtract the token from the list of tokens.
- // tokens.remove(token);
-
- // // Save the list of tokens back to the box.
- // // box.write(BoxName.tokens, tokens);
- // tokens = box.read(BoxName.tokens);
- // for (var i = 0; i < tokens.length; i++) {
- // http
- // .post(
- // Uri.parse('https://fcm.googleapis.com/fcm/send'),
- // headers: {
- // 'Content-Type': 'application/json',
- // 'Authorization': 'key=${AK.serverAPI}'
- // },
- // body: jsonEncode({
- // 'message': {
- // 'token': token,
- // 'notification': {
- // 'title': title,
- // 'body': body,
- // },
- // // 'data': {
- // // 'DriverList': jsonEncode(data),
- // // },
- // 'android': {
- // 'priority': 'HIGH ', // Set priority to high
- // 'notification': {
- // 'sound': tone,
- // },
- // },
- // 'apns': {
- // 'headers': {
- // 'apns-priority': '10', // Set APNs priority to 10
- // },
- // 'payload': {
- // 'aps': {
- // 'sound': tone,
- // },
- // },
- // },
- // },
- // }),
- // )
- // .whenComplete(() {})
- // .catchError((e) {});
- // }
- // }
-
- // for (var i = 0; i < tokens.length; i++) {
- // http
- // .post(Uri.parse('https://fcm.googleapis.com/fcm/send'),
- // headers: {
- // 'Content-Type': 'application/json',
- // 'Authorization': 'key=${storage.read(key: BoxName.serverAPI}'
- // },
- // body: jsonEncode({
- // 'notification': {
- // 'title': title,
- // 'body': body,
- // 'sound': 'true'
- // },
- // 'priority': 'HIGH ',
- // 'data': {
- // 'click_action': 'FLUTTER_NOTIFICATION_CLICK',
- // 'id': '1',
- // 'status': 'done'
- // },
- // 'to': tokens[i],
- // }))
- // .whenComplete(() {})
- // .catchError((e) {
- // });
- // }
- // }
-
- // late String serviceAccountKeyJson;
- // '{"type": "service_account", "project_id": "intaleq-d48a7", "private_key_id": "d63a627dad96d0050c08a76c2920b1e48ddc4d38", "private_key": "-----BEGIN PRIVATE KEY-----\\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDHgHWUIlGskFWT\\nkjBvSiAYzXz51NbyMtqlvq1rZaiokd/yzqcEsjgxcAEGap93gRu72cuJ7QzDOpec\\nXSmhQwaGrdDyGyuS5x8nBa9ea3QEUGKjk975OhgIDoaIX2YHjah+jf/p3CPvwovC\\n+qypLsErv5DtcFfKtHkL+Z8gKJojU3p0gP2cVLHlhodGG4767w1f70fIv5LmQRHh\\nE0x5GgjO7MfA1CJewgHDWzj9GTuTd9o3G5nF6ojn8H1EOWminNDrsHAagsplY7iV\\nNmdvGoIAg2kRt66y5k4Li7EiH3e2ILvomGvUe3ahxBTcyFAt7UuAC5aPTmB0OCtN\\n39vMkJGtAgMBAAECggEAQ/FoWcBMX4AyXNUzQJuWjcvhzbXiVE7kbwEez44qH+q6\\nQdeGQw+tGo0iFDzYvVrPhqzYaEs+hvib7Kk/xcdtYA2vNNzy/I9Q6TnC7V2b/+Ie\\njcYM8IUL7SaBQ811kon4gc07hDowVPXFImy7w8yEBjGyGmMhywumk+D6A/o/8Fph\\n3lGRzgYZ7K7+mXxDpJVFp8DwX+uqP/3wOzcITXE12GZpvB+re7TQTs01qjsSTJ3/\\nCZMC6CvwYr3BvJzvgrn2TNZ6N6yowHE2iJo/HnoY/DutiB1V0B2EAMgcy05ZUouH\\nnTTOMAyV5LdcxgCtzlz+meCuhV5SUtfSz27bnUluMwKBgQDz+qJM38NhUpW7tmxZ\\nQsYwlo3Zp2a38UV8VC4mNDM9jjsft9QRHShos7potlIvmn9ryxP87SGNZrW9xy/k\\ngvTbDXu65/TwCUa3HYFCC+eJ5S4bBK/ctFwn1sr5AFjxavY2VV6YHUIzGezo8Bsj\\n1R5IGy3UHreTWngDapJYpA3JQwKBgQDRVNK7UP/Qt4qovrTVlNJ5mHjpwk7VoKBC\\nV0yrfbYVjYETFRFMrsKkcwCTQ3uk3lEl/UzAt2vV6o4Ql8KDzYJ/8ZHHXp9Z2eK9\\nTgR2fOIaEh2JJUjyVAUtuJo7RFl61K3a080+ZGWuZCY6K+prGneFqGuJ7XTtveGy\\njIsZTUhSTwKBgQCS0n5/Qp1iYP+IsjQr1zpLnR6KH+p5wXEua75F8V3wqjo8UTUG\\ng4SA1b/VKfr1eMU7ij9iExYA8RFnvom8u248sLWH+fT1yq9KnS/fHijdXBTN35kx\\neTyIIQOOqz3bMqIuelttsRXYiL6AQ5Yhjywk+m4u27lfrK7SZ3zgaQF+3wKBgEBy\\nfgKfmHLY3z6+oAwVqos3LxrA8OaCcnSaTgeKR5HxI+kNFmtmbpSUt3ufTiTfMVqh\\n1oyKrA+LDDv9jSxpDCF57SjVb/gIxe8EYwlbv3zJUQCVUxUQWxvNduaCT44qhnAV\\nv13TKR78xGwqcxyQZHXo+VrYmaRMTn1bGcQrb/WvAoGAIWUnnGQsvf6SwPQ/7gXC\\nVAq4i3E+coLStVyPK552HVorKa7J+TQnNBGHjCaQhxfCgp59/4qeT5AizzQaMhuS\\noGiUwGeo4RY4A1EEGoUpUk3zWZfC+bAjHVDyIjfN0YfxobL6Sh/97N68PMzb6ppq\\nybvddSGGsqZgucSxkEhIdTw=\\n-----END PRIVATE KEY-----\\n", "client_email": "firebase-adminsdk-fbsvc@intaleq-d48a7.iam.gserviceaccount.com", "client_id": "100558924056484926665", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-fbsvc%40intaleq-d48a7.iam.gserviceaccount.com", "universe_domain": "googleapis.com"}';
- @override
- Future onInit() async {
- super.onInit();
- // try {
- // // var encryptedKey = Env.privateKeyFCM;
- // // // Log.print('encryptedKey: ${encryptedKey}');
- // // serviceAccountKeyJson =
- // // EncryptionHelper.instance.decryptData(encryptedKey);
- // // Log.print('serviceAccountKeyJson: ${serviceAccountKeyJson}');
- // } catch (e) {
- // print('🔴 Error decrypting FCM key: $e');
- // }
- }
-
- // Future sendNotificationToDriverMAP(
- // String title, String body, String token, List data, String tone,
- // {int retryCount = 1}) async {
- // try {
- // if (serviceAccountKeyJson.isEmpty) {
- // print("🔴 Error: Service Account Key is empty");
- // return;
- // }
-
- // // Initialize AccessTokenManager
- // final accessTokenManager = AccessTokenManager(serviceAccountKeyJson);
- // // Log.print(
- // // 'accessTokenManager: ${accessTokenManager.serviceAccountJsonKey}');
-
- // // Obtain an OAuth 2.0 access token
- // final accessToken = await accessTokenManager.getAccessToken();
- // // Log.print('accessToken: ${accessToken}');
-
- // // Send the notification
- // final response = await http.post(
- // Uri.parse(
- // 'https://fcm.googleapis.com/v1/projects/intaleq-d48a7/messages:send'),
- // headers: {
- // 'Content-Type': 'application/json',
- // 'Authorization': 'Bearer $accessToken',
- // },
- // body: jsonEncode({
- // 'message': {
- // 'token': token,
- // 'notification': {
- // 'title': title,
- // 'body': body,
- // },
- // 'data': {
- // 'DriverList': jsonEncode(data),
- // },
- // 'android': {
- // 'priority': 'HIGH ', // Set priority to high
- // 'notification': {
- // 'sound': tone,
- // },
- // },
- // 'apns': {
- // 'headers': {
- // 'apns-priority': '10', // Set APNs priority to 10
- // },
- // 'payload': {
- // 'aps': {
- // 'sound': tone,
- // },
- // },
- // },
- // },
- // }),
- // );
-
- // if (response.statusCode == 200) {
- // print(
- // 'Notification sent successfully. Status code: ${response.statusCode}');
- // // print('Response token: ${token}');
- // } else {
- // print(
- // 'Failed to send notification. Status code: ${response.statusCode}');
- // print('Response body: ${response.body}');
- // if (retryCount > 0) {
- // print('Retrying... Attempts remaining: $retryCount');
- // await Future.delayed(
- // Duration(seconds: 2)); // Optional delay before retrying
- // return sendNotificationToDriverMAP(title, body, token, data, tone,
- // retryCount: retryCount - 1);
- // }
- // }
- // } catch (e) {
- // print('Error sending notification: $e');
- // if (retryCount > 0) {
- // print('Retrying... Attempts remaining: $retryCount');
- // await Future.delayed(
- // Duration(seconds: 2)); // Optional delay before retrying
- // return sendNotificationToDriverMAP(title, body, token, data, tone,
- // retryCount: retryCount - 1);
- // }
- // }
- // }
-
- // void sendNotificationToPassengerToken(
- // String title, body, token, List map, String tone) async {
- // try {
- // if (serviceAccountKeyJson.isEmpty) {
- // print("🔴 Error: Service Account Key is empty");
- // return;
- // }
- // // Initialize AccessTokenManager
- // final accessTokenManager = AccessTokenManager(serviceAccountKeyJson);
-
- // // Obtain an OAuth 2.0 access token
- // final accessToken = await accessTokenManager.getAccessToken();
- // // Log.print('accessToken: ${accessToken}');
-
- // // Send the notification
- // final response = await http.post(
- // Uri.parse(
- // 'https://fcm.googleapis.com/v1/projects/intaleq-d48a7/messages:send'),
- // headers: {
- // 'Content-Type': 'application/json',
- // 'Authorization': 'Bearer $accessToken',
- // },
- // body: jsonEncode({
- // 'message': {
- // 'token': token,
- // 'notification': {
- // 'title': title,
- // 'body': body,
- // },
- // 'android': {
- // 'priority': 'HIGH ', // Set priority to high
- // 'notification': {
- // 'sound': tone,
- // },
- // },
- // 'apns': {
- // 'headers': {
- // 'apns-priority': '10', // Set APNs priority to 10
- // },
- // 'payload': {
- // 'aps': {
- // 'sound': tone,
- // },
- // },
- // },
- // },
- // }),
- // );
-
- // if (response.statusCode == 200) {
- // print('✅ Notification sent successfully!');
- // } else {
- // print(
- // '🔴 Failed to send notification. Status code: ${response.statusCode}');
- // print('Response body: ${response.body}');
- // }
- // } catch (e) {
- // print('🔴 Error sending notification: $e');
- // }
- // }
}
class DriverTipWidget extends StatelessWidget {
diff --git a/lib/controller/firebase/notification_service.dart b/lib/controller/firebase/notification_service.dart
index 11b7e6b..233b7b2 100644
--- a/lib/controller/firebase/notification_service.dart
+++ b/lib/controller/firebase/notification_service.dart
@@ -1,3 +1,4 @@
+import 'package:Intaleq/print.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
@@ -5,11 +6,13 @@ class NotificationService {
// استبدل هذا الرابط بالرابط الصحيح لملف PHP على السيرفر الخاص بك
static const String _serverUrl =
'https://syria.intaleq.xyz/intaleq/fcm/send_fcm.php';
-
+ static const String _batchServerUrl =
+ 'https://syria.intaleq.xyz/intaleq/fcm/send_fcm_batch.php';
static Future sendNotification({
required String target,
required String title,
required String body,
+ required String? category, // <-- [الإضافة الأولى]
String? tone,
List? driverList, // <-- [تعديل 1] : إضافة المتغير الجديد
bool isTopic = false,
@@ -21,7 +24,10 @@ class NotificationService {
'body': body,
'isTopic': isTopic,
};
-
+ if (category != null) {
+ payload['category'] =
+ category; // <-- [الإضافة الثانية] (النص الثابت للتحكم)
+ }
// نضيف النغمة فقط إذا لم تكن فارغة
if (tone != null) {
payload['tone'] = tone;
@@ -52,4 +58,56 @@ class NotificationService {
print('❌ An error occurred while sending notification: $e');
}
}
+
+ /// [4] !! دالة جديدة مضافة !!
+ /// ترسل إشعاراً "مجمعاً" إلى قائمة من السائقين
+ static Future sendBatchNotification({
+ required List targets, // <-- قائمة التوكينز
+ required String title,
+ required String body,
+ String? tone,
+ List? driverList, // <-- بيانات الرحلة (نفسها للجميع)
+ }) async {
+ // لا ترسل شيئاً إذا كانت القائمة فارغة
+ if (targets.isEmpty) {
+ Log.print('⚠️ [Batch] No targets to send to. Skipped.');
+ return;
+ }
+
+ try {
+ final Map payload = {
+ // "targets" بدلاً من "target"
+ 'targets': jsonEncode(targets), // تشفير قائمة التوكينز
+ 'title': title,
+ 'body': body,
+ };
+
+ if (tone != null) {
+ payload['tone'] = tone;
+ }
+
+ // بيانات الرحلة (DriverList)
+ if (driverList != null) {
+ payload['driverList'] = jsonEncode(driverList);
+ }
+
+ final response = await http.post(
+ Uri.parse(_batchServerUrl), // <-- !! تستخدم الرابط الجديد
+ headers: {
+ 'Content-Type': 'application/json; charset=UTF-8',
+ },
+ body: jsonEncode(payload),
+ );
+
+ if (response.statusCode == 200) {
+ Log.print('✅ [Batch] Notifications sent successfully.');
+ Log.print('Server Response: ${response.body}');
+ } else {
+ Log.print('❌ [Batch] Failed to send. Status: ${response.statusCode}');
+ Log.print('Server Error: ${response.body}');
+ }
+ } catch (e) {
+ Log.print('❌ [Batch] An error occurred: $e');
+ }
+ }
}
diff --git a/lib/controller/functions/crud.dart b/lib/controller/functions/crud.dart
index 6e40486..6e63ba5 100644
--- a/lib/controller/functions/crud.dart
+++ b/lib/controller/functions/crud.dart
@@ -17,9 +17,6 @@ import 'encrypt_decrypt.dart';
import 'upload_image.dart';
import 'dart:io';
-import 'package:jwt_decoder/jwt_decoder.dart';
-
-import 'network/connection_check.dart';
import 'network/net_guard.dart';
class CRUD {
@@ -364,29 +361,29 @@ class CRUD {
}
}
- Future getTokenParent({
- required String link,
- Map? payload,
- }) async {
- // Uses Basic Auth, so it's a separate implementation.
- var url = Uri.parse(
- link,
- );
- var response = await http.post(
- url,
- body: payload,
- headers: {
- "Content-Type": "application/x-www-form-urlencoded",
- 'Authorization':
- 'Basic ${base64Encode(utf8.encode(AK.basicAuthCredentials.toString()))}',
- },
- );
- if (response.statusCode == 200) {
- return jsonDecode(response.body);
- }
- // Consider adding error handling here.
- return null;
- }
+ // Future getTokenParent({
+ // required String link,
+ // Map? payload,
+ // }) async {
+ // // Uses Basic Auth, so it's a separate implementation.
+ // var url = Uri.parse(
+ // link,
+ // );
+ // var response = await http.post(
+ // url,
+ // body: payload,
+ // headers: {
+ // "Content-Type": "application/x-www-form-urlencoded",
+ // 'Authorization':
+ // 'Basic ${base64Encode(utf8.encode(AK.basicAuthCredentials.toString()))}',
+ // },
+ // );
+ // if (response.statusCode == 200) {
+ // return jsonDecode(response.body);
+ // }
+ // // Consider adding error handling here.
+ // return null;
+ // }
Future sendWhatsAppAuth(String to, String token) async {
var res = await CRUD()
diff --git a/lib/controller/functions/launch.dart b/lib/controller/functions/launch.dart
index f80ab1f..e0c2a7e 100644
--- a/lib/controller/functions/launch.dart
+++ b/lib/controller/functions/launch.dart
@@ -8,11 +8,32 @@ void showInBrowser(String url) async {
}
Future makePhoneCall(String phoneNumber) async {
+ // 1. تنظيف الرقم (إزالة المسافات والفواصل)
+ String formattedNumber = phoneNumber.replaceAll(RegExp(r'\s+'), '');
+
+ // 2. التحقق من طول الرقم لتحديد طريقة التنسيق
+ if (formattedNumber.length > 6) {
+ // --- التعديل المطلوب ---
+ if (formattedNumber.startsWith('09')) {
+ // إذا كان يبدأ بـ 09 (رقم موبايل سوري محلي)
+ // نحذف أول خانة (الصفر) ونضيف +963
+ formattedNumber = '+963${formattedNumber.substring(1)}';
+ } else if (!formattedNumber.startsWith('+')) {
+ // إذا لم يكن يبدأ بـ + (ولم يكن يبدأ بـ 09)، نضيف + في البداية
+ // هذا للحفاظ على منطقك القديم للأرقام الدولية الأخرى
+ formattedNumber = '+$formattedNumber';
+ }
+ }
+
+ // 3. التنفيذ (Launch)
final Uri launchUri = Uri(
scheme: 'tel',
- path: phoneNumber,
+ path: formattedNumber,
);
- await launchUrl(launchUri);
+
+ if (await canLaunchUrl(launchUri)) {
+ await launchUrl(launchUri);
+ }
}
void launchCommunication(
diff --git a/lib/controller/functions/location_controller.dart b/lib/controller/functions/location_controller.dart
index e6be0e2..d559fd0 100644
--- a/lib/controller/functions/location_controller.dart
+++ b/lib/controller/functions/location_controller.dart
@@ -1,148 +1,148 @@
-import 'dart:async';
+// import 'dart:async';
-import 'package:get/get.dart';
-import 'package:google_maps_flutter/google_maps_flutter.dart';
-import 'package:location/location.dart';
-import 'package:Intaleq/constant/box_name.dart';
-import 'package:Intaleq/constant/links.dart';
-import 'package:Intaleq/controller/functions/crud.dart';
-import 'package:Intaleq/controller/home/payment/captain_wallet_controller.dart';
-import 'package:Intaleq/main.dart';
+// import 'package:get/get.dart';
+// import 'package:google_maps_flutter/google_maps_flutter.dart';
+// import 'package:location/location.dart';
+// import 'package:Intaleq/constant/box_name.dart';
+// import 'package:Intaleq/constant/links.dart';
+// import 'package:Intaleq/controller/functions/crud.dart';
+// import 'package:Intaleq/controller/home/payment/captain_wallet_controller.dart';
+// import 'package:Intaleq/main.dart';
-// LocationController.dart
-class LocationController extends GetxController {
- LocationData? _currentLocation;
- late Location location;
- bool isLoading = false;
- late double heading = 0;
- late double accuracy = 0;
- late double previousTime = 0;
- late double latitude;
- late double totalDistance = 0;
- late double longitude;
- late DateTime time;
- late double speed = 0;
- late double speedAccuracy = 0;
- late double headingAccuracy = 0;
- bool isActive = false;
- late LatLng myLocation;
- String totalPoints = '0';
- LocationData? get currentLocation => _currentLocation;
- Timer? _locationTimer;
+// // LocationController.dart
+// class LocationController extends GetxController {
+// LocationData? _currentLocation;
+// late Location location;
+// bool isLoading = false;
+// late double heading = 0;
+// late double accuracy = 0;
+// late double previousTime = 0;
+// late double latitude;
+// late double totalDistance = 0;
+// late double longitude;
+// late DateTime time;
+// late double speed = 0;
+// late double speedAccuracy = 0;
+// late double headingAccuracy = 0;
+// bool isActive = false;
+// late LatLng myLocation;
+// String totalPoints = '0';
+// LocationData? get currentLocation => _currentLocation;
+// Timer? _locationTimer;
- @override
- void onInit() async {
- super.onInit();
- location = Location();
- getLocation();
- // startLocationUpdates();
+// @override
+// void onInit() async {
+// super.onInit();
+// location = Location();
+// getLocation();
+// // startLocationUpdates();
- totalPoints = Get.put(CaptainWalletController()).totalPoints;
- }
+// totalPoints = Get.put(CaptainWalletController()).totalPoints;
+// }
- Future startLocationUpdates() async {
- if (box.read(BoxName.driverID) != null) {
- _locationTimer =
- Timer.periodic(const Duration(seconds: 5), (timer) async {
- try {
- totalPoints = Get.find().totalPoints;
+// Future startLocationUpdates() async {
+// if (box.read(BoxName.driverID) != null) {
+// _locationTimer =
+// Timer.periodic(const Duration(seconds: 5), (timer) async {
+// try {
+// totalPoints = Get.find().totalPoints;
- // if (isActive) {
- if (double.parse(totalPoints) > -300) {
- await getLocation();
+// // if (isActive) {
+// if (double.parse(totalPoints) > -300) {
+// await getLocation();
- // if (box.read(BoxName.driverID) != null) {
- await CRUD()
- .post(link: AppLink.addCarsLocationByPassenger, payload: {
- 'driver_id': box.read(BoxName.driverID).toString(),
- 'latitude': myLocation.latitude.toString(),
- 'longitude': myLocation.longitude.toString(),
- 'heading': heading.toString(),
- 'speed': (speed * 3.6).toStringAsFixed(1),
- 'distance': totalDistance == 0
- ? '0'
- : totalDistance < 1
- ? totalDistance.toStringAsFixed(3)
- : totalDistance.toStringAsFixed(1),
- 'status': box.read(BoxName.statusDriverLocation).toString()
- });
- }
+// // if (box.read(BoxName.driverID) != null) {
+// await CRUD()
+// .post(link: AppLink.addCarsLocationByPassenger, payload: {
+// 'driver_id': box.read(BoxName.driverID).toString(),
+// 'latitude': myLocation.latitude.toString(),
+// 'longitude': myLocation.longitude.toString(),
+// 'heading': heading.toString(),
+// 'speed': (speed * 3.6).toStringAsFixed(1),
+// 'distance': totalDistance == 0
+// ? '0'
+// : totalDistance < 1
+// ? totalDistance.toStringAsFixed(3)
+// : totalDistance.toStringAsFixed(1),
+// 'status': box.read(BoxName.statusDriverLocation).toString()
+// });
+// }
- // }
- } catch (e) {
- // Handle the error gracefully
- }
- });
- }
- }
+// // }
+// } catch (e) {
+// // Handle the error gracefully
+// }
+// });
+// }
+// }
- void stopLocationUpdates() {
- _locationTimer?.cancel();
- }
+// void stopLocationUpdates() {
+// _locationTimer?.cancel();
+// }
- Future getLocation() async {
- // isLoading = true;
- // update();
- bool serviceEnabled;
- PermissionStatus permissionGranted;
+// Future getLocation() async {
+// // isLoading = true;
+// // update();
+// bool serviceEnabled;
+// PermissionStatus permissionGranted;
- // Check if location services are enabled
- serviceEnabled = await location.serviceEnabled();
- if (!serviceEnabled) {
- serviceEnabled = await location.requestService();
- if (!serviceEnabled) {
- // Location services are still not enabled, handle the error
- return;
- }
- }
+// // Check if location services are enabled
+// serviceEnabled = await location.serviceEnabled();
+// if (!serviceEnabled) {
+// serviceEnabled = await location.requestService();
+// if (!serviceEnabled) {
+// // Location services are still not enabled, handle the error
+// return;
+// }
+// }
- // Check if the app has permission to access location
- permissionGranted = await location.hasPermission();
- if (permissionGranted == PermissionStatus.denied) {
- permissionGranted = await location.requestPermission();
- if (permissionGranted != PermissionStatus.granted) {
- // Location permission is still not granted, handle the error
- return;
- }
- }
+// // Check if the app has permission to access location
+// permissionGranted = await location.hasPermission();
+// if (permissionGranted == PermissionStatus.denied) {
+// permissionGranted = await location.requestPermission();
+// if (permissionGranted != PermissionStatus.granted) {
+// // Location permission is still not granted, handle the error
+// return;
+// }
+// }
- // Configure location accuracy
- // LocationAccuracy desiredAccuracy = LocationAccuracy.high;
+// // Configure location accuracy
+// // LocationAccuracy desiredAccuracy = LocationAccuracy.high;
- // Get the current location
- LocationData _locationData = await location.getLocation();
- myLocation =
- (_locationData.latitude != null && _locationData.longitude != null
- ? LatLng(_locationData.latitude!, _locationData.longitude!)
- : null)!;
- speed = _locationData.speed!;
- heading = _locationData.heading!;
-// Calculate the distance between the current location and the previous location
- // if (Get.find().rideId == 'rideId') {
- // if (previousTime > 0) {
- // double distance = calculateDistanceInKmPerHour(
- // previousTime, _locationData.time, speed);
- // totalDistance += distance;
- // }
+// // Get the current location
+// LocationData _locationData = await location.getLocation();
+// myLocation =
+// (_locationData.latitude != null && _locationData.longitude != null
+// ? LatLng(_locationData.latitude!, _locationData.longitude!)
+// : null)!;
+// speed = _locationData.speed!;
+// heading = _locationData.heading!;
+// // Calculate the distance between the current location and the previous location
+// // if (Get.find().rideId == 'rideId') {
+// // if (previousTime > 0) {
+// // double distance = calculateDistanceInKmPerHour(
+// // previousTime, _locationData.time, speed);
+// // totalDistance += distance;
+// // }
- // previousTime = _locationData.time!;
- // }
- // Print location details
- // isLoading = false;
- update();
- }
+// // previousTime = _locationData.time!;
+// // }
+// // Print location details
+// // isLoading = false;
+// update();
+// }
- double calculateDistanceInKmPerHour(
- double? startTime, double? endTime, double speedInMetersPerSecond) {
- // Calculate the time difference in hours
- double timeDifferenceInHours = (endTime! - startTime!) / 1000 / 3600;
+// double calculateDistanceInKmPerHour(
+// double? startTime, double? endTime, double speedInMetersPerSecond) {
+// // Calculate the time difference in hours
+// double timeDifferenceInHours = (endTime! - startTime!) / 1000 / 3600;
- // Convert speed to kilometers per hour
- double speedInKmPerHour = speedInMetersPerSecond * 3.6;
+// // Convert speed to kilometers per hour
+// double speedInKmPerHour = speedInMetersPerSecond * 3.6;
- // Calculate the distance in kilometers
- double distanceInKilometers = speedInKmPerHour * timeDifferenceInHours;
+// // Calculate the distance in kilometers
+// double distanceInKilometers = speedInKmPerHour * timeDifferenceInHours;
- return distanceInKilometers;
- }
-}
+// return distanceInKilometers;
+// }
+// }
diff --git a/lib/controller/home/contact_us_controller.dart b/lib/controller/home/contact_us_controller.dart
index afc879f..48dbe29 100644
--- a/lib/controller/home/contact_us_controller.dart
+++ b/lib/controller/home/contact_us_controller.dart
@@ -1,3 +1,4 @@
+import 'dart:math';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_font_icons/flutter_font_icons.dart';
@@ -7,10 +8,9 @@ import '../../../constant/colors.dart';
import '../functions/launch.dart';
class ContactUsController extends GetxController {
- final String phone1 = '+201018805430';
- final String phone2 = '+201080182934';
- final TimeOfDay workStartTime = const TimeOfDay(hour: 12, minute: 0);
- final TimeOfDay workEndTime = const TimeOfDay(hour: 19, minute: 0);
+ /// WORKING HOURS (10:00 → 16:00)
+ final TimeOfDay workStartTime = const TimeOfDay(hour: 10, minute: 0);
+ final TimeOfDay workEndTime = const TimeOfDay(hour: 16, minute: 0);
bool _isWithinWorkTime(TimeOfDay now) {
return (now.hour > workStartTime.hour ||
@@ -20,8 +20,23 @@ class ContactUsController extends GetxController {
(now.hour == workEndTime.hour && now.minute <= workEndTime.minute));
}
+ /// PHONE LIST (USED FOR CALLS + WHATSAPP)
+ final List phoneNumbers = [
+ '+963952475734',
+ '+963952475740',
+ '+963952475742'
+ ];
+
+ /// RANDOM PHONE SELECTOR
+ String getRandomPhone() {
+ final random = Random();
+ return phoneNumbers[random.nextInt(phoneNumbers.length)];
+ }
+
+ /// SHOW DIALOG
void showContactDialog(BuildContext context) {
TimeOfDay now = TimeOfDay.now();
+ bool withinHours = _isWithinWorkTime(now);
showCupertinoModalPopup(
context: context,
@@ -29,25 +44,34 @@ class ContactUsController extends GetxController {
title: Text('Contact Us'.tr),
message: Text('Choose a contact option'.tr),
actions: [
- if (_isWithinWorkTime(now))
+ /// 📞 CALL (RANDOM) — ONLY DURING WORK HOURS
+ if (withinHours)
CupertinoActionSheetAction(
- child: Text(phone1),
- onPressed: () => makePhoneCall(
- phone1,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ const Icon(CupertinoIcons.phone),
+ Text('Call Support'.tr),
+ ],
),
+ onPressed: () {
+ final phone = getRandomPhone();
+ makePhoneCall(phone);
+ },
),
- if (_isWithinWorkTime(now))
- CupertinoActionSheetAction(
- child: Text(phone2),
- onPressed: () => makePhoneCall(phone2),
- ),
- if (!_isWithinWorkTime(now))
+
+ /// ⛔ OUTSIDE WORK HOURS — SHOW INFO
+ if (!withinHours)
CupertinoActionSheetAction(
child: Text(
- 'Work time is from 12:00 - 19:00.\nYou can send a WhatsApp message or email.'
- .tr),
+ 'Work time is from 10:00 AM to 16:00 PM.\nYou can send a WhatsApp message or email.'
+ .tr,
+ textAlign: TextAlign.center,
+ ),
onPressed: () => Navigator.pop(context),
),
+
+ /// 💬 WHATSAPP (RANDOM)
CupertinoActionSheetAction(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
@@ -59,15 +83,21 @@ class ContactUsController extends GetxController {
Text('Send WhatsApp Message'.tr),
],
),
- onPressed: () =>
- launchCommunication('whatsapp', phone1, 'Hello'.tr),
+ onPressed: () {
+ final phone = getRandomPhone();
+ launchCommunication('whatsapp', phone, 'Hello'.tr);
+ },
),
+
+ /// 📧 EMAIL
CupertinoActionSheetAction(
child: Text('Send Email'.tr),
- onPressed: () =>
- launchCommunication('email', 'support@sefer.live', 'Hello'.tr),
+ onPressed: () => launchCommunication(
+ 'email', 'support@intaleqapp.com', 'Hello'.tr),
),
],
+
+ /// ❌ CANCEL BUTTON
cancelButton: CupertinoActionSheetAction(
child: Text('Cancel'.tr),
onPressed: () => Navigator.pop(context),
diff --git a/lib/controller/home/map_passenger_controller.dart b/lib/controller/home/map_passenger_controller.dart
index 0db38f3..509eb98 100644
--- a/lib/controller/home/map_passenger_controller.dart
+++ b/lib/controller/home/map_passenger_controller.dart
@@ -5,6 +5,9 @@ import 'dart:math' show Random, atan2, cos, max, min, pi, pow, sin, sqrt;
import 'dart:math' as math;
import 'dart:ui';
import 'dart:convert';
+import 'package:crypto/crypto.dart';
+import 'package:Intaleq/views/Rate/rate_captain.dart';
+import 'package:Intaleq/views/Rate/rating_driver_bottom.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
@@ -32,9 +35,11 @@ import 'package:Intaleq/controller/home/points_for_rider_controller.dart';
import 'package:Intaleq/views/home/map_widget.dart/form_serch_multiy_point.dart';
import '../../constant/api_key.dart';
import '../../constant/box_name.dart';
+import '../../constant/country_polygons.dart';
import '../../constant/info.dart';
import '../../constant/links.dart';
import '../../constant/table_names.dart';
+import '../../env/env.dart';
import '../../main.dart';
import '../../models/model/locations.dart';
import '../../models/model/painter_copoun.dart';
@@ -54,11 +59,23 @@ import '../functions/launch.dart';
import '../functions/package_info.dart';
import '../functions/secure_storage.dart';
import '../payment/payment_controller.dart';
+import '../rate/rate_conroller.dart';
import 'decode_polyline_isolate.dart';
import 'deep_link_controller.dart';
import 'device_tier.dart';
import 'vip_waitting_page.dart';
+enum RideState {
+ noRide, // لا يوجد رحلة جارية، عرض واجهة البحث
+ cancelled, // تم إلغاء الرحلة
+ preCheckReview, // يوجد رحلة منتهية، تحقق من التقييم
+ searching, // جاري البحث عن كابتن
+ driverApplied, // تم قبول الطلب
+ driverArrived, // وصل السائق
+ inProgress, // الرحلة بدأت بالفعل
+ finished, // انتهت الرحلة (سيتم تحويلها إلى preCheckReview)
+}
+
class MapPassengerController extends GetxController {
bool isLoading = true;
TextEditingController placeDestinationController = TextEditingController();
@@ -269,6 +286,812 @@ class MapPassengerController extends GetxController {
late double costDistance = 0;
late double distance = 0;
late double duration = 0;
+ bool _isDriverAppliedLogicExecuted = false; // فلاج لمنع التنفيذ المتكرر
+ bool _isDriverArrivedLogicExecuted = false;
+ bool _isRideBeginLogicExecuted = false;
+ DateTime? _searchStartTime; // لتتبع مدة البحث
+ DateTime? _lastDriversNotifyTime; // لتتبع آخر مرة تم إرسال إشعار للسائقين
+ final int _masterTimerIntervalSeconds = 5; // فاصل زمني ثابت للمؤقت الرئيسي
+ final int _searchTimeoutSeconds = 60; // مهلة البحث قبل عرض خيار زيادة السعر
+ final int _notifyDriversIntervalSeconds =
+ 25; // إرسال إشعار للسائقين كل 25 ثانية
+ // --- إضافة جديدة: متغيرات لإدارة البحث المتوسع ---
+ int _currentSearchPhase = 0; // لتتبع المرحلة الحالية للبحث
+ // قائمة بأنصاف الأقطار (بالأمتار) لكل مرحلة
+ final List _searchRadii = [
+ 3000,
+ 4500,
+ 6000
+ ]; // 0 ثانية، 30 ثانية، 60 ثانية
+ // المدة الزمنية لكل مرحلة بحث (بالثواني)
+ final int _searchPhaseDurationSeconds = 30;
+ // المهلة الإجمالية للبحث قبل عرض خيار زيادة السعر
+ final int _totalSearchTimeoutSeconds = 90; // 90 ثانية
+// --- noRide throttling ---
+ int _noRideSearchCount = 0;
+ final int _noRideMaxTries = 3; // نفذ البحث 6 مرات فقط
+ final int _noRideIntervalSec = 5; // بين كل محاولة وأخرى 5 ثواني
+ DateTime? _noRideNextAllowed; // متى نسمح بالمحاولة التالية
+ bool _noRideSearchCapped = false; // وصلنا للحد وتوقفنا
+ // ============== new design to manage ride state ==============
+ // === 1. حالة الرحلة والمؤقت الرئيسي (Single Source of Truth) ===
+ Rx currentRideState = RideState.noRide.obs;
+ Timer? _masterTimer;
+ final int _pollingIntervalSeconds = 4; // فاصل زمني موحد للاستعلام
+
+ void _startMasterTimer() {
+ // نضمن أن مؤقت واحد فقط يعمل في أي وقت
+ _masterTimer?.cancel();
+ _masterTimer =
+ Timer.periodic(Duration(seconds: _pollingIntervalSeconds), (_) {
+ _handleRideState(currentRideState.value);
+ });
+ }
+
+ void stopAllTimers() {
+ _masterTimer?.cancel();
+ // إذا كان لديك مؤقتات زمنية (مثل عداد الـ 5 دقائق للانتظار) قم بإلغائها هنا أيضاً
+ cancelTimerToPassengerFromDriverAfterApplied();
+ // ...
+ }
+
+ final int _maxNoRideSearch = 3; // عدد المرات القصوى
+ final int _noRideDelaySeconds = 6; // الفاصل الزمني بين كل بحث
+//
+ //
+ // !!! يرجى استبدال الدالة القديمة بالكامل بهذه الدالة الجديدة !!!
+ //
+ //
+
+ Future _handleRideState(RideState state) async {
+ Log.print('Handling state: $state');
+
+ int effectivePollingInterval = _pollingIntervalSeconds;
+
+ switch (state) {
+ case RideState.noRide:
+ final now = DateTime.now();
+ if (_noRideSearchCount >= _noRideMaxTries) {
+ if (!_noRideSearchCapped) {
+ _noRideSearchCapped = true;
+ Log.print('[noRide] search capped at $_noRideMaxTries attempts');
+ }
+ break;
+ }
+ if (_noRideNextAllowed != null && now.isBefore(_noRideNextAllowed!)) {
+ break;
+ }
+ _noRideSearchCount++;
+ Log.print('_noRideSearchCount: ${_noRideSearchCount}');
+ _noRideNextAllowed = now.add(Duration(seconds: _noRideIntervalSec));
+ String currentCarType = box.read(BoxName.carType) ?? 'yet';
+ getCarsLocationByPassengerAndReloadMarker(currentCarType, 3000);
+ getNearestDriverByPassengerLocation();
+ break;
+
+ case RideState.cancelled:
+ Log.print('[handleRideState] Ride cancelled. Stopping polling.');
+ stopAllTimers();
+ effectivePollingInterval = 3600;
+ break;
+
+ case RideState.preCheckReview:
+ stopAllTimers();
+ _checkLastRideForReview();
+ break;
+
+ case RideState.searching:
+ effectivePollingInterval = 5;
+
+ // 1. التحقق من حالة الطلب (هل قبله أحد؟)
+ try {
+ String statusFromServer = await getRideStatus(rideId);
+ if (statusFromServer == 'Apply' || statusFromServer == 'Applied') {
+ await processRideAcceptance();
+ break;
+ }
+ } catch (e) {
+ Log.print('Error polling getRideStatus: $e');
+ }
+
+ final now = DateTime.now();
+ final int elapsedSeconds = now.difference(_searchStartTime!).inSeconds;
+
+ // انتهاء وقت البحث الكلي
+ if (elapsedSeconds > _totalSearchTimeoutSeconds) {
+ stopAllTimers();
+ currentRideState.value = RideState.noRide;
+ isSearchingWindow = false;
+ update();
+ _showIncreaseFeeDialog();
+ break;
+ }
+
+ // 2. إدارة مراحل البحث (توسيع النطاق)
+ // السيناريو الجديد: لا نقوم بالقصف العشوائي، نرسل بناء على المرحلة أو مرور وقت كافٍ لدخول سائقين جدد
+
+ int targetPhase =
+ (elapsedSeconds / _searchPhaseDurationSeconds).floor();
+ if (targetPhase >= _searchRadii.length) {
+ targetPhase = _searchRadii.length - 1;
+ }
+
+ // هل تغيرت المرحلة (توسع النطاق)؟ أو هل مر 10 ثواني منذ آخر محاولة إرسال؟
+ // هذا يمنع إرسال الإشعار في كل دورة (كل 5 ثواني) ويقلل الازعاج
+ bool isNewPhase = targetPhase > _currentSearchPhase;
+ bool timeToScanForNewDrivers =
+ (elapsedSeconds % 15 == 0); // كل 15 ثانية نفحص الدخول الجديد
+
+ if (isNewPhase || timeToScanForNewDrivers || elapsedSeconds < 5) {
+ _currentSearchPhase = targetPhase;
+ int currentRadius = _searchRadii[_currentSearchPhase];
+
+ Log.print(
+ '[Search Logic] Scanning for drivers. Phase: $_currentSearchPhase, Radius: $currentRadius');
+ // استدعاء دالة الإشعار الذكية
+ _findAndNotifyNearestDrivers(currentRadius);
+ }
+
+ // تحديث نصوص الواجهة
+ if (elapsedSeconds < 5) {
+ driversStatusForSearchWindow = 'Your order is being prepared'.tr;
+ } else if (elapsedSeconds < 15) {
+ driversStatusForSearchWindow = 'Your order sent to drivers'.tr;
+ } else {
+ driversStatusForSearchWindow =
+ 'The drivers are reviewing your request'.tr;
+ }
+ update();
+ break;
+
+ case RideState.driverApplied:
+ effectivePollingInterval = 10;
+ if (!_isDriverAppliedLogicExecuted) {
+ Log.print('[handleRideState] Execution driverApplied logic.');
+ rideAppliedFromDriver(true);
+ _isDriverAppliedLogicExecuted = true;
+ }
+ try {
+ String statusFromServer = await getRideStatus(rideId);
+ if (statusFromServer == 'Arrived') {
+ currentRideState.value = RideState.driverArrived;
+ break;
+ } else if (statusFromServer == 'Begin' ||
+ statusFromServer == 'inProgress') {
+ processRideBegin();
+ break;
+ }
+ } catch (e) {
+ Log.print('Error polling for Arrived/Begin status: $e');
+ }
+ getDriverCarsLocationToPassengerAfterApplied();
+ break;
+
+ case RideState.driverArrived:
+ if (!_isDriverArrivedLogicExecuted) {
+ _isDriverArrivedLogicExecuted = true;
+ startTimerDriverWaitPassenger5Minute();
+ driverArrivePassengerDialoge();
+ }
+ effectivePollingInterval = 8;
+ break;
+
+ case RideState.inProgress:
+ effectivePollingInterval = 11;
+ try {
+ String statusFromServer = await getRideStatus(rideId);
+ if (statusFromServer == 'Finished' ||
+ statusFromServer == 'finished') {
+ if (currentRideState.value == RideState.inProgress) {
+ currentRideState.value = RideState.finished;
+ break;
+ }
+ }
+ } catch (e) {
+ Log.print('Error polling for Finished status: $e');
+ }
+
+ if (!_isRideBeginLogicExecuted) {
+ _isRideBeginLogicExecuted = true;
+ _executeBeginRideLogic();
+ }
+ getDriverCarsLocationToPassengerAfterApplied();
+ break;
+
+ case RideState.finished:
+ tripFinishedFromDriver();
+ stopAllTimers();
+ effectivePollingInterval = 3600;
+ break;
+ }
+
+ if (_masterTimer?.tick != effectivePollingInterval) {
+ _masterTimer?.cancel();
+ _masterTimer =
+ Timer.periodic(Duration(seconds: effectivePollingInterval), (_) {
+ _handleRideState(currentRideState.value);
+ });
+ }
+ }
+// Future _handleRideState(RideState state) async {
+// Log.print('Handling state: $state');
+
+// int effectivePollingInterval = _pollingIntervalSeconds;
+
+// switch (state) {
+// // 1. تم فصل "noRide" عن "cancelled"
+// case RideState.noRide:
+// final now = DateTime.now();
+// if (_noRideSearchCount >= _noRideMaxTries) {
+// if (!_noRideSearchCapped) {
+// _noRideSearchCapped = true;
+// Log.print('[noRide] search capped at $_noRideMaxTries attempts');
+// }
+// break;
+// }
+// if (_noRideNextAllowed != null && now.isBefore(_noRideNextAllowed!)) {
+// break;
+// }
+// _noRideSearchCount++;
+// Log.print('_noRideSearchCount: ${_noRideSearchCount}');
+// _noRideNextAllowed = now.add(Duration(seconds: _noRideIntervalSec));
+// String currentCarType = box.read(BoxName.carType) ?? 'yet';
+// getCarsLocationByPassengerAndReloadMarker(currentCarType, 3000);
+// getNearestDriverByPassengerLocation();
+// break;
+
+// // 2. "cancelled" أصبحت حالة منفصلة توقف كل شيء
+// case RideState.cancelled:
+// Log.print('[handleRideState] Ride cancelled. Stopping polling.');
+// stopAllTimers(); // أوقف المؤقت الرئيسي
+// effectivePollingInterval = 3600; // إيقاف فعلي للمؤقت
+// break;
+
+// case RideState.preCheckReview:
+// stopAllTimers();
+// _checkLastRideForReview();
+// break;
+
+// case RideState.searching:
+// // ... (منطق هذا الكيس سيبقى كما هو تماماً - لا تغيير هنا)
+// effectivePollingInterval = 3;
+// try {
+// String statusFromServer = await getRideStatus(rideId);
+// if (statusFromServer == 'Apply' || statusFromServer == 'Applied') {
+// await processRideAcceptance();
+// break;
+// }
+// } catch (e) {
+// Log.print('Error polling getRideStatus: $e');
+// }
+// final now = DateTime.now();
+// final int elapsedSeconds = now.difference(_searchStartTime!).inSeconds;
+// if (elapsedSeconds > _totalSearchTimeoutSeconds) {
+// stopAllTimers();
+// currentRideState.value = RideState.noRide;
+// isSearchingWindow = false;
+// update();
+// _showIncreaseFeeDialog();
+// break;
+// }
+// int targetPhase =
+// (elapsedSeconds / _searchPhaseDurationSeconds).floor();
+// if (targetPhase >= _searchRadii.length) {
+// targetPhase = _searchRadii.length - 1;
+// }
+// bool needsNewSearch = false;
+// if (targetPhase > _currentSearchPhase) {
+// _currentSearchPhase = targetPhase;
+// needsNewSearch = true;
+// Log.print(
+// '[Search] Expanding to Phase $_currentSearchPhase (Radius: ${_searchRadii[_currentSearchPhase]}m)');
+// } else if (elapsedSeconds < effectivePollingInterval) {
+// needsNewSearch = true;
+// Log.print('[Search] Starting Phase 0 (Radius: ${_searchRadii[0]}m)');
+// }
+// // if (needsNewSearch) {
+// int currentRadius = _searchRadii[_currentSearchPhase];
+// // _findAndNotifyNearestDrivers(currentRadius);
+// // }
+// // (3) [!! التعديل الجوهري !!]
+// // احذف 'if (needsNewSearch)' وقم بالاستدعاء مباشرة
+// // هذا سيضمن أنه في كل دورة (كل 4 ثوانٍ)، يتم إعادة جلب السائقين
+// Log.print(
+// '[Search Polling] Finding new drivers in Phase $_currentSearchPhase (Radius: ${currentRadius}m)');
+// _findAndNotifyNearestDrivers(currentRadius);
+// if (elapsedSeconds < 5) {
+// driversStatusForSearchWindow = 'Your order is being prepared'.tr;
+// } else if (elapsedSeconds < 15) {
+// driversStatusForSearchWindow = 'Your order sent to drivers'.tr;
+// } else {
+// driversStatusForSearchWindow =
+// 'The drivers are reviewing your request'.tr;
+// }
+// update();
+// break;
+
+// // ...
+// case RideState.driverApplied:
+// effectivePollingInterval = 10; // فاصل زمني مناسب
+// if (!_isDriverAppliedLogicExecuted) {
+// Log.print('[handleRideState] تنفيذ منطق "driverApplied" لأول مرة.');
+// rideAppliedFromDriver(true); // هذا يشغل عداد وصول السائق
+// _isDriverAppliedLogicExecuted = true;
+// }
+
+// // [!! إضافة مهمة !!]
+// // استمر في التحقق من حالة الرحلة (Status)
+// try {
+// String statusFromServer = await getRideStatus(rideId);
+// if (statusFromServer == 'Arrived') {
+// Log.print('[Polling] اكتشف "Arrived". تغيير الحالة.');
+// currentRideState.value = RideState.driverArrived;
+// break; // اخرج (سيتم تفعيل case driverArrived في الدورة القادمة)
+// } else if (statusFromServer == 'Begin' ||
+// statusFromServer == 'inProgress') {
+// Log.print('[Polling] اكتشف "Begin" (تجاوز حالة الوصول).');
+// // استدعاء حارس البوابة الآمن
+// processRideBegin(); // هذه الدالة ستغير الحالة إلى inProgress
+// break;
+// }
+// } catch (e) {
+// Log.print('Error polling for Arrived/Begin status: $e');
+// }
+// // [!! نهاية الإضافة !!]
+
+// getDriverCarsLocationToPassengerAfterApplied(); // استمر بجلب الموقع أيضاً
+// break;
+// // ...
+
+// case RideState.driverArrived:
+// if (!_isDriverArrivedLogicExecuted) {
+// _isDriverArrivedLogicExecuted = true;
+// Log.print(
+// '[handleRideState] اكتشف "driverArrived". بدء عداد 5 دقائق.');
+// startTimerDriverWaitPassenger5Minute();
+// driverArrivePassengerDialoge();
+// }
+// effectivePollingInterval = 8; // يبقى يعمل لاكتشاف "inProgress"
+// break;
+
+// case RideState.inProgress:
+// effectivePollingInterval = 11;
+
+// // 3. إضافة "بحث دوري" (Polling) لاكتشاف إنهاء الرحلة
+// try {
+// String statusFromServer = await getRideStatus(rideId);
+// if (statusFromServer == 'Finished' ||
+// statusFromServer == 'finished') {
+// if (currentRideState.value == RideState.inProgress) {
+// Log.print('[Polling] اكتشف "Finished". تغيير الحالة.');
+// currentRideState.value = RideState.finished; // غيّر الحالة
+// break; // اخرج (سيتم تفعيل case finished في الدورة القادمة)
+// }
+// }
+// } catch (e) {
+// Log.print('Error polling for Finished status: $e');
+// }
+// // --- نهاية الإضافة ---
+
+// if (!_isRideBeginLogicExecuted) {
+// _isRideBeginLogicExecuted = true;
+// _executeBeginRideLogic();
+// }
+// getDriverCarsLocationToPassengerAfterApplied(); // استمر في تتبع الموقع
+// break;
+
+// // 4. "finished" أصبحت حالة نهائية آمنة
+// case RideState.finished:
+// // إشعار FCM (الذي يملك بيانات السعر) هو المسؤول عن الانتقال للتقييم
+// // هذه الحالة هي مجرد "نقطة توقف" للمؤقت.
+// Log.print('[handleRideState] Ride is Finished. Stopping all activity.');
+
+// // نستدعي هذه لضمان تصفير الواجهة، حتى لو فاز البحث الدوري
+// tripFinishedFromDriver(); // (سنقوم بتعديل هذه الدالة في الخطوة 3)
+
+// stopAllTimers();
+// effectivePollingInterval = 3600; // إيقاف فعلي
+// break;
+// }
+
+// if (_masterTimer?.tick != effectivePollingInterval) {
+// _masterTimer?.cancel();
+// _masterTimer =
+// Timer.periodic(Duration(seconds: effectivePollingInterval), (_) {
+// _handleRideState(currentRideState.value);
+// });
+// }
+// }
+// // === 4. المنطق الجديد: فحص الرحلة الأخيرة للتقييم ===
+
+ Future _checkInitialRideStatus() async {
+ // 1. جلب الحالة من السيرفر (باستخدام getRideStatusFromStartApp)
+ await getRideStatusFromStartApp();
+ String _status = rideStatusFromStartApp['data']['status'];
+ // Log.print('rideStatusFromStartApp: ${rideStatusFromStartApp}');
+ // Log.print('_status: ${_status}');
+
+ if (_status == 'waiting' || _status == 'Apply' || _status == 'Begin') {
+ // رحلة جارية
+ rideId = rideStatusFromStartApp['data']['rideId'].toString();
+ currentRideState.value = _status == 'waiting'
+ ? RideState.searching
+ : _status == 'Apply'
+ ? RideState.driverApplied
+ : _status == 'Begin'
+ ? RideState.inProgress
+ : _status == 'Cancel'
+ ? RideState.cancelled
+ : RideState.noRide;
+ } else if (_status == 'Finished') {
+ // رحلة منتهية/ملغاة
+ if (rideStatusFromStartApp['data']['needsReview'] == 1) {
+ currentRideState.value = RideState.preCheckReview;
+ } else {
+ currentRideState.value = RideState.noRide;
+ }
+ } else {
+ currentRideState.value = RideState.noRide;
+ }
+
+ // بدء المعالجة الفورية
+ _handleRideState(currentRideState.value);
+ }
+
+ Future _checkLastRideForReview() async {
+ // (يتم استدعاؤها مرة واحدة عند الدخول لحالة preCheckReview)
+ // 1. استعلام السيرفر للتأكد من الحاجة للتقييم
+ getRideStatusFromStartApp();
+ String needsReview =
+ rideStatusFromStartApp['data']['needsReview'].toString();
+
+ if (needsReview == '1') {
+ // 2. إظهار Bottom Sheet للتقييم (إجبار الراكب على التقييم)
+ Get.to(() => RatingDriverBottomSheet(), arguments: {
+ 'driverId': rideStatusFromStartApp['data']['driver_id'].toString(),
+ 'rideId': rideStatusFromStartApp['data']['rideId'].toString(),
+ 'driverName': rideStatusFromStartApp['data']['driverName'],
+ 'price': rideStatusFromStartApp['data']['price'],
+ });
+ // showRatingScreen();
+ print('>>> Showing forced Rating Bottom Sheet for ride: $rideId');
+
+ // بمجرد انتهاء التقييم، يتم تعيين الحالة إلى NO_RIDE
+ // onRatingSubmitted: () {
+ // currentRideState.value = RideState.noRide;
+ // _startMasterTimer(); // إعادة تشغيل المؤقت لحالة NO_RIDE
+ // }
+ } else {
+ // لا تحتاج تقييم، العودة لحالة لا رحلة
+ currentRideState.value = RideState.noRide;
+ _startMasterTimer(); // إعادة تشغيل المؤقت لحالة NO_RIDE
+ }
+ }
+
+ // [داخل MapPassengerController]
+
+// (افترض وجود هذه الدالة لديك بالفعل)
+ // === 5. دوال التغيير في الحالة التي تستدعى من واجهة المستخدم ===
+
+ // void startSearchingForDriver() {
+ // confirmRideForAllDriverAvailable();
+ // currentRideState.value = RideState.searching;
+ // _startMasterTimer();
+ // }
+
+ /// هذه هي الدالة التي يتم استدعاؤها من الواجهة عند ضغط المستخدم على زر تأكيد الطلب
+
+ void startSearchingForDriver() async {
+ isSearchingWindow = true;
+ update();
+
+ bool rideCreated = await postRideDetailsToServer();
+ if (!rideCreated) {
+ isSearchingWindow = false;
+ update();
+ return;
+ }
+
+ await _addRideToWaitingTable();
+
+ Log.print('[startSearchingForDriver] Starting fresh search sequence.');
+
+ // تصفير القائمة هنا ضروري لأنها رحلة جديدة
+ notifiedDrivers.clear();
+
+ _searchStartTime = DateTime.now();
+ _lastDriversNotifyTime = null;
+ _currentSearchPhase = 0;
+ _isDriverAppliedLogicExecuted = false;
+ _isDriverArrivedLogicExecuted = false;
+ _isRideBeginLogicExecuted = false;
+
+ // تنفيذ البحث الأولي فوراً
+ await _findAndNotifyNearestDrivers(_searchRadii[0]);
+
+ currentRideState.value = RideState.searching;
+ isSearchingWindow = true;
+ update();
+ _startMasterTimer();
+ }
+
+ /// دالة جديدة للبحث عن السائقين وإرسال الإشعارات لهم
+ // تم التعديل: الآن تقبل نصف القطر (radius)
+ /// [!! إصلاح خطأ البيلود !!]
+ /// تم التعديل: العودة إلى إرسال إشعارات فردية (لكل سائق)
+ /// لإرسال "البيلود" الصحيح الذي يتوقعه تطبيق السائق
+ Future _findAndNotifyNearestDrivers(int radius) async {
+ Log.print('[Notify Logic] Finding drivers within $radius meters...');
+
+ // 1. جلب السائقين وتحديث الماركر
+ // ملاحظة: تأكد أن هذه الدالة تعيد true/false لتدل على النجاح
+ await getCarsLocationByPassengerAndReloadMarker(
+ box.read(BoxName.carType), radius);
+
+ // التأكد من صحة البيانات
+ if (dataCarsLocationByPassenger == null ||
+ dataCarsLocationByPassenger == 'failure' ||
+ dataCarsLocationByPassenger['message'] == null) {
+ Log.print('[Notify Logic] No drivers found or API failure.');
+ return;
+ }
+
+ int newDriversNotified = 0;
+ var driversList = dataCarsLocationByPassenger['message'];
+
+ if (driversList is! List) {
+ Log.print('[Notify Logic] Drivers data is not a list.');
+ return;
+ }
+
+ // 2. المرور على كل سائق
+ for (var driverData in driversList) {
+ // حماية من البيانات الناقصة
+ if (driverData['driver_id'] == null || driverData['token'] == null) {
+ continue;
+ }
+
+ String driverId = driverData['driver_id'].toString();
+ String driverToken = driverData['token'].toString();
+
+ // تجاهل التوكن الفارغ أو غير الصالح
+ if (driverToken.isEmpty || driverToken == 'null') continue;
+
+ // 3. التحقق من القائمة المرجعية (المنع الصارم للتكرار)
+ if (!notifiedDrivers.contains(driverId)) {
+ // إضافة السائق للقائمة فوراً لمنع تكرار الإرسال في الدورات القادمة
+ notifiedDrivers.add(driverId);
+ newDriversNotified++;
+
+ // 4. بناء البيلود وإرسال الإشعار
+ try {
+ final body = constructNotificationBody(driverData);
+
+ Log.print('[Notify Logic] Sending New Order to Driver ID: $driverId');
+
+ NotificationService.sendNotification(
+ target: driverToken,
+ title: 'Order',
+ body: endNameAddress, // عنوان الوجهة كنص مختصر
+ isTopic: false,
+ tone: 'tone1',
+ category: 'Order',
+ driverList: body);
+ } catch (e) {
+ Log.print('[Notify Logic] Error sending to driver $driverId: $e');
+ // في حال فشل الإرسال، هل تريد حذفه من القائمة ليحاول مرة أخرى؟
+ // يفضل عدم الحذف لتجنب الإزعاج، إلا إذا كان خطأ شبكة مؤقت.
+ }
+ } else {
+ // Log.print('[Notify Logic] Driver $driverId already notified. Skipping.');
+ }
+ }
+ Log.print(
+ '[Notify Logic] Cycle finished. Sent to $newDriversNotified NEW drivers.');
+ }
+
+ /// دالة لإظهار النافذة المنبثقة لزيادة السعر
+ void _showIncreaseFeeDialog() {
+ Get.dialog(
+ CupertinoAlertDialog(
+ title: Text("No drivers accepted your request yet".tr),
+ content: Text(
+ "Increasing the fare might attract more drivers. Would you like to increase the price?"
+ .tr),
+ actions: [
+ CupertinoDialogAction(
+ child: Text("Cancel Ride".tr,
+ style: const TextStyle(color: AppColor.redColor)),
+ onPressed: () {
+ Get.back();
+ changeCancelRidePageShow();
+ // cancelRide(); // دالة إلغاء الرحلة
+ },
+ ),
+ CupertinoDialogAction(
+ child: Text("Increase Fare".tr,
+ style: const TextStyle(color: AppColor.greenColor)),
+ onPressed: () {
+ Get.back();
+ // هنا يمكنك عرض نافذة أخرى لإدخال السعر الجديد
+ // وبعدها استدعاء الدالة التالية
+ // كمثال، سنزيد السعر بنسبة 10%
+ double newPrice = totalPassenger * 1.10;
+ increasePriceAndRestartSearch(newPrice);
+ },
+ ),
+ ],
+ ),
+ barrierDismissible: false,
+ );
+ }
+
+ /// دالة لتحديث السعر وإعادة بدء البحث
+ Future increasePriceAndRestartSearch(double newPrice) async {
+ totalPassenger = newPrice;
+ update();
+
+ await CRUD().post(link: AppLink.updateRides, payload: {
+ "id": rideId,
+ "price": newPrice.toStringAsFixed(2),
+ });
+ CRUD().post(link: "${AppLink.server}/ride/rides/update.php", payload: {
+ "id": rideId,
+ "price": newPrice.toStringAsFixed(2),
+ });
+
+ // تصفير القائمة لأن السعر تغير، ويجب إبلاغ الجميع (حتى من وصله الإشعار سابقاً)
+ Log.print(
+ '[increasePrice] Price changed. Clearing notified list to resend.');
+ notifiedDrivers.clear();
+
+ _searchStartTime = DateTime.now();
+ _currentSearchPhase = 0;
+
+ isSearchingWindow = true;
+ update();
+
+ _startMasterTimer();
+ }
+
+ /// (دالة جديدة موحدة)
+ /// هذه هي الدالة الوحيدة المسؤولة عن بدء عملية قبول الرحلة.
+ /// يتم استدعاؤها إما من إشعار Firebase أو من البحث الدوري (Polling).
+ /// هي تحتوي على "حارس البوابة" لمنع تضارب السباق.
+ Future processRideAcceptance(
+ {String? driverIdFromFCM, String? rideIdFromFCM}) async {
+ // 1. حارس البوابة (منع السباق)
+ // هل ما زلنا في حالة البحث؟
+ if (currentRideState.value != RideState.searching) {
+ Log.print(
+ '[processRideAcceptance] تم الحظر: الحالة ليست searching، تم قبول الرحلة مسبقاً.');
+ return; // اخرج فوراً. العملية تمت بالفعل.
+ }
+
+// getDriverCarsLocationToPassengerAfterApplied();
+ // 2. فزنا بالسباق! قم بتغيير الحالة فوراً
+ // هذا السطر يضمن أن أي استدعاء آخر (من الإشعار أو البحث) سيفشل في الشرط أعلاه
+ currentRideState.value = RideState.driverApplied;
+ Log.print('[processRideAcceptance] نجح: تغيير الحالة إلى driverApplied.');
+
+ // 3. تحديث البيانات (كما في كود الإشعار الخاص بك)
+ // إذا كان الاستدعاء من الإشعار، استخدم البيانات الممررة
+ if (driverIdFromFCM != null) {
+ driverId = driverIdFromFCM;
+ }
+ if (rideIdFromFCM != null) {
+ rideId = rideIdFromFCM;
+ }
+ // (ملاحظة: إذا كان الاستدعاء من البحث الدوري، فإن 'rideId' معروف مسبقاً)
+ await getUpdatedRideForDriverApply(rideId);
+ // 4. تحديث واجهة المستخدم (كما في كود الإشعار)
+ statusRide = 'Apply';
+ isSearchingWindow = false;
+ update(); // إخفاء نافذة البحث وتحديث الواجهة
+
+ // 5. إظهار الإشعار المحلي (توحيد المنطق)
+ // (نقلنا هذا من معالج الإشعارات إلى هنا)
+ if (Get.isRegistered()) {
+ Get.find().showNotification(
+ 'Accepted Ride'.tr, 'Driver Accepted the Ride for You'.tr, 'ding');
+ }
+
+ // 6. !! تم الحذف !!
+ // await rideAppliedFromDriver(true); <-- (تم حذف هذا السطر)
+ // الآن هذه الدالة آمنة ولا تشغل أي تايمرات.
+ }
+
+ Future driverArrivePassengerDialoge() {
+ return Get.defaultDialog(
+ barrierDismissible: false,
+ title: 'Hi ,I Arrive your site'.tr,
+ titleStyle: AppStyle.title,
+ middleText: 'Please go to Car Driver'.tr,
+ middleTextStyle: AppStyle.title,
+ confirm: MyElevatedButton(
+ title: 'Ok I will go now.'.tr,
+ onPressed: () {
+ NotificationService.sendNotification(
+ target: driverToken.toString(),
+ title: 'Hi ,I will go now'.tr,
+ body: 'I will go now'.tr,
+ isTopic: false, // Important: this is a token
+ tone: 'ding',
+ driverList: [],
+ category: 'Hi ,I will go now',
+ );
+
+ Get.back();
+ remainingTime = 0;
+ update();
+ }));
+ }
+
+ /// (دالة خاصة جديدة)
+ /// تحتوي على كل المنطق الفعلي لبدء الرحلة.
+ void _executeBeginRideLogic() {
+ Log.print('[executeBeginRideLogic] تنفيذ منطق بدء الرحلة...');
+
+ // 1. تصفير كل عدادات ما قبل الرحلة
+ timeToPassengerFromDriverAfterApplied = 0;
+ remainingTime = 0;
+ remainingTimeToPassengerFromDriverAfterApplied = 0;
+ remainingTimeDriverWaitPassenger5Minute = 0;
+
+ // 2. تحديث الحالة والواجهة
+ rideTimerBegin = true;
+ statusRide = 'Begin';
+ isDriverInPassengerWay = false;
+ isDriverArrivePassenger = false; // لإخفاء واجهة "السائق وصل"
+
+ // 3. (من كود الإشعار الخاص بك)
+ box.write(BoxName.passengerWalletTotal, '0');
+ update(); // تحديث الواجهة قبل بدء المؤقتات
+
+ // 4. بدء مؤقتات الرحلة الفعلية
+ rideIsBeginPassengerTimer(); // مؤقت عداد مدة الرحلة
+ runWhenRideIsBegin(); // مؤقت تتبع موقع السائق أثناء الرحلة
+
+ // 5. إشعار الراكب (من كود الإشعار الخاص بك)
+ 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,
+ 'start');
+ }
+
+ /// (دالة جديدة موحدة)
+ /// حارس البوابة الآمن لبدء الرحلة. تمنع تضارب السباق.
+ //
+ //
+ // !!! يرجى استبدال الدالة القديمة بالكامل بهذه الدالة الجديدة !!!
+ //
+ //
+
+ /// (دالة جديدة موحدة)
+ /// حارس البوابة الآمن لبدء الرحلة. تمنع تضارب السباق.
+ void processRideBegin() {
+ // [!! تعديل رقم 3: حل مشكلة "تم الحظر" !!]
+ // اقبل بدء الرحلة إذا كانت الحالة (وصل) أو (قَبِل)
+ // هذا يضمن أنه إذا فاتنا إشعار "الوصول" واستلمنا "البدء" مباشرة، فإنه سيعمل
+ if (currentRideState.value != RideState.driverArrived &&
+ currentRideState.value != RideState.driverApplied) {
+ Log.print(
+ '[processRideBegin] تم الحظر: الحالة ليست driverArrived أو driverApplied.');
+ return;
+ }
+
+ // تأكد من تغيير الحالة فقط إذا لم تكن كذلك بالفعل
+ if (currentRideState.value != RideState.inProgress) {
+ currentRideState.value = RideState.inProgress;
+ Log.print('[processRideBegin] نجح: تغيير الحالة إلى inProgress.');
+ }
+
+ // لا تقم بتشغيل أي منطق هنا
+ // المنطق الفعلي (_executeBeginRideLogic) سيتم استدعاؤه بواسطة
+ // المؤقت الرئيسي (_handleRideState) عند اكتشاف حالة inProgress
+ // هذا يضمن أنه يعمل مرة واحدة فقط وبشكل آمن
+ }
late Duration durationToAdd;
late DateTime newTime = DateTime.now();
@@ -406,41 +1229,33 @@ class MapPassengerController extends GetxController {
"order_id": rideId.toString(), // Convert to String
"status": 'waiting'
});
- if (AppLink.endPoint != AppLink.IntaleqSyriaServer) {
- CRUD().post(
- link: "${AppLink.endPoint}/ride/driver_order/update.php",
- payload: {
- "order_id": rideId.toString(), // Convert to String
- "status": 'waiting'
- });
- }
+
await CRUD().post(link: AppLink.updateRides, payload: {
"id": rideId.toString(), // Convert to String
"status": 'waiting'
});
- if (AppLink.endPoint != AppLink.IntaleqSyriaServer) {
- CRUD().post(
- link: "${AppLink.endPoint}/ride/rides/update.php",
- payload: {
- "id": rideId.toString(), // Convert to String
- "status": 'waiting'
- });
- }
+
CRUD().post(link: AppLink.updateWaitingTrip, payload: {
"id": rideId.toString(), // Convert to String
"status": 'wait'
});
- if (AppLink.endPoint != AppLink.IntaleqSyriaServer) {
- CRUD().post(
- link:
- "${AppLink.endPoint}/ride/notificationCaptain/updateWaitingTrip.php",
- payload: {
- "id": rideId.toString(), // Convert to String
- "status": 'wait'
- });
- }
- tick = 0;
+ CRUD().post(
+ link: "${AppLink.endPoint}/ride/rides/update.php",
+ payload: {
+ "id": rideId.toString(), // Convert to String
+ "status": 'waiting'
+ });
+ // if (AppLink.endPoint != AppLink.IntaleqSyriaServer) {
+ CRUD().post(
+ link:
+ "${AppLink.endPoint}/ride/notificationCaptain/updateWaitingTrip.php",
+ payload: {
+ "id": rideId.toString(), // Convert to String
+ "status": 'wait'
+ });
}
+ tick = 0;
+ // }
await getCarsLocationByPassengerAndReloadMarker(
box.read(BoxName.carType), 4000);
// confirmRideForAllDriverAvailable();
@@ -597,16 +1412,49 @@ class MapPassengerController extends GetxController {
launchCommunication('sms', to, message);
}
- void sendWhatsapp(String to) async {
- // Get the driver's phone number.
- // String driverPhone = dataCarsLocationByPassenger['message'][carsOrder]['phone'].toString();
+ String formatSyrianPhone(String phone) {
+ // Remove spaces and +
+ phone = phone.replaceAll(' ', '').replaceAll('+', '');
- // Format the message.
+ // If starts with 00963 → remove 00 → 963
+ if (phone.startsWith('00963')) {
+ phone = phone.replaceFirst('00963', '963');
+ }
+
+ // If starts with 0963 (common mistake) → fix it
+ if (phone.startsWith('0963')) {
+ phone = phone.replaceFirst('0963', '963');
+ }
+
+ // If starts with 963 (already correct)
+ if (phone.startsWith('963')) {
+ return phone; // nothing to do
+ }
+
+ // If starts with 09 → remove leading 0 → add 963
+ if (phone.startsWith('09')) {
+ return '963' + phone.substring(1); // 9xxxxxxxxx
+ }
+
+ // If starts with 9xxxxxxxxx (no country code)
+ if (phone.startsWith('9') && phone.length == 9) {
+ return '963' + phone;
+ }
+
+ // Otherwise return raw phone
+ return phone;
+ }
+
+ void sendWhatsapp(String to) async {
+ // Normalize phone number before sending
+ String formattedPhone = formatSyrianPhone(to);
+
+ // Message body
String message =
'${'${'Hi! This is'.tr} ${(box.read(BoxName.name).toString().split(' ')[0]).toString()}.\n${' I am using'.tr}'} ${AppInformation.appName}${' to ride with'.tr} $passengerName${' as the driver.'.tr} $passengerName \n${'is driving a '.tr}$model\n${' with license plate '.tr}$licensePlate.\n${' I am currently located at '.tr} https://www.google.com/maps/place/${passengerLocation.latitude},${passengerLocation.longitude}.\n${' If you need to reach me, please contact the driver directly at'.tr}\n\n $driverPhone.';
- // Launch the URL to send the WhatsApp message.
- launchCommunication('whatsapp', to, message);
+ // Send WhatsApp message
+ launchCommunication('whatsapp', formattedPhone, message);
}
void changeCancelRidePageShow() {
@@ -634,44 +1482,6 @@ 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;
@@ -679,53 +1489,62 @@ class MapPassengerController extends GetxController {
int beginRideInterval = 4; // Interval in seconds for getBeginRideFromDriver
void startTimerFromDriverToPassengerAfterApplied() {
- if (isTimerRunning) return; // Prevent duplicate streams
+ if (isTimerRunning) return;
isTimerRunning = true;
int secondsElapsed = 0;
- // Start the stream
+ // استدعاء فوري لأول مرة
+ getDriverCarsLocationToPassengerAfterApplied();
+
Timer.periodic(const Duration(seconds: 1), (timer) {
+ // شروط الإيقاف
if (secondsElapsed > timeToPassengerFromDriverAfterApplied ||
!isTimerFromDriverToPassengerAfterAppliedRunning) {
timer.cancel();
isTimerRunning = false;
- _timerStreamController.close(); // Close the stream when done
+ if (!_timerStreamController.isClosed) {
+ _timerStreamController.close();
+ }
return;
}
secondsElapsed++;
- _timerStreamController.add(secondsElapsed); // Emit elapsed time
+ if (!_timerStreamController.isClosed) {
+ _timerStreamController.add(secondsElapsed);
+ }
- // Calculate progress and remaining time
- progressTimerToPassengerFromDriverAfterApplied =
- secondsElapsed / timeToPassengerFromDriverAfterApplied;
+ // حسابات الوقت للواجهة
remainingTimeToPassengerFromDriverAfterApplied =
timeToPassengerFromDriverAfterApplied - secondsElapsed;
- // Update remaining time as string
+ // حماية من القيم السالبة
+ if (remainingTimeToPassengerFromDriverAfterApplied < 0)
+ remainingTimeToPassengerFromDriverAfterApplied = 0;
+
int minutes =
(remainingTimeToPassengerFromDriverAfterApplied / 60).floor();
int seconds = remainingTimeToPassengerFromDriverAfterApplied % 60;
stringRemainingTimeToPassenger =
'$minutes:${seconds.toString().padLeft(2, '0')}';
- if (remainingTimeToPassengerFromDriverAfterApplied < 59 &&
- !rideTimerBegin) {
- rideTimerBegin = true;
- }
-
- // Call periodic functions
+ // كل 4 ثواني، نحدث موقع السائق ونعيد الرسم
if (secondsElapsed % beginRideInterval == 0) {
+ // 1. تحقق من حالة الرحلة (هل بدأت؟)
getBeginRideFromDriver();
+
+ // 2. ارفع موقع الراكب
uploadPassengerLocation();
+
+ // 3. الأهم: جلب موقع السائق وتحديث الخريطة والمسار
+ // لا نحتاج لعمل await هنا حتى لا نعطل عداد الثواني
+ getDriverCarsLocationToPassengerAfterApplied();
+ } else {
+ // تحديث الواجهة فقط للعداد في الثواني التي لا نطلب فيها الموقع
+ update();
}
-
- update(); // Notify listeners
});
- }
-
- // void startTimerFromDriverToPassengerAfterApplied() async {
+ } // void startTimerFromDriverToPassengerAfterApplied() async {
// if (isTimerRunning) return; // Exit if timer is already running
// isTimerRunning = true; // Set the flag to true
@@ -771,13 +1590,53 @@ class MapPassengerController extends GetxController {
}
void startTimerDriverWaitPassenger5Minute() async {
+ // 1. [مهم] إيقاف المؤقت السابق (مؤقت تتبع وصول السائق)
stopTimerFromDriverToPassengerAfterApplied();
+ isTimerRunning = false; // (إذا كنت تستخدم فلاج للتحكم بالمؤقت السابق)
+
+ // 2. تحديث حالة الواجهة فوراً
isDriverArrivePassenger = true;
isDriverInPassengerWay = false;
timeToPassengerFromDriverAfterApplied = 0;
update();
+
+ Log.print('[startTimerDriverWaitPassenger5Minute] بدأ عداد الـ 5 دقائق.');
+
+ // 3. بدء عداد الخمس دقائق (300 ثانية)
for (int i = 0; i <= 300; i++) {
- await Future.delayed(const Duration(seconds: 1));
+ // 4. [حارس السباق 1] التحقق من الحالة
+ // إذا فاز إشعار FCM (FCM Winner) وتغيرت الحالة، أوقف هذا العداد فوراً.
+ if (currentRideState.value != RideState.driverArrived) {
+ Log.print(
+ '[startTimerDriverWaitPassenger5Minute] إيقاف العد: الحالة تغيرت (FCM فاز).');
+ break; // اخرج من loop الخمس دقائق
+ }
+
+ // 5. [البحث الدوري 2] التحقق من السيرفر (كل 6 ثوانٍ)
+ if (i % 6 == 0 && i > 0) {
+ // (نتخطى الثانية صفر)
+ try {
+ var res = await CRUD().get(
+ link: AppLink.getRideStatusBegin, payload: {'ride_id': rideId});
+
+ if (res != 'failure') {
+ var decode = jsonDecode(res);
+ if (decode['data']['status'] == 'Begin') {
+ Log.print(
+ '[startTimerDriverWaitPassenger5Minute] اكتشف "Begin" (Polling فاز).');
+
+ // 6. استدعاء حارس البوابة الآمن
+ processRideBegin();
+
+ break; // اخرج من loop الخمس دقائق
+ }
+ }
+ } catch (e) {
+ Log.print('خطأ أثناء البحث الدوري عن بدء الرحلة: $e');
+ }
+ }
+
+ // 7. تحديث واجهة المستخدم (العداد)
progressTimerDriverWaitPassenger5Minute = i / 300;
remainingTimeDriverWaitPassenger5Minute = 300 - i;
@@ -787,7 +1646,13 @@ class MapPassengerController extends GetxController {
'$minutes:${seconds.toString().padLeft(2, '0')}';
update();
+
+ // 8. الانتظار ثانية واحدة
+ await Future.delayed(const Duration(seconds: 1));
}
+
+ Log.print(
+ '[startTimerDriverWaitPassenger5Minute] انتهى (إما بالوقت أو ببدء الرحلة).');
}
// Create a StreamController to manage the timer values
@@ -977,57 +1842,45 @@ class MapPassengerController extends GetxController {
}
void tripFinishedFromDriver() {
+ // هذه الدالة الآن مسؤولة فقط عن تصفير الواجهة
+ // معالج الإشعار (FCM) هو المسؤول عن الانتقال لصفحة التقييم
+ Log.print('[tripFinishedFromDriver] Resetting UI flags for finished ride.');
+
isRideFinished = true;
rideTimerBegin = false;
statusRideVip = 'Finished';
+ statusRide = 'Finished'; // لضمان التناسق
box.write(BoxName.arrivalTime, '');
remainingTimeTimerRideBegin = 0;
- box.write(BoxName.passengerWalletTotal, '0');
+
+ // (ملاحظة: لقد أبقيت على منطق المحفظة في معالج الإشعار لأنه مرتبط بالسعر)
+ // box.write(BoxName.passengerWalletTotal, '0'); // تم نقله إلى FCM
+
update();
+
+ // إرسال إشعار للوالدين (إذا كان مفعلاً)
if (box.read(BoxName.parentTripSelected) == true) {
NotificationService.sendNotification(
+ category: "Finish Monitor",
target: box.read(BoxName.tokenParent),
title: "Finish Monitor".tr,
body: 'Finish Monitor'.tr,
- isTopic: false, // Important: this is a token
+ isTopic: false,
tone: 'tone1',
);
box.write(BoxName.parentTripSelected, false);
box.remove(BoxName.tokenParent);
}
+
+ // ---!! تم حذف الانتقال من هنا لمنع الازدواجية !! ---
+ // Get.to(() => RateDriverFromPassenger(), arguments: {
+ // 'driverId': driverId.toString(),
+ // 'rideId': rideId.toString(),
+ // 'price': costForDriver.toString()
+ // });
+ // --- نهاية الحذف ---
}
- // bool isBeginRideFromDriver = false;
- // void getBeginRideFromDriver() async {
- // try {
- // if (isBeginRideFromDriver) return; // Prevent duplicate streams
- // isBeginRideFromDriver = true;
- // var res = await CRUD()
- // .get(link: AppLink.getRideStatusBegin, payload: {'ride_id': rideId});
- // if (res != 'failure') {
- // var decode = jsonDecode(res);
-
- // // if (decode['data']['status'] != 'Apply') {
- // if (decode['data']['status'] == 'Begin') {
- // timeToPassengerFromDriverAfterApplied = 0;
- // remainingTime = 0;
- // remainingTimeToPassengerFromDriverAfterApplied = 0;
- // remainingTimeDriverWaitPassenger5Minute = 0;
- // rideTimerBegin = true;
- // statusRide = 'Begin';
- // isDriverInPassengerWay = false;
- // isDriverArrivePassenger = false;
- // update();
- // // isCancelRidePageShown = true;
- // rideIsBeginPassengerTimer();
- // runWhenRideIsBegin();
- // } else {}
- // }
- // } catch (e) {
- // // Handle the error or perform any necessary actions
- // }
- // }
-
StreamController _beginRideStreamController =
StreamController.broadcast();
Stream get beginRideStream => _beginRideStreamController.stream;
@@ -1108,44 +1961,43 @@ class MapPassengerController extends GetxController {
}
Map rideStatusFromStartApp = {};
+ bool isStartAppHasRide = false;
getRideStatusFromStartApp() async {
try {
var res = await CRUD().get(
link: AppLink.getRideStatusFromStartApp,
payload: {'passenger_id': box.read(BoxName.passengerID)});
- print(res);
- print('1070');
+ // print(res);
+ Log.print('rideStatusFromStartApp: ${res}');
+ // print('1070');
if (res == 'failure') {
+ rideStatusFromStartApp = {
+ 'data': {'status': 'NoRide', 'needsReview': false}
+ };
+ isStartAppHasRide = false;
print(
"No rides found for the given passenger ID within the last hour.");
}
rideStatusFromStartApp = jsonDecode(res);
- if (rideStatusFromStartApp['data']['status'] == 'Begin') {
- statusRide = 'Begin';
+ if (rideStatusFromStartApp['data']['status'] == 'Begin' ||
+ rideStatusFromStartApp['data']['status'] == 'Apply' ||
+ rideStatusFromStartApp['data']['status'] == 'Applied') {
+ statusRide = rideStatusFromStartApp['data']['status'];
+ isStartAppHasRide = true;
+ RideState.inProgress;
driverId = rideStatusFromStartApp['data']['driver_id'];
passengerName = rideStatusFromStartApp['data']['driverName'];
driverRate = rideStatusFromStartApp['data']['rateDriver'].toString();
statusRideFromStart = true;
- // DateTime endTime =
- // DateTime.parse(rideStatusFromStartApp['data']['endtime']);
- // DateTime rideTimeStart =
- // DateTime.parse(rideStatusFromStartApp['data']['rideTimeStart']);
- //
- // // Calculate the new end time by adding the duration to the rideTimeStart
- // DateTime newEndTime = rideTimeStart.add(
- // Duration(seconds: endTime.difference(rideTimeStart).inSeconds));
- //
- // // Save the new end time in a variable
- // var newEndTimeVariable = newEndTime.toString();
+
update();
Map tripData =
box.read(BoxName.tripData) as Map;
- String pointsString =
- (tripData["routes"][0]["overview_polyline"]["points"]);
-
+ final String pointsString = tripData['polyline'];
List decodedPoints =
await compute(decodePolylineIsolate, pointsString);
+
// decodePolyline(response["routes"][0]["overview_polyline"]["points"]);
for (int i = 0; i < decodedPoints.length; i++) {
polylineCoordinates.add(decodedPoints[i]);
@@ -1167,7 +2019,7 @@ class MapPassengerController extends GetxController {
isDriverArrivePassenger = false;
// update();
// isCancelRidePageShown = true;
- durationToAdd = tripData['routes'][0]['legs'][0]['duration']['value'];
+ durationToAdd = tripData['distance_m'];
rideIsBeginPassengerTimer();
runWhenRideIsBegin();
update();
@@ -1379,24 +2231,34 @@ class MapPassengerController extends GetxController {
Set notifiedDrivers = {};
- addRideToNotificationDriverAvailable() async {
- await CRUD().post(link: AppLink.addWaitingRide, payload: {
- 'id': rideId.toString(),
- 'start_location':
- '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
- 'end_location':
- '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}',
- "date": DateTime.now().toString(),
- "time": DateTime.now().toString(),
- "price": totalPassenger.toStringAsFixed(2),
- 'passenger_id': box.read(BoxName.passengerID).toString(),
- 'status': 'waiting',
- 'carType': box.read(BoxName.carType),
- 'passengerRate': passengerRate.toStringAsFixed(2),
- 'price_for_passenger': totalME.toStringAsFixed(2),
- 'distance': distance.toStringAsFixed(1),
- 'duration': duration.toStringAsFixed(1),
- });
+ /// [إضافة جديدة]
+ /// دالة مخصصة لإضافة الرحلة إلى جدول الانتظار (waiting_ride)
+ Future _addRideToWaitingTable() async {
+ try {
+ await CRUD().post(link: AppLink.addWaitingRide, payload: {
+ 'id': rideId.toString(),
+ "start_location":
+ '${startLocation.latitude},${startLocation.longitude}',
+ "end_location": '${endLocation.latitude},${endLocation.longitude}',
+ // 'start_location':
+ // '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
+ // 'end_location':
+ // '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}',
+ "date": DateTime.now().toString(),
+ "time": DateTime.now().toString(),
+ "price": totalPassenger.toStringAsFixed(2),
+ 'passenger_id': box.read(BoxName.passengerID).toString(),
+ 'status': 'waiting', // الحالة الرئيسية لجدول الانتظار
+ 'carType': box.read(BoxName.carType),
+ 'passengerRate': passengerRate.toStringAsFixed(2),
+ 'price_for_passenger': totalME.toStringAsFixed(2),
+ 'distance': distance.toStringAsFixed(1),
+ 'duration': duration.toStringAsFixed(1),
+ });
+ Log.print('[WaitingTable] Ride $rideId added to waiting_ride table.');
+ } catch (e) {
+ Log.print('Error adding ride to waiting_ride table: $e');
+ }
}
// Future confirmRideForAllDriverAvailable1() async {
@@ -1777,58 +2639,58 @@ class MapPassengerController extends GetxController {
// });
// }
- showAndResearchForCaptain() {
- Get.snackbar(
- "No Captain Accepted Your Order".tr,
- "We are looking for a captain but the price may increase to let a captain accept"
- .tr,
- duration: const Duration(seconds: 5),
- backgroundColor: AppColor.yellowColor,
- );
- isSearchingWindow == true;
- update();
- }
+ // showAndResearchForCaptain() {
+ // Get.snackbar(
+ // "No Captain Accepted Your Order".tr,
+ // "We are looking for a captain but the price may increase to let a captain accept"
+ // .tr,
+ // duration: const Duration(seconds: 5),
+ // backgroundColor: AppColor.yellowColor,
+ // );
+ // isSearchingWindow == true;
+ // update();
+ // }
String driversStatusForSearchWindow = '';
- Future confirmRideForAllDriverAvailable() async {
- bool driversFound = false;
- const maxAttempts = 8;
- const attemptDelay = Duration(seconds: 3);
+ // 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();
- currentTimeSearchingCaptainWindow = 0;
- driversStatusForSearchWindow = 'We are search for nearst driver'.tr;
- if (isDriversDataValid()) {
- driversFound = true;
- break;
- }
+ // for (int attempt = 0; attempt < maxAttempts; attempt++) {
+ // final reloadDuration = attempt > 5 ? 4500 : 3000;
+ // await getCarsLocationByPassengerAndReloadMarker(
+ // box.read(BoxName.carType), reloadDuration);
+ // // await getNearestDriverByPassengerLocation();
+ // currentTimeSearchingCaptainWindow = 0;
+ // driversStatusForSearchWindow = 'We are search for nearst driver'.tr;
+ // if (isDriversDataValid()) {
+ // driversFound = true;
+ // break;
+ // }
- await Future.delayed(attemptDelay);
- }
+ // await Future.delayed(attemptDelay);
+ // }
- if (!driversFound) {
- showNoDriversDialog();
- return;
- }
- driversStatusForSearchWindow = 'Your order is being prepared'.tr;
- Log.print('driversStatusForSearchWindow: $driversStatusForSearchWindow');
- update();
- await postRideDetailsToServer();
- driversStatusForSearchWindow = 'Your order sent to drivers'.tr;
+ // if (!driversFound) {
+ // showNoDriversDialog();
+ // return;
+ // }
+ // driversStatusForSearchWindow = 'Your order is being prepared'.tr;
+ // Log.print('driversStatusForSearchWindow: $driversStatusForSearchWindow');
+ // update();
+ // await postRideDetailsToServer();
+ // driversStatusForSearchWindow = 'Your order sent to drivers'.tr;
- await notifyAvailableDrivers();
+ // await notifyAvailableDrivers();
- driversStatusForSearchWindow = 'The drivers are reviewing your request'.tr;
- Log.print('driversStatusForSearchWindow: $driversStatusForSearchWindow');
- update();
- delayAndFetchRideStatusForAllDriverAvailable(rideId);
- // update();
- }
+ // driversStatusForSearchWindow = 'The drivers are reviewing your request'.tr;
+ // Log.print('driversStatusForSearchWindow: $driversStatusForSearchWindow');
+ // update();
+ // delayAndFetchRideStatusForAllDriverAvailable(rideId);
+ // // update();
+ // }
Future updateConfirmRideForAllDriverAvailable() async {
bool driversFound = false;
@@ -1855,7 +2717,7 @@ class MapPassengerController extends GetxController {
}
// await postRideDetailsToServer();
- delayAndFetchRideStatusForAllDriverAvailable(rideId);
+ // delayAndFetchRideStatusForAllDriverAvailable(rideId);
// update();
await notifyAvailableDrivers();
}
@@ -1893,52 +2755,97 @@ class MapPassengerController extends GetxController {
);
}
- Future postRideDetailsToServer() async {
+ Future postRideDetailsToServer() async {
final paymentController = Get.find();
+ startLocation = polylineCoordinates.first;
+ endLocation = polylineCoordinates.last;
+ // '${startLocation.latitude},${startLocation.longitude}',
+ // "end_location": '${endLocation.latitude},${endLocation.longitude}',
final payload = constructRidePayload(paymentController);
+ Log.print('constructRidePayload: ${payload}');
try {
- final response = await CRUD().post(
- link: "${AppLink.IntaleqSyriaServer}/ride/rides/add.php",
- payload: payload);
+ final response = await CRUD()
+ .post(link: "${AppLink.ride}/ride/rides/add.php", payload: payload);
if (response is String) {
final parsedValue = jsonDecode(response);
rideId = parsedValue['message'];
+ return true;
} else if (response is Map) {
rideId = response['message'];
+ CRUD().post(
+ link: "${AppLink.server}/ride/rides/add.php", payload: payload);
+ return true;
} else {
Log.print('Unexpected response type: ${response.runtimeType}');
+ return false;
}
} catch (e) {
Log.print('Error posting ride details: $e');
+ return false;
}
}
- Map constructRidePayload(
+ late LatLng endLocation;
+// polylineCoordinates.last;
+ // Log.print('endLocation: ${endLocation}');
+ late LatLng startLocation;
+ // polylineCoordinates.first;
+ // Log.print('startLocation: ${startLocation}');
+ 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']}';
+ try {
+ final msg = dataCarsLocationByPassenger?['message'];
+ final hasDrivers = msg is List &&
+ msg.isNotEmpty &&
+ carsOrder >= 0 &&
+ carsOrder < msg.length;
- return {
- "start_location": startLocation,
- "end_location": endLocation,
- "date": DateTime.now().toString(),
- "time": DateTime.now().toString(),
- "endtime": durationToAdd.toString(),
- "price": totalPassenger.toStringAsFixed(2),
- "passenger_id": box.read(BoxName.passengerID).toString(),
- "driver_id": dataCarsLocationByPassenger['message'][carsOrder]
- ['driver_id']
- .toString(),
- "status": "waiting",
- 'carType': box.read(BoxName.carType),
- "price_for_driver": totalPassenger.toString(),
- "price_for_passenger": totalME.toString(),
- "distance": distance.toString(),
- "paymentMethod": paymentController.isWalletChecked.toString(),
- };
+ if (!hasDrivers) {
+ // لا يوجد سائقين -> عرض دايلوغ وارجاع null
+ _showNoDriversDialog();
+ return null;
+ }
+
+ // الآن آمن القراءة
+ final driverId = msg[carsOrder]['driver_id'] ?? 'new_driver';
+
+ return {
+ "start_location":
+ '${startLocation.latitude},${startLocation.longitude}',
+ "end_location": '${endLocation.latitude},${endLocation.longitude}',
+ "date": DateTime.now().toString(),
+ "time": DateTime.now().toString(),
+ "endtime": durationToAdd.toString(),
+ "price": totalPassenger.toStringAsFixed(2),
+ "passenger_id": box.read(BoxName.passengerID).toString(),
+ "driver_id": driverId,
+ "status": "waiting",
+ 'carType': box.read(BoxName.carType),
+ "price_for_driver": totalPassenger.toString(),
+ "price_for_passenger": totalME.toString(),
+ "distance": distance.toString(),
+ "paymentMethod": paymentController.isWalletChecked.toString(),
+ };
+ } catch (e, st) {
+ Log.print('Error in constructRidePayload: $e');
+ Log.print(st.toString());
+ // في حال أي استثناء، اعتبره كعدم وجود سائقين أو خطأ -> عرض دايلوغ
+ _showNoDriversDialog();
+ return null;
+ }
+ }
+
+ void _showNoDriversDialog() {
+ // اذا تستخدم GetX:
+ MyDialog().getDialog(
+ 'Sorry'.tr,
+ 'No cars are available at the moment. Please try again later.'.tr,
+ () {
+ Get.back(); // closes the dialog
+ cancelRide(); // cancels or resets the ride
+ },
+ );
}
Future notifyAvailableDrivers() async {
@@ -1986,8 +2893,9 @@ class MapPassengerController extends GetxController {
// body,
// 'order');
NotificationService.sendNotification(
+ category: 'Order',
target: (driverData['token'].toString()),
- title: 'Order',
+ title: 'Order'.tr,
body: endNameAddress,
isTopic: false, // Important: this is a token
tone: 'tone1',
@@ -2032,18 +2940,14 @@ class MapPassengerController extends GetxController {
(distanceToDriverInMeters * 1.25).toStringAsFixed(0);
Future.delayed(const Duration(microseconds: 10));
final body = constructNotificationBody(driverData);
- // Log.print('body:ww ${body}');
+ Log.print('body:ww ${body}');
Log.print(
'[DEBUG] Sending to driver: ${driverData['driver_id']}, token: ${driverData['token']}');
- // firebaseMessagesController.sendNotificationToDriverMAP(
- // 'Order', // without tr since background not valid
- // endNameAddress,
- // (driverData['token'].toString()),
- // body,
- // 'order');
+
NotificationService.sendNotification(
+ category: 'Order',
target: (driverData['token'].toString()),
- title: 'Order',
+ title: 'Order'.tr,
body: endNameAddress,
isTopic: false, // Important: this is a token
tone: 'tone1',
@@ -2056,13 +2960,15 @@ class MapPassengerController extends GetxController {
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']}',
+ // '${data[0]['start_location']['lat']},${data[0]['start_location']['lng']}',
+ // '${data[0]['end_location']['lat']},${data[0]['end_location']['lng']}',
+ '${startLocation.latitude},${startLocation.longitude}',
+ '${endLocation.latitude},${endLocation.longitude}',
totalPassenger.toStringAsFixed(2),
totalDriver.toStringAsFixed(2),
durationToRide.toString(),
distance.toStringAsFixed(2),
- driverData['driver_id'].toString(),
+ driverData?['driver_id']?.toString() ?? 'N/A',
box.read(BoxName.passengerID).toString(),
(box.read(BoxName.name).toString().split(' ')[0]).toString(),
(box.read(BoxName.tokenFCM).toString()),
@@ -2070,11 +2976,11 @@ class MapPassengerController extends GetxController {
durationToPassenger.toStringAsFixed(0) ?? '120',
distanceByPassenger.toString() ?? '2000',
paymentController.isWalletChecked.toString(),
- (driverData['token'].toString()),
+ driverData?['token']?.toString() ?? 'N/A',
durationToPassenger.toString(),
rideId.toString(),
rideTimerBegin.toString(),
- driverData['driver_id'].toString(),
+ driverData?['driver_id']?.toString() ?? 'N/A',
durationToRide.toString(),
Get.find().wayPoints.length > 1
? 'haveSteps'
@@ -2089,9 +2995,9 @@ class MapPassengerController extends GetxController {
? 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.email).toString() ?? 'none',
+ startNameAddress,
+ endNameAddress,
box.read(BoxName.carType),
kazan.toStringAsFixed(0),
passengerRate.toStringAsFixed(2),
@@ -2104,88 +3010,88 @@ class MapPassengerController extends GetxController {
int maxAttempts = 28;
- Future delayAndFetchRideStatusForAllDriverAvailable(
- String rideId) async {
- int attemptCounter = 0;
- bool isApplied = false;
- tick = 0;
- await addRideToNotificationDriverAvailable();
- Timer.periodic(const Duration(seconds: 1), (timer) async {
- if (attemptCounter >= maxAttempts || isApplied == true) {
- timer.cancel();
- _rideStatusStreamController.close(); // Close the stream when done
- return;
- }
+ // Future delayAndFetchRideStatusForAllDriverAvailable(
+ // String rideId) async {
+ // int attemptCounter = 0;
+ // bool isApplied = false;
+ // tick = 0;
+ // await addRideToNotificationDriverAvailable();
+ // Timer.periodic(const Duration(seconds: 1), (timer) async {
+ // if (attemptCounter >= maxAttempts || isApplied == true) {
+ // timer.cancel();
+ // _rideStatusStreamController.close(); // Close the stream when done
+ // return;
+ // }
- attemptCounter++;
- tick++;
+ // attemptCounter++;
+ // tick++;
- try {
- var res = await getRideStatus(rideId);
- String rideStatusDelayed = res.toString();
- Log.print('rideStatusDelayed: $rideStatusDelayed');
+ // try {
+ // var res = await getRideStatus(rideId);
+ // String rideStatusDelayed = res.toString();
+ // Log.print('rideStatusDelayed: $rideStatusDelayed');
- _rideStatusStreamController
- .add(rideStatusDelayed); // Emit the ride status
- // addRideToNotificationDriverString();
- if (rideStatusDelayed == 'Cancel') {
- timer.cancel();
- NotificationController().showNotification(
- "Order Cancelled".tr, "you canceled order".tr, 'ding');
- _rideStatusStreamController
- .close(); // Close stream after cancellation
- //
- //
- } else if (rideStatusDelayed == 'Apply' ||
- rideStatusDelayed == 'Applied') {
- isApplied = true;
- // timer.cancel();
- rideAppliedFromDriver(isApplied);
+ // _rideStatusStreamController
+ // .add(rideStatusDelayed); // Emit the ride status
+ // // addRideToNotificationDriverString();
+ // if (rideStatusDelayed == 'Cancel') {
+ // timer.cancel();
+ // NotificationController().showNotification(
+ // "Order Cancelled".tr, "you canceled order".tr, 'ding');
+ // _rideStatusStreamController
+ // .close(); // Close stream after cancellation
+ // //
+ // //
+ // } else if (rideStatusDelayed == 'Apply' ||
+ // rideStatusDelayed == 'Applied') {
+ // isApplied = true;
+ // // timer.cancel();
+ // rideAppliedFromDriver(isApplied);
- timer.cancel();
- // Close stream after applying
- } else if (attemptCounter >= maxAttempts ||
- rideStatusDelayed == 'waiting') {
- // timer.cancel(); //todo
- // addRideToNotificationDriverString();
- // Show dialog to increase fee...
+ // timer.cancel();
+ // // Close stream after applying
+ // } else if (attemptCounter >= maxAttempts ||
+ // rideStatusDelayed == 'waiting') {
+ // // timer.cancel(); //todo
+ // // addRideToNotificationDriverString();
+ // // Show dialog to increase fee...
- // buildTimerForIncrease();
- Get.defaultDialog(
- title: 'Are you want to wait drivers to accept your order'.tr,
- middleText: '',
- onConfirm: () {
- Log.print('[DEBUG] User chose to wait again');
- Get.back();
- notifyAvailableDriversAgain();
- delayAndFetchRideStatusForAllDriverAvailable(rideId);
- // addRideToNotificationDriverAvailable();
- },
- onCancel: () {
- timer.cancel();
- Get.back();
- showCancelRideBottomSheet();
- },
- );
- // MyDialog().getDialog(
- // 'Are you want to wait drivers to accept your order'.tr, '', () {
- // Get.back();
- // addRideToNotificationDriverAvailable();
- // });
- update();
- _rideStatusStreamController
- .close(); // Close stream after max attempts
- }
- } catch (e) {
- _rideStatusStreamController.addError(e); // Handle errors in the stream
- }
- });
- }
+ // // buildTimerForIncrease();
+ // Get.defaultDialog(
+ // title: 'Are you want to wait drivers to accept your order'.tr,
+ // middleText: '',
+ // onConfirm: () {
+ // Log.print('[DEBUG] User chose to wait again');
+ // Get.back();
+ // notifyAvailableDriversAgain();
+ // delayAndFetchRideStatusForAllDriverAvailable(rideId);
+ // // addRideToNotificationDriverAvailable();
+ // },
+ // onCancel: () {
+ // timer.cancel();
+ // Get.back();
+ // showCancelRideBottomSheet();
+ // },
+ // );
+ // // MyDialog().getDialog(
+ // // 'Are you want to wait drivers to accept your order'.tr, '', () {
+ // // Get.back();
+ // // addRideToNotificationDriverAvailable();
+ // // });
+ // update();
+ // _rideStatusStreamController
+ // .close(); // Close stream after max attempts
+ // }
+ // } catch (e) {
+ // _rideStatusStreamController.addError(e); // Handle errors in the stream
+ // }
+ // });
+ // }
Future rideAppliedFromDriver(bool isApplied) async {
await getUpdatedRideForDriverApply(rideId);
NotificationController().showNotification(
- 'Accepted Ride',
+ 'Accepted Ride'.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' ||
@@ -2204,14 +3110,95 @@ class MapPassengerController extends GetxController {
rideConfirm = false;
isSearchingWindow = false;
update();
- startTimer();
-// todo stop this because this method in startTimer()
- // startTimerFromDriverToPassengerAfterApplied();
+ // تشغيل التايمر لجلب موقع السائق بشكل دوري
+ startTimerFromDriverToPassengerAfterApplied();
+ // 1. جلب موقع السائق الأولي فوراً
+ await getDriverCarsLocationToPassengerAfterApplied();
- // timer.cancel();
+ // 2. رسم المسار مرة واحدة فقط هنا
+ if (driverCarsLocationToPassengerAfterApplied.isNotEmpty) {
+ await drawDriverPathOnly(
+ driverCarsLocationToPassengerAfterApplied.last, passengerLocation);
+
+ // ضبط الكاميرا لتشمل السائق والراكب مرة واحدة في البداية
+ _fitCameraToPoints(
+ driverCarsLocationToPassengerAfterApplied.last, passengerLocation);
+ }
+
+ startUiCountdown();
_rideStatusStreamController.close();
}
+// دالة خفيفة وسريعة لرسم خط المسار فقط (بدون أسعار أو خطوات)
+ Future drawDriverPathOnly(LatLng driverPos, LatLng passengerPos) async {
+ final String apiUrl = 'https://routec.intaleq.xyz/route';
+ final String apiKey = Env.mapKeyOsm;
+
+ final String origin = '${driverPos.latitude},${driverPos.longitude}';
+ final String dest = '${passengerPos.latitude},${passengerPos.longitude}';
+
+ // استخدام overview=full للدقة، و steps=false للسرعة
+ final Uri uri = Uri.parse(
+ '$apiUrl?origin=$origin&destination=$dest&steps=false&overview=full');
+
+ try {
+ final response = await http.get(uri, headers: {'X-API-KEY': apiKey});
+
+ if (response.statusCode == 200) {
+ final data = jsonDecode(response.body);
+
+ if (data['status'] == 'ok' && data['polyline'] != null) {
+ final String pointsString = data['polyline'];
+
+ // فك التشفير
+ List decodedPoints =
+ await compute(decodePolylineIsolate, pointsString);
+
+ // إزالة خط مسار السائق القديم فقط
+ polyLines
+ .removeWhere((p) => p.polylineId.value == 'driver_track_line');
+
+ // إضافة الخط الجديد
+ polyLines.add(Polyline(
+ polylineId: const PolylineId('driver_track_line'),
+ points: decodedPoints,
+ color: Colors.black87, // لون مميز لمسار السائق
+ width: 5,
+ jointType: JointType.round,
+ startCap: Cap.roundCap,
+ endCap: Cap.roundCap,
+ patterns: [
+ PatternItem.dash(10),
+ PatternItem.gap(10)
+ ], // جعله منقطاً
+ ));
+
+ // لا تستدعي update هنا، سيتم استدعاؤها في الدالة الأب (getDriverCars...) لتقليل عدد التحديثات
+ }
+ }
+ } catch (e) {
+ print('Error drawing driver path: $e');
+ }
+ }
+
+ // دالة مساعدة لضبط الكاميرا
+ void _fitCameraToPoints(LatLng p1, LatLng p2) {
+ double minLat = min(p1.latitude, p2.latitude);
+ double maxLat = max(p1.latitude, p2.latitude);
+ double minLng = min(p1.longitude, p2.longitude);
+ double maxLng = max(p1.longitude, p2.longitude);
+
+ mapController?.animateCamera(
+ CameraUpdate.newLatLngBounds(
+ LatLngBounds(
+ southwest: LatLng(minLat, minLng),
+ northeast: LatLng(maxLat, maxLng),
+ ),
+ 100 // Padding
+ ),
+ );
+ }
+
// Listening to the Stream
void listenToRideStatusStream() {
rideStatusStream.listen((rideStatus) {
@@ -2236,27 +3223,43 @@ class MapPassengerController extends GetxController {
void start15SecondTimer(String rideId) {
Timer(const Duration(seconds: 15), () {
- delayAndFetchRideStatusForAllDriverAvailable(rideId);
+ // delayAndFetchRideStatusForAllDriverAvailable(rideId);
});
}
- void startTimer() async {
- for (int i = 0; i <= durationTimer; i++) {
- await Future.delayed(const Duration(seconds: 1));
+ // Replaces void startTimer()
+ Timer?
+ _uiCountdownTimer; // Add this variable to your class to manage lifecycle
+
+ void startUiCountdown() {
+ // Cancel any existing timer to avoid duplicates
+ _uiCountdownTimer?.cancel();
+
+ // Reset variables
+ progress = 0;
+ remainingTime = durationTimer;
+
+ _uiCountdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
+ // Logic from your loop, but non-blocking
+ int i = timer.tick; // current tick
+
progress = i / durationTimer;
remainingTime = durationTimer - i;
- if (remainingTime == 0) {
+
+ if (remainingTime <= 0) {
+ timer.cancel(); // Stop this specific timer
rideConfirm = false;
+ // Add the duration to the tracking time logic
timeToPassengerFromDriverAfterApplied += durationToPassenger;
- // timeToPassengerFromDriverAfterApplied.toString());
- startTimerFromDriverToPassengerAfterApplied();
- update();
+ // Note: We do NOT call startTimerFromDriverToPassengerAfterApplied() here
+ // because we already started it in rideAppliedFromDriver!
+
+ timerEnded(); // Call your existing completion logic
}
- update();
- }
- timerEnded();
+ update(); // Update the UI progress bar
+ });
}
void timerEnded() async {
@@ -2268,7 +3271,7 @@ class MapPassengerController extends GetxController {
Future getRideStatus(String rideId) async {
final response = await CRUD().get(
- link: "${AppLink.endPoint}/ride/rides/getRideStatus.php",
+ link: "${AppLink.ride}/ride/rides/getRideStatus.php",
payload: {'id': rideId});
print(response);
print('2176');
@@ -2279,48 +3282,60 @@ class MapPassengerController extends GetxController {
driverCarMake,
driverLicensePlate,
driverName = '';
- getUpdatedRideForDriverApply(String rideId) async {
- // if (isDriversTokensSend) {
- final res = await CRUD().get(
- link: "${AppLink.endPoint}/ride/rides/getRideOrderID.php",
- payload: {'id': rideId});
- if (res != 'failure') {
- var response = jsonDecode(res);
- Log.print('getUpdatedRideForDriverApply: $response');
- driverId = response['data']['driver_id'];
- driverPhone = (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']);
- passengerName = (response['data']['passengerName']);
- driverName = (response['data']['driverName'].toString());
- driverToken = (response['data']['token']);
- // Log.print('driverToken updated: $driverToken');
- carYear = response['data']['year'];
- driverRate = response['data']['ratingDriver'].toString();
+ Future getUpdatedRideForDriverApply(String rideId) async {
+ // حماية مبدئية: إذا كان المعرف غير صالح لا تكمل
+ if (rideId == 'yet' || rideId.isEmpty) return;
+
+ try {
+ final res = await CRUD().get(
+ link: "${AppLink.server}/ride/rides/getRideOrderID.php",
+ payload: {'passengerID': box.read(BoxName.passengerID).toString()});
+
+ if (res != 'failure') {
+ var response = jsonDecode(res);
+ Log.print('getUpdatedRideForDriverApply Response: $response');
+
+ // [هام] التحقق من أن data عبارة عن Map وليست false أو null
+ // هذا يمنع الخطأ: Class 'bool' has no instance method '[]'
+ if (response['status'] == 'success' &&
+ response['data'] != null &&
+ response['data'] is Map) {
+ var data = response['data'];
+
+ // استخدام ?.toString() ?? '' للحماية من القيم الفارغة (Null Safety)
+ driverId = data['driver_id']?.toString() ?? '';
+ driverPhone = data['phone']?.toString() ?? '';
+ driverCarMake = data['make']?.toString() ?? '';
+ model = data['model']?.toString() ?? '';
+ colorHex = data['color_hex']?.toString() ?? '';
+ carColor = data['color']?.toString() ?? '';
+ make = data['make']?.toString() ?? '';
+ licensePlate = data['car_plate']?.toString() ?? '';
+
+ // دمج الاسم الأول والأخير للراكب
+ String firstName = data['passengerName']?.toString() ?? '';
+ String lastName = data['last_name']?.toString() ?? '';
+ passengerName =
+ lastName.isNotEmpty ? "$firstName $lastName" : firstName;
+
+ driverName = data['driverName']?.toString() ?? '';
+
+ // [هام] التوكن ضروري للإشعارات
+ driverToken = data['token']?.toString() ?? '';
+
+ carYear = data['year']?.toString() ?? '';
+ driverRate = data['ratingDriver']?.toString() ?? '5.0';
+
+ update(); // تحديث الواجهة بالبيانات الجديدة
+ } else {
+ Log.print(
+ "Warning: Ride data not found or invalid (data is false/null)");
+ // اختياري: يمكنك هنا التعامل مع حالة عدم العثور على السائق بعد
+ }
+ }
+ } catch (e) {
+ Log.print("Error in getUpdatedRideForDriverApply: $e");
}
- // driversToken.remove(driverToken);
- // for (var i = 1; i < driversToken.length; i++) {
- // firebaseMessagesController.sendNotificationToDriverMAP(
- // 'Order Accepted',
- // '$driverName${'Accepted your order'.tr}',
- // driverToken.toString(),
- // [],
- // 'start',
- // );
- NotificationService.sendNotification(
- target: driverToken.toString(),
- title: 'Order Accepted',
- body: '$driverName${'Accepted your order'.tr}',
- isTopic: false, // Important: this is a token
- tone: 'tone1',
- // driverList: body,
- );
- // }
- // }
}
late LatLng currentDriverLocation;
@@ -2532,42 +3547,73 @@ class MapPassengerController extends GetxController {
});
}
+ // String getLocationArea(double latitude, double longitude) {
+ // final locations = box.read(BoxName.locationName) ?? [];
+ // for (final location in locations) {
+ // final locationData = location as Map;
+
+ // // Debugging: Print location data
+ // // print('Location Data: $locationData');
+
+ // // Convert string values to double
+ // final minLatitude =
+ // double.tryParse(locationData['min_latitude'].toString()) ?? 0.0;
+ // final maxLatitude =
+ // double.tryParse(locationData['max_latitude'].toString()) ?? 0.0;
+ // final minLongitude =
+ // double.tryParse(locationData['min_longitude'].toString()) ?? 0.0;
+ // final maxLongitude =
+ // double.tryParse(locationData['max_longitude'].toString()) ?? 0.0;
+
+ // // Debugging: Print converted values
+ // print(
+ // 'Converted Values: minLatitude=$minLatitude, maxLatitude=$maxLatitude, minLongitude=$minLongitude, maxLongitude=$maxLongitude');
+
+ // if (latitude >= minLatitude &&
+ // latitude <= maxLatitude &&
+ // longitude >= minLongitude &&
+ // longitude <= maxLongitude) {
+ // box.write(BoxName.serverChosen, (locationData['server_link']));
+ // // Log.print(
+ // // 'locationData----server_link: ${(locationData['server_link'])}');
+ // return locationData['name'];
+ // }
+ // }
+
+ // // Default case
+ // box.write(BoxName.serverChosen, AppLink.IntaleqSyriaServer);
+ // return 'Cairo';
+ // }
String getLocationArea(double latitude, double longitude) {
- final locations = box.read(BoxName.locationName) ?? [];
- for (final location in locations) {
- final locationData = location as Map;
+ LatLng passengerPoint = LatLng(latitude, longitude);
- // Debugging: Print location data
- // print('Location Data: $locationData');
-
- // Convert string values to double
- final minLatitude =
- double.tryParse(locationData['min_latitude'].toString()) ?? 0.0;
- final maxLatitude =
- double.tryParse(locationData['max_latitude'].toString()) ?? 0.0;
- final minLongitude =
- double.tryParse(locationData['min_longitude'].toString()) ?? 0.0;
- final maxLongitude =
- double.tryParse(locationData['max_longitude'].toString()) ?? 0.0;
-
- // Debugging: Print converted values
- print(
- 'Converted Values: minLatitude=$minLatitude, maxLatitude=$maxLatitude, minLongitude=$minLongitude, maxLongitude=$maxLongitude');
-
- if (latitude >= minLatitude &&
- latitude <= maxLatitude &&
- longitude >= minLongitude &&
- longitude <= maxLongitude) {
- box.write(BoxName.serverChosen, (locationData['server_link']));
- // Log.print(
- // 'locationData----server_link: ${(locationData['server_link'])}');
- return locationData['name'];
- }
+ // 1. فحص الأردن
+ if (isPointInPolygon(passengerPoint, CountryPolygons.jordanBoundary)) {
+ box.write(BoxName.countryCode, 'Jordan');
+ // يمكنك تعيين AppLink.endPoint هنا إذا كان منطقك الداخلي لا يزال يعتمد عليه
+ box.write(BoxName.serverChosen,
+ AppLink.IntaleqSyriaServer); // مثال: اختر سيرفر سوريا للبيانات
+ return 'Jordan';
}
- // Default case
+ // 2. فحص سوريا
+ if (isPointInPolygon(passengerPoint, CountryPolygons.syriaBoundary)) {
+ box.write(BoxName.countryCode, 'Syria');
+ box.write(BoxName.serverChosen, AppLink.IntaleqSyriaServer);
+ return 'Syria';
+ }
+
+ // 3. فحص مصر
+ if (isPointInPolygon(passengerPoint, CountryPolygons.egyptBoundary)) {
+ box.write(BoxName.countryCode, 'Egypt');
+ box.write(BoxName.serverChosen, AppLink.IntaleqAlexandriaServer);
+ return 'Egypt';
+ }
+
+ // 4. الافتراضي (إذا كان خارج المناطق المخدومة)
+ box.write(BoxName.countryCode, 'Jordan');
box.write(BoxName.serverChosen, AppLink.IntaleqSyriaServer);
- return 'Cairo';
+ return 'Unknown Location (Defaulting to Jordan)';
}
// if (latitude >= 29.918901 &&
@@ -2668,6 +3714,15 @@ class MapPassengerController extends GetxController {
'northeastLon': bounds.northeast.longitude.toString(),
});
break;
+ case 'Van':
+ res = await CRUD()
+ .get(link: AppLink.getCarsLocationByPassengerVan, payload: {
+ 'southwestLat': bounds.southwest.latitude.toString(),
+ 'southwestLon': bounds.southwest.longitude.toString(),
+ 'northeastLat': bounds.northeast.latitude.toString(),
+ 'northeastLon': bounds.northeast.longitude.toString(),
+ });
+ break;
default:
res = await CRUD()
.get(link: AppLink.getCarsLocationByPassenger, payload: {
@@ -2692,17 +3747,6 @@ class MapPassengerController extends GetxController {
// Check if 'message' is present and not null
if (dataCarsLocationByPassenger != null &&
dataCarsLocationByPassenger.isNotEmpty) {
- // Check if carsOrder is within bounds
- // if (carsOrder < dataCarsLocationByPassenger['message'].length) {
- // driverId = dataCarsLocationByPassenger['message'][carsOrder]
- // ['driver_id']
- // .toString();
- // gender = dataCarsLocationByPassenger['message'][carsOrder]['gender']
- // .toString();
- // driverToken = dataCarsLocationByPassenger['message'][carsOrder]
- // ['token']
- // .toString();
- // } else {
print('carsOrder is in of bounds for message array');
// return false;
// }
@@ -2813,43 +3857,6 @@ class MapPassengerController extends GetxController {
}
}
- void _smoothlyUpdateMarker(Marker oldMarker, LatLng newPosition,
- double newHeading, BitmapDescriptor icon) {
- String markerId = oldMarker.markerId.value;
- LatLng startPosition = oldMarker.position;
- double startHeading = oldMarker.rotation ?? 0;
-
- _animationTimers[markerId]?.cancel();
- _animationTimers[markerId] =
- Timer.periodic(Duration(milliseconds: updateIntervalMs), (timer) {
- double progress =
- timer.tick / (500 / updateIntervalMs); // 500ms total duration
- if (progress >= 1.0) {
- timer.cancel();
- _animationTimers.remove(markerId);
- progress = 1.0;
- }
-
- LatLng intermediatePosition = LatLng(
- startPosition.latitude +
- (newPosition.latitude - startPosition.latitude) * progress,
- startPosition.longitude +
- (newPosition.longitude - startPosition.longitude) * progress);
- double intermediateHeading =
- startHeading + (newHeading - startHeading) * progress;
-
- markers.removeWhere((m) => m.markerId == oldMarker.markerId);
- markers.add(Marker(
- markerId: oldMarker.markerId,
- position: intermediatePosition,
- rotation: intermediateHeading,
- icon: icon,
- ));
-
- update();
- });
- }
-
double _calculateDistance(LatLng start, LatLng end) {
// Implement distance calculation (e.g., Haversine formula)
// For simplicity, this is a placeholder. Replace with actual implementation.
@@ -2875,8 +3882,30 @@ class MapPassengerController extends GetxController {
return '963$trimmedPhone';
}
- Future getTokenForParent() async {
- if (box.read(BoxName.sosPhonePassenger) == null) {
+ String generateTrackingLink(String rideId, String driverId) {
+ String cleanRideId = rideId.toString().trim();
+ String cleanDriverId = driverId.toString().trim();
+
+ // الكلمة السرية للمطابقة مع السيرفر
+ const String secretSalt = "Intaleq_Secure_Track_2025";
+
+ // الدمج والتشفير
+ String rawString = "$cleanRideId$cleanDriverId$secretSalt";
+ var bytes = utf8.encode(rawString);
+ var digest = md5.convert(bytes);
+ String token = digest.toString();
+
+ // الرابط المباشر لصفحة التتبع
+ return "https://intaleqapp.com/track/index.html?id=$cleanRideId&token=$token";
+ }
+
+ // 2. الدالة الرئيسية (تم تعديلها لإرسال واتساب بدلاً من الإشعارات)
+ Future shareTripWithFamily() async {
+ // التحقق أولاً: هل الرقم موجود؟
+ String? storedPhone = box.read(BoxName.sosPhonePassenger);
+
+ if (storedPhone == null) {
+ // --- (نفس المنطق القديم: فتح ديالوج لإضافة الرقم) ---
Get.defaultDialog(
title: 'Add SOS Phone'.tr,
titleStyle: AppStyle.title,
@@ -2894,8 +3923,11 @@ class MapPassengerController extends GetxController {
onPressed: () async {
if (sosFormKey.currentState!.validate()) {
Get.back();
+ // تنسيق الرقم
var numberPhone =
formatSyrianPhoneNumber(sosPhonePassengerProfile.text);
+
+ // حفظ في السيرفر
await CRUD().post(
link: AppLink.updateprofile,
payload: {
@@ -2903,22 +3935,223 @@ class MapPassengerController extends GetxController {
'sosPhone': numberPhone,
},
);
+
+ // حفظ محلياً
box.write(BoxName.sosPhonePassenger, numberPhone);
+
+ // استدعاء الدالة مرة أخرى للمتابعة
+ shareTripWithFamily();
}
}));
+ return;
}
- var numberPhone = formatSyrianPhoneNumber(sosPhonePassengerProfile.text);
- var res = await CRUD().getTokenParent(
- link: AppLink.getTokenParent, payload: {'phone': numberPhone});
- // Check if `res` is already a map
+ // --- (المنطق الجديد: إرسال واتساب مباشرة) ---
+
+ // 1. التأكد من وجود بيانات للرحلة
+ if (rideId == 'yet' || driverId.isEmpty) {
+ Get.snackbar("Alert".tr, "Wait for the trip to start first".tr);
+ return;
+ }
+
+ // 2. تنسيق الرقم
+ var numberPhone = formatSyrianPhoneNumber(storedPhone);
+
+ // 3. توليد الرابط
+ String trackingLink = generateTrackingLink(rideId, driverId);
+
+ // 4. تجهيز الرسالة (بالإنجليزية وجاهزة للترجمة)
+ // لاحظ: استخدمت المتغيرات الموجودة في الكنترولر (passengerName هنا عادة يحمل اسم السائق في الكنترولر الخاص بك حسب الكود السابق)
+ String message = """
+مرحباً، تابع رحلتي مباشرة على تطبيق انطلق 🚗
+
+يمكنك تتبع مسار الرحلة من هنا:
+$trackingLink
+
+السائق: $passengerName
+السيارة: $model - $licensePlate
+شكراً لاستخدامك انطلق!
+"""
+ .tr;
+
+ String messageEn = """Hello, follow my trip live on Intaleq 🚗
+
+Track my ride here:
+$trackingLink
+
+Driver: $passengerName
+Car: $model - $licensePlate
+Thank you for using Intaleq!
+""";
+
+ // اختر الرسالة بناءً على اللغة المفضلة (مثال بسيط)
+ String userLanguage = box.read(BoxName.lang) ?? 'ar';
+ message = (userLanguage == 'ar') ? message : messageEn;
+// وضعنا .tr لكي تتمكن من ترجمتها للعربية في ملفات اللغة إذا أردت، أو تركها إنجليزية
+
+ print("Sending WhatsApp to: $numberPhone");
+
+ // 5. فتح واتساب
+ launchCommunication('whatsapp', numberPhone, message);
+
+ // (اختياري) حفظ أن التتبع مفعل لتغيير حالة الأيقونة في الواجهة
+ box.write(BoxName.parentTripSelected, true);
+ update();
+ }
+
+ Future getTokenForParent() async {
+ // 1. التحقق أولاً: هل الرقم موجود؟
+ String? storedPhone = box.read(BoxName.sosPhonePassenger);
+
+ if (storedPhone == null) {
+ // --- حالة الرقم غير موجود: نفتح الديالوج فقط ---
+ Get.defaultDialog(
+ title: 'Add SOS Phone'.tr,
+ titleStyle: AppStyle.title,
+ content: Form(
+ key: sosFormKey,
+ child: MyTextForm(
+ controller: sosPhonePassengerProfile,
+ label: 'insert sos phone'.tr,
+ hint: 'e.g. 0912345678'.tr,
+ type: TextInputType.phone,
+ ),
+ ),
+ confirm: MyElevatedButton(
+ title: 'Add SOS Phone'.tr,
+ onPressed: () async {
+ if (sosFormKey.currentState!.validate()) {
+ // إغلاق الديالوج الحالي
+ Get.back();
+
+ // تنسيق الرقم (تأكد أن هذا التنسيق يطابق ما تم تخزينه عند تسجيل الراكب)
+ var numberPhone =
+ formatSyrianPhoneNumber(sosPhonePassengerProfile.text);
+
+ // حفظ الرقم في السيرفر (تحديث البروفايل)
+ await CRUD().post(
+ link: AppLink.updateprofile,
+ payload: {
+ 'id': box.read(BoxName.passengerID),
+ 'sosPhone': numberPhone,
+ },
+ );
+
+ // حفظ الرقم محلياً
+ box.write(BoxName.sosPhonePassenger, numberPhone);
+
+ // استدعاء الدالة مرة أخرى
+ getTokenForParent();
+ }
+ }));
+ return;
+ }
+ generateTrackingLink(rideId, driverId);
+ // --- حالة الرقم موجود: نكمل التنفيذ ---
+ var numberPhone = formatSyrianPhoneNumber(storedPhone);
+ print("Searching for Parent Token with Phone: $numberPhone");
+
+ // استدعاء السكريبت (استخدم POST بدلاً من GET)
+ var res = await CRUD()
+ .post(link: AppLink.getTokenParent, payload: {'phone': numberPhone});
+
+ // التعامل مع الاستجابة
if (res is Map) {
- var res1 = res;
- handleResponse(res1);
+ handleResponse(res);
} else {
- // If it's a string, decode it
- var res1 = jsonDecode(res);
- handleResponse(res1);
+ try {
+ // var jsonRes = jsonDecode(res);
+ handleResponse(res);
+ } catch (e) {
+ print("Error parsing response: $res");
+ }
+ }
+ }
+
+ void handleResponse(Map res) {
+ print("Handle Response: $res"); // للتأكد من دخول الدالة
+
+ // الحالة 1: الرقم غير مسجل (Failure)
+ if (res['status'] == 'failure') {
+ // إذا كان هناك أي ديالوج تحميل مفتوح، نغلقه أولاً، لكن بحذر
+ if (Get.isDialogOpen ?? false) Get.back();
+
+ Get.defaultDialog(
+ title: "No user found".tr, // اختصرت العنوان ليظهر بشكل أفضل
+ titleStyle: AppStyle.title,
+ content: Column(
+ children: [
+ Text(
+ "No passenger found for the given phone number".tr,
+ style: AppStyle.title, // غيرت الستايل ليكون أصغر قليلاً
+ textAlign: TextAlign.center,
+ ),
+ const SizedBox(height: 10),
+ Text(
+ "Send Intaleq app to him".tr,
+ style: AppStyle.title
+ .copyWith(color: AppColor.greenColor, fontSize: 14),
+ textAlign: TextAlign.center,
+ )
+ ],
+ ),
+ confirm: MyElevatedButton(
+ title: 'Send Invite'.tr,
+ onPressed: () {
+ Get.back(); // إغلاق الديالوج
+
+ var rawPhone = box.read(BoxName.sosPhonePassenger);
+ // تأكد أن rawPhone ليس null
+ if (rawPhone == null) return;
+
+ var phone = formatSyrianPhoneNumber(rawPhone);
+
+ // تصحيح نص الرسالة
+ var message = '''Dear Friend,
+
+🚀 I have just started an exciting trip on Intaleq!
+Download the app to track my ride:
+
+👉 Android: https://play.google.com/store/apps/details?id=com.Intaleq.intaleq&hl=en-US
+👉 iOS: https://apps.apple.com/st/app/intaleq-rider/id6748075179
+
+See you there!
+Intaleq Team''';
+
+ launchCommunication('whatsapp', phone, message);
+ }),
+ cancel: MyElevatedButton(
+ title: 'Cancel'.tr,
+ onPressed: () {
+ Get.back();
+ }));
+ }
+ // الحالة 2: نجاح (Success)
+ else if (res['status'] == 'success') {
+ // إغلاق أي ديالوج سابق (مثل Loading)
+ if (Get.isDialogOpen ?? false) Get.back();
+
+ Get.snackbar("Success".tr, "The invitation was sent successfully".tr,
+ backgroundColor: AppColor.greenColor, colorText: Colors.white);
+
+ List tokensData = res['data'];
+
+ for (var device in tokensData) {
+ String tokenParent = device['token'];
+
+ NotificationService.sendNotification(
+ category: "Trip Monitoring",
+ target: tokenParent,
+ title: "Trip Monitoring".tr,
+ body: "Click to track the trip".tr,
+ isTopic: false,
+ tone: 'tone1',
+ driverList: [rideId, driverId],
+ );
+ // حفظ آخر توكن
+ box.write(BoxName.tokenParent, tokenParent);
+ }
+ box.write(BoxName.parentTripSelected, true);
}
}
@@ -3009,95 +4242,47 @@ class MapPassengerController extends GetxController {
}
}
- void handleResponse(Map res1) {
- if (res1['message'] == "No passenger found for the given phone number") {
- Get.defaultDialog(
- title: "No user found for the given phone number".tr,
- titleStyle: AppStyle.title,
- content: Column(
- children: [
- Text(
- "No passenger found for the given phone number".tr,
- style: AppStyle.title,
- ),
- Text(
- "Send Intaleq app to him".tr,
- style: AppStyle.title.copyWith(color: AppColor.greenColor),
- )
- ],
- ),
- confirm: MyElevatedButton(
- title: 'Ok'.tr,
- onPressed: () {
- Get.back();
- var phone = box.read(BoxName.countryCode) == 'Egypt'
- ? '+2${box.read(BoxName.sosPhonePassenger)}'
- : '+962${box.read(BoxName.sosPhonePassenger)}';
- var message = '''Dear ,
-
- 🚀 I have just started an exciting trip and I would like to share the details of my journey and my current location with you in real-time! Please download the Intaleq app. It will allow you to view my trip details and my latest location.
-
- 👉 Download link:
- Android [https://play.google.com/store/apps/details?id=com.mobileapp.store.ride]
- iOS [https://getapp.cc/app/6458734951]
-
- I look forward to keeping you close during my adventure!
-
- Intaleq ,'''
- .tr;
- launchCommunication('whatsapp', phone, message);
- }),
- cancel: MyElevatedButton(
- title: 'No'.tr,
- onPressed: () {
- Get.back();
- }));
- } else if (res1['status'] == 'success') {
- var tokenParent = (res1['data'][0]['token']);
- Get.snackbar("The invitation was sent successfully".tr, '',
- backgroundColor: AppColor.greenColor);
- // firebaseMessagesController.sendNotificationToPassengerToken(
- // "Trip Monitoring".tr,
- // "Trip Monitoring".tr,
- // tokenParent,
- // [rideId, driverId],
- // 'order1',
- // );
- NotificationService.sendNotification(
- target: tokenParent.toString(),
- title: "Trip Monitoring".tr,
- body: "Trip Monitoring".tr,
- isTopic: false, // Important: this is a token
- tone: 'tone1',
- driverList: [rideId, driverId],
- );
- box.write(BoxName.parentTripSelected, true);
- box.write(BoxName.tokenParent, tokenParent);
- }
- }
-
LatLng driverLocationToPassenger = const LatLng(32, 35);
Future getDriverCarsLocationToPassengerAfterApplied() async {
- driverCarsLocationToPassengerAfterApplied = [];
-
+ // 1. جلب البيانات من السيرفر
var res = await CRUD().get(
link: AppLink.getDriverCarsLocationToPassengerAfterApplied,
payload: {'driver_id': driverId});
- datadriverCarsLocationToPassengerAfterApplied = jsonDecode(res);
- driverLocationToPassenger = LatLng(
- double.parse(datadriverCarsLocationToPassengerAfterApplied['message'][0]
- ['latitude']),
- double.parse(datadriverCarsLocationToPassengerAfterApplied['message'][0]
- ['longitude']));
- driverCarsLocationToPassengerAfterApplied.add(LatLng(
- double.parse(datadriverCarsLocationToPassengerAfterApplied['message'][0]
- ['latitude']),
- double.parse(datadriverCarsLocationToPassengerAfterApplied['message'][0]
- ['longitude'])));
- CarLocationModel model = CarLocationModel.fromJson(
- datadriverCarsLocationToPassengerAfterApplied['message'][0]);
- carLocationsModels.add(model);
+ if (res != 'failure') {
+ datadriverCarsLocationToPassengerAfterApplied = jsonDecode(res);
+
+ if (datadriverCarsLocationToPassengerAfterApplied['message'] != null &&
+ datadriverCarsLocationToPassengerAfterApplied['message'].isNotEmpty) {
+ var _data = datadriverCarsLocationToPassengerAfterApplied['message'][0];
+
+ // تحديث إحداثيات السائق الحالية
+ LatLng newDriverPos = LatLng(
+ double.parse(_data['latitude']), double.parse(_data['longitude']));
+
+ driverLocationToPassenger = newDriverPos;
+ driverCarsLocationToPassengerAfterApplied.add(newDriverPos);
+
+ // 2. تنظيف الخريطة من السيارات الوهمية والقديمة (الإبقاء فقط على السائق والمسار)
+ clearMarkersExceptStartEndAndDriver();
+
+ // 3. تحديث ماركر السائق (تحريكه)
+ reloadMarkerDriverCarsLocationToPassengerAfterApplied();
+
+ // 4. رسم/تحديث خط المسار بين السائق والراكب
+ // نتحقق أننا في حالة تستدعي الرسم
+ // if (rideTimerBegin ||
+ // statusRide == 'Apply' ||
+ // currentRideState.value == RideState.driverApplied ||
+ // currentRideState.value == RideState.inProgress) {
+ // await drawDriverPathOnly(newDriverPos, passengerLocation);
+ // }
+
+ // // 5. تحديث الكاميرا لتشمل السائق والراكب (اختياري: يمكنك وضع شرط لعدم الازعاج اذا حرك المستخدم الخريطة)
+ // _fitCameraToPoints(newDriverPos, passengerLocation);
+ }
+ }
+ // 6. تحديث الواجهة بعد انتهاء كل العمليات
update();
}
@@ -3136,6 +4321,22 @@ class MapPassengerController extends GetxController {
// final int updateIntervalMs = 100; // Update every 100ms
// final double minMovementThreshold =
// 1.0; // Minimum movement in meters to trigger update
+ void clearMarkersExceptStartEndAndDriver() {
+ markers.removeWhere((marker) {
+ String id = marker.markerId.value;
+ // لا تحذف نقطة البداية
+ if (id == 'start') return false;
+ // لا تحذف نقطة النهاية
+ if (id == 'end') return false;
+ // لا تحذف السائق الحالي
+ if (id == currentDriverMarkerId) return false;
+
+ // احذف أي شيء آخر (مثل السيارات التي ظهرت وقت البحث)
+ return true;
+ });
+
+ // ملاحظة: لا نستدعي update() هنا لأننا سنستدعيها في نهاية الدالة الرئيسية
+ }
void clearMarkersExceptStartEnd() {
Set markersToRemove = markers
@@ -3150,36 +4351,120 @@ class MapPassengerController extends GetxController {
update();
}
+ // 1. تعريف ID ثابت للسائق طوال الرحلة
+ String get currentDriverMarkerId => 'driver_marker_$driverId';
+
void reloadMarkerDriverCarsLocationToPassengerAfterApplied() {
- // clearMarkersExceptStartEnd();
+ if (datadriverCarsLocationToPassengerAfterApplied == null ||
+ datadriverCarsLocationToPassengerAfterApplied['message'] == null ||
+ datadriverCarsLocationToPassengerAfterApplied['message'].isEmpty) {
+ return;
+ }
- LatLng driverPosition = LatLng(
- double.parse(datadriverCarsLocationToPassengerAfterApplied['message'][0]
- ['latitude']),
- double.parse(datadriverCarsLocationToPassengerAfterApplied['message'][0]
- ['longitude']));
+ var driverData =
+ datadriverCarsLocationToPassengerAfterApplied['message'][0];
- double heading = double.parse(
- datadriverCarsLocationToPassengerAfterApplied['message'][0]['heading']
- .toString());
+ // جلب الإحداثيات الجديدة
+ LatLng newPosition = LatLng(double.parse(driverData['latitude'].toString()),
+ double.parse(driverData['longitude'].toString()));
- BitmapDescriptor icon =
- datadriverCarsLocationToPassengerAfterApplied['message'][0]
- ['model']
- .toString()
- .contains('دراجة') ||
- datadriverCarsLocationToPassengerAfterApplied['message'][0]
- ['make']
- .toString()
- .contains('دراجة')
- ? motoIcon
- : datadriverCarsLocationToPassengerAfterApplied['message'][0]
- ['gender'] ==
- 'Female'
- ? ladyIcon
- : carIcon;
+ double newHeading =
+ double.tryParse(driverData['heading'].toString()) ?? 0.0;
- _updateMarkerPosition(driverPosition, heading, icon);
+ // تحديد الأيقونة
+ BitmapDescriptor icon;
+ if (driverData['model'].toString().contains('دراجة') ||
+ driverData['make'].toString().contains('دراجة')) {
+ icon = motoIcon;
+ } else if (driverData['gender'] == 'Female') {
+ icon = ladyIcon;
+ } else {
+ icon = carIcon;
+ }
+
+ // 2. البحث عن الماركر القديم وتحديثه أو إنشاء جديد
+ final MarkerId markerId = MarkerId(currentDriverMarkerId);
+
+ // التحقق هل الماركر موجود مسبقاً؟
+ final int existingIndex = markers.indexWhere((m) => m.markerId == markerId);
+
+ if (existingIndex != -1) {
+ // الماركر موجود، نقوم بتحريكه (Animation)
+ Marker oldMarker = markers[existingIndex];
+ _smoothlyUpdateMarker(oldMarker, newPosition, newHeading, icon);
+ } else {
+ // الماركر غير موجود، نقوم بإنشائه
+ markers.add(Marker(
+ markerId: markerId,
+ position: newPosition,
+ rotation: newHeading,
+ icon: icon,
+ anchor: const Offset(0.5, 0.5), // مهم لكي تدور السيارة حول مركزها
+ infoWindow: InfoWindow(title: driverName),
+ ));
+ update(); // تحديث الخريطة
+ }
+ }
+
+ // التأكد من دالة التحريك السلس
+ void _smoothlyUpdateMarker(Marker oldMarker, LatLng newPosition,
+ double newHeading, BitmapDescriptor icon) {
+ // إذا كانت المسافة صغيرة جداً لا داعي للتحريك (لتقليل الوميض)
+ double distance = Geolocator.distanceBetween(
+ oldMarker.position.latitude,
+ oldMarker.position.longitude,
+ newPosition.latitude,
+ newPosition.longitude);
+
+ if (distance < 2.0) return;
+
+ final String markerIdKey = oldMarker.markerId.value;
+
+ // إلغاء أي أنيميشن سابق لنفس الماركر
+ _animationTimers[markerIdKey]?.cancel();
+
+ int ticks = 0;
+ const int totalSteps = 20; // عدد الخطوات (نعومة الحركة)
+ const int stepDuration = 50; // سرعة التحديث بالميلي ثانية (المجموع 1 ثانية)
+
+ double latStep =
+ (newPosition.latitude - oldMarker.position.latitude) / totalSteps;
+ double lngStep =
+ (newPosition.longitude - oldMarker.position.longitude) / totalSteps;
+ double headingStep = (newHeading - oldMarker.rotation) / totalSteps;
+
+ // معالجة مشكلة الدوران (مثلاً الانتقال من 350 درجة إلى 10 درجات)
+ if (headingStep.abs() > 180) {
+ // منطق لضبط الدوران في الاتجاه الأقرب (اختياري)
+ }
+
+ LatLng currentPos = oldMarker.position;
+ double currentHeading = oldMarker.rotation;
+
+ _animationTimers[markerIdKey] =
+ Timer.periodic(const Duration(milliseconds: stepDuration), (timer) {
+ ticks++;
+
+ currentPos =
+ LatLng(currentPos.latitude + latStep, currentPos.longitude + lngStep);
+ currentHeading += headingStep;
+
+ // تحديث القائمة
+ int index = markers.indexWhere((m) => m.markerId.value == markerIdKey);
+ if (index != -1) {
+ markers[index] = oldMarker.copyWith(
+ positionParam: currentPos,
+ rotationParam: currentHeading,
+ iconParam: icon, // تحديث الأيقونة في حال تغيرت
+ );
+ update(); // تحديث الواجهة في كل خطوة
+ }
+
+ if (ticks >= totalSteps) {
+ timer.cancel();
+ _animationTimers.remove(markerIdKey);
+ }
+ });
}
void _updateMarkerPosition(
@@ -3211,25 +4496,19 @@ class MapPassengerController extends GetxController {
mapController?.animateCamera(CameraUpdate.newLatLng(newPosition));
}
- // @override
- // void onClose() {
- // _timer?.cancel();
- // _animationTimers.forEach((_, timer) => timer.cancel());
- // _animationTimers.clear();
- // super.onClose();
- // }
@override
void onClose() {
print(
"--- MapPassengerController: Closing and cleaning up all resources. ---");
- // 1. إلغاء المؤقتات الفردية
- // Using ?.cancel() is safe even if the timer is null
- markerReloadingTimer!.cancel();
- markerReloadingTimer1!.cancel();
- markerReloadingTimer2!.cancel();
+ // 1. إلغاء المؤقتات الفردية (باستخدام ?. الآمن)
+ markerReloadingTimer?.cancel();
+ markerReloadingTimer1?.cancel();
+ markerReloadingTimer2?.cancel();
timerToPassengerFromDriverAfterApplied?.cancel();
_timer?.cancel();
+ _masterTimer?.cancel(); // (أضف المؤقت الرئيسي)
+ _camThrottle?.cancel(); // (أضف مؤقت الكاميرا)
// 2. إلغاء جميع المؤقتات في الخريطة (للتحريكات السلسة)
_animationTimers.forEach((key, timer) {
@@ -3238,7 +4517,6 @@ class MapPassengerController extends GetxController {
_animationTimers.clear();
// 3. إغلاق متحكمات البث (StreamControllers) لمنع تسريب الذاكرة
- // Using .close() is the correct way to shut down a stream
if (!_timerStreamController.isClosed) {
_timerStreamController.close();
}
@@ -3307,12 +4585,12 @@ class MapPassengerController extends GetxController {
"id": rideId.toString(), // Convert to String
"status": 'notApplyFromAnyDriver'
});
- if (AppLink.endPoint != AppLink.IntaleqSyriaServer) {
- CRUD().post(link: "${AppLink.endPoint}/ride/rides/update.php", payload: {
- "id": rideId.toString(), // Convert to String
- "status": 'notApplyFromAnyDriver'
- });
- }
+
+ CRUD().post(link: "${AppLink.endPoint}/ride/rides/update.php", payload: {
+ "id": rideId.toString(), // Convert to String
+ "status": 'notApplyFromAnyDriver'
+ });
+
rideConfirm = false;
statusRide == 'Cancel';
isSearchingWindow = false;
@@ -3331,42 +4609,43 @@ class MapPassengerController extends GetxController {
Future cancelRide() async {
clearPlacesDestination();
clearPolyline();
- // clearPolylineAll();
data = [];
changeCancelRidePageShow();
+
if (rideId != 'yet') {
Log.print('cancelRide: 1');
- // await firebaseMessagesController.sendNotificationToDriverMAP(
- // 'Cancel Trip',
- // 'Trip Cancelled'.tr,
- // driverToken.toString(),
- // [],
- // 'cancel',
- // );
await NotificationService.sendNotification(
+ category: 'Cancel Trip',
target: driverToken.toString(),
title: 'Cancel Trip'.tr,
body: 'Cancel Trip'.tr,
- isTopic: false, // Important: this is a token
+ isTopic: false,
tone: 'tone1',
driverList: [],
);
await Future.wait([
- CRUD().post(link: AppLink.updateRides, payload: {
- "id": rideId.toString(), // Convert to String
- "status": 'Cancel'
- }),
- CRUD().post(link: AppLink.updateDriverOrder, payload: {
- "order_id": rideId.toString(), // Convert to String
- "status": 'Cancel'
- }),
- CRUD().post(link: AppLink.updateWaitingTrip, payload: {
- "id": rideId.toString(), // Convert to String
- "status": 'Cancel'
- }),
+ CRUD().post(
+ link: AppLink.updateRides,
+ payload: {"id": rideId.toString(), "status": 'Cancel'}),
+ CRUD().post(
+ link: "${AppLink.server}/ride/rides/update.php",
+ payload: {"id": rideId.toString(), "status": 'Cancel'}),
+ CRUD().post(
+ link: AppLink.updateDriverOrder,
+ payload: {"order_id": rideId.toString(), "status": 'Cancel'}),
+ CRUD().post(
+ link: AppLink.updateWaitingTrip,
+ payload: {"id": rideId.toString(), "status": 'Cancel'}),
]);
}
- // Future.delayed(const Duration(seconds: 1));
+
+ // ---!! الإضافة الحاسمة لحل مشكلة "cancelled" !! ---
+ Log.print(
+ '[cancelRide] User cancelled. Setting state and stopping timers.');
+ currentRideState.value = RideState.cancelled; // 1. تعيين الحالة
+ stopAllTimers(); // 2. إيقاف المؤقت الرئيسي
+ // --- نهاية الإضافة ---
+
Get.offAll(() => const MapPagePassenger());
}
@@ -3598,7 +4877,7 @@ class MapPassengerController extends GetxController {
final lng = passengerLocation.longitude;
// نصف قطر البحث بالكيلومتر
- const radiusKm = 200.0;
+ const radiusKm = 45.0;
// حساب النطاق الجغرافي (Bounding Box) لإرساله للسيرفر
final latDelta = _kmToLatDelta(radiusKm);
@@ -4004,7 +5283,6 @@ class MapPassengerController extends GetxController {
Timer? _camThrottle;
DateTime _lastUiUpdate = DateTime.fromMillisecondsSinceEpoch(0);
-// نادِها في onInit مثلاً
Future detectPerfMode() async {
try {
if (GetPlatform.isAndroid) {
@@ -4299,12 +5577,12 @@ class MapPassengerController extends GetxController {
(_locationData.latitude != null && _locationData.longitude != null
? LatLng(_locationData.latitude!, _locationData.longitude!)
: null)!;
- getLocationArea(passengerLocation.latitude, passengerLocation.longitude);
- Log.print('AppLink.endPoint: ${AppLink.endPoint}');
+ // getLocationArea(passengerLocation.latitude, passengerLocation.longitude);
+ // Log.print('AppLink.endPoint: ${AppLink.endPoint}');
// Log.print('BoxName.serverChosen: ${box.read(BoxName.serverChosen)}');
newStartPointLocation = passengerLocation;
- Log.print('passengerLocation: $passengerLocation');
+ // Log.print('passengerLocation: $passengerLocation');
speed = _locationData.speed!;
// //print location details
isLoading = false;
@@ -4676,86 +5954,347 @@ class MapPassengerController extends GetxController {
stopPoints.remove(stop);
update(); // Trigger a rebuild of the UI
}
+// [تعديل] نحتاج هذه المكتبات لإرسال طلب HTTP مع هيدر
- getDirectionMap(String origin, destination,
+// ... (باقي imports الخاصة بك)
+// داخل MapPassengerController
+ // Future getReverseGeocoding(LatLng location) async {
+ // final lat = location.latitude;
+ // final lon = location.longitude;
+
+ // // بناء رابط الـ Reverse Geocoding
+ // final url =
+ // 'https://geocode.intaleq.xyz/reverse_geocode.php?lat=$lat&lon=$lon';
+
+ // try {
+ // // استخدام دالة CRUD للطلب (نفترض أن CRUD تستخدم http.get أو ما شابه)
+ // final response = await CRUD().get(link: url, payload: {});
+
+ // if (response != 'failure') {
+ // final data = jsonDecode(response);
+ // // if (data['status'] == 'ok') {
+ // // نفضل استخدام display_name أو neighbourhood إذا كان متاحًا
+ // String name = data['display_name'] ??
+ // data['neighbourhood'] ??
+ // 'Unknown Location'.tr;
+ // return name;
+ // // }
+ // }
+ // } catch (e) {
+ // Log.print('Error in Reverse Geocoding: $e');
+ // }
+
+ // // العودة لقيمة افتراضية في حالة الفشل
+ // return 'Unknown Location'.tr;
+ // }
+
+ Future getReverseGeocoding(LatLng location) async {
+ final lat = location.latitude;
+ final lon = location.longitude;
+ final url =
+ 'https://geocode.intaleq.xyz/reverse_geocode.php?lat=$lat&lon=$lon';
+
+ try {
+ final response = await http.get(Uri.parse(url));
+
+ // Log raw response for debugging
+
+ // Check if the request was successful
+ if (response.statusCode == 200) {
+ String body = response.body.trim();
+
+ // Validate it's actual JSON
+ if (body.startsWith('{') && body.endsWith('}')) {
+ final data = jsonDecode(body);
+
+ // Handle case where API returns {"status":"ok", ...}
+ if (data is Map && data['status'] == 'ok') {
+ String? name = data['display_name'] ?? data['neighbourhood'];
+ return name ?? 'Unknown Location'.tr;
+ } else {
+ // API returned JSON but not with "status: ok"
+ return 'Unknown Location'.tr;
+ }
+ } else {
+ // Not valid JSON (e.g., just "ok" or error message)
+ print('[WARNING] Invalid JSON: $body');
+ return 'Unknown Location'.tr;
+ }
+ } else {
+ print('[ERROR] HTTP ${response.statusCode}: ${response.body}');
+ return 'Unknown Location'.tr;
+ }
+ } catch (e) {
+ print('Error in Reverse Geocoding: $e');
+ return 'Unknown Location'.tr;
+ }
+ }
+
+ bool isDrawingRoute = false;
+ showDrawingBottomSheet() {
+ Get.bottomSheet(
+ Container(
+ width: double.infinity,
+ padding: const EdgeInsets.all(20),
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: const BorderRadius.only(
+ topLeft: Radius.circular(20),
+ topRight: Radius.circular(20),
+ ),
+ ),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ CircularProgressIndicator(
+ color: AppColor.primaryColor,
+ ),
+ const SizedBox(height: 15),
+ Text(
+ 'Drawing route on map...'.tr,
+ style: AppStyle.title.copyWith(fontSize: 16),
+ ),
+ const SizedBox(height: 5),
+ Text(
+ 'Please wait while we prepare your trip.'.tr,
+ style: TextStyle(color: Colors.grey[600]),
+ ),
+ ],
+ ),
+ ),
+ isDismissible: false,
+ enableDrag: false,
+ );
+ }
+
+ String dynamicApiUrl = 'https://routec.intaleq.xyz/route';
+ Future getDistanceFromDriverAfterAcceptedRide(
+ String origin, String destination) async {
+ String apiKey = Env.mapKeyOsm; // مفتاح API الخاص بك
+ if (origin.isEmpty) {
+ origin =
+ '${passengerLocation.latitude.toString().split(',')[0]},${passengerLocation.longitude.toString().split(',')[1]}';
+ }
+ // 2. بناء الرابط (URI)
+ // Waypoints غير مدعومة حالياً في OSRM، لذلك تم تجاهلها
+ var uri = Uri.parse(
+ '$dynamicApiUrl?origin=$origin&destination=$destination&steps=false&overview=false');
+ Log.print('uri: ${uri}');
+
+ // 3. إرسال الطلب مع الهيدر
+ http.Response response;
+ Map responseData;
+
+ try {
+ response = await http.get(
+ uri,
+ headers: {
+ 'X-API-KEY': apiKey,
+ },
+ ).timeout(const Duration(seconds: 20)); // تايم آوت 20 ثانية
+
+ if (response.statusCode != 200) {
+ print('Error from API: ${response.statusCode}');
+ isLoading = false;
+ update();
+ return; // خروج في حالة الخطأ
+ }
+ if (Get.isBottomSheetOpen ?? false) {
+ Get.back(); // لإغلاق شاشة "جاري الرسم"
+ }
+ isDrawingRoute = false; // Reset state
+
+ responseData = json.decode(response.body);
+ Log.print('responseData: ${responseData}');
+
+ if (responseData['status'] != 'ok') {
+ print('API returned an error: ${responseData['message']}');
+ isLoading = false;
+ update();
+ return; // خروج في حالة خطأ منطقي (مثل "no path")
+ }
+ } catch (e) {
+ print('Failed to get directions: $e');
+ isLoading = false;
+ update();
+ return; // خروج عند فشل الاتصال
+ }
+ }
+
+ // (b = 1.5348) هو المعامل الذي تم حسابه من مقارنة 60 رحلة بين Google و OSRM
+ double kDurationScalar =
+ 1.5348; //this from colab 60 random locations from google and routec
+// LatLng endPoint=LatLng(33, 36);
+ Future getDirectionMap(String origin, String destination,
[List waypoints = const []]) async {
isLoading = true;
+ isDrawingRoute = true;
update();
- remainingTime = 25; //to make cancel every call
- // startCarLocationSearch(box.read(BoxName.carType));
+ if (isDrawingRoute) showDrawingBottomSheet();
+ // --- هذا الجزء يبقى كما هو (تحميل السيارات، الخ) ---
+ remainingTime = 25;
await getCarsLocationByPassengerAndReloadMarker(
box.read(BoxName.carType), 5000);
- // await getCarsLocationByPassengerAndReloadMarker();
var coordDestination = destination.split(',');
double latPassengerDestination = double.parse(coordDestination[0]);
double lngPassengerDestination = double.parse(coordDestination[1]);
myDestination = LatLng(latPassengerDestination, lngPassengerDestination);
if (origin.isEmpty) {
origin =
- '${passengerLocation.latitude.toString().split(',')[0]},${passengerLocation.longitude.toString().split(',')[1]}'; //todo
+ '${passengerLocation.latitude.toString().split(',')[0]},${passengerLocation.longitude.toString().split(',')[1]}';
}
isLoading = false;
+
update();
- var url =
- ('${AppLink.googleMapsLink}directions/json?&language=${box.read(BoxName.lang) ?? 'ar'}&avoid=tolls|ferries&destination=$destination&origin=$origin&key=${AK.mapAPIKEY}');
- if (waypoints.isNotEmpty) {
- String formattedWaypoints = waypoints.join('|');
- url += '&waypoints=$formattedWaypoints';
+
+ // --- [تعديل] بناء الرابط والاتصال بالـ API الجديد ---
+
+ // 1. تعريف الرابط والمفتاح
+ // final String countryCode =
+ // box.read(BoxName.countryCode)?.toString() ?? 'Jordan';
+
+ // تحديد رابط API المناسب
+ String dynamicApiUrl;
+
+ dynamicApiUrl = 'https://routec.intaleq.xyz/route';
+
+ String apiKey = Env.mapKeyOsm; // مفتاح API الخاص بك
+
+ // 2. بناء الرابط (URI)
+ // Waypoints غير مدعومة حالياً في OSRM، لذلك تم تجاهلها
+ var uri = Uri.parse(
+ '$dynamicApiUrl?origin=$origin&destination=$destination&steps=false&overview=full');
+ Log.print('uri: ${uri}');
+
+ // 3. إرسال الطلب مع الهيدر
+ http.Response response;
+ Map responseData;
+
+ try {
+ response = await http.get(
+ uri,
+ headers: {
+ 'X-API-KEY': apiKey,
+ },
+ ).timeout(const Duration(seconds: 20)); // تايم آوت 20 ثانية
+
+ if (response.statusCode != 200) {
+ print('Error from API: ${response.statusCode}');
+ isLoading = false;
+ update();
+ return; // خروج في حالة الخطأ
+ }
+
+ responseData = json.decode(response.body);
+ Log.print('responseData: ${responseData}');
+
+ if (responseData['status'] != 'ok') {
+ print('API returned an error: ${responseData['message']}');
+ isLoading = false;
+ update();
+ return; // خروج في حالة خطأ منطقي (مثل "no path")
+ }
+ } catch (e) {
+ print('Failed to get directions: $e');
+ isLoading = false;
+ update();
+ return; // خروج عند فشل الاتصال
}
- var response = await CRUD().getGoogleApi(link: url, payload: {});
+ // --- نهاية جزء [تعديل] الاتصال ---
+
+ // --- [تعديل] قراءة البيانات من الـ API الجديد ---
+ // الـ API الجديد لا يرسل 'legs' أو 'routes'، البيانات مباشرة
- data = response['routes'][0]['legs'];
box.remove(BoxName.tripData);
- box.write(BoxName.tripData, response);
+ box.write(
+ BoxName.tripData, polylineCoordinate); // [تعديل] حفظ الاستجابة الجديدة
- startNameAddress = shortenAddress(data[0]['start_address']);
- // print('data[0][start_address]: ${data[0]['start_address']}');
- endNameAddress = shortenAddress(data[0]['end_address']);
- isLoading = false;
- newStartPointLocation = LatLng(
- data[0]["start_location"]['lat'], data[0]["start_location"]['lng']);
+ isBottomSheetShown = true;
- durationToRide = data[0]['duration']['value'];
- final String pointsString =
- response['routes'][0]["overview_polyline"]["points"];
+ // [تعديل] قراءة البولي لاين والزمن والمسافة
+ // durationToRide = ((responseData['duration_s'] as num) * 1.4).toInt();
+ durationToRide =
+ ((responseData['duration_s'] as num) * kDurationScalar).toInt();
+ Log.print('durationToRide: ${durationToRide}');
+ final String pointsString = responseData['polyline'];
+ double distanceOfTrip = (responseData['distance_m'] as num) / 1000.0;
+ Log.print('distanceOfTrip: ${distanceOfTrip}');
+ distance = distanceOfTrip;
+ Log.print('distance: ${distance}');
+ Log.print('distance: ${distance.toString()}');
+// ... داخل getDirectionMap, بعد التحقق من responseData['status'] == 'ok' ...
+ data = responseData['steps'];
+// ... أكمل باقي الكود ...
List decodedPoints =
await compute(decodePolylineIsolate, pointsString);
- // decodePolyline(response["routes"][0]["overview_polyline"]["points"]);
+
+ // مسح الإحداثيات القديمة وإضافة الجديدة
+ polylineCoordinates.clear();
+ // box.remove(BoxName.tripData);
for (int i = 0; i < decodedPoints.length; i++) {
- // double lat = decodedPoints[i][0].toDouble();
- // double lng = decodedPoints[i][1].toDouble();
polylineCoordinates.add(decodedPoints[i]);
}
-// Define the northeast and southwest coordinates
+ box.write(BoxName.tripData, responseData);
+ if (polylineCoordinates.isEmpty) {
+ print("Polyline is empty!");
+ return;
+ }
+ final LatLng startLoc = decodedPoints.first;
+ final LatLng endLoc = decodedPoints.last;
-// Define the northeast and southwest coordinates
- final bounds = response["routes"][0]["bounds"];
- LatLng northeast =
- LatLng(bounds['northeast']['lat'], bounds['northeast']['lng']);
- LatLng southwest =
- LatLng(bounds['southwest']['lat'], bounds['southwest']['lng']);
+ try {
+ final results = await Future.wait([
+ getReverseGeocoding(startLoc), // الطلب الأول (index 0)
+ getReverseGeocoding(endLoc), // الطلب الثاني (index 1)
+ ]);
-// Create the LatLngBounds object
- LatLngBounds boundsData =
- LatLngBounds(northeast: northeast, southwest: southwest);
+ startNameAddress = results[0];
+ endNameAddress = results[1];
+ } catch (e) {
+ // في حال حدث خطأ في Future.wait
+ print("Error in parallel reverse geocoding: $e");
+ startNameAddress = 'Unknown Location'.tr;
+ endNameAddress = 'Unknown Location'.tr;
+ }
+ // [تعديل] الـ API الجديد لا يرسل 'start_location' أو 'bounds'
+ // لذلك سنقوم باشتقاقها مباشرة من البولي لاين
+ if (Get.isBottomSheetOpen ?? false) {
+ Get.back(); // لإغلاق شاشة "جاري الرسم"
+ }
+ isDrawingRoute = false; // Reset state
+ // 1. تحديد نقطة البداية والنهاية من البولي لاين
+ newStartPointLocation = polylineCoordinates.first;
+ LatLng endLocation = polylineCoordinates.last;
-// Fit the camera to the bounds
+ // 2. إنشاء 'bounds' يدوياً ليناسب الكاميرا
+ // Find the northeast and southwest points from polyline coordinates
+ double? minLat, maxLat, minLng, maxLng;
+ for (LatLng point in polylineCoordinates) {
+ minLat = minLat == null ? point.latitude : min(minLat!, point.latitude);
+ maxLat = maxLat == null ? point.latitude : max(maxLat!, point.latitude);
+ minLng = minLng == null ? point.longitude : min(minLng!, point.longitude);
+ maxLng = maxLng == null ? point.longitude : max(maxLng!, point.longitude);
+ }
+ LatLngBounds boundsData = LatLngBounds(
+ northeast: LatLng(maxLat!, maxLng!),
+ southwest: LatLng(minLat!, minLng!));
+
+ // 3. تحديث الكاميرا (نفس الكود القديم، سيعمل الآن)
var cameraUpdate = CameraUpdate.newLatLngBounds(boundsData, 130);
mapController!.animateCamera(cameraUpdate);
- // getDistanceFromText(data[0]['distance']['text']);
- double distanceOfTrip = (data[0]['distance']['value']) / 1000;
- distance = distanceOfTrip;
+ // --- باقي الكود (إضافة العلامات ورسم الخطوط) يبقى كما هو تقريباً ---
+
durationToAdd = Duration(seconds: durationToRide);
hours = durationToAdd.inHours;
minutes = (durationToAdd.inMinutes % 60).round();
- // updateCameraForDistanceAfterGetMap();
+
markers.clear();
update();
markers.add(
Marker(
markerId: const MarkerId('start'),
- position: newStartPointLocation,
+ position: newStartPointLocation, // [تعديل] نستخدم النقطة من البولي لاين
icon: startIcon,
infoWindow: InfoWindow(
title: startNameAddress,
@@ -4764,12 +6303,11 @@ class MapPassengerController extends GetxController {
),
);
-// Add end marker
+ // Add end marker
markers.add(
Marker(
markerId: const MarkerId('end'),
- position: LatLng(
- data[0]["end_location"]['lat'], data[0]["end_location"]['lng']),
+ position: endLocation, // [تعديل] نستخدم النقطة من البولي لاين
icon: endIcon,
infoWindow: InfoWindow(
title: endNameAddress,
@@ -4777,28 +6315,16 @@ class MapPassengerController extends GetxController {
'$distance ${'KM'.tr} ⌛ ${hours > 0 ? '${'Your Ride Duration is '.tr}$hours ${'H and'.tr} $minutes ${'m'.tr}' : '${'Your Ride Duration is '.tr} $minutes ${'m'.tr}'}'),
),
);
-// // Show info windows automatically
- // Future.delayed(const Duration(milliseconds: 500), () {
- // mapController?.showMarkerInfoWindow(const MarkerId('start'));
- // });
- // Future.delayed(const Duration(milliseconds: 500), () {
- // mapController?.showMarkerInfoWindow(const MarkerId('end'));
- // });
- // update();
if (polyLines.isNotEmpty) {
clearPolyline();
} else {
- // الآن نقرأ القيمة ونحدد عدد النقاط بناءً عليها
- bool lowEndMode = box.read(BoxName.lowEndMode) ??
- false; // الأفضل أن يكون الافتراضي هو الجودة العالية
+ bool lowEndMode = box.read(BoxName.lowEndMode) ?? false;
- // نمرر عدد النقاط المناسب هنا
if (Platform.isIOS) {
animatePolylineLayered(
polylineCoordinates,
- maxPoints:
- lowEndMode ? 30 : 150, // 30 نقطة لوضع الأداء، 150 للوضع العادي
+ maxPoints: lowEndMode ? 30 : 150,
);
} else {
polyLines.add(Polyline(
@@ -4819,6 +6345,148 @@ class MapPassengerController extends GetxController {
}
}
+// getDirectionMap(String origin, destination,
+// [List waypoints = const []]) async {
+// isLoading = true;
+// update();
+// remainingTime = 25; //to make cancel every call
+// // startCarLocationSearch(box.read(BoxName.carType));
+// await getCarsLocationByPassengerAndReloadMarker(
+// box.read(BoxName.carType), 5000);
+// // await getCarsLocationByPassengerAndReloadMarker();
+// var coordDestination = destination.split(',');
+// double latPassengerDestination = double.parse(coordDestination[0]);
+// double lngPassengerDestination = double.parse(coordDestination[1]);
+// myDestination = LatLng(latPassengerDestination, lngPassengerDestination);
+// if (origin.isEmpty) {
+// origin =
+// '${passengerLocation.latitude.toString().split(',')[0]},${passengerLocation.longitude.toString().split(',')[1]}'; //todo
+// }
+// isLoading = false;
+// update();
+// var url =
+// ('${AppLink.googleMapsLink}directions/json?&language=${box.read(BoxName.lang) ?? 'ar'}&avoid=tolls|ferries&destination=$destination&origin=$origin&key=${AK.mapAPIKEY}');
+// if (waypoints.isNotEmpty) {
+// String formattedWaypoints = waypoints.join('|');
+// url += '&waypoints=$formattedWaypoints';
+// }
+// var response = await CRUD().getGoogleApi(link: url, payload: {});
+
+// data = response['routes'][0]['legs'];
+// box.remove(BoxName.tripData);
+// box.write(BoxName.tripData, response);
+
+// startNameAddress = shortenAddress(data[0]['start_address']);
+// // print('data[0][start_address]: ${data[0]['start_address']}');
+// endNameAddress = shortenAddress(data[0]['end_address']);
+// isLoading = false;
+// newStartPointLocation = LatLng(
+// data[0]["start_location"]['lat'], data[0]["start_location"]['lng']);
+
+// durationToRide = data[0]['duration']['value'];
+// final String pointsString =
+// response['routes'][0]["overview_polyline"]["points"];
+// List decodedPoints =
+// await compute(decodePolylineIsolate, pointsString);
+// // decodePolyline(response["routes"][0]["overview_polyline"]["points"]);
+// for (int i = 0; i < decodedPoints.length; i++) {
+// // double lat = decodedPoints[i][0].toDouble();
+// // double lng = decodedPoints[i][1].toDouble();
+// polylineCoordinates.add(decodedPoints[i]);
+// }
+// // Define the northeast and southwest coordinates
+
+// // Define the northeast and southwest coordinates
+// final bounds = response["routes"][0]["bounds"];
+// LatLng northeast =
+// LatLng(bounds['northeast']['lat'], bounds['northeast']['lng']);
+// LatLng southwest =
+// LatLng(bounds['southwest']['lat'], bounds['southwest']['lng']);
+
+// // Create the LatLngBounds object
+// LatLngBounds boundsData =
+// LatLngBounds(northeast: northeast, southwest: southwest);
+
+// // Fit the camera to the bounds
+// var cameraUpdate = CameraUpdate.newLatLngBounds(boundsData, 130);
+// mapController!.animateCamera(cameraUpdate);
+
+// // getDistanceFromText(data[0]['distance']['text']);
+// double distanceOfTrip = (data[0]['distance']['value']) / 1000;
+// distance = distanceOfTrip;
+// durationToAdd = Duration(seconds: durationToRide);
+// hours = durationToAdd.inHours;
+// minutes = (durationToAdd.inMinutes % 60).round();
+// // updateCameraForDistanceAfterGetMap();
+// markers.clear();
+// update();
+// markers.add(
+// Marker(
+// markerId: const MarkerId('start'),
+// position: newStartPointLocation,
+// icon: startIcon,
+// infoWindow: InfoWindow(
+// title: startNameAddress,
+// snippet: '',
+// ),
+// ),
+// );
+
+// // Add end marker
+// markers.add(
+// Marker(
+// markerId: const MarkerId('end'),
+// position: LatLng(
+// data[0]["end_location"]['lat'], data[0]["end_location"]['lng']),
+// icon: endIcon,
+// infoWindow: InfoWindow(
+// title: endNameAddress,
+// snippet:
+// '$distance ${'KM'.tr} ⌛ ${hours > 0 ? '${'Your Ride Duration is '.tr}$hours ${'H and'.tr} $minutes ${'m'.tr}' : '${'Your Ride Duration is '.tr} $minutes ${'m'.tr}'}'),
+// ),
+// );
+// // // Show info windows automatically
+// // Future.delayed(const Duration(milliseconds: 500), () {
+// // mapController?.showMarkerInfoWindow(const MarkerId('start'));
+// // });
+// // Future.delayed(const Duration(milliseconds: 500), () {
+// // mapController?.showMarkerInfoWindow(const MarkerId('end'));
+// // });
+// // update();
+
+// if (polyLines.isNotEmpty) {
+// clearPolyline();
+// } else {
+// // الآن نقرأ القيمة ونحدد عدد النقاط بناءً عليها
+// bool lowEndMode = box.read(BoxName.lowEndMode) ??
+// false; // الأفضل أن يكون الافتراضي هو الجودة العالية
+
+// // نمرر عدد النقاط المناسب هنا
+// if (Platform.isIOS) {
+// animatePolylineLayered(
+// polylineCoordinates,
+// maxPoints:
+// lowEndMode ? 30 : 150, // 30 نقطة لوضع الأداء، 150 للوضع العادي
+// );
+// } else {
+// polyLines.add(Polyline(
+// polylineId: const PolylineId('route'),
+// points: polylineCoordinates,
+// width: 6,
+// color: AppColor.primaryColor,
+// endCap: Cap.roundCap,
+// startCap: Cap.roundCap,
+// jointType: JointType.round,
+// ));
+// }
+
+// rideConfirm = false;
+// isMarkersShown = true;
+
+// update();
+// }
+// }
+
// 1) تقليل النقاط إلى حد أقصى 30 نقطة (مع بداية ونهاية محفوظة وتوزيع متساوٍ)
List _downsampleEven(List coords, {int maxPoints = 30}) {
if (coords.isEmpty) return const [];
@@ -5071,7 +6739,7 @@ class MapPassengerController extends GetxController {
final promo = TextEditingController();
bool promoTaken = false;
- applyPromoCodeToPassenger(BuildContext context) async {
+ void applyPromoCodeToPassenger(BuildContext context) async {
if (promoTaken == true) {
MyDialog().getDialog(
'Promo Already Used'.tr,
@@ -5083,8 +6751,8 @@ class MapPassengerController extends GetxController {
if (!promoFormKey.currentState!.validate()) return;
- // عتبات تفعيل البرومو بالليرة السورية
- const double minPromoLowSYP = 16000; // Speed / Balash
+ // العتبات بالليرة السورية
+ const double minPromoLowSYP = 17200; // Speed / Balash
const double minPromoHighSYP = 20000; // Comfort / Electric / Lady
try {
@@ -5102,7 +6770,7 @@ class MapPassengerController extends GetxController {
return;
}
- // تحقق أولي: هل عندنا أي فئة حاليًا فوق العتبات لتفعيل البرومو؟
+ // هل يوجد فئة مؤهلة أصلاً قبل الخصم؟
final bool eligibleNow = (totalPassengerSpeed >= minPromoLowSYP) ||
(totalPassengerBalash >= minPromoLowSYP) ||
(totalPassengerComfort >= minPromoHighSYP) ||
@@ -5111,8 +6779,10 @@ class MapPassengerController extends GetxController {
if (!eligibleNow) {
Get.snackbar(
- 'Lowest Price Achieved'.tr, 'Cannot apply further discounts.'.tr,
- backgroundColor: AppColor.yellowColor);
+ 'Lowest Price Achieved'.tr,
+ 'Cannot apply further discounts.'.tr,
+ backgroundColor: AppColor.yellowColor,
+ );
return;
}
@@ -5133,33 +6803,41 @@ class MapPassengerController extends GetxController {
final int discountPercentage =
int.tryParse(firstElement['amount'].toString()) ?? 0;
- // قيمة المحفظة (قد تكون سالبة)
+ // قيمة المحفظة - قد تكون سالبة
final double walletVal = double.tryParse(
box.read(BoxName.passengerWalletTotal)?.toString() ?? '0') ??
0.0;
- // دالة مساعدة: تطبق الخصم لكل فئة حسب عتبتها
+ final bool isWalletNegative = walletVal < 0;
+
+ // --------------------------
+ // دالة تُطبّق الخصم دون النزول تحت الحد الأدنى
+ // --------------------------
double _applyDiscountPerTier({
required double fare,
required double minThreshold,
required bool isWalletNegative,
}) {
- if (fare < minThreshold) return fare; // غير مؤهل
+ if (fare < minThreshold) return fare; // غير مؤهل أصلاً
- // منطقك السابق:
- // - إذا المحفظة سالبة: fare + (-wallet) - (fare * pct)
- // - إذا المحفظة ليست سالبة: fare - (fare * pct)
final double discount = fare * (discountPercentage / 100.0);
+ double result;
if (isWalletNegative) {
- final double neg = (-1) * walletVal; // walletVal < 0
- return (fare + neg - discount).clamp(0, double.infinity);
+ double neg = (-1) * walletVal; // walletVal < 0 => neg positive
+ result = fare + neg - discount;
} else {
- return (fare - discount).clamp(0, double.infinity);
+ result = fare - discount;
}
- }
- final bool isWalletNegative = walletVal < 0;
+ // لا نسمح بالنزول دون الحد الأدنى
+ if (result < minThreshold) {
+ result = minThreshold;
+ }
+
+ // ولا نسمح بمبلغ سالب
+ return result.clamp(0.0, double.infinity);
+ }
// Comfort
totalPassengerComfort = _applyDiscountPerTier(
@@ -5196,15 +6874,13 @@ class MapPassengerController extends GetxController {
isWalletNegative: isWalletNegative,
);
- // (اختياري) لو عندك فئات أخرى تريد تطبيق البرومو عليها، أضفها بنفس النمط.
-
- // تعديل دخل السائق حسب نسبة البرومو (كما كان في كودك)
+ // تعديل دخل السائق وفق نسبة الخصم
totalDriver = totalDriver - (totalDriver * discountPercentage / 100.0);
promoTaken = true;
update();
- // مؤثرات نجاح
+ // مؤثرات
Confetti.launch(
context,
options: const ConfettiOptions(particleCount: 100, spread: 70, y: 0.6),
@@ -5237,7 +6913,7 @@ class MapPassengerController extends GetxController {
double totalPassengerRayehGaiComfort = 0;
double totalPassengerRayehGaiBalash = 0;
Future bottomSheet() async {
- if (data.isEmpty) return;
+ // if (data.isEmpty) return;
// === إعدادات عامة ===
const double minFareSYP = 16000; // حد أدنى
@@ -5245,6 +6921,10 @@ class MapPassengerController extends GetxController {
const double ladyFlatAddon = 2000; // إضافة ثابتة لـ Lady
const double airportAddonSYP = 20000; // إضافة المطار
+ // --- ⬇️ الإضافة الجديدة: إضافة حدود مطار دمشق ⬇️ ---
+ const double damascusAirportBoundAddon = 140000; // إضافة المطار (حدود)
+ // --- ⬆️ نهاية الإضافة ⬆️ ---
+
// كهرباء
const double electricPerKmUplift = 400; // زيادة/كم
const double electricFlatAddon = 1000; // زيادة ثابتة
@@ -5258,7 +6938,7 @@ class MapPassengerController extends GetxController {
const double longDistThresholdKm = 35.0; // >35كم
const double longTripPerMin = 600.0;
const int minuteCapMedium = 60; // سقف دقائق عند >25كم
- const int minuteCapLong = 60; // سقف دقائق عند >35كم
+ const int minuteCapLong = 80; // سقف دقائق عند >35كم
const int freeMinutesLong = 10; // عفو 10 دقائق عند >35كم
// تخفيضات المسافات الكبيرة للفئات غير Speed
@@ -5291,6 +6971,23 @@ class MapPassengerController extends GetxController {
s.contains('ملهى ليلي');
}
+ // --- ⬇️ الإضافة الجديدة: دالة التحقق من حدود المطار ⬇️ ---
+ // (P1: 33.415313, 36.499687) (P2: 33.400265, 36.531505)
+ bool _isInsideDamascusAirportBounds(double lat, double lng) {
+ final double northLat = 33.415313;
+ final double southLat = 33.400265;
+ final double eastLng = 36.531505;
+ final double westLng = 36.499687;
+
+ // التحقق من خط العرض (بين الشمال والجنوب)
+ bool isLatInside = (lat <= northLat) && (lat >= southLat);
+ // التحقق من خط الطول (بين الشرق والغرب)
+ bool isLngInside = (lng <= eastLng) && (lng >= westLng);
+
+ return isLatInside && isLngInside;
+ }
+ // --- ⬆️ نهاية الإضافة ⬆️ ---
+
// أسعار الدقيقة من السيرفر
final double naturePerMin = naturePrice; // طبيعي
final double latePerMin = latePrice; // ليل
@@ -5318,6 +7015,18 @@ class MapPassengerController extends GetxController {
_isAirport(startNameAddress) || _isAirport(endNameAddress);
final bool clubCtx = _isClub(startNameAddress) || _isClub(endNameAddress);
+ // --- ⬇️ الإضافة الجديدة: التحقق من سياق حدود المطار ⬇️ ---
+ // !! ⚠️ تأكد من أن هذه هي المتغيرات الصحيحة لإحداثيات نقطة النهاية !!
+ final bool damascusAirportBoundCtx = _isInsideDamascusAirportBounds(
+ myDestination.latitude, // <-- ⚠️ غيّر هذا للمتغير الصحيح
+ myDestination.longitude, // <-- ⚠️ غيّر هذا للمتغير الصحيح
+ );
+ final bool isInDamascusAirportBoundCtx = _isInsideDamascusAirportBounds(
+ newMyLocation.latitude, // <-- ⚠️ غيّر هذا للمتغير الصحيح
+ newMyLocation.longitude, // <-- ⚠️ غيّر هذا للمتغير الصحيح
+ );
+ // --- ⬆️ نهاية الإضافة ⬆️ ---
+
// ====== مسافة مفوترة ======
final double billableDistance =
(distance < minBillableKm) ? minBillableKm : distance;
@@ -5330,18 +7039,15 @@ class MapPassengerController extends GetxController {
isLongSpeed ? longSpeedPerKm : perKmSpeedBaseFromServer;
// ====== تخفيضات الفئات الأخرى حسب بُعد الرحلة ======
- // نسبة التخفيض عند >40كم محسوبة مقارنة بسعر Speed الأساسي القادم من السيرفر
+ // ... (الكود كما هو) ...
double reductionPct40 = 0.0;
if (perKmSpeedBaseFromServer > 0) {
reductionPct40 = (1.0 - (longSpeedPerKm / perKmSpeedBaseFromServer))
.clamp(0.0, maxReductionCap);
}
- // نسبة التخفيض عند >100كم
final double reductionPct100 =
(reductionPct40 + extraReduction100).clamp(0.0, maxReductionCap);
-
- // نحدد أي تخفيض سنستخدمه
- double distanceReduction = 0.0; // لا تخفيض افتراضيًا
+ double distanceReduction = 0.0;
if (billableDistance > 100.0) {
distanceReduction = reductionPct100;
} else if (billableDistance > 40.0) {
@@ -5349,45 +7055,38 @@ class MapPassengerController extends GetxController {
}
// ====== منطق الدقيقة يعمل لكل الأوقات ويتكيّف مع المسافة ======
+ // ... (الكود كما هو) ...
double effectivePerMin = _perMinuteByTime(currentTime, clubCtx);
int billableMinutes = totalMinutes;
-
if (billableDistance > longDistThresholdKm) {
- // >35كم: 600/د + سقف 60 + عفو 10
effectivePerMin = longTripPerMin;
final int capped =
(billableMinutes > minuteCapLong) ? minuteCapLong : billableMinutes;
billableMinutes = capped - freeMinutesLong;
if (billableMinutes < 0) billableMinutes = 0;
} else if (billableDistance > mediumDistThresholdKm) {
- // >25كم و≤35كم: 600/د + سقف 60 (بدون عفو)
effectivePerMin = longTripPerMin;
billableMinutes = (billableMinutes > minuteCapMedium)
? minuteCapMedium
: billableMinutes;
}
- // ≤25كم: نبقي السعر حسب الوقت بدون سقف/عفو
// ====== أسعار/كم قبل التخفيض ======
+ // ... (الكود كما هو) ...
final double perKmComfortRaw = comfortPrice;
final double perKmDelivery = deliveryPrice;
final double perKmVanRaw =
(familyPrice > 0 ? familyPrice : (speedPrice + 1300));
- // Electric مبني على Comfort
final double perKmElectricRaw = perKmComfortRaw + electricPerKmUplift;
// ====== تطبيق التخفيضات على الفئات (نفس نسبة Speed للبعيد) ======
- // ملاحظة: Balash يتبع Speed دائمًا (Speed-500) فلا حاجة لتخفيض إضافي له.
+ // ... (الكود كما هو) ...
double perKmComfort = perKmComfortRaw * (1.0 - distanceReduction);
double perKmElectric = perKmElectricRaw * (1.0 - distanceReduction);
double perKmVan = perKmVanRaw * (1.0 - distanceReduction);
-
- // نضمن عدم الهبوط تحت الصفر
perKmComfort = perKmComfort.clamp(0, double.infinity);
perKmElectric = perKmElectric.clamp(0, double.infinity);
perKmVan = perKmVan.clamp(0, double.infinity);
-
- // Awfar/Balash: مرتبط بسرعة Speed بعد التفعيل
final double perKmBalash = (perKmSpeed - 500).clamp(0, double.infinity);
// ====== دوال الاحتساب ======
@@ -5402,6 +7101,13 @@ class MapPassengerController extends GetxController {
fare += flatAddon;
if (isLady) fare += ladyFlatAddon;
if (airportCtx) fare += airportAddonSYP;
+
+ // --- ⬇️ الإضافة الجديدة: تطبيق إضافة حدود المطار ⬇️ ---
+ if (damascusAirportBoundCtx || isInDamascusAirportBoundCtx) {
+ fare += damascusAirportBoundAddon;
+ }
+ // --- ⬆️ نهاية الإضافة ⬆️ ---
+
return _applyMinFare(fare);
}
@@ -5412,6 +7118,14 @@ class MapPassengerController extends GetxController {
double timePart = (billableMinutes * 2) * effectivePerMin;
double fare = distPart + timePart;
if (airportCtx) fare += airportAddonSYP;
+
+ // --- ⬇️ الإضافة الجديدة: تطبيق إضافة حدود المطار ⬇️ ---
+ // تنطبق أيضاً على رحلات الذهاب والعودة لأنها "تصل" إلى الوجهة
+ if (damascusAirportBoundCtx || isInDamascusAirportBoundCtx) {
+ fare += damascusAirportBoundAddon;
+ }
+ // --- ⬆️ نهاية الإضافة ⬆️ ---
+
return _applyMinFare(fare);
}
@@ -5469,7 +7183,6 @@ class MapPassengerController extends GetxController {
update();
changeBottomSheetShown();
}
-
// addToken() async {
// String fingerPrint = await DeviceHelper.getDeviceFingerprint();
@@ -5751,8 +7464,9 @@ class MapPassengerController extends GetxController {
// ],
// 'order');
await NotificationService.sendNotification(
+ category: 'OrderVIP',
target: driver['token'].toString(),
- title: 'OrderVIP',
+ title: 'OrderVIP'.tr,
body: '$rideId - VIP Trip',
isTopic: false, // Important: this is a token
tone: 'tone1',
@@ -5785,6 +7499,7 @@ class MapPassengerController extends GetxController {
// 'cancel',
// );
await NotificationService.sendNotification(
+ category: 'Order VIP Canceld',
target: response['previous_driver_token'].toString(),
title: 'Order VIP Canceld'.tr,
body: 'Passenger cancel order'.tr,
@@ -5825,14 +7540,8 @@ class MapPassengerController extends GetxController {
}
sendToDriverAgain(String token) {
- // firebaseMessagesController.sendNotificationToDriverMAP(
- // 'Order VIP Canceld'.tr,
- // 'Passenger cancel order'.tr,
- // token,
- // [],
- // 'cancel',
- // );
NotificationService.sendNotification(
+ category: 'Order VIP Canceld',
target: token.toString(),
title: 'Order VIP Canceld'.tr,
body: 'Passenger cancel order'.tr,
@@ -6026,7 +7735,8 @@ class MapPassengerController extends GetxController {
unawaited(_stageNiceToHave());
// ابدأ إعادة تحميل الماركر لكن بثروتل داخلي
- startMarkerReloading(); // تأكد أنه مَخنوق التحديث (throttled)
+ // startMarkerReloading(); // تأكد أنه مَخنوق التحديث (throttled)
+ _startMasterTimer();
}
// === Helpers ===
@@ -6043,7 +7753,7 @@ class MapPassengerController extends GetxController {
await getKazanPercent(); // أسعار السيرفر
} catch (_) {}
try {
- await getRideStatusFromStartApp();
+ _checkInitialRideStatus(); // تحقق من حالة الرحلة الحالية
} catch (_) {}
// لو عندك ضبط “وضع خفيف” حسب الجهاز:
_applyLowEndModeIfNeeded();
@@ -6108,42 +7818,6 @@ class MapPassengerController extends GetxController {
// لاحقاً فعّل: map.trafficEnabled=false, buildingsEnabled=false, تبسيط polylines...
// controller.lowEndMode = true;
}
- // @override
- // void onInit() async {
- // mapAPIKEY = await storage.read(key: BoxName.mapAPIKEY);
- // // k = await getAIKey('HERE_API');
- // getFavioratePlaces();
- // readyWayPoints();
- // addCustomPicker();
- // addCustomCarIcon();
- // addCustomLadyIcon();
- // addCustomMotoIcon();
- // addCustomStepIcon();
- // addCustomStartIcon();
- // addCustomEndIcon();
- // addToken();
- // await getLocation();
- // addFingerPrint();
- // // getPassengerLocationUniversity();
- // // _initializePolygons();
- // // await addToken();
- // getKazanPercent();
- // getPassengerRate();
- // getRideStatusFromStartApp();
- // reloadStartApp = false;
- // startMarkerReloading();
- // Get.put(TextToSpeechController());
- // Get.put(FirebaseMessagesController());
- // box.write(BoxName.carType, 'yet');
- // box.write(BoxName.tipPercentage, '0');
- // Get.put(AudioRecorderController());
- // // await getNearestDriverByPassengerLocation();
- // firstTimeRunToGetCoupon();
- // initilizeGetStorage();
- // cardNumber = await SecureStorage().readData(BoxName.cardNumber);
-
- // super.onInit();
- // }
uploadPassengerLocation() async {
await CRUD().post(link: AppLink.addpassengerLocation, payload: {
diff --git a/lib/controller/home/points_for_rider_controller.dart b/lib/controller/home/points_for_rider_controller.dart
index 5c9a551..10ff0ba 100644
--- a/lib/controller/home/points_for_rider_controller.dart
+++ b/lib/controller/home/points_for_rider_controller.dart
@@ -112,7 +112,7 @@ class WayPointController extends GetxController {
@override
void onInit() {
- Get.put(LocationController());
+ // Get.put(LocationController());
addWayPoints();
myLocation = Get.find().passengerLocation;
super.onInit();
diff --git a/lib/controller/home/profile/invit_controller.dart b/lib/controller/home/profile/invit_controller.dart
index 329270f..c73c06c 100644
--- a/lib/controller/home/profile/invit_controller.dart
+++ b/lib/controller/home/profile/invit_controller.dart
@@ -162,7 +162,7 @@ ${'Download the Intaleq app now and enjoy your ride!'.tr}
// 2. If it already starts with the country code, we assume it's correct.
if (digitsOnly.startsWith('963')) {
- return '+$digitsOnly';
+ return '$digitsOnly';
}
// 3. If it starts with '09' (common local format), remove the leading '0'.
@@ -171,7 +171,7 @@ ${'Download the Intaleq app now and enjoy your ride!'.tr}
}
// 4. Prepend the Syrian country code.
- return '+963$digitsOnly';
+ return '963$digitsOnly';
}
/// **IMPROVEMENT**: This method now uses the new phone formatting logic and
diff --git a/lib/controller/local/phone_intel/countries.dart b/lib/controller/local/phone_intel/countries.dart
index 13e4bab..528d4fa 100644
--- a/lib/controller/local/phone_intel/countries.dart
+++ b/lib/controller/local/phone_intel/countries.dart
@@ -6603,7 +6603,7 @@ const List countries = [
code: "SY",
dialCode: "963",
minLength: 9,
- maxLength: 9,
+ maxLength: 10,
),
Country(
name: "Taiwan",
diff --git a/lib/controller/local/translations.dart b/lib/controller/local/translations.dart
index 99c614c..d688007 100644
--- a/lib/controller/local/translations.dart
+++ b/lib/controller/local/translations.dart
@@ -201,7 +201,16 @@ class MyTranslation extends Translations {
"Top up Wallet": "تعبئة المحفظة",
"Add funds using our secure methods":
"أضف رصيداً باستخدام طرقنا الآمنة",
- "Speed": "سرعة",
+ 'Driver is waiting': 'الكابتن في انتظارك',
+ 'Type your message...': 'اكتب رسالتك...',
+ 'Driver Accepted Request': 'الكابتن قبل الطلب',
+ 'Message': 'رسالة',
+ 'Call': 'اتصال',
+ "You can call or record audio during this trip.":
+ "يمكنك الاتصال أو تسجيل صوت أثناء هذه الرحلة.",
+ "Warning: Speeding detected!": "تحذير: تم الكشف عن تجاوز السرعة!",
+ 'Fixed Price': 'سعر ثابت',
+ 'Report': 'إبلاغ',
"Comfort": "مريحة",
"Intaleq Balance": "رصيد انطلق",
'Search for a starting point': 'ابحث عن نقطة انطلاق',
@@ -316,6 +325,8 @@ class MyTranslation extends Translations {
"Van for familly": "سيارة فان للعائلة",
"Are you sure to delete this location?":
"هل أنت متأكد من حذف هذا الموقع؟",
+ 'Change Work location?': 'تغيير موقع العمل؟',
+ 'Change Home location?': 'تغيير موقع البيت؟',
"Submit a Complaint": "تقديم شكوى",
"Submit Complaint": "إرسال الشكوى",
"No trip history found": "لا يوجد سجل للرحلات",
@@ -395,6 +406,41 @@ class MyTranslation extends Translations {
"OK": "موافق",
"Confirm Pick-up Location": "تأكيد موقع الانطلاق",
"Set Location on Map": "حدد الموقع على الخريطة",
+ 'Leave a detailed comment (Optional)':
+ 'اترك تعليقاً مفصلاً (اختياري)',
+ 'Share your experience to help us improve...':
+ 'شارك تجربتك لمساعدتنا على التحسن...',
+ 'Your valuable feedback helps us improve our service quality.':
+ 'ملاحظاتك القيمة تساعدنا في تحسين جودة خدماتنا.',
+ 'witout zero': 'بدون صفر',
+ 'Top up Balance': 'اشحن الرصيد',
+ 'An error occurred': 'حدث خطأ',
+ 'Send WhatsApp Message': 'إرسال رسالة واتساب',
+ 'How was your trip with': 'كيف كانت رحلتك مع',
+ 'Drawing route on map...': 'جارٍ رسم المسار على الخريطة...',
+ 'Please wait while we prepare your trip.':
+ 'يرجى الانتظار بينما نحضر رحلتك.',
+ 'Submit Rating': 'إرسال التقييم',
+ 'Call Support': 'الاتصال بالدعم',
+ "You can contact us during working hours from 10:00 - 16:00.":
+ "يمكنك التواصل معنا خلال ساعات العمل من 10:00 إلى 16:00.",
+ "Intaleq is the safest and most reliable ride-sharing app designed especially for passengers in Syria. We provide a comfortable, respectful, and affordable riding experience with features that prioritize your safety and convenience. Our trusted captains are verified, insured, and supported by regular car maintenance carried out by top engineers. We also offer on-road support services to make sure every trip is smooth and worry-free. With Intaleq, you enjoy quality, safety, and peace of mind—every time you ride.":
+ """إنطلِق هو التطبيق الأكثر أماناً وموثوقية لمشاركة الركوب والمصمم خصيصاً للركّاب في سوريا. نوفر لك تجربة تنقّل مريحة، محترمة، وبأسعار مناسبة، مع ميزات تضع سلامتك وراحتك في المقام الأول.
+
+جميع الكباتن لدينا موثوقون، مُؤمَّنون، وتخضع سياراتهم لصيانة دورية يقوم بها مهندسون مختصون لضمان أفضل جودة. كما نقدّم خدمات دعم على الطريق لضمان أن تكون كل رحلة سلسة وخالية من القلق.
+
+مع إنطلِق، ستستمتع دائماً بالأمان، والجودة، وراحة البال في كل رحلة تقوم بها.""",
+ 'Work time is from 10:00 AM to 16:00 PM.\nYou can send a WhatsApp message or email.':
+ 'وقت العمل من 10:00 صباحاً إلى 16:00 مساءً.\nيمكنك إرسال رسالة واتساب أو بريد إلكتروني.',
+ 'Sorry': 'عذراً',
+ "Customer MSISDN doesn’t have customer wallet":
+ "رقم هاتف العميل لا يحتوي على محفظة عميل",
+ 'Please enter the number without the leading 0':
+ 'يرجى إدخال الرقم بدون الصفر الأولي',
+ 'Please enter your phone number': 'يرجى إدخال رقم هاتفك',
+ 'Phone number seems too short': 'يبدو أن رقم الهاتف قصير جدًا',
+ 'No cars are available at the moment. Please try again later.':
+ 'لا توجد سيارات متاحة حالياً. الرجاء المحاولة مرة أخرى لاحقاً.',
"Nearest Car: ~": "أقرب سيارة: ~",
"Nearest Car": "أقرب سيارة",
"No cars nearby": "لا توجد سيارات قريبة",
diff --git a/lib/controller/notification/passenger_notification_controller.dart b/lib/controller/notification/passenger_notification_controller.dart
index fb7e617..04c8cb4 100644
--- a/lib/controller/notification/passenger_notification_controller.dart
+++ b/lib/controller/notification/passenger_notification_controller.dart
@@ -56,6 +56,7 @@ class PassengerNotificationController extends GetxController {
// 'iphone_ringtone',
// );
await NotificationService.sendNotification(
+ category: title,
target: 'token'.toString(),
title: title,
body: body.tr,
diff --git a/lib/controller/payment/passenger_wallet_history_controller.dart b/lib/controller/payment/passenger_wallet_history_controller.dart
index b9f9d4d..33ae390 100644
--- a/lib/controller/payment/passenger_wallet_history_controller.dart
+++ b/lib/controller/payment/passenger_wallet_history_controller.dart
@@ -31,9 +31,9 @@ class PassengerWalletHistoryController extends GetxController {
});
}
} catch (e) {
- MyDialog().getDialog('An error occurred'.tr, e.toString(), () {
- Get.back();
- });
+ // MyDialog().getDialog('An error occurred'.tr, '', () {
+ // Get.back();
+ // });
} finally {
isLoading = false;
update();
diff --git a/lib/controller/payment/payment_controller.dart b/lib/controller/payment/payment_controller.dart
index c44f88a..15a30e1 100644
--- a/lib/controller/payment/payment_controller.dart
+++ b/lib/controller/payment/payment_controller.dart
@@ -144,8 +144,9 @@ class PaymentController extends GetxController {
// 'cancel',
// );
await NotificationService.sendNotification(
+ category: 'Cancel',
target: Get.find().driverToken.toString(),
- title: 'Cancel',
+ title: 'Cancel'.tr,
body:
'Trip Cancelled. The cost of the trip will be added to your wallet.'
.tr,
diff --git a/lib/controller/rate/rate_conroller.dart b/lib/controller/rate/rate_conroller.dart
index 77bac9b..8bdd4f4 100644
--- a/lib/controller/rate/rate_conroller.dart
+++ b/lib/controller/rate/rate_conroller.dart
@@ -9,7 +9,6 @@ import 'package:Intaleq/main.dart';
import 'package:Intaleq/views/home/map_page_passenger.dart';
import 'package:Intaleq/views/widgets/elevated_btn.dart';
-import '../firebase/firbase_messge.dart';
import '../firebase/notification_service.dart';
import '../payment/payment_controller.dart';
@@ -18,7 +17,7 @@ import '../payment/payment_controller.dart';
class RateController extends GetxController {
double selectedRateItemId = -1;
TextEditingController comment = TextEditingController();
- String? rideId, passengerId, driverId, price;
+ String? rideId, passengerId, driverId, driverName, price;
late GlobalKey formKey;
@override
void onInit() {
@@ -26,6 +25,7 @@ class RateController extends GetxController {
passengerId = Get.arguments['passengerId'];
rideId = Get.arguments['rideId'];
driverId = Get.arguments['driverId'];
+ driverName = Get.arguments['driverName'];
price = Get.arguments['price'];
box.write(BoxName.tipPercentage, '0');
super.onInit();
@@ -61,7 +61,7 @@ class RateController extends GetxController {
box.read(BoxName.countryCode) == 'Egypt'
? tip.toStringAsFixed(0)
: (tip * 100).toString());
- await CRUD().post(link: AppLink.addDriversWalletPoints, payload: {
+ await CRUD().postWallet(link: AppLink.addDriversWalletPoints, payload: {
'driverID': Get.find().driverId.toString(),
'paymentID': '${Get.find().rideId}tip',
'amount': box.read(BoxName.countryCode) == 'Egypt'
@@ -71,16 +71,10 @@ class RateController extends GetxController {
'token': token1,
});
if (res != 'failure') {
- // Get.find().sendNotificationToDriverMAP(
- // 'You Have Tips'.tr,
- // '${'${tip.toString()}\$${' tips\nTotal is'.tr}'} ${tip + (Get.find().totalPassenger)}',
- // Get.find().driverToken.toString(),
- // [],
- // 'ding',
- // );
await NotificationService.sendNotification(
+ category: 'You Have Tips',
target: Get.find().driverToken.toString(),
- title: 'You Have Tips',
+ title: 'You Have Tips'.tr,
body:
'${'${tip.toString()}\$${' tips\nTotal is'.tr}'} ${tip + (Get.find().totalPassenger)}',
isTopic: false, // Important: this is a token
@@ -91,26 +85,15 @@ class RateController extends GetxController {
}
}
await CRUD().post(
- link: "${AppLink.IntaleqSyriaServer}/ride/rate/addRateToDriver.php",
- payload: {
- 'passenger_id': box.read(BoxName.passengerID).toString(),
- 'driver_id': driverId.toString(),
- 'ride_id': rideId.toString(),
- 'rating': selectedRateItemId.toString(),
- 'comment': comment.text,
- });
-
- if (AppLink.endPoint != AppLink.IntaleqSyriaServer) {
- CRUD().post(
- link: "${AppLink.endPoint}/ride/rate/addRateToDriver.php",
- payload: {
- 'passenger_id': box.read(BoxName.passengerID).toString(),
- 'driver_id': driverId.toString(),
- 'ride_id': rideId.toString(),
- 'rating': selectedRateItemId.toString(),
- 'comment': comment.text,
- });
- }
+ link: "${AppLink.server}/ride/rate/addRateToDriver.php",
+ payload: {
+ 'passenger_id': box.read(BoxName.passengerID).toString(),
+ 'driver_id': driverId.toString(),
+ 'ride_id': rideId.toString(),
+ 'rating': selectedRateItemId.toString(),
+ 'comment': comment.text,
+ },
+ );
Get.find().restCounter();
Get.offAll(const MapPagePassenger());
diff --git a/lib/env/env.dart b/lib/env/env.dart
index 7f8874e..736322a 100644
--- a/lib/env/env.dart
+++ b/lib/env/env.dart
@@ -10,6 +10,9 @@ abstract class Env {
@EnviedField(varName: 'basicCompareFaces', obfuscate: true)
static final String basicCompareFaces = _Env.basicCompareFaces;
+ @EnviedField(varName: 'mapKeyOsm', obfuscate: true)
+ static final String mapKeyOsm = _Env.mapKeyOsm;
+
@EnviedField(varName: 'sss_encryptionSalt', obfuscate: true)
static final String sss_encryptionSalt = _Env.sss_encryptionSalt;
diff --git a/lib/env/env.g.dart b/lib/env/env.g.dart
index 2db99d7..caf595d 100644
--- a/lib/env/env.g.dart
+++ b/lib/env/env.g.dart
@@ -11,71 +11,71 @@ part of 'env.dart';
// generated_from: .env
final class _Env {
static const List _enviedkeybasicAuthCredentials = [
- 4234915833,
- 3928216899,
- 3410912984,
- 2407692179,
- 2446795710,
- 2936914067,
- 2249400578,
- 1163862693,
- 2186618797,
- 2677973112,
- 2210337486,
- 2863659743,
- 1943484302,
- 244978853,
- 2460307113,
- 3175448389,
- 3712650198,
- 188576852,
- 1433192897,
- 350773884,
- 907745278,
- 2290737213,
- 2700419638,
- 2264853687,
- 1243244371,
- 4034005781,
- 2222610217,
- 963001681,
- 3316612901,
- 92693012,
- 2456022798,
+ 43044676,
+ 864909550,
+ 4242758126,
+ 2514357568,
+ 1555483995,
+ 1142069238,
+ 1205503833,
+ 1967239324,
+ 1860681093,
+ 3229905743,
+ 3243147856,
+ 1002171964,
+ 2971668333,
+ 3009646440,
+ 331994719,
+ 3443456963,
+ 813108254,
+ 2398669640,
+ 2665467623,
+ 1880765956,
+ 3552236665,
+ 3431379130,
+ 4129886444,
+ 2497907908,
+ 2195738790,
+ 3192394429,
+ 1329286224,
+ 3931833945,
+ 353914251,
+ 1168254924,
+ 1798346792,
];
static const List _envieddatabasicAuthCredentials = [
- 4234915726,
- 3928216882,
- 3410912950,
- 2407692286,
- 2446795727,
- 2936914146,
- 2249400689,
- 1163862735,
- 2186618836,
- 2677973006,
- 2210337465,
- 2863659701,
- 1943484408,
- 244978847,
- 2460307143,
- 3175448372,
- 3712650148,
- 188576781,
- 1433192843,
- 350773804,
- 907745214,
- 2290737164,
- 2700419585,
- 2264853636,
- 1243244388,
- 4034005837,
- 2222610267,
- 963001609,
- 3316612937,
- 92693078,
- 2456022882,
+ 43044659,
+ 864909471,
+ 4242758016,
+ 2514357549,
+ 1555483946,
+ 1142069127,
+ 1205503786,
+ 1967239414,
+ 1860681212,
+ 3229905721,
+ 3243147815,
+ 1002171990,
+ 2971668251,
+ 3009646418,
+ 331994673,
+ 3443456946,
+ 813108332,
+ 2398669585,
+ 2665467565,
+ 1880766036,
+ 3552236601,
+ 3431379083,
+ 4129886427,
+ 2497907959,
+ 2195738769,
+ 3192394469,
+ 1329286178,
+ 3931833857,
+ 353914343,
+ 1168254862,
+ 1798346820,
];
static final String basicAuthCredentials = String.fromCharCodes(
@@ -88,65 +88,65 @@ final class _Env {
_enviedkeybasicAuthCredentials[i]));
static const List _enviedkeybasicCompareFaces = [
- 3670186193,
- 1875065285,
- 413592326,
- 3628880127,
- 497603442,
- 1766586063,
- 2090599229,
- 2847291910,
- 3987981166,
- 2577739453,
- 1431163461,
- 65696213,
- 616553583,
- 758841712,
- 3076780249,
- 1221199957,
- 331246655,
- 422005507,
- 332597777,
- 2348587503,
- 2833388866,
- 1661320722,
- 3311668374,
- 361129657,
- 2620096974,
- 3531121486,
- 3707762195,
- 1920617253,
+ 3727333105,
+ 1843694516,
+ 3611997723,
+ 2407362513,
+ 1356628908,
+ 2977101071,
+ 1936901014,
+ 2964813805,
+ 197648233,
+ 3590224812,
+ 3940587702,
+ 2375653923,
+ 764212019,
+ 500016560,
+ 3035095344,
+ 1159165809,
+ 3677722776,
+ 3500824290,
+ 3405327942,
+ 2095637207,
+ 3941804910,
+ 2161512590,
+ 1479882886,
+ 327839885,
+ 153188006,
+ 365671944,
+ 436594973,
+ 98326119,
];
static const List _envieddatabasicCompareFaces = [
- 3670186155,
- 1875065263,
- 413592435,
- 3628880021,
- 497603358,
- 1766586042,
- 2090599244,
- 2847292000,
- 3987981086,
- 2577739479,
- 1431163519,
- 65696187,
- 616553502,
- 758841602,
- 3076780160,
- 1221199935,
- 331246671,
- 422005571,
- 332597792,
- 2348587480,
- 2833388913,
- 1661320741,
- 3311668430,
- 361129675,
- 2620096918,
- 3531121442,
- 3707762257,
- 1920617289,
+ 3727333003,
+ 1843694558,
+ 3611997806,
+ 2407362491,
+ 1356628928,
+ 2977101178,
+ 1936901095,
+ 2964813707,
+ 197648153,
+ 3590224838,
+ 3940587660,
+ 2375653965,
+ 764212034,
+ 500016578,
+ 3035095401,
+ 1159165723,
+ 3677722856,
+ 3500824226,
+ 3405327991,
+ 2095637216,
+ 3941804893,
+ 2161512633,
+ 1479882974,
+ 327839999,
+ 153188094,
+ 365672036,
+ 436595039,
+ 98326027,
];
static final String basicCompareFaces = String.fromCharCodes(
@@ -157,136 +157,188 @@ final class _Env {
).map((int i) =>
_envieddatabasicCompareFaces[i] ^ _enviedkeybasicCompareFaces[i]));
+ static const List _enviedkeymapKeyOsm = [
+ 1880725877,
+ 1912740320,
+ 3266542548,
+ 2054336914,
+ 1379127872,
+ 227009578,
+ 1846478925,
+ 2878974208,
+ 3213278626,
+ 1144816508,
+ 2203359042,
+ 735878522,
+ 2466200304,
+ 946402320,
+ 879102837,
+ 2671812745,
+ 3872307814,
+ 4055984631,
+ 763879643,
+ 2036980354,
+ ];
+
+ static const List _envieddatamapKeyOsm = [
+ 1880725784,
+ 1912740225,
+ 3266542520,
+ 2054337014,
+ 1379127845,
+ 227009628,
+ 1846478861,
+ 2878974322,
+ 3213278669,
+ 1144816393,
+ 2203359030,
+ 735878431,
+ 2466200285,
+ 946402420,
+ 879102746,
+ 2671812837,
+ 3872307722,
+ 4055984534,
+ 763879593,
+ 2036980465,
+ ];
+
+ static final String mapKeyOsm = String.fromCharCodes(List.generate(
+ _envieddatamapKeyOsm.length,
+ (int i) => i,
+ growable: false,
+ ).map((int i) => _envieddatamapKeyOsm[i] ^ _enviedkeymapKeyOsm[i]));
+
static const List _enviedkeysss_encryptionSalt = [
- 3363710070,
- 4271671361,
- 1265812073,
- 1283668769,
- 4162856663,
- 761049106,
- 1572031423,
- 4193649778,
- 1826833844,
- 3927730830,
- 3291753144,
- 2560155452,
- 2345185371,
- 1056977461,
- 698954416,
- 2553363475,
- 2947812014,
- 1283225378,
- 4289553862,
- 1542386655,
- 1827775001,
- 1077873162,
- 1858272745,
- 499846513,
- 701552642,
- 2360041577,
- 1152655624,
- 3490004507,
- 898560501,
- 1333751609,
- 4168446801,
- 3381376174,
- 1704048368,
- 284631013,
- 2153842081,
- 331530398,
- 3998206813,
- 2500954056,
- 4084136045,
- 4167242937,
- 208606685,
- 3900195215,
- 2793181355,
- 131568241,
- 1382602125,
- 3695432877,
- 818015198,
- 2083106888,
- 46646629,
- 2704955575,
- 99966621,
- 2095833913,
- 1835928593,
- 4112801470,
- 1337663931,
- 1986459651,
- 1312582186,
- 2401667805,
- 4239913855,
- 3205692034,
- 753076457,
- 2877179298,
- 2068671395,
+ 2142255476,
+ 284366874,
+ 1270706260,
+ 748215919,
+ 3776340499,
+ 2561096438,
+ 2457298913,
+ 2960978234,
+ 3161273143,
+ 3930985837,
+ 1018819817,
+ 2074811740,
+ 3001526957,
+ 4071104153,
+ 2899558977,
+ 2789268373,
+ 2541058341,
+ 1634579503,
+ 997672564,
+ 2969112716,
+ 2447544998,
+ 1502588636,
+ 1988629125,
+ 2924861119,
+ 2138175500,
+ 2187714698,
+ 1601108451,
+ 228144794,
+ 2397079823,
+ 3312472734,
+ 2136600304,
+ 998965048,
+ 129266895,
+ 4206281394,
+ 1306643977,
+ 3223055380,
+ 1131453015,
+ 1087145342,
+ 259389477,
+ 315073875,
+ 112155829,
+ 841060857,
+ 3480083606,
+ 3550310828,
+ 1157550670,
+ 3157014039,
+ 2803451551,
+ 3492161659,
+ 296978924,
+ 3653454494,
+ 3228245663,
+ 2933207844,
+ 571656288,
+ 748970365,
+ 3674906033,
+ 659647310,
+ 2533357593,
+ 2934855029,
+ 11938227,
+ 2934294970,
+ 940307896,
+ 2899367891,
+ 1005948227,
];
static const List _envieddatasss_encryptionSalt = [
- 3363709964,
- 4271671334,
- 1265812036,
- 1283668823,
- 4162856636,
- 761049214,
- 1572031446,
- 4193649687,
- 1826833817,
- 3927730876,
- 3291753172,
- 2560155405,
- 2345185281,
- 1056977497,
- 698954432,
- 2553363563,
- 2947812039,
- 1283225454,
- 4289553804,
- 1542386665,
- 1827775086,
- 1077873243,
- 1858272678,
- 499846407,
- 701552736,
- 2360041483,
- 1152655676,
- 3490004559,
- 898560411,
- 1333751674,
- 4168446824,
- 3381376246,
- 1704048258,
- 284630941,
- 2153842118,
- 331530443,
- 3998206744,
- 2500954033,
- 4084135995,
- 4167242984,
- 208606612,
- 3900195322,
- 2793181341,
- 131568165,
- 1382602180,
- 3695432937,
- 818015210,
- 2083106873,
- 46646581,
- 2704955523,
- 99966683,
- 2095833964,
- 1835928644,
- 4112801487,
- 1337663956,
- 1986459728,
- 1312582175,
- 2401667717,
- 4239913741,
- 3205692122,
- 753076357,
- 2877179360,
- 2068671439,
+ 2142255374,
+ 284366973,
+ 1270706297,
+ 748215833,
+ 3776340600,
+ 2561096346,
+ 2457298824,
+ 2960978271,
+ 3161273114,
+ 3930985823,
+ 1018819717,
+ 2074811757,
+ 3001527031,
+ 4071104245,
+ 2899558961,
+ 2789268461,
+ 2541058380,
+ 1634579555,
+ 997672510,
+ 2969112762,
+ 2447545041,
+ 1502588557,
+ 1988629194,
+ 2924861129,
+ 2138175598,
+ 2187714792,
+ 1601108439,
+ 228144846,
+ 2397079905,
+ 3312472797,
+ 2136600265,
+ 998965088,
+ 129266877,
+ 4206281418,
+ 1306644078,
+ 3223055425,
+ 1131452946,
+ 1087145223,
+ 259389555,
+ 315073794,
+ 112155900,
+ 841060748,
+ 3480083616,
+ 3550310904,
+ 1157550599,
+ 3157014099,
+ 2803451563,
+ 3492161546,
+ 296978876,
+ 3653454506,
+ 3228245721,
+ 2933207921,
+ 571656245,
+ 748970252,
+ 3674906078,
+ 659647261,
+ 2533357612,
+ 2934854957,
+ 11938241,
+ 2934295010,
+ 940307924,
+ 2899367825,
+ 1005948207,
];
static final String sss_encryptionSalt = String.fromCharCodes(
@@ -298,73 +350,73 @@ final class _Env {
_envieddatasss_encryptionSalt[i] ^ _enviedkeysss_encryptionSalt[i]));
static const List _enviedkeysss_pass = [
- 2957388960,
- 1016568316,
- 4031218948,
- 3443559542,
- 2187924255,
- 2971503316,
- 1774974948,
- 3367538086,
- 1707922614,
- 4183558157,
- 2928123449,
- 1864070315,
- 1235324979,
- 3477070092,
- 2220030051,
- 235258417,
- 3712415255,
- 1505115718,
- 1498006653,
- 3503228559,
- 3072328486,
- 3341712304,
- 467164808,
- 2037769495,
- 2236257785,
- 3903148985,
- 754995296,
- 3924320121,
- 2099864066,
- 4025262266,
- 1235350657,
- 4240041822,
+ 2936667352,
+ 876206380,
+ 3186128085,
+ 3644475235,
+ 4171551389,
+ 3935055651,
+ 4185160202,
+ 3383043288,
+ 3512428989,
+ 273877880,
+ 2194175269,
+ 1682477365,
+ 3966359733,
+ 1028886641,
+ 3350459976,
+ 4292396371,
+ 3148371564,
+ 710615900,
+ 1115304974,
+ 2505747022,
+ 3041382642,
+ 2936086504,
+ 4085505205,
+ 108362252,
+ 2692491002,
+ 2152838152,
+ 3563449119,
+ 2874766139,
+ 555351262,
+ 3788871382,
+ 3226362165,
+ 1225811350,
];
static const List _envieddatasss_pass = [
- 2957389015,
- 1016568205,
- 4031219050,
- 3443559451,
- 2187924334,
- 2971503269,
- 1774974871,
- 3367538124,
- 1707922639,
- 4183558267,
- 2928123470,
- 1864070365,
- 1235324937,
- 3477070178,
- 2220029970,
- 235258435,
- 3712415354,
- 1505115679,
- 1498006583,
- 3503228639,
- 3072328550,
- 3341712257,
- 467164863,
- 2037769508,
- 2236257742,
- 3903148929,
- 754995256,
- 3924320011,
- 2099864154,
- 4025262294,
- 1235350723,
- 4240041778,
+ 2936667311,
+ 876206429,
+ 3186128059,
+ 3644475150,
+ 4171551468,
+ 3935055698,
+ 4185160313,
+ 3383043250,
+ 3512428996,
+ 273877774,
+ 2194175314,
+ 1682477379,
+ 3966359695,
+ 1028886559,
+ 3350459961,
+ 4292396321,
+ 3148371457,
+ 710615813,
+ 1115305028,
+ 2505746974,
+ 3041382578,
+ 2936086489,
+ 4085505154,
+ 108362303,
+ 2692490957,
+ 2152838192,
+ 3563449159,
+ 2874766153,
+ 555351174,
+ 3788871354,
+ 3226362231,
+ 1225811450,
];
static final String sss_pass = String.fromCharCodes(List.generate(
@@ -374,21 +426,21 @@ final class _Env {
).map((int i) => _envieddatasss_pass[i] ^ _enviedkeysss_pass[i]));
static const List _enviedkeyaddd = [
- 3802864355,
- 694127154,
- 2637747405,
- 3297266250,
- 1735467737,
- 547178785,
+ 856359347,
+ 522158964,
+ 1370037474,
+ 3606466936,
+ 960432668,
+ 1732434775,
];
static const List _envieddataaddd = [
- 3802864289,
- 694127198,
- 2637747343,
- 3297266214,
- 1735467671,
- 547178829,
+ 856359409,
+ 522158872,
+ 1370037408,
+ 3606466836,
+ 960432722,
+ 1732434747,
];
static final String addd = String.fromCharCodes(List.generate(
@@ -398,35 +450,35 @@ final class _Env {
).map((int i) => _envieddataaddd[i] ^ _enviedkeyaddd[i]));
static const List _enviedkeypassnpassenger = [
- 735262426,
- 1065404328,
- 2592209502,
- 1331943947,
- 3853096721,
- 1438384492,
- 3632062475,
- 3777234152,
- 2773181059,
- 2100082350,
- 241029789,
- 2804430832,
- 943434224,
+ 1792474850,
+ 1924104668,
+ 391311376,
+ 1647542146,
+ 668170995,
+ 988459319,
+ 1243891080,
+ 2395250797,
+ 2083894806,
+ 163003598,
+ 2320848855,
+ 3562560371,
+ 3133824981,
];
static const List _envieddatapassnpassenger = [
- 735262386,
- 1065404362,
- 2592209465,
- 1331944041,
- 3853096824,
- 1438384408,
- 3632062569,
- 3777234096,
- 2773181169,
- 2100082422,
- 241029871,
- 2804430770,
- 943434114,
+ 1792474762,
+ 1924104638,
+ 391311479,
+ 1647542240,
+ 668170906,
+ 988459331,
+ 1243891178,
+ 2395250741,
+ 2083894884,
+ 163003542,
+ 2320848805,
+ 3562560305,
+ 3133824935,
];
static final String passnpassenger = String.fromCharCodes(List.generate(
@@ -436,15 +488,15 @@ final class _Env {
).map((int i) => _envieddatapassnpassenger[i] ^ _enviedkeypassnpassenger[i]));
static const List _enviedkeynewId = [
- 1840427478,
- 1515241912,
- 727169366,
+ 3220512096,
+ 1148287903,
+ 4066941307,
];
static const List _envieddatanewId = [
- 1840427448,
- 1515241949,
- 727169313,
+ 3220512014,
+ 1148287994,
+ 4066941196,
];
static final String newId = String.fromCharCodes(List.generate(
@@ -454,31 +506,31 @@ final class _Env {
).map((int i) => _envieddatanewId[i] ^ _enviedkeynewId[i]));
static const List _enviedkeyallowed = [
- 3245922844,
- 3960293110,
- 2494038330,
- 3383672532,
- 2565644717,
- 633540861,
- 1073844359,
- 3761346352,
- 3217759142,
- 794258953,
- 587814512,
+ 1921270333,
+ 2061111604,
+ 3841100501,
+ 4129347794,
+ 1797614554,
+ 2186603037,
+ 2827436722,
+ 1539632237,
+ 3191692936,
+ 736776115,
+ 218392634,
];
static const List _envieddataallowed = [
- 3245922929,
- 3960293017,
- 2494038360,
- 3383672509,
- 2565644737,
- 633540760,
- 1073844394,
- 3761346385,
- 3217759190,
- 794259065,
- 587814474,
+ 1921270352,
+ 2061111643,
+ 3841100471,
+ 4129347771,
+ 1797614518,
+ 2186603128,
+ 2827436703,
+ 1539632140,
+ 3191693048,
+ 736776131,
+ 218392576,
];
static final String allowed = String.fromCharCodes(List.generate(
@@ -488,107 +540,107 @@ final class _Env {
).map((int i) => _envieddataallowed[i] ^ _enviedkeyallowed[i]));
static const List _enviedkeyapiKeyHere = [
- 2497256966,
- 2656782120,
- 2954632987,
- 1480445769,
- 2031217901,
- 2952958862,
- 645891282,
- 4176787568,
- 2720346953,
- 1022134612,
- 540296077,
- 1179899270,
- 68211885,
- 688928707,
- 864767937,
- 1652463025,
- 1422712854,
- 2353119962,
- 4283815969,
- 2188302898,
- 956858964,
- 2655359296,
- 304137545,
- 3887053185,
- 1170711390,
- 770074829,
- 2764237341,
- 1813058297,
- 2277735149,
- 151036681,
- 1454785905,
- 1157158939,
- 510843536,
- 1229132871,
- 1139320636,
- 1283343580,
- 2072923610,
- 3731187106,
- 1369691015,
- 52820701,
- 3058040268,
- 799434774,
- 3408763096,
- 389600260,
- 1956942181,
- 3371512899,
- 37659254,
- 743953669,
- 700307688,
+ 3817268896,
+ 4161775699,
+ 3301141030,
+ 1134146372,
+ 3857066077,
+ 2722898092,
+ 3934718659,
+ 3063587468,
+ 1822209404,
+ 4077554629,
+ 757295573,
+ 976327143,
+ 3144131708,
+ 3652349276,
+ 4136573864,
+ 1630918124,
+ 1883011707,
+ 2138798218,
+ 3463168398,
+ 2798516309,
+ 2130629731,
+ 2691517471,
+ 944278046,
+ 1837676307,
+ 3326908696,
+ 3172767852,
+ 2506241482,
+ 4072360526,
+ 2641044003,
+ 2624375478,
+ 1621395439,
+ 1757597560,
+ 2570551575,
+ 2303844382,
+ 1388240981,
+ 545560487,
+ 2022366108,
+ 4107939182,
+ 3708908872,
+ 2921895529,
+ 971259046,
+ 1041402734,
+ 1428626189,
+ 1025360981,
+ 2661920942,
+ 2598284823,
+ 4170160364,
+ 3394231170,
+ 108567072,
];
static const List _envieddataapiKeyHere = [
- 2497257057,
- 2656782199,
- 2954633036,
- 1480445703,
- 2031217848,
- 2952958956,
- 645891303,
- 4176787516,
- 2720346980,
- 1022134560,
- 540296191,
- 1179899375,
- 68211933,
- 688928697,
- 864767990,
- 1652463004,
- 1422712912,
- 2353119970,
- 4283816014,
- 2188302943,
- 956858908,
- 2655359280,
- 304137500,
- 3887053292,
- 1170711353,
- 770074756,
- 2764237415,
- 1813058225,
- 2277735130,
- 151036748,
- 1454785829,
- 1157159038,
- 510843608,
- 1229132926,
- 1139320644,
- 1283343494,
- 2072923618,
- 3731187184,
- 1369691120,
- 52820634,
- 3058040203,
- 799434799,
- 3408763015,
- 389600323,
- 1956942173,
- 3371512889,
- 37659182,
- 743953724,
- 700307625,
+ 3817268935,
+ 4161775628,
+ 3301141105,
+ 1134146314,
+ 3857065992,
+ 2722898126,
+ 3934718710,
+ 3063587520,
+ 1822209361,
+ 4077554609,
+ 757295527,
+ 976327054,
+ 3144131596,
+ 3652349222,
+ 4136573855,
+ 1630918081,
+ 1883011645,
+ 2138798258,
+ 3463168481,
+ 2798516280,
+ 2130629675,
+ 2691517551,
+ 944278091,
+ 1837676414,
+ 3326908799,
+ 3172767781,
+ 2506241456,
+ 4072360454,
+ 2641043988,
+ 2624375539,
+ 1621395387,
+ 1757597469,
+ 2570551647,
+ 2303844391,
+ 1388240941,
+ 545560573,
+ 2022366116,
+ 4107939132,
+ 3708908863,
+ 2921895470,
+ 971259105,
+ 1041402711,
+ 1428626258,
+ 1025360914,
+ 2661920918,
+ 2598284909,
+ 4170160308,
+ 3394231227,
+ 108567137,
];
static final String apiKeyHere = String.fromCharCodes(List.generate(
@@ -598,159 +650,159 @@ final class _Env {
).map((int i) => _envieddataapiKeyHere[i] ^ _enviedkeyapiKeyHere[i]));
static const List _enviedkeygetLocationAreaLinks = [
- 2988453148,
- 2427406755,
- 1366167126,
- 3982814353,
- 1564633143,
- 3641240814,
- 1007919736,
- 3681940381,
- 1220962261,
- 3358260054,
- 3925413382,
- 3554111612,
- 1572983115,
- 1753439515,
- 681883205,
- 3362728642,
- 2943311915,
- 1919392411,
- 2331593584,
- 3479475485,
- 3433683882,
- 4233658646,
- 4251689545,
- 686782064,
- 991537699,
- 3065403344,
- 4183052841,
- 1331978172,
- 2497444547,
- 4134340357,
- 1589859267,
- 1612562513,
- 417229842,
- 348492015,
- 1228022136,
- 2938089358,
- 1062314894,
- 2386688534,
- 1460800261,
- 3486570222,
- 2025986404,
- 2877703752,
- 1594211637,
- 89922563,
- 702876642,
- 4195064730,
- 1564366935,
- 2736689991,
- 3769208807,
- 3501429881,
- 2464905282,
- 2741498107,
- 1394551862,
- 1880674917,
- 263113450,
- 2778976267,
- 619190408,
- 1184445795,
- 1477467582,
- 485455791,
- 386751047,
- 4105952945,
- 3145334149,
- 2133229612,
- 2508559635,
- 1272931009,
- 2059251576,
- 181250125,
- 3050152587,
- 3821717176,
- 527371541,
- 4224031242,
- 2339418020,
- 3117132197,
- 343452524,
+ 3404126900,
+ 3635509459,
+ 2760068551,
+ 1135026344,
+ 361014727,
+ 2319372031,
+ 2714864201,
+ 3531563054,
+ 1810411494,
+ 3495896604,
+ 3923131927,
+ 3463236857,
+ 4273060280,
+ 3250330773,
+ 3596924584,
+ 2134775821,
+ 760926808,
+ 73878508,
+ 1821638353,
+ 582171256,
+ 3456259047,
+ 842584153,
+ 4259212386,
+ 3452581713,
+ 596600050,
+ 898075563,
+ 2734934163,
+ 626507477,
+ 2488240861,
+ 1729100675,
+ 2304482244,
+ 2116746605,
+ 2229198287,
+ 4054662819,
+ 919217506,
+ 3217274338,
+ 87409090,
+ 3028410396,
+ 2357937549,
+ 2039888758,
+ 918643754,
+ 676818405,
+ 2278470455,
+ 762101466,
+ 703159238,
+ 4078132155,
+ 2102302303,
+ 1758233505,
+ 327406267,
+ 2205087070,
+ 3204855632,
+ 3474242571,
+ 576463225,
+ 2529772108,
+ 1816139063,
+ 186395551,
+ 170455642,
+ 873083301,
+ 406004334,
+ 1746650876,
+ 3404571507,
+ 3278932612,
+ 2364323337,
+ 1029539922,
+ 391278705,
+ 943403502,
+ 341044865,
+ 1925641005,
+ 708085454,
+ 878870981,
+ 406709643,
+ 1348206451,
+ 2204128571,
+ 1007920868,
+ 4073079278,
];
static const List _envieddatagetLocationAreaLinks = [
- 2988453236,
- 2427406807,
- 1366167074,
- 3982814433,
- 1564633156,
- 3641240788,
- 1007919703,
- 3681940402,
- 1220962228,
- 3358260006,
- 3925413487,
- 3554111570,
- 1572983103,
- 1753439593,
- 681883180,
- 3362728626,
- 2943311953,
- 1919392438,
- 2331593493,
- 3479475578,
- 3433683923,
- 4233658726,
- 4251689533,
- 686782046,
- 991537728,
- 3065403327,
- 4183052868,
- 1331978131,
- 2497444535,
- 4134340471,
- 1589859242,
- 1612562465,
- 417229928,
- 348491968,
- 1228022026,
- 2938089447,
- 1062314986,
- 2386688627,
- 1460800298,
- 3486570114,
- 2025986315,
- 2877703723,
- 1594211668,
- 89922679,
- 702876555,
- 4195064821,
- 1564366905,
- 2736690024,
- 3769208704,
- 3501429788,
- 2464905270,
- 2741498020,
- 1394551898,
- 1880674826,
- 263113353,
- 2778976362,
- 619190524,
- 1184445706,
- 1477467601,
- 485455809,
- 386751000,
- 4105952976,
- 3145334263,
- 2133229641,
- 2508559730,
- 1272930974,
- 2059251476,
- 181250084,
- 3050152677,
- 3821717203,
- 527371622,
- 4224031268,
- 2339418068,
- 3117132237,
- 343452444,
+ 3404126940,
+ 3635509415,
+ 2760068531,
+ 1135026392,
+ 361014708,
+ 2319371973,
+ 2714864230,
+ 3531563009,
+ 1810411399,
+ 3495896684,
+ 3923132030,
+ 3463236823,
+ 4273060300,
+ 3250330855,
+ 3596924609,
+ 2134775933,
+ 760926754,
+ 73878465,
+ 1821638324,
+ 582171167,
+ 3456258974,
+ 842584105,
+ 4259212310,
+ 3452581759,
+ 596599953,
+ 898075588,
+ 2734934270,
+ 626507514,
+ 2488240809,
+ 1729100785,
+ 2304482221,
+ 2116746525,
+ 2229198261,
+ 4054662796,
+ 919217424,
+ 3217274251,
+ 87409062,
+ 3028410489,
+ 2357937570,
+ 2039888666,
+ 918643781,
+ 676818310,
+ 2278470486,
+ 762101422,
+ 703159215,
+ 4078132180,
+ 2102302257,
+ 1758233486,
+ 327406300,
+ 2205087035,
+ 3204855588,
+ 3474242644,
+ 576463125,
+ 2529772067,
+ 1816139092,
+ 186395646,
+ 170455598,
+ 873083340,
+ 406004225,
+ 1746650770,
+ 3404571436,
+ 3278932709,
+ 2364323451,
+ 1029539895,
+ 391278608,
+ 943403441,
+ 341044973,
+ 1925641028,
+ 708085408,
+ 878870958,
+ 406709752,
+ 1348206429,
+ 2204128587,
+ 1007920780,
+ 4073079198,
];
static final String getLocationAreaLinks = String.fromCharCodes(
@@ -763,53 +815,53 @@ final class _Env {
_enviedkeygetLocationAreaLinks[i]));
static const List _enviedkeyinitializationVector = [
- 2749286500,
- 653011017,
- 3823850079,
- 2819999775,
- 1828554081,
- 1417689459,
- 2041538623,
- 4027765927,
- 2690507925,
- 259394592,
- 1388767888,
- 4160915698,
- 3456260235,
- 1870239472,
- 1244522141,
- 3402656970,
- 3451631790,
- 1672669364,
- 1333095329,
- 3397434145,
- 3170698581,
- 886305628,
+ 2201295168,
+ 2446211413,
+ 1881952212,
+ 2993956456,
+ 972975111,
+ 3151220221,
+ 1530369156,
+ 2788019061,
+ 326364544,
+ 3044280583,
+ 983993733,
+ 1260359253,
+ 3722860874,
+ 3461661086,
+ 667702118,
+ 2522204854,
+ 3330797164,
+ 3115156146,
+ 3573155996,
+ 2827515416,
+ 2004019848,
+ 428764783,
];
static const List _envieddatainitializationVector = [
- 2749286421,
- 653010993,
- 3823850041,
- 2819999846,
- 1828553995,
- 1417689350,
- 2041538644,
- 4027765968,
- 2690508026,
- 259394629,
- 1388767991,
- 4160915584,
- 3456260325,
- 1870239378,
- 1244522228,
- 3402656956,
- 3451631862,
- 1672669382,
- 1333095417,
- 3397434195,
- 3170698519,
- 886305582,
+ 2201295153,
+ 2446211373,
+ 1881952178,
+ 2993956369,
+ 972975213,
+ 3151220104,
+ 1530369263,
+ 2788018946,
+ 326364655,
+ 3044280674,
+ 983993826,
+ 1260359207,
+ 3722860836,
+ 3461661180,
+ 667702031,
+ 2522204864,
+ 3330797108,
+ 3115156160,
+ 3573156036,
+ 2827515498,
+ 2004019914,
+ 428764701,
];
static final String initializationVector = String.fromCharCodes(
@@ -822,129 +874,129 @@ final class _Env {
_enviedkeyinitializationVector[i]));
static const List _enviedkeybasicCompareFacesURL = [
- 3973357826,
- 3400198887,
- 1985631089,
- 449323848,
- 2450512581,
- 2954390111,
- 772002673,
- 1275342913,
- 3409575041,
- 2693850305,
- 1906547295,
- 2121046676,
- 3828437909,
- 292288749,
- 182293311,
- 2911142470,
- 895482220,
- 1085090462,
- 3682883958,
- 3937131252,
- 2270937189,
- 1896177220,
- 3005596072,
- 3786810795,
- 897648963,
- 2010438215,
- 2008207525,
- 4189171810,
- 571207742,
- 2706353813,
- 4111807772,
- 3398991102,
- 2640382327,
- 3461238840,
- 2837856734,
- 1097237133,
- 271369583,
- 2291505016,
- 885623071,
- 1390450226,
- 1279809183,
- 2867177619,
- 3044088392,
- 2714439012,
- 1260508590,
- 2151000133,
- 782957065,
- 427958147,
- 286478089,
- 1660724572,
- 3444945325,
- 2047686065,
- 133130603,
- 3706437223,
- 4278524698,
- 3687107300,
- 3186266519,
- 2298471765,
- 2265388252,
- 672076337,
+ 1330600922,
+ 2887722883,
+ 2311059944,
+ 1416268531,
+ 3823483437,
+ 1178246148,
+ 2679379553,
+ 3811548580,
+ 1911437534,
+ 697424122,
+ 3139472572,
+ 2497341502,
+ 2812690971,
+ 2271326259,
+ 1920762681,
+ 2993486050,
+ 1687020017,
+ 3048008054,
+ 2830274653,
+ 62070531,
+ 1614942967,
+ 3087909243,
+ 3525994045,
+ 1276239452,
+ 748595692,
+ 32173991,
+ 1537813415,
+ 503865261,
+ 1130536453,
+ 48682119,
+ 1829158149,
+ 297207651,
+ 2478383607,
+ 2655797692,
+ 450448992,
+ 1384807967,
+ 1659905640,
+ 475498785,
+ 3310131022,
+ 1000386431,
+ 1876247973,
+ 1266592207,
+ 2214694242,
+ 3501035720,
+ 2217940831,
+ 4007139879,
+ 635569862,
+ 2304126238,
+ 1402568687,
+ 3524149872,
+ 3624292399,
+ 930448730,
+ 4143781031,
+ 3937919167,
+ 577897467,
+ 18660539,
+ 792610170,
+ 442906291,
+ 2690221051,
+ 2753670074,
];
static const List _envieddatabasicCompareFacesURL = [
- 3973357930,
- 3400198803,
- 1985630981,
- 449323832,
- 2450512566,
- 2954390117,
- 772002654,
- 1275342958,
- 3409575143,
- 2693850272,
- 1906547260,
- 2121046769,
- 3828437944,
- 292288649,
- 182293338,
- 2911142450,
- 895482121,
- 1085090557,
- 3682883842,
- 3937131225,
- 2270937091,
- 1896177266,
- 3005596049,
- 3786810777,
- 897649015,
- 2010438260,
- 2008207516,
- 4189171792,
- 571207773,
- 2706353825,
- 4111807871,
- 3398991049,
- 2640382297,
- 3461238864,
- 2837856699,
- 1097237247,
- 271369472,
- 2291504915,
- 885623146,
- 1390450259,
- 1279809263,
- 2867177699,
- 3044088422,
- 2714438919,
- 1260508609,
- 2151000104,
- 782957094,
- 427958240,
- 286478182,
- 1660724529,
- 3444945373,
- 2047686096,
- 133130521,
- 3706437122,
- 4278524741,
- 3687107202,
- 3186266614,
- 2298471734,
- 2265388217,
- 672076354,
+ 1330600882,
+ 2887722999,
+ 2311059868,
+ 1416268419,
+ 3823483486,
+ 1178246206,
+ 2679379534,
+ 3811548555,
+ 1911437496,
+ 697424027,
+ 3139472607,
+ 2497341531,
+ 2812690998,
+ 2271326295,
+ 1920762716,
+ 2993485974,
+ 1687019924,
+ 3048007957,
+ 2830274601,
+ 62070574,
+ 1614942865,
+ 3087909197,
+ 3525993988,
+ 1276239470,
+ 748595672,
+ 32173972,
+ 1537813406,
+ 503865247,
+ 1130536550,
+ 48682163,
+ 1829158246,
+ 297207636,
+ 2478383577,
+ 2655797716,
+ 450448901,
+ 1384808045,
+ 1659905543,
+ 475498826,
+ 3310131003,
+ 1000386334,
+ 1876248021,
+ 1266592191,
+ 2214694220,
+ 3501035691,
+ 2217940784,
+ 4007139914,
+ 635569897,
+ 2304126333,
+ 1402568576,
+ 3524149789,
+ 3624292447,
+ 930448699,
+ 4143781077,
+ 3937919194,
+ 577897380,
+ 18660573,
+ 792610075,
+ 442906320,
+ 2690220958,
+ 2753670089,
];
static final String basicCompareFacesURL = String.fromCharCodes(
@@ -957,91 +1009,91 @@ final class _Env {
_enviedkeybasicCompareFacesURL[i]));
static const List _enviedkeyaccountSIDTwillo = [
- 862883526,
- 2506887672,
- 493950747,
- 884738397,
- 4093901780,
- 3055722528,
- 1985935270,
- 3249999780,
- 1595427159,
- 2189070063,
- 1170800771,
- 409183994,
- 1101502682,
- 3046523219,
- 1554121562,
- 1059275136,
- 1654115409,
- 1193768856,
- 1440036812,
- 2426275277,
- 3185807929,
- 1139172162,
- 4266152669,
- 1901245621,
- 1031726709,
- 526581723,
- 417278390,
- 2785846020,
- 587347324,
- 2240635656,
- 2339279274,
- 2087305137,
- 3725764621,
- 720696096,
- 2518537674,
- 3736050,
- 2055925477,
- 4222223098,
- 37289279,
- 3489115850,
- 2024307616,
+ 2843783092,
+ 1674419346,
+ 3803422258,
+ 132889725,
+ 1586455900,
+ 3294810875,
+ 2713641844,
+ 719237140,
+ 2160285213,
+ 3355031642,
+ 1044812735,
+ 465231708,
+ 2773128885,
+ 2458872187,
+ 1257532603,
+ 2310638280,
+ 311739674,
+ 4045327999,
+ 3499891219,
+ 628184479,
+ 4039907483,
+ 2533330186,
+ 1341177550,
+ 1025907715,
+ 509633930,
+ 1553205648,
+ 1248145143,
+ 3082345651,
+ 2221820334,
+ 3094338270,
+ 624605643,
+ 2263308676,
+ 3691275035,
+ 383131392,
+ 2080149801,
+ 794174709,
+ 2136872233,
+ 468082603,
+ 3193516271,
+ 3874655752,
+ 284351138,
];
static const List _envieddataaccountSIDTwillo = [
- 862883479,
- 2506887614,
- 493950819,
- 884738413,
- 4093901733,
- 3055722585,
- 1985935250,
- 3249999761,
- 1595427169,
- 2189069957,
- 1170800886,
- 409183888,
- 1101502697,
- 3046523243,
- 1554121577,
- 1059275246,
- 1654115432,
- 1193768928,
- 1440036793,
- 2426275252,
- 3185807883,
- 1139172211,
- 4266152676,
- 1901245569,
- 1031726596,
- 526581741,
- 417278340,
- 2785846077,
- 587347213,
- 2240635705,
- 2339279308,
- 2087305179,
- 3725764669,
- 720696153,
- 2518537725,
- 3735978,
- 2055925399,
- 4222223010,
- 37289299,
- 3489115784,
- 2024307660,
+ 2843783141,
+ 1674419412,
+ 3803422282,
+ 132889677,
+ 1586455853,
+ 3294810754,
+ 2713641792,
+ 719237153,
+ 2160285227,
+ 3355031600,
+ 1044812746,
+ 465231670,
+ 2773128838,
+ 2458872131,
+ 1257532552,
+ 2310638246,
+ 311739683,
+ 4045327879,
+ 3499891302,
+ 628184550,
+ 4039907497,
+ 2533330235,
+ 1341177591,
+ 1025907767,
+ 509634043,
+ 1553205670,
+ 1248145093,
+ 3082345610,
+ 2221820383,
+ 3094338287,
+ 624605613,
+ 2263308782,
+ 3691275051,
+ 383131513,
+ 2080149790,
+ 794174637,
+ 2136872283,
+ 468082675,
+ 3193516163,
+ 3874655818,
+ 284351182,
];
static final String accountSIDTwillo = String.fromCharCodes(
@@ -1053,325 +1105,325 @@ final class _Env {
_envieddataaccountSIDTwillo[i] ^ _enviedkeyaccountSIDTwillo[i]));
static const List _enviedkeyserverAPI = [
- 2656647173,
- 3738555971,
- 281108270,
- 4209723979,
- 3567021072,
- 225360194,
- 874230964,
- 324448041,
- 4273370024,
- 3171290864,
- 3765819248,
- 662724599,
- 2047066182,
- 3619519493,
- 2897286852,
- 3047694147,
- 790659686,
- 3515074197,
- 375327146,
- 3529926859,
- 2573542243,
- 4228737078,
- 2913594502,
- 1383997884,
- 4292492298,
- 4229937260,
- 3722853826,
- 399391593,
- 2098092523,
- 2507927804,
- 4182713389,
- 4136321482,
- 4031642392,
- 2906398568,
- 3039433485,
- 1486469364,
- 3287927332,
- 4051855707,
- 874928375,
- 1533236064,
- 2824180974,
- 4042253442,
- 4239930079,
- 3443675196,
- 3564716468,
- 2704577044,
- 1407020766,
- 312475642,
- 2940173961,
- 461690708,
- 4218258654,
- 1405581974,
- 807774814,
- 463555677,
- 2318036706,
- 748138614,
- 800580694,
- 446356513,
- 2242146812,
- 3132748825,
- 2324944470,
- 2382836717,
- 2471074835,
- 709103031,
- 2588627834,
- 2571233829,
- 4257930202,
- 880614792,
- 2534172517,
- 646656926,
- 807045942,
- 3223547540,
- 637703075,
- 1161587113,
- 1694926235,
- 1130740693,
- 2040003736,
- 3957767449,
- 4089869355,
- 3570713510,
- 14130367,
- 1219576427,
- 4201913743,
- 3699569853,
- 3757563907,
- 2804661805,
- 2691763876,
- 608324039,
- 549520705,
- 3637140130,
- 1657339636,
- 3671506957,
- 2075237918,
- 1542357058,
- 2069518540,
- 2531153218,
- 3715703881,
- 3990467227,
- 1608006243,
- 1174025013,
- 69564333,
- 661473778,
- 1070512231,
- 3865136733,
- 2115837623,
- 648310106,
- 335258452,
- 1021565787,
- 3703954938,
- 3375890797,
- 4224311122,
- 2559482853,
- 2713989796,
- 3392185994,
- 1571061530,
- 2723313727,
- 1224456781,
- 1568446486,
- 3259926001,
- 360597493,
- 1929460937,
- 3726881885,
- 246635299,
- 1295436405,
- 4117808221,
- 2081777050,
- 1862431732,
- 2724794958,
- 2157849827,
- 1478656727,
- 2788113587,
- 3645565086,
- 2252213239,
- 1228971111,
- 2723608337,
- 1859167267,
- 2665722216,
- 883112983,
- 2670082788,
- 313566081,
- 1766825866,
- 1040972825,
- 1061049477,
- 3364769065,
- 2283071929,
- 3916915195,
- 3165275472,
- 4175844886,
- 3353368993,
- 1446547397,
- 3161796460,
- 2394438245,
- 3575040228,
- 3064925708,
- 845257575,
- 2932532219,
- 2414616306,
- 3520694036,
+ 3976340862,
+ 876930661,
+ 2754762348,
+ 2464537893,
+ 3707602655,
+ 2489749710,
+ 3424437440,
+ 1372632324,
+ 2975339402,
+ 2676738093,
+ 3221041012,
+ 744897494,
+ 1424458647,
+ 1079081365,
+ 3562411819,
+ 4004226372,
+ 2704808793,
+ 1168829629,
+ 1992531918,
+ 3180887892,
+ 1772554705,
+ 4274017960,
+ 263526825,
+ 1684978867,
+ 3658977582,
+ 2764849002,
+ 2435386837,
+ 2434610909,
+ 1238171864,
+ 3938577549,
+ 3000351850,
+ 1398183753,
+ 75887018,
+ 774832896,
+ 1523285360,
+ 309110719,
+ 858312180,
+ 2818584421,
+ 3270452275,
+ 983656457,
+ 1664075801,
+ 2926896384,
+ 769664241,
+ 1537228947,
+ 2075245662,
+ 3146684998,
+ 2628184795,
+ 1239022201,
+ 654943327,
+ 1715476740,
+ 1718664042,
+ 2638834984,
+ 4184911395,
+ 489667049,
+ 1830225181,
+ 2640753699,
+ 4200140839,
+ 201082292,
+ 701445777,
+ 3501131445,
+ 1086182735,
+ 2058515131,
+ 4059527038,
+ 950334178,
+ 587472557,
+ 1704249165,
+ 922220226,
+ 1556517143,
+ 1406823262,
+ 2446727386,
+ 2079624285,
+ 37938373,
+ 1344228475,
+ 3910369000,
+ 1492984777,
+ 1437083473,
+ 2842770769,
+ 2576354000,
+ 1864807939,
+ 2895209442,
+ 2917935409,
+ 567043849,
+ 576658584,
+ 4104668683,
+ 289522001,
+ 3394727170,
+ 3201674837,
+ 1290177783,
+ 3115294296,
+ 4259693824,
+ 3129141406,
+ 325281440,
+ 530300610,
+ 415806151,
+ 187464629,
+ 530694302,
+ 2938142458,
+ 1021781952,
+ 291246485,
+ 3228999424,
+ 3831388593,
+ 2533438819,
+ 2895384640,
+ 3081205453,
+ 2373368017,
+ 2532170150,
+ 3060366470,
+ 4244026566,
+ 1554490727,
+ 3410670928,
+ 960347257,
+ 3614687388,
+ 3705063013,
+ 198619704,
+ 705028789,
+ 3504828489,
+ 1242117333,
+ 774908927,
+ 3721749151,
+ 4098061798,
+ 942891585,
+ 3861283949,
+ 111830844,
+ 3658249279,
+ 446418689,
+ 869497804,
+ 1866712611,
+ 1426830386,
+ 2940675768,
+ 3528266654,
+ 331680518,
+ 3378186940,
+ 1334652234,
+ 596949604,
+ 1854281103,
+ 2800667846,
+ 476777023,
+ 3236423334,
+ 2603128686,
+ 503959906,
+ 3681931758,
+ 2093974656,
+ 2704910478,
+ 2439513144,
+ 3257918460,
+ 2319599066,
+ 1093709546,
+ 3895079102,
+ 2569178988,
+ 3737864579,
+ 839085567,
+ 273990226,
+ 2247636415,
+ 1654429663,
+ 3419379873,
+ 3959242870,
+ 3890025019,
+ 3201343901,
];
static const List _envieddataserverAPI = [
- 2656647252,
- 3738555922,
- 281108351,
- 4209723930,
- 3567021183,
- 225360160,
- 874231015,
- 324448091,
- 4273370074,
- 3171290806,
- 3765819161,
- 662724557,
- 2047066135,
- 3619519571,
- 2897286805,
- 3047694203,
- 790659665,
- 3515074285,
- 375327231,
- 3529926908,
- 2573542169,
- 4228737089,
- 2913594565,
- 1383997898,
- 4292492391,
- 4229937206,
- 3722853816,
- 399391539,
- 2098092431,
- 2507927709,
- 4182713429,
- 4136321471,
- 4031642443,
- 2906398554,
- 3039433579,
- 1486469318,
- 3287927319,
- 4051855618,
- 874928323,
- 1533235981,
- 2824180884,
- 4042253493,
- 4239930002,
- 3443675206,
- 3564716493,
- 2704577115,
- 1407020708,
- 312475528,
- 2940174001,
- 461690683,
- 4218258618,
- 1405581988,
- 807774780,
- 463555631,
- 2318036692,
- 748138557,
- 800580623,
- 446356568,
- 2242146713,
- 3132748895,
- 2324944439,
- 2382836665,
- 2471074885,
- 709103099,
- 2588627773,
- 2571233814,
- 4257930129,
- 880614843,
- 2534172429,
- 646656998,
- 807045891,
- 3223547598,
- 637703106,
- 1161587196,
- 1694926306,
- 1130740653,
- 2040003759,
- 3957767548,
- 4089869426,
- 3570713552,
- 14130430,
- 1219576370,
- 4201913855,
- 3699569916,
- 3757563989,
- 2804661833,
- 2691763951,
- 608324012,
- 549520748,
- 3637140112,
- 1657339596,
- 3671507003,
- 2075237968,
- 1542357014,
- 2069518494,
- 2531153195,
- 3715703930,
- 3990467297,
- 1608006160,
- 1174024972,
- 69564356,
- 661473697,
- 1070512168,
- 3865136691,
- 2115837679,
- 648310062,
- 335258380,
- 1021565705,
- 3703954867,
- 3375890709,
- 4224311073,
- 2559482770,
- 2713989827,
- 3392186041,
- 1571061585,
- 2723313754,
- 1224456750,
- 1568446548,
- 3259925916,
- 360597382,
- 1929460901,
- 3726881902,
- 246635381,
- 1295436301,
- 4117808151,
- 2081777059,
- 1862431619,
- 2724794881,
- 2157849806,
- 1478656673,
- 2788113658,
- 3645565166,
- 2252213120,
- 1228971026,
- 2723608357,
- 1859167347,
- 2665722142,
- 883112992,
- 2670082688,
- 313566186,
- 1766825922,
- 1040972914,
- 1061049565,
- 3364769095,
- 2283071952,
- 3916915086,
- 3165275432,
- 4175844955,
- 3353369074,
- 1446547329,
- 3161796363,
- 2394438194,
- 3575040188,
- 3064925822,
- 845257535,
- 2932532119,
- 2414616240,
- 3520694136,
+ 3976340783,
+ 876930612,
+ 2754762301,
+ 2464537972,
+ 3707602608,
+ 2489749676,
+ 3424437395,
+ 1372632438,
+ 2975339512,
+ 2676738155,
+ 3221040925,
+ 744897516,
+ 1424458694,
+ 1079081411,
+ 3562411898,
+ 4004226428,
+ 2704808814,
+ 1168829637,
+ 1992531867,
+ 3180887907,
+ 1772554667,
+ 4274018015,
+ 263526890,
+ 1684978885,
+ 3658977603,
+ 2764848944,
+ 2435386799,
+ 2434610823,
+ 1238171836,
+ 3938577644,
+ 3000351762,
+ 1398183740,
+ 75887097,
+ 774832946,
+ 1523285270,
+ 309110669,
+ 858312135,
+ 2818584380,
+ 3270452231,
+ 983656548,
+ 1664075875,
+ 2926896439,
+ 769664188,
+ 1537229033,
+ 2075245607,
+ 3146684937,
+ 2628184737,
+ 1239022091,
+ 654943335,
+ 1715476843,
+ 1718663950,
+ 2638834970,
+ 4184911425,
+ 489666971,
+ 1830225195,
+ 2640753768,
+ 4200140926,
+ 201082317,
+ 701445876,
+ 3501131507,
+ 1086182702,
+ 2058515183,
+ 4059526952,
+ 950334126,
+ 587472618,
+ 1704249214,
+ 922220169,
+ 1556517156,
+ 1406823222,
+ 2446727330,
+ 2079624296,
+ 37938335,
+ 1344228378,
+ 3910368957,
+ 1492984752,
+ 1437083433,
+ 2842770790,
+ 2576353973,
+ 1864808026,
+ 2895209364,
+ 2917935472,
+ 567043920,
+ 576658664,
+ 4104668746,
+ 289521927,
+ 3394727270,
+ 3201674782,
+ 1290177692,
+ 3115294325,
+ 4259693874,
+ 3129141414,
+ 325281430,
+ 530300556,
+ 415806099,
+ 187464679,
+ 530694391,
+ 2938142409,
+ 1021781946,
+ 291246566,
+ 3228999481,
+ 3831388632,
+ 2533438768,
+ 2895384591,
+ 3081205411,
+ 2373367945,
+ 2532170194,
+ 3060366558,
+ 4244026516,
+ 1554490670,
+ 3410670888,
+ 960347146,
+ 3614687467,
+ 3705062914,
+ 198619659,
+ 705028862,
+ 3504828460,
+ 1242117302,
+ 774908861,
+ 3721749234,
+ 4098061717,
+ 942891565,
+ 3861283934,
+ 111830890,
+ 3658249287,
+ 446418763,
+ 869497845,
+ 1866712660,
+ 1426830461,
+ 2940675733,
+ 3528266728,
+ 331680591,
+ 3378186956,
+ 1334652221,
+ 596949521,
+ 1854281147,
+ 2800667798,
+ 476777033,
+ 3236423313,
+ 2603128586,
+ 503959817,
+ 3681931686,
+ 2093974763,
+ 2704910550,
+ 2439513174,
+ 3257918357,
+ 2319599023,
+ 1093709458,
+ 3895079155,
+ 2569178943,
+ 3737864647,
+ 839085464,
+ 273990149,
+ 2247636455,
+ 1654429613,
+ 3419379961,
+ 3959242778,
+ 3890025081,
+ 3201343985,
];
static final String serverAPI = String.fromCharCodes(List.generate(
@@ -1381,87 +1433,87 @@ final class _Env {
).map((int i) => _envieddataserverAPI[i] ^ _enviedkeyserverAPI[i]));
static const List _enviedkeymapAPIKEY = [
- 3780650790,
- 1261206206,
- 3582205783,
- 970938258,
- 1442725955,
- 2770555723,
- 1628950528,
- 982096424,
- 968348506,
- 689305316,
- 2208399948,
- 4025436180,
- 1752391980,
- 1211534907,
- 1702474257,
- 3952957510,
- 881139483,
- 2801348158,
- 2349501027,
- 3888249220,
- 95826764,
- 932877792,
- 341649545,
- 2915100818,
- 2442586933,
- 937444368,
- 661481258,
- 2388784846,
- 3646082583,
- 2359603322,
- 1469672324,
- 424347918,
- 1593811254,
- 836201946,
- 1783687237,
- 476826234,
- 4268923061,
- 4222039827,
- 2938372691,
+ 2247714160,
+ 2560268629,
+ 60973890,
+ 4238015695,
+ 3486272014,
+ 4139058870,
+ 3284541187,
+ 1937795265,
+ 4268641415,
+ 3452889939,
+ 3658126130,
+ 253733115,
+ 3331289064,
+ 2627639475,
+ 4246775286,
+ 878786301,
+ 3804413434,
+ 2745587036,
+ 1763947689,
+ 295551841,
+ 2115785072,
+ 88958942,
+ 1115480111,
+ 3276376593,
+ 4136534122,
+ 1162804378,
+ 14284426,
+ 17535057,
+ 2319425705,
+ 1953711881,
+ 3792644850,
+ 1255190121,
+ 514431811,
+ 3899457619,
+ 2021344858,
+ 1913226202,
+ 3546162315,
+ 698376319,
+ 2354027959,
];
static const List _envieddatamapAPIKEY = [
- 3780650855,
- 1261206263,
- 3582205741,
- 970938355,
- 1442725904,
- 2770555698,
- 1628950593,
- 982096504,
- 968348444,
- 689305270,
- 2208399891,
- 4025436236,
- 1752392014,
- 1211534953,
- 1702474335,
- 3952957558,
- 881139523,
- 2801348196,
- 2349501014,
- 3888249293,
- 95826742,
- 932877779,
- 341649608,
- 2915100875,
- 2442586993,
- 937444474,
- 661481316,
- 2388784791,
- 3646082655,
- 2359603261,
- 1469672398,
- 424347977,
- 1593811204,
- 836201897,
- 1783687287,
- 476826155,
- 4268923106,
- 4222039908,
- 2938372638,
+ 2247714097,
+ 2560268572,
+ 60973880,
+ 4238015662,
+ 3486272093,
+ 4139058895,
+ 3284541250,
+ 1937795217,
+ 4268641473,
+ 3452889857,
+ 3658126189,
+ 253733027,
+ 3331288970,
+ 2627639521,
+ 4246775224,
+ 878786253,
+ 3804413346,
+ 2745586950,
+ 1763947676,
+ 295551784,
+ 2115784970,
+ 88958957,
+ 1115480174,
+ 3276376648,
+ 4136534062,
+ 1162804464,
+ 14284484,
+ 17534984,
+ 2319425761,
+ 1953711950,
+ 3792644792,
+ 1255190062,
+ 514431857,
+ 3899457568,
+ 2021344872,
+ 1913226123,
+ 3546162396,
+ 698376200,
+ 2354028026,
];
static final String mapAPIKEY = String.fromCharCodes(List.generate(
@@ -1471,87 +1523,87 @@ final class _Env {
).map((int i) => _envieddatamapAPIKEY[i] ^ _enviedkeymapAPIKEY[i]));
static const List _enviedkeymapAPIKEYIOS = [
- 3558174711,
- 1259904136,
- 726466956,
- 1207571,
- 371587597,
- 1439381955,
- 1288967613,
- 403535858,
- 2033538595,
- 3229798007,
- 1556181043,
- 4256166143,
- 580211841,
- 4069263894,
- 4260167336,
- 2217180963,
- 1433884945,
- 3562866388,
- 4013472303,
- 1563614508,
- 3243019766,
- 2861043552,
- 3591305057,
- 967952859,
- 2224222952,
- 3330350152,
- 1623144648,
- 3466748051,
- 4002234704,
- 1043529504,
- 3166071709,
- 65434727,
- 2697161795,
- 1158757060,
- 2532362030,
- 3449892849,
- 3651832823,
- 2612912611,
- 3303365501,
+ 3242026595,
+ 226759590,
+ 3513945943,
+ 1675836857,
+ 2070623184,
+ 1212962385,
+ 2949685960,
+ 2314727532,
+ 4229834780,
+ 2675409629,
+ 4268245054,
+ 2647028317,
+ 1980982459,
+ 2590627602,
+ 4006411907,
+ 740712139,
+ 2498147417,
+ 130942695,
+ 3681207417,
+ 3402766120,
+ 3536327117,
+ 3770297355,
+ 2085970437,
+ 566701769,
+ 4055782816,
+ 1608102648,
+ 3393804425,
+ 2100732790,
+ 3315765567,
+ 1614848706,
+ 1829636998,
+ 2806101795,
+ 3386515473,
+ 2410019939,
+ 3104463353,
+ 924278124,
+ 6962405,
+ 2844298305,
+ 701510329,
];
static const List _envieddatamapAPIKEYIOS = [
- 3558174646,
- 1259904193,
- 726467062,
- 1207666,
- 371587678,
- 1439381946,
- 1288967673,
- 403535766,
- 2033538642,
- 3229797916,
- 1556181119,
- 4256166066,
- 580211906,
- 4069263972,
- 4260167385,
- 2217181001,
- 1433884999,
- 3562866342,
- 4013472321,
- 1563614491,
- 3243019694,
- 2861043469,
- 3591304960,
- 967952831,
- 2224222881,
- 3330350137,
- 1623144625,
- 3466748157,
- 4002234665,
- 1043529551,
- 3166071775,
- 65434630,
- 2697161844,
- 1158757012,
- 2532362012,
- 3449892806,
- 3651832760,
- 2612912518,
- 3303365424,
+ 3242026530,
+ 226759663,
+ 3513945901,
+ 1675836888,
+ 2070623107,
+ 1212962344,
+ 2949685900,
+ 2314727432,
+ 4229834861,
+ 2675409590,
+ 4268245106,
+ 2647028240,
+ 1980982520,
+ 2590627680,
+ 4006412018,
+ 740712097,
+ 2498147343,
+ 130942613,
+ 3681207319,
+ 3402766111,
+ 3536327061,
+ 3770297446,
+ 2085970532,
+ 566701741,
+ 4055782889,
+ 1608102537,
+ 3393804528,
+ 2100732696,
+ 3315765574,
+ 1614848685,
+ 1829637060,
+ 2806101826,
+ 3386515494,
+ 2410019891,
+ 3104463307,
+ 924278107,
+ 6962346,
+ 2844298276,
+ 701510388,
];
static final String mapAPIKEYIOS = String.fromCharCodes(List.generate(
@@ -1561,71 +1613,71 @@ final class _Env {
).map((int i) => _envieddatamapAPIKEYIOS[i] ^ _enviedkeymapAPIKEYIOS[i]));
static const List _enviedkeytwilloRecoveryCode = [
- 3532317025,
- 3199852271,
- 2853477449,
- 91396203,
- 170144762,
- 875721478,
- 3209237056,
- 2472742181,
- 828886629,
- 154594601,
- 4221098919,
- 1304577431,
- 3884436887,
- 2931382789,
- 1842499728,
- 3015782631,
- 383382245,
- 3050150358,
- 705517746,
- 1694727442,
- 2134281548,
- 1184063988,
- 3679795016,
- 4016059634,
- 2102036619,
- 3275788957,
- 3673929929,
- 3273665123,
- 1892561227,
- 153252413,
- 4225481428,
+ 2689140138,
+ 1298299846,
+ 2057967448,
+ 2137865182,
+ 2938356726,
+ 1691312281,
+ 2231705315,
+ 59667461,
+ 1041068572,
+ 1212147038,
+ 3924764144,
+ 1831149843,
+ 40385226,
+ 1407278889,
+ 3376967208,
+ 2930603709,
+ 2681028551,
+ 325951936,
+ 450904546,
+ 1158123913,
+ 3461876794,
+ 4048211225,
+ 3908777410,
+ 1222192183,
+ 3459582394,
+ 3627977289,
+ 1751140149,
+ 3573607933,
+ 3595094674,
+ 3865880740,
+ 714370723,
];
static const List _envieddatatwilloRecoveryCode = [
- 3532316962,
- 3199852206,
- 2853477404,
- 91396188,
- 170144707,
- 875721538,
- 3209237000,
- 2472742261,
- 828886573,
- 154594584,
- 4221098981,
- 1304577533,
- 3884436946,
- 2931382844,
- 1842499776,
- 3015782578,
- 383382189,
- 3050150370,
- 705517815,
- 1694727494,
- 2134281492,
- 1184063904,
- 3679794971,
- 4016059562,
- 2102036689,
- 3275788997,
- 3673929915,
- 3273665083,
- 1892561191,
- 153252479,
- 4225481400,
+ 2689140201,
+ 1298299783,
+ 2057967373,
+ 2137865193,
+ 2938356687,
+ 1691312349,
+ 2231705259,
+ 59667541,
+ 1041068628,
+ 1212147055,
+ 3924764082,
+ 1831149945,
+ 40385167,
+ 1407278864,
+ 3376967288,
+ 2930603752,
+ 2681028495,
+ 325951988,
+ 450904487,
+ 1158123997,
+ 3461876834,
+ 4048211277,
+ 3908777361,
+ 1222192239,
+ 3459582432,
+ 3627977233,
+ 1751140167,
+ 3573607845,
+ 3595094782,
+ 3865880806,
+ 714370767,
];
static final String twilloRecoveryCode = String.fromCharCodes(
@@ -1637,87 +1689,87 @@ final class _Env {
_envieddatatwilloRecoveryCode[i] ^ _enviedkeytwilloRecoveryCode[i]));
static const List _enviedkeyauthTokenTwillo = [
- 274874504,
- 136604541,
- 414657959,
- 1621923202,
- 1616905471,
- 2762008141,
- 364105633,
- 3728798235,
- 2362214629,
- 723326659,
- 1267630251,
- 2027904562,
- 431311898,
- 2109483493,
- 2341226229,
- 1345512578,
- 71674775,
- 1837938758,
- 265252728,
- 3925064266,
- 2036788307,
- 3280316594,
- 3656116441,
- 3050273829,
- 60991170,
- 4083413127,
- 1762064368,
- 1766803797,
- 3219199410,
- 1656327530,
- 693339638,
- 859012280,
- 1647514073,
- 1031863580,
- 3538902529,
- 3536934850,
- 1232882253,
- 2131218398,
- 3734232272,
+ 550160046,
+ 2319335841,
+ 1053614357,
+ 3805976816,
+ 2370913201,
+ 1385227187,
+ 1955262560,
+ 3654581219,
+ 3218643785,
+ 3775928016,
+ 1080892875,
+ 1144318036,
+ 1298398762,
+ 3254180924,
+ 4054769829,
+ 576524082,
+ 916329670,
+ 4055003212,
+ 986404453,
+ 521422304,
+ 1307751592,
+ 641572031,
+ 1969181429,
+ 3951897168,
+ 828310667,
+ 3969389323,
+ 1200210257,
+ 3203333471,
+ 2467733379,
+ 917204918,
+ 3855643778,
+ 3370839775,
+ 2467915783,
+ 2462259520,
+ 2536763376,
+ 2301343237,
+ 309682522,
+ 1346811043,
+ 9843013,
];
static const List _envieddataauthTokenTwillo = [
- 274874559,
- 136604493,
- 414658002,
- 1621923259,
- 1616905415,
- 2762008103,
- 364105684,
- 3728798251,
- 2362214615,
- 723326706,
- 1267630239,
- 2027904605,
- 431311970,
- 2109483421,
- 2341226177,
- 1345512691,
- 71674791,
- 1837938739,
- 265252687,
- 3925064318,
- 2036788323,
- 3280316544,
- 3656116449,
- 3050273872,
- 60991218,
- 4083413173,
- 1762064321,
- 1766803744,
- 3219199366,
- 1656327451,
- 693339523,
- 859012238,
- 1647514092,
- 1031863620,
- 3538902643,
- 3536934810,
- 1232882209,
- 2131218332,
- 3734232252,
+ 550160025,
+ 2319335825,
+ 1053614432,
+ 3805976777,
+ 2370913161,
+ 1385227225,
+ 1955262485,
+ 3654581203,
+ 3218643835,
+ 3775928033,
+ 1080892927,
+ 1144318011,
+ 1298398802,
+ 3254180932,
+ 4054769809,
+ 576524099,
+ 916329718,
+ 4055003193,
+ 986404434,
+ 521422292,
+ 1307751576,
+ 641571981,
+ 1969181389,
+ 3951897125,
+ 828310715,
+ 3969389369,
+ 1200210272,
+ 3203333418,
+ 2467733431,
+ 917204935,
+ 3855643895,
+ 3370839785,
+ 2467915826,
+ 2462259480,
+ 2536763266,
+ 2301343325,
+ 309682486,
+ 1346811105,
+ 9842985,
];
static final String authTokenTwillo = String.fromCharCodes(List.generate(
@@ -1728,125 +1780,125 @@ final class _Env {
(int i) => _envieddataauthTokenTwillo[i] ^ _enviedkeyauthTokenTwillo[i]));
static const List _enviedkeychatGPTkey = [
- 4275741706,
- 3718972910,
- 3196369652,
- 2031227723,
- 3134027384,
- 4064693075,
- 291469558,
- 3411741135,
- 2968554073,
- 2817510438,
- 3503277486,
- 3746671217,
- 74427877,
- 3579890133,
- 621990733,
- 2368351242,
- 1505340524,
- 2610042925,
- 339161536,
- 3505456852,
- 1010166058,
- 3088827491,
- 2642115279,
- 2270149424,
- 2082203779,
- 2160805222,
- 3641083247,
- 3515011331,
- 1037012782,
- 3698404289,
- 4115396302,
- 779215860,
- 163353457,
- 2991164379,
- 775012981,
- 3559214986,
- 669368105,
- 2049312221,
- 2077048456,
- 3255335914,
- 2185432953,
- 585786041,
- 394093760,
- 59889921,
- 405419837,
- 3151098589,
- 2669471785,
- 3133493717,
- 4152667824,
- 3681742960,
- 1163287264,
- 1561021221,
- 2482595902,
- 4214399238,
- 3685519560,
- 3855750523,
- 3182280582,
- 4054153899,
+ 3411261939,
+ 2148041557,
+ 1239406863,
+ 2505787222,
+ 1026121752,
+ 506996797,
+ 1625950291,
+ 2287542558,
+ 1602415689,
+ 3979349983,
+ 3431506210,
+ 2145365833,
+ 1700889457,
+ 2046901692,
+ 1940607177,
+ 3545010845,
+ 1595543080,
+ 51154378,
+ 3799259360,
+ 2429407672,
+ 4164116956,
+ 2680039016,
+ 3275785567,
+ 1250429927,
+ 2147043762,
+ 1486248192,
+ 1272778244,
+ 2987720676,
+ 1957620816,
+ 568908027,
+ 2422341873,
+ 2109254189,
+ 2435992579,
+ 3518627944,
+ 1350420187,
+ 2603668676,
+ 3520694324,
+ 799269050,
+ 1126040433,
+ 3973271653,
+ 3874166578,
+ 2691444775,
+ 499201732,
+ 1725502412,
+ 512811952,
+ 3550319764,
+ 2791440863,
+ 3370105785,
+ 213525776,
+ 3622779136,
+ 3508089745,
+ 3424172753,
+ 2441788357,
+ 1587664731,
+ 3861880036,
+ 3873561842,
+ 3004624558,
+ 3359940933,
];
static const List