Update: 2026-06-11 18:22:57

This commit is contained in:
Hamza-Ayed
2026-06-11 18:22:59 +03:00
parent c5170a88d2
commit 727068b668
629 changed files with 46050 additions and 46109 deletions

View File

@@ -43,3 +43,8 @@ app.*.map.json
/android/app/debug
/android/app/profile
/android/app/release
# Sensitive keys & environment files
key.properties
*.env
**/lib/env/env.g.dart

View File

@@ -0,0 +1,15 @@
import 'package:siro_rider/main.dart';
import 'package:siro_rider/constant/box_name.dart';
import 'package:get/get.dart';
class CurrencyHelper {
static String get currency {
String country = box.read(BoxName.countryCode) ?? 'Jordan';
switch (country) {
case 'Syria': return 'SYP'.tr;
case 'Egypt': return 'EGP'.tr;
case 'Jordan':
default: return 'JOD'.tr;
}
}
}

View File

@@ -4,293 +4,318 @@ import 'package:siro_rider/main.dart';
class AppLink {
static const String appDomain = 'siromove.com';
///https://walletintaleq.intaleq.xyz/v1/main
static String paymentServer = 'https://walletintaleq.intaleq.xyz/v2/main';
static String get paymentServer => 'https://walletintaleq.intaleq.xyz/v2/main';
///https://api.intaleq.xyz/siro/ride/location
static String location = 'https://api.intaleq.xyz/siro_v3/ride/location';
static String get location => 'https://api.intaleq.xyz/siro_v3/ride/location';
/// هذا الرابط خاص برحلات الركاب، ويستخدمه السيرفر الجانبي للرحلات (Ride Server Side) للتعامل مع عمليات إلغاء الرحلات وتحديث حالة الرحلات وغيرها من العمليات المتعلقة بالرحلات.
/// https://routesy.intaleq.xyz for syria
/// for jordan https://routesjo.intaleq.xyz
static String routesOsm = 'https://routesy.intaleq.xyz';
static String mapSaasRoute = 'https://map-saas.intaleqapp.com/api/maps/route';
static String reverseGeocoding =
static String get routesOsm => 'https://routesy.intaleq.xyz';
static String get mapSaasRoute => 'https://map-saas.intaleqapp.com/api/maps/route';
static String get reverseGeocoding =>
'https://map-saas.intaleqapp.com/api/geocoding/reverse';
static String searchGeocoding =
static String get searchGeocoding =>
'https://map-saas.intaleqapp.com/api/geocoding/search';
static String mapSaasPlaces =
static String get mapSaasPlaces =>
'https://map-saas.intaleqapp.com/api/geocoding/places';
///https://location.intaleq.xyz/siro/ride/location
///locationServerSide هو السيرفر الجانبي الخاص بموقع السائقين، حيث يتم إرسال تحديثات الموقع من التطبيق إلى هذا السيرفر، ومن ثم يقوم هذا السيرفر بتوزيع هذه التحديثات إلى الركاب المتصلين الذين يتابعون السائق في الوقت الحقيقي.
static String locationServerSide =
static String get locationServerSide =>
'https://location.intaleq.xyz/siro/ride/location';
static String get currentCountry => box.read(BoxName.countryCode) ?? 'Jordan';
///https://api.intaleq.xyz/siro
static final String endPoint = 'https://api.intaleq.xyz/siro_v3';
static String get endPoint => server;
/// هذا الرابط خاص برحلات الركاب، ويستخدمه السيرفر الجانبي للرحلات (Ride Server Side) للتعامل مع عمليات إلغاء الرحلات وتحديث حالة الرحلات وغيرها من العمليات المتعلقة بالرحلات.
/// https://rides.intaleq.xyz/siro
static final String rideServerSide = 'https://rides.intaleq.xyz/siro';
static String get rideServerSide => 'https://rides.intaleq.xyz/siro';
///https://api.intaleq.xyz/siro
/// main api link for all api calls except rides and location
static final String server = 'https://api.intaleq.xyz/siro_v3';
static String get server {
switch (currentCountry) {
case 'Syria':
return 'https://api-syria.siromove.com/siro_v3';
case 'Egypt':
return 'https://api-egypt.siromove.com/siro_v3';
case 'Jordan':
default:
return 'https://api-jordan.siromove.com/siro_v3';
}
}
///https://rides.intaleq.xyz
/// هذا الرابط خاص برحلات الركاب، ويستخدمه السيرفر الجانبي للرحلات (Ride Server Side) للتعامل مع عمليات إلغاء الرحلات وتحديث حالة الرحلات وغيرها من العمليات المتعلقة بالرحلات.
static final String serverSocket = 'https://rides.intaleq.xyz';
static String get serverSocket => 'https://rides.intaleq.xyz';
///
static String googleMapsLink = 'https://maps.googleapis.com/maps/api/';
static String get googleMapsLink => 'https://maps.googleapis.com/maps/api/';
/// here map link for searching for places
static String searcMaps =
static String get searcMaps =>
'https://autosuggest.search.hereapi.com/v1/autosuggest';
static String test = "$server/test.php";
static String get test => "$server/test.php";
//===============firebase==========================
static String getTokens = "$server/ride/firebase/getTokensPassenger.php";
static String getTokenParent = "$server/ride/firebase/getTokenParent.php";
static String addTokens = "$server/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";
static String get getTokens => "$server/ride/firebase/getTokensPassenger.php";
static String get getTokenParent => "$server/ride/firebase/getTokenParent.php";
static String get addTokens => "$server/ride/firebase/add.php";
static String get addFingerPrint => "$paymentServer/ride/firebase/add.php";
static String get addTokensDriver => "$server/ride/firebase/addDriver.php";
static String get packageInfo => "$server/auth/packageInfo.php";
//=======================Wallet===================
static String wallet = '$paymentServer/ride/passengerWallet';
static String walletDriver = '$paymentServer/ride/driverWallet';
static String getAllPassengerTransaction =
static String get wallet => '$paymentServer/ride/passengerWallet';
static String get walletDriver => '$paymentServer/ride/driverWallet';
static String get getAllPassengerTransaction =>
"$wallet/getAllPassengerTransaction.php";
static String getWalletByPassenger = "$wallet/getWalletByPassenger.php";
static String getPassengersWallet = "$wallet/get.php";
static String payWithPayMobWalletPasenger =
static String get getWalletByPassenger => "$wallet/getWalletByPassenger.php";
static String get getPassengersWallet => "$wallet/get.php";
static String get payWithPayMobWalletPasenger =>
'$paymentServer/ride/payMob/wallet/payWithPayMob.php';
static String payWithPayMobCardPassenger =
static String get payWithPayMobCardPassenger =>
'$paymentServer/ride/payMob/payWithPayMob.php';
static String payWithEcash = "$paymentServer/ecash/payWithEcash.php";
static String get payWithEcash => "$paymentServer/ecash/payWithEcash.php";
static String paymetVerifyPassenger =
static String get paymetVerifyPassenger =>
"$paymentServer/ride/payMob/paymet_verfy.php";
static String getPassengerWalletArchive =
static String get getPassengerWalletArchive =>
"$wallet/getPassengerWalletArchive.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";
static String get addDrivePayment => "$paymentServer/ride/payment/add.php";
static String get addSeferWallet => "$paymentServer/ride/seferWallet/add.php";
static String get addPassengersWallet => "$wallet/add.php";
static String get deletePassengersWallet => "$wallet/delete.php";
static String get updatePassengersWallet => "$wallet/update.php";
static String getWalletByDriver = "$walletDriver/getWalletByDriver.php";
static String getDriversWallet = "$walletDriver/get.php";
static String addDriversWalletPoints = "$walletDriver/add.php";
static String deleteDriversWallet = "$walletDriver/delete.php";
static String updateDriversWallet = "$walletDriver/update.php";
static String get getWalletByDriver => "$walletDriver/getWalletByDriver.php";
static String get getDriversWallet => "$walletDriver/get.php";
static String get addDriversWalletPoints => "$walletDriver/add.php";
static String get deleteDriversWallet => "$walletDriver/delete.php";
static String get updateDriversWallet => "$walletDriver/update.php";
//=======================promo===================ride.mobile-app.store/ride/promo/get.php
static String promo = '$server/ride/promo';
static String getPassengersPromo = "$promo/get.php";
static String getPromoFirst = "$promo/getPromoFirst.php";
static String getPromoBytody = "$promo/getPromoBytody.php";
static String addPassengersPromo = "$promo/add.php";
static String deletePassengersPromo = "$promo/delete.php";
static String updatePassengersPromo = "$promo/update.php";
static String get promo => '$server/ride/promo';
static String get getPassengersPromo => "$promo/get.php";
static String get getPromoFirst => "$promo/getPromoFirst.php";
static String get getPromoBytody => "$promo/getPromoBytody.php";
static String get addPassengersPromo => "$promo/add.php";
static String get deletePassengersPromo => "$promo/delete.php";
static String get updatePassengersPromo => "$promo/update.php";
//===============contact==========================
static String savePhones = "$server/ride/egyptPhones/add.php";
static String getPhones = "$server/ride/egyptPhones/get.php";
static String get savePhones => "$server/ride/egyptPhones/add.php";
static String get getPhones => "$server/ride/egyptPhones/get.php";
////=======================cancelRide===================
// static String ride = '$server/ride';
static String addCancelRideFromPassenger =
static String get addCancelRideFromPassenger =>
"$rideServerSide/cancelRide/add.php";
static String cancelRide = "$rideServerSide/cancelRide/get.php";
static String get cancelRide => "$rideServerSide/cancelRide/get.php";
//-----------------ridessss------------------
static String addRides = "$rideServerSide/ride/rides/add.php";
static String getRides = "$rideServerSide/ride/rides/get.php";
static String getRideOrderID =
static String get addRides => "$rideServerSide/ride/rides/add.php";
static String get getRides => "$rideServerSide/ride/rides/get.php";
static String get getRideOrderID =>
"$rideServerSide/ride/rides/getRideOrderID.php";
static String getRideStatus = "$rideServerSide/ride/rides/getRideStatus.php";
static String getRideStatusBegin =
static String get getRideStatus => "$rideServerSide/ride/rides/getRideStatus.php";
static String get getRideStatusBegin =>
"$rideServerSide/ride/rides/getRideStatusBegin.php";
static String getRideStatusFromStartApp =
static String get getRideStatusFromStartApp =>
"$server/ride/rides/getRideStatusFromStartApp.php";
static String updateRides = "$rideServerSide/ride/rides/update.php";
static String updateStausFromSpeed =
static String get updateRides => "$rideServerSide/ride/rides/update.php";
static String get updateStausFromSpeed =>
"$rideServerSide/ride/rides/updateStausFromSpeed.php";
static String deleteRides = "$rideServerSide/ride/rides/delete.php";
static String get deleteRides => "$rideServerSide/ride/rides/delete.php";
//-----------------DriverPayment------------------
static String adddriverScam = "$server/driver_scam/add.php";
static String getdriverScam = "$server/ride/driver_scam/get.php";
static String get adddriverScam => "$server/driver_scam/add.php";
static String get getdriverScam => "$server/ride/driver_scam/get.php";
/////////---getKazanPercent===////////////
static String getKazanPercent = "$server/ride/kazan/get.php";
static String addKazanPercent = "$server/ride/kazan/add.php";
static String get getKazanPercent => "$server/ride/kazan/get.php";
static String get addKazanPercent => "$server/ride/kazan/add.php";
////-----------------DriverPayment------------------
static String addDriverpayment = "$paymentServer/ride/payment/add.php";
static String addDriverPaymentPoints =
static String get addDriverpayment => "$paymentServer/ride/payment/add.php";
static String get addDriverPaymentPoints =>
"$paymentServer/ride/driverPayment/add.php";
static String addPaymentTokenPassenger =
static String get addPaymentTokenPassenger =>
"$paymentServer/ride/passengerWallet/addPaymentTokenPassenger.php";
static String addPaymentTokenDriver =
static String get addPaymentTokenDriver =>
"$paymentServer/ride/driverWallet/addPaymentToken.php";
static String getDriverPaymentPoints =
static String get getDriverPaymentPoints =>
"$paymentServer/ride/driverWallet/get.php";
static String payWithEcashPassenger =
static String get payWithEcashPassenger =>
"$paymentServer/ride/ecash/passenger/payWithEcash.php";
static String payWithMTNConfirm =
static String get payWithMTNConfirm =>
"$paymentServer/ride/mtn/passenger/mtn_confirm.php";
static String payWithMTNStart =
static String get payWithMTNStart =>
"$paymentServer/ride/mtn/passenger/mtn_start.php";
static String payWithSyriatelConfirm =
static String get payWithSyriatelConfirm =>
"$paymentServer/ride/syriatel/passenger/confirm_payment.php";
static String payWithSyriatelStart =
static String get payWithSyriatelStart =>
"$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 =
static String get getDriverpaymentToday => "$paymentServer/ride/payment/get.php";
static String get getCountRide => "$paymentServer/ride/payment/getCountRide.php";
static String get getAllPaymentFromRide =>
"$paymentServer/ride/payment/getAllPayment.php";
static String getAllPaymentVisa =
static String get getAllPaymentVisa =>
"$paymentServer/ride/payment/getAllPaymentVisa.php";
static String get createMtnInvoice =>
"$paymentServer/ride/mtn_new/create_mtn_invoice.php";
static String get createCliqInvoice =>
"$paymentServer/ride/cliq/create_cliq_invoice.php";
static String get checkMtnStatus => "$paymentServer/ride/mtn_new/check_status.php";
static String get checkCliqStatus => "$paymentServer/ride/cliq/check_status.php";
static String get uploadMtnProof => "$paymentServer/ride/mtn_new/verify_payment_ai.php";
static String get uploadCliqProof => "$paymentServer/ride/cliq/verify_payment_ai.php";
//-----------------Passenger NotificationCaptain------------------
static String addNotificationPassenger =
static String get addNotificationPassenger =>
"$server/ride/notificationPassenger/add.php";
static String getNotificationPassenger =
static String get getNotificationPassenger =>
"$server/ride/notificationPassenger/get.php";
static String updateNotificationPassenger =
static String get updateNotificationPassenger =>
"$server/ride/notificationPassenger/update.php";
//-----------------Driver NotificationCaptain------------------
static String addNotificationCaptain =
static String get addNotificationCaptain =>
"$server/ride/notificationCaptain/add.php";
static String addWaitingRide =
static String get addWaitingRide =>
"$server/ride/notificationCaptain/addWaitingRide.php";
static String updateWaitingTrip =
static String get updateWaitingTrip =>
"$server/ride/notificationCaptain/updateWaitingTrip.php";
static String getRideWaiting =
static String get getRideWaiting =>
"$endPoint/ride/notificationCaptain/getRideWaiting.php";
static String getNotificationCaptain =
static String get getNotificationCaptain =>
"$server/ride/notificationCaptain/get.php";
static String updateNotificationCaptain =
static String get updateNotificationCaptain =>
"$server/ride/notificationCaptain/update.php";
static String deleteNotificationCaptain =
static String get deleteNotificationCaptain =>
"$server/ride/notificationCaptain/delete.php";
//-----------------invitor------------------
static String getUnifiedCode = "$server/ride/invitor/get_unified_code.php";
static String addUnifiedInvite = "$server/ride/invitor/add_unified_invite.php";
static String getPassengerReferrals = "$server/ride/invitor/get_passenger_referrals.php";
static String addInviteDriver = "$server/ride/invitor/add.php";
static String addInvitationPassenger =
static String get getUnifiedCode => "$server/ride/invitor/get_unified_code.php";
static String get addUnifiedInvite => "$server/ride/invitor/add_unified_invite.php";
static String get getPassengerReferrals => "$server/ride/invitor/get_passenger_referrals.php";
static String get addInviteDriver => "$server/ride/invitor/add.php";
static String get addInvitationPassenger =>
"$server/ride/invitor/addInvitationPassenger.php";
static String getInviteDriver = "$server/ride/invitor/get.php";
static String getDriverInvitationToPassengers =
static String get getInviteDriver => "$server/ride/invitor/get.php";
static String get getDriverInvitationToPassengers =>
"$server/ride/invitor/getDriverInvitationToPassengers.php";
static String updateInviteDriver = "$server/ride/invitor/update.php";
static String updatePassengerGift =
static String get updateInviteDriver => "$server/ride/invitor/update.php";
static String get updatePassengerGift =>
"$server/ride/invitor/updatePassengerGift.php";
static String get claimInviteReward => "$server/ride/invitor/claim.php";
//-----------------Api Key------------------
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 = "$server/ride/apiKey/update.php";
static String deleteApiKey = "$server/ride/apiKey/delete.php";
static String getPlacesSyria = "$server/ride/places_syria/get.php";
static String get addApiKey => "$server/ride/apiKey/add.php";
static String get getApiKey => "$server/ride/apiKey/get.php";
static String get getCnMap => "$server/auth/cnMap.php";
static String get updateApiKey => "$server/ride/apiKey/update.php";
static String get deleteApiKey => "$server/ride/apiKey/delete.php";
static String get getPlacesSyria => "$server/ride/places_syria/get.php";
//-----------------Feed Back------------------
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";
static String get addFeedBack => "$server/ride/feedBack/add.php";
static String get add_solve_all => "$server/ride/feedBack/add_solve_all.php";
static String get uploadAudio => "$server/ride/feedBack/upload_audio.php";
static String get getFeedBack => "$server/ride/feedBack/get.php";
static String get updateFeedBack => "$server/ride/feedBack/updateFeedBack.php";
//-----------------Tips------------------
static String addTips = "$server/ride/tips/add.php";
static String getTips = "$server/ride/tips/get.php";
static String updateTips = "$server/ride/tips/update.php";
static String get addTips => "$server/ride/tips/add.php";
static String get getTips => "$server/ride/tips/get.php";
static String get updateTips => "$server/ride/tips/update.php";
//-----------------Help Center------------------
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";
static String get addhelpCenter => "$server/ride/helpCenter/add.php";
static String get gethelpCenter => "$server/ride/helpCenter/get.php";
static String get getByIdhelpCenter => "$server/ride/helpCenter/getById.php";
static String get updatehelpCenter => "$server/ride/helpCenter/update.php";
static String get deletehelpCenter => "$server/ride/helpCenter/delete.php";
//-----------------license------------------
static String addLicense = "$server/ride/license/add.php";
static String getLicense = "$server/ride/license/get.php";
static String updateLicense = "$server/ride/license/updateFeedBack.php";
static String get addLicense => "$server/ride/license/add.php";
static String get getLicense => "$server/ride/license/get.php";
static String get updateLicense => "$server/ride/license/updateFeedBack.php";
//-----------------RegisrationCar------------------
static String addRegisrationCar = "$server/ride/RegisrationCar/add.php";
static String getRegisrationCar =
static String get addRegisrationCar => "$server/ride/RegisrationCar/add.php";
static String get getRegisrationCar =>
"${box.read(BoxName.serverChosen)}/server/ride/RegisrationCar/get.php";
static String selectDriverAndCarForMishwariTrip =
static String get selectDriverAndCarForMishwariTrip =>
"$server/ride/RegisrationCar/selectDriverAndCarForMishwariTrip.php";
static String updateRegisrationCar = "$server/ride/RegisrationCar/update.php";
static String get updateRegisrationCar => "$server/ride/RegisrationCar/update.php";
//-----------------mishwari------------------
static String addMishwari = "$server/ride/mishwari/add.php";
static String cancelMishwari = "$server/ride/mishwari/cancel.php";
static String getMishwari = "$server/ride/mishwari/get.php";
static String sendChatMessage = "$server/ride/chat/send_message.php";
static String get addMishwari => "$server/ride/mishwari/add.php";
static String get cancelMishwari => "$server/ride/mishwari/cancel.php";
static String get getMishwari => "$server/ride/mishwari/get.php";
static String get sendChatMessage => "$server/ride/chat/send_message.php";
//-----------------DriverOrder------------------
static String addDriverOrder = "$server/ride/driver_order/add.php";
static String getDriverOrder = "$server/ride/driver_order/get.php";
static String getOrderCancelStatus =
static String get addDriverOrder => "$server/ride/driver_order/add.php";
static String get getDriverOrder => "$server/ride/driver_order/get.php";
static String get getOrderCancelStatus =>
"$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 get updateDriverOrder => "$server/ride/driver_order/update.php";
static String get deleteDriverOrder => "$server/ride/driver_order/delete.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";
static String get addRateToPassenger => "$server/ride/rate/add.php";
static String get savePlacesServer => "$server/ride/places/add.php";
static String get getapiKey => "$server/ride/apiKey/get.php";
// Endpoint لجلب التسعيرة من السيرفر (Server-Side Pricing)
static String get getPrices => "$server/ride/pricing/get.php";
static String get addRateToDriver => "$server/ride/rate/addRateToDriver.php";
static String get getDriverRate => "$server/ride/rate/getDriverRate.php";
static String get getPassengerRate => "$server/ride/rate/getPassengerRate.php";
////////////////emails ============//
static String sendEmailToPassengerForTripDetails =
static String get sendEmailToPassengerForTripDetails =>
"$server/ride/rides/emailToPassengerTripDetail.php";
// ===========================================
static String pathImage = "$server/upload/types/";
static String uploadImage = "$server/uploadImage.php";
static String uploadImage1 = "$server/uploadImage1.php";
static String uploadImagePortrate = "$server/uploadImagePortrate.php";
static String uploadImageType = "$server/uploadImageType.php";
static String get pathImage => "$server/upload/types/";
static String get uploadImage => "$server/uploadImage.php";
static String get uploadImage1 => "$server/uploadImage1.php";
static String get uploadImagePortrate => "$server/uploadImagePortrate.php";
static String get uploadImageType => "$server/uploadImageType.php";
//=============egypt documents ==============
static String uploadEgyptidFront =
static String get uploadEgyptidFront =>
"$server/EgyptDocuments/uploadEgyptidFront.php";
static String uploadEgypt = "$server/uploadEgypt.php";
static String get uploadEgypt => "$server/uploadEgypt.php";
//==================certifcate==========
// static String location = '${box.read(BoxName.serverChosen)}/ride/location';
static String getCarsLocationByPassenger = "$location/get.php";
static String get getCarsLocationByPassenger => "$location/get.php";
static String getLocationAreaLinks =
static String get getLocationAreaLinks =>
'$server/ride/location/get_location_area_links.php';
static String addpassengerLocation =
static String get addpassengerLocation =>
"$locationServerSide/addpassengerLocation.php";
static String getCarsLocationByPassengerSpeed = "$location/getSpeed.php";
static String getCarsLocationByPassengerComfort = "$location/getComfort.php";
static String getCarsLocationByPassengerBalash = "$location/getBalash.php";
static String getCarsLocationByPassengerElectric =
static String get getCarsLocationByPassengerSpeed => "$location/getSpeed.php";
static String get getCarsLocationByPassengerComfort => "$location/getComfort.php";
static String get getCarsLocationByPassengerBalash => "$location/getBalash.php";
static String get getCarsLocationByPassengerElectric =>
"$location/getElectric.php";
static String getCarsLocationByPassengerPinkBike =
static String get getCarsLocationByPassengerPinkBike =>
"$location/getPinkBike.php";
static String getCarsLocationByPassengerVan =
static String get getCarsLocationByPassengerVan =>
"$location/getCarsLocationByPassengerVan.php";
static String getCarsLocationByPassengerDelivery =
static String get getCarsLocationByPassengerDelivery =>
"$location/getDelivery.php";
static String getLocationParents = "$location/getLocationParents.php";
static String getFemalDriverLocationByPassenger =
static String get getLocationParents => "$location/getLocationParents.php";
static String get getFemalDriverLocationByPassenger =>
"$location/getFemalDriver.php";
static String getDriverCarsLocationToPassengerAfterApplied =
static String get getDriverCarsLocationToPassengerAfterApplied =>
"$location/getDriverCarsLocationToPassengerAfterApplied.php";
// static String addCarsLocationByPassenger = "$location/add.php";
// static String deleteCarsLocationByPassenger = "$location/delete.php";
@@ -300,76 +325,76 @@ class AppLink {
// "$location/getTotalDriverDurationToday.php";
//==================Blog=============
static String profile = '$server/ride/profile';
static String getprofile = "$profile/get.php";
static String getCaptainProfile = "$profile/getCaptainProfile.php";
static String addprofile = "$profile/add.php";
static String deleteprofile = "$profile/delete.php";
static String updateprofile = "$profile/update.php";
static String get profile => '$server/ride/profile';
static String get getprofile => "$profile/get.php";
static String get getCaptainProfile => "$profile/getCaptainProfile.php";
static String get addprofile => "$profile/add.php";
static String get deleteprofile => "$profile/delete.php";
static String get updateprofile => "$profile/update.php";
//===================Auth============
static String auth = '$server/auth';
static String login = "$auth/login.php";
static String loginJwtRider = "$server/login.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";
static String signUp = "$auth/signup.php";
static String sendVerifyEmail = "$auth/sendVerifyEmail.php";
static String loginFromGooglePassenger = "$auth/loginFromGooglePassenger.php";
static String checkPhoneNumberISVerfiedPassenger =
static String get auth => '$server/auth';
static String get login => "$auth/login.php";
static String get loginJwtRider => "$server/login.php";
static String get loginJwtWalletRider => "$server/loginWallet.php";
static String get loginFirstTime => "$server/loginFirstTime.php";
static String get getTesterApp => "$auth/Tester/getTesterApp.php";
static String get updateTesterApp => "$auth/Tester/updateTesterApp.php";
static String get signUp => "$auth/signup.php";
static String get sendVerifyEmail => "$auth/sendVerifyEmail.php";
static String get loginFromGooglePassenger => "$auth/loginFromGooglePassenger.php";
static String get checkPhoneNumberISVerfiedPassenger =>
"$auth/checkPhoneNumberISVerfiedPassenger.php";
static String passengerRemovedAccountEmail =
static String get passengerRemovedAccountEmail =>
"$auth/passengerRemovedAccountEmail.php";
static String verifyEmail = "$auth/verifyEmail.php";
static String get verifyEmail => "$auth/verifyEmail.php";
//===================Auth Captin============
static String authCaptin = '$server/auth/captin';
static String loginCaptin = "$authCaptin/login.php";
static String loginFromGoogleCaptin = "$authCaptin/loginFromGoogle.php";
static String signUpCaptin = "$authCaptin/register.php";
static String sendVerifyEmailCaptin = "$authCaptin/sendVerifyEmail.php";
static String sendVerifyOtpMessage = "$server/auth/otpmessage.php";
static String verifyOtpMessage = "$server/auth/verifyOtpMessage.php";
static String verifyEmailCaptin = "$authCaptin/verifyEmail.php";
static String removeUser = "$authCaptin/removeAccount.php";
static String deletecaptainAccounr = "$authCaptin/deletecaptainAccounr.php";
static String updateAccountBank = "$authCaptin/updateAccountBank.php";
static String getAccount = "$authCaptin/getAccount.php";
static String updatePassengersInvitation =
static String get authCaptin => '$server/auth/captin';
static String get loginCaptin => "$authCaptin/login.php";
static String get loginFromGoogleCaptin => "$authCaptin/loginFromGoogle.php";
static String get signUpCaptin => "$authCaptin/register.php";
static String get sendVerifyEmailCaptin => "$authCaptin/sendVerifyEmail.php";
static String get sendVerifyOtpMessage => "$server/auth/otpmessage.php";
static String get verifyOtpMessage => "$server/auth/verifyOtpMessage.php";
static String get verifyEmailCaptin => "$authCaptin/verifyEmail.php";
static String get removeUser => "$authCaptin/removeAccount.php";
static String get deletecaptainAccounr => "$authCaptin/deletecaptainAccounr.php";
static String get updateAccountBank => "$authCaptin/updateAccountBank.php";
static String get getAccount => "$authCaptin/getAccount.php";
static String get updatePassengersInvitation =>
"$server/ride/invitor/updatePassengersInvitation.php";
static String updateDriverInvitationDirectly =
static String get updateDriverInvitationDirectly =>
"$server/ride/invitor/updateDriverInvitationDirectly.php";
//===================Admin Captin============
static String getPassengerDetailsByPassengerID =
static String get getPassengerDetailsByPassengerID =>
"$server/Admin/getPassengerDetailsByPassengerID.php";
static String getPassengerDetails = "$server/Admin/getPassengerDetails.php";
static String getPassengerbyEmail = "$server/Admin/getPassengerbyEmail.php";
static String addAdminUser = "$server/Admin/adminUser/add.php";
static String getAdminUser = "$server/Admin/adminUser/get.php";
static String addError = "$server/Admin/errorApp.php";
static String getCaptainDetailsByEmailOrIDOrPhone =
static String get getPassengerDetails => "$server/Admin/getPassengerDetails.php";
static String get getPassengerbyEmail => "$server/Admin/getPassengerbyEmail.php";
static String get addAdminUser => "$server/Admin/adminUser/add.php";
static String get getAdminUser => "$server/Admin/adminUser/get.php";
static String get addError => "$server/Admin/errorApp.php";
static String get getCaptainDetailsByEmailOrIDOrPhone =>
"$server/Admin/AdminCaptain/getCaptainDetailsByEmailOrIDOrPhone.php";
static String getCaptainDetails = "$server/Admin/AdminCaptain/get.php";
static String getRidesPerMonth =
static String get getCaptainDetails => "$server/Admin/AdminCaptain/get.php";
static String get getRidesPerMonth =>
"$server/Admin/AdminRide/getRidesPerMonth.php";
static String getRidesDetails = "$server/Admin/AdminRide/get.php";
static String get getRidesDetails => "$server/Admin/AdminRide/get.php";
//////////Sms egypt///////////
static String sendSms = "https://sms.kazumi.me/api/sms/send-sms";
static String sendSmsFromPHP =
static String get sendSms => "https://sms.kazumi.me/api/sms/send-sms";
static String get sendSmsFromPHP =>
'$server/auth/sms_new_backend/sendOtpPassenger.php';
static String verifyOtpPassenger =
static String get verifyOtpPassenger =>
'$server/auth/passengerOTP/verifyOtpPassenger.php';
static String senddlr = "https://sms.kazumi.me/api/sms/send-dlr";
static String sendvalidity = "https://sms.kazumi.me/api/sms/send-validity";
static String sendmany = "https://sms.kazumi.me/api/sms/send-many";
static String checkCredit = "https://sms.kazumi.me/api/sms/check-credit";
static String getSender = "$server/auth/sms/getSender.php";
static String checkStatus = "https://sms.kazumi.me/api/sms/check-status";
static String updatePhoneInvalidSMSPassenger =
static String get senddlr => "https://sms.kazumi.me/api/sms/send-dlr";
static String get sendvalidity => "https://sms.kazumi.me/api/sms/send-validity";
static String get sendmany => "https://sms.kazumi.me/api/sms/send-many";
static String get checkCredit => "https://sms.kazumi.me/api/sms/check-credit";
static String get getSender => "$server/auth/sms/getSender.php";
static String get checkStatus => "https://sms.kazumi.me/api/sms/check-status";
static String get updatePhoneInvalidSMSPassenger =>
"$server/auth/sms/updatePhoneInvalidSMSPassenger.php";
}

View File

@@ -1,5 +1,4 @@
import 'package:siro_rider/constant/links.dart';
import 'package:siro_rider/views/home/map_page_passenger.dart';
import 'package:get/get.dart';
import '../../../constant/box_name.dart';
import '../../../main.dart';
@@ -8,6 +7,7 @@ import '../../views/auth/otp_page.dart';
import '../../views/widgets/error_snakbar.dart';
import '../functions/crud.dart';
import '../functions/package_info.dart';
import '../functions/country_logic.dart';
import 'login_controller.dart';
// --- Helper Class for Phone Authentication ---
@@ -19,67 +19,13 @@ 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;
}
// removed formatSyrianPhone
/// Sends an OTP to the provided phone number.
static Future<bool> sendOtp(String phoneNumber) async {
try {
// إصلاح الرقم قبل الإرسال
final fixedPhone = formatSyrianPhone(phoneNumber);
final fixedPhone = CountryLogic.formatCurrentCountryPhone(phoneNumber);
final response = await CRUD().post(
link: _sendOtpUrl,
@@ -109,7 +55,7 @@ class PhoneAuthHelper {
static Future<void> verifyOtp(String phoneNumber, String otpCode) async {
try {
final fixedPhone = formatSyrianPhone(phoneNumber);
final fixedPhone = CountryLogic.formatCurrentCountryPhone(phoneNumber);
final response = await CRUD().post(
link: _verifyOtpUrl,
payload: {

View File

@@ -666,7 +666,7 @@ class DriverTipWidget extends StatelessWidget {
Toast.show(
context,
'${'Tip is '.tr}${(controller.totalPassenger) * (double.parse(box.read(BoxName.tipPercentage.toString())))}',
'${'Tip is '.tr}${(double.parse(controller.totalPassenger.toString())) * (double.parse(box.read(BoxName.tipPercentage.toString())))}',
AppColor.cyanBlue);
controller.update();
},
@@ -685,7 +685,7 @@ class DriverTipWidget extends StatelessWidget {
box.write(BoxName.tipPercentage, '0.10');
Toast.show(
context,
'${'Tip is'.tr} ${(controller.totalPassenger) * (double.parse(box.read(BoxName.tipPercentage.toString())))}',
'${'Tip is'.tr} ${(double.parse(controller.totalPassenger.toString())) * (double.parse(box.read(BoxName.tipPercentage.toString())))}',
AppColor.cyanBlue);
controller.update();
},
@@ -704,7 +704,7 @@ class DriverTipWidget extends StatelessWidget {
box.write(BoxName.tipPercentage, '0.15');
Toast.show(
context,
'${'Tip is'.tr} ${(controller.totalPassenger) * (double.parse(box.read(BoxName.tipPercentage.toString())))}',
'${'Tip is'.tr} ${(double.parse(controller.totalPassenger.toString())) * (double.parse(box.read(BoxName.tipPercentage.toString())))}',
AppColor.cyanBlue);
controller.update();
},
@@ -723,7 +723,7 @@ class DriverTipWidget extends StatelessWidget {
box.write(BoxName.tipPercentage, '0.20');
Toast.show(
context,
'${'Tip is'.tr} ${(controller.totalPassenger) * (double.parse(box.read(BoxName.tipPercentage.toString())))}',
'${'Tip is'.tr} ${(double.parse(controller.totalPassenger.toString())) * (double.parse(box.read(BoxName.tipPercentage.toString())))}',
AppColor.cyanBlue);
controller.update();
},
@@ -754,7 +754,7 @@ class DriverTipWidget extends StatelessWidget {
child: Padding(
padding: const EdgeInsets.all(6),
child: Text(
'${(controller.totalPassenger) * (double.parse(box.read(BoxName.tipPercentage.toString())))} ${box.read(BoxName.countryCode) == 'Egypt' ? 'LE'.tr : 'JOD'.tr}',
'${(double.parse(controller.totalPassenger.toString())) * (double.parse(box.read(BoxName.tipPercentage.toString())))} ${box.read(BoxName.countryCode) == 'Egypt' ? 'LE'.tr : 'JOD'.tr}',
style: AppStyle.title,
),
),

View File

@@ -0,0 +1,94 @@
import 'package:siro_rider/constant/box_name.dart';
import 'package:siro_rider/main.dart';
class CountryLogic {
/// Formats the phone number based on the country's dialing rules.
static String formatPhone(String phone, String country) {
phone = phone.replaceAll(RegExp(r'[ \-\(\)\+]'), '').trim();
if (country == 'Egypt') {
// Rule: 010, 011, 012, 015 -> 2010, 2011, 2012, 2015
if (phone.startsWith('0020')) phone = phone.replaceFirst('0020', '20');
if (phone.startsWith('01') && phone.length >= 10) {
return '20${phone.substring(1)}';
}
if (phone.startsWith('1') &&
phone.length >= 9 &&
!phone.startsWith('20')) {
return '20$phone';
}
if (!phone.startsWith('20') && phone.length > 8) return '20$phone';
} else if (country == 'Jordan') {
// Rule: 07x -> 9627x
if (phone.startsWith('00962')) phone = phone.replaceFirst('00962', '962');
if (phone.startsWith('07') && phone.length >= 9) {
return '962${phone.substring(1)}';
}
if (phone.startsWith('7') &&
phone.length >= 8 &&
!phone.startsWith('962')) {
return '962$phone';
}
if (!phone.startsWith('962') && phone.length > 7) return '962$phone';
} else {
// Default to Syria
if (phone.startsWith('00963')) phone = phone.replaceFirst('00963', '963');
if (phone.startsWith('0963')) phone = phone.replaceFirst('0963', '963');
if (phone.startsWith('096309')) {
phone = phone.replaceFirst('096309', '963');
}
if (phone.startsWith('96309')) phone = '9639${phone.substring(5)}';
if (phone.startsWith('9630')) phone = '9639${phone.substring(4)}';
if (phone.startsWith('9639') && phone.length == 12) return phone;
if (phone.startsWith('963') &&
phone.length > 3 &&
!phone.startsWith('9639')) {
phone = '9639${phone.substring(3)}';
}
if (phone.startsWith('09')) return '963${phone.substring(1)}';
if (phone.startsWith('9') && phone.length == 9) return '963$phone';
if (phone.startsWith('0') && phone.length == 10) {
return '963${phone.substring(1)}';
}
}
return phone;
}
/// Returns the default country prefix (EG, JO, SY) for UI initial selection.
static String getCountryPrefix(String country) {
if (country == 'Egypt') return 'EG';
if (country == 'Jordan') return 'JO';
return 'SY';
}
/// Returns the default emergency number for the country.
static String getEmergencyNumber(String country) {
if (country == 'Egypt') return '122';
if (country == 'Jordan') return '911';
return '112'; // Syria
}
/// Returns the hint text for phone inputs based on the country.
static String getPhoneHint(String country) {
if (country == 'Egypt') return 'e.g. 01012345678 (Default +20)';
if (country == 'Jordan') return 'e.g. 0791234567 (Default +962)';
return 'e.g. 0912345678 (Default +963)'; // Syria
}
/// Helper to format phone using the current country in box.
static String formatCurrentCountryPhone(String phone) {
String cleanPhone = phone.replaceAll(RegExp(r'[ \-\(\)]'), '').trim();
if (cleanPhone.startsWith('+963') || cleanPhone.startsWith('00963')) {
return formatPhone(cleanPhone, 'Syria');
}
if (cleanPhone.startsWith('+20') || cleanPhone.startsWith('0020')) {
return formatPhone(cleanPhone, 'Egypt');
}
if (cleanPhone.startsWith('+962') || cleanPhone.startsWith('00962')) {
return formatPhone(cleanPhone, 'Jordan');
}
final country = box.read(BoxName.countryCode) ?? 'Syria';
return formatPhone(cleanPhone, country);
}
}

View File

@@ -1,6 +1,7 @@
import 'package:siro_rider/print.dart';
import 'package:url_launcher/url_launcher.dart';
import 'dart:io';
import 'package:siro_rider/controller/functions/country_logic.dart';
void showInBrowser(String url) async {
if (await canLaunchUrl(Uri.parse(url))) {
@@ -9,16 +10,11 @@ void showInBrowser(String url) async {
}
Future<void> makePhoneCall(String phoneNumber) async {
// 1. تنظيف الرقم (إزالة المسافات والفواصل)
String formattedNumber = phoneNumber.replaceAll(RegExp(r'\s+'), '');
// 2. منطق التنسيق (مع الحفاظ على الأرقام القصيرة مثل 112 كما هي)
if (formattedNumber.length > 6) {
if (formattedNumber.startsWith('09')) {
// إذا كان يبدأ بـ 09 (رقم موبايل سوري محلي) -> +963
formattedNumber = '+963${formattedNumber.substring(1)}';
} else if (!formattedNumber.startsWith('+')) {
// إذا لم يكن دولياً ولا محلياً معروفاً -> إضافة + فقط
formattedNumber = CountryLogic.formatCurrentCountryPhone(formattedNumber);
if (!formattedNumber.startsWith('+')) {
formattedNumber = '+$formattedNumber';
}
}

View File

@@ -125,25 +125,23 @@ class RideLifecycleController extends GetxController {
late String driverCompletedRides = '0';
late String driverTier = 'Verified driver';
late String driverToken = '';
double kazan = 8;
double totalPassenger = 0;
String totalPassenger = '0';
double totalDriver = 0;
double costDistance = 0;
double costDuration = 0;
double averageDuration = 0;
double totalCostPassenger = 0;
String totalCostPassenger = '0';
double totalPassengerSpeed = 0;
double totalPassengerBalash = 0;
double totalPassengerComfort = 0;
double totalPassengerElectric = 0;
double totalPassengerLady = 0;
double totalPassengerScooter = 0;
double totalPassengerVan = 0;
double totalPassengerRayehGai = 0;
double totalPassengerRayehGaiComfort = 0;
double totalPassengerRayehGaiBalash = 0;
String totalPassengerSpeed = '0';
String totalPassengerBalash = '0';
String totalPassengerComfort = '0';
String totalPassengerElectric = '0';
String totalPassengerLady = '0';
String totalPassengerScooter = '0';
String totalPassengerVan = '0';
String totalPassengerRayehGai = '0';
String totalPassengerRayehGaiComfort = '0';
String totalPassengerRayehGaiBalash = '0';
double latePrice = 0;
double fuelPrice = 0;
@@ -744,7 +742,7 @@ class RideLifecycleController extends GetxController {
style: TextStyle(color: AppColor.greenColor)),
onPressed: () {
Get.back();
double newPrice = totalPassenger * 1.10;
double newPrice = double.parse(totalPassenger) * 1.10;
increasePriceAndRestartSearch(newPrice);
},
),
@@ -755,7 +753,7 @@ class RideLifecycleController extends GetxController {
}
Future<void> increasePriceAndRestartSearch(double newPrice) async {
totalPassenger = newPrice;
totalPassenger = newPrice.toStringAsFixed(2);
update();
await CRUD()
@@ -822,6 +820,7 @@ class RideLifecycleController extends GetxController {
_isRideStartedProcessed = true;
currentRideState.value = RideState.inProgress;
statusRide = 'Begin';
box.write(BoxName.passengerWalletTotal, '0');
remainingTimeDriverWaitPassenger5Minute = 0;
_stopWaitPassengerTimer();
@@ -1413,7 +1412,7 @@ class RideLifecycleController extends GetxController {
"date": DateTime.now().toString(),
"time": DateTime.now().toString(),
"endtime": "00:00:00",
"price": totalPassenger.toStringAsFixed(2),
"price": double.parse(totalPassenger.toString()).toStringAsFixed(2),
"passenger_id": box.read(BoxName.passengerID).toString(),
"driver_id": "0",
"status": "waiting",
@@ -1694,7 +1693,6 @@ class RideLifecycleController extends GetxController {
box.write(BoxName.serverChosen, AppLink.server);
if (newCountry != previousCountry) {
unawaited(getKazanPercent());
}
return newCountry;
@@ -1775,135 +1773,56 @@ class RideLifecycleController extends GetxController {
void applyPromoCodeToPassenger(BuildContext context) async {
if (promoTaken == true) {
MyDialog().getDialog(
'Promo Already Used'.tr,
'You have already used this promo code.'.tr,
() => Get.back(),
);
MyDialog().getDialog('Promo Already Used'.tr, 'You have already used this promo code.'.tr, () => Get.back());
return;
}
if (!promoFormKey.currentState!.validate()) return;
const double minPromoLowSYP = 172;
const double minPromoHighSYP = 200;
try {
final value = await CRUD().get(
link: AppLink.getPassengersPromo,
payload: {'promo_code': promo.text},
);
final res = await CRUD().post(link: AppLink.getPrices, payload: {
'distance': distance.toString(),
'durationToRide': durationToRide.toString(),
'startNameAddress': startNameAddress,
'endNameAddress': endNameAddress,
'destLat': myDestination.latitude.toString(),
'destLng': myDestination.longitude.toString(),
'passengerLat': newMyLocation.latitude.toString(),
'passengerLng': newMyLocation.longitude.toString(),
'walletVal': box.read(BoxName.passengerWalletTotal)?.toString() ?? '0',
'activeMenuWaypointCount': activeMenuWaypointCount.toString(),
'promo_code': promo.text,
'passenger_id' :box.read(BoxName.passengerID),
'country': box.read(BoxName.countryCode) ?? '',
});
if (value == 'failure') {
MyDialog().getDialog(
'Promo Ended'.tr,
'The promotion period has ended.'.tr,
() => Get.back(),
);
return;
}
final bool eligibleNow = (totalPassengerSpeed >= minPromoLowSYP) ||
(totalPassengerBalash >= minPromoLowSYP) ||
(totalPassengerComfort >= minPromoHighSYP) ||
(totalPassengerElectric >= minPromoHighSYP) ||
(totalPassengerLady >= minPromoHighSYP);
if (!eligibleNow) {
Get.snackbar(
'Lowest Price Achieved'.tr,
'Cannot apply further discounts.'.tr,
backgroundColor: AppColor.yellowColor,
);
return;
}
final decode = jsonDecode(value);
if (decode["status"] != "success") {
MyDialog().getDialog(
'Promo Ended'.tr,
'The promotion period has ended.'.tr,
() => Get.back(),
);
return;
}
Get.snackbar('Promo Code Accepted'.tr, '',
backgroundColor: AppColor.greenColor);
final firstElement = decode["message"][0];
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;
final double discount = fare * (discountPercentage / 100.0);
double result;
if (isWalletNegative) {
double neg = (-1) * walletVal;
result = fare + neg - discount;
if (res != 'failure') {
var response = jsonDecode(res);
if (response['status'] == 'success') {
var data = response['data'];
totalPassengerSpeed = data['totalPassengerSpeed']?.toString() ?? '0';
totalPassengerBalash = data['totalPassengerBalash']?.toString() ?? '0';
totalPassengerComfort = data['totalPassengerComfort']?.toString() ?? '0';
totalPassengerElectric = data['totalPassengerElectric']?.toString() ?? '0';
totalPassengerLady = data['totalPassengerLady']?.toString() ?? '0';
totalPassengerScooter = data['totalPassengerScooter']?.toString() ?? '0';
totalPassengerVan = data['totalPassengerVan']?.toString() ?? '0';
totalPassengerRayehGai = data['totalPassengerRayehGai']?.toString() ?? '0';
totalPassengerRayehGaiComfort = data['totalPassengerRayehGaiComfort']?.toString() ?? '0';
totalPassengerRayehGaiBalash = data['totalPassengerRayehGaiBalash']?.toString() ?? '0';
promoTaken = true;
update();
Confetti.launch(
context,
options: const ConfettiOptions(particleCount: 100, spread: 70, y: 0.6),
);
} else {
result = fare - discount;
MyDialog().getDialog('Promo Error'.tr, response['message']?.toString() ?? 'Invalid Promo'.tr, () => Get.back());
return;
}
if (result < minThreshold) {
result = minThreshold;
}
return result.clamp(0.0, double.infinity);
}
totalPassengerComfort = _applyDiscountPerTier(
fare: totalPassengerComfort,
minThreshold: minPromoHighSYP,
isWalletNegative: isWalletNegative,
);
totalPassengerElectric = _applyDiscountPerTier(
fare: totalPassengerElectric,
minThreshold: minPromoHighSYP,
isWalletNegative: isWalletNegative,
);
totalPassengerLady = _applyDiscountPerTier(
fare: totalPassengerLady,
minThreshold: minPromoHighSYP,
isWalletNegative: isWalletNegative,
);
totalPassengerSpeed = _applyDiscountPerTier(
fare: totalPassengerSpeed,
minThreshold: minPromoLowSYP,
isWalletNegative: isWalletNegative,
);
totalPassengerBalash = _applyDiscountPerTier(
fare: totalPassengerBalash,
minThreshold: minPromoLowSYP,
isWalletNegative: isWalletNegative,
);
totalDriver = totalDriver - (totalDriver * discountPercentage / 100.0);
promoTaken = true;
update();
Confetti.launch(
context,
options: const ConfettiOptions(particleCount: 100, spread: 70, y: 0.6),
);
Get.back();
Get.back();
await Future.delayed(const Duration(milliseconds: 120));
} catch (e) {
Get.snackbar('Error'.tr, e.toString(),
@@ -1920,236 +1839,49 @@ class RideLifecycleController extends GetxController {
double costForDriver = 0;
Future bottomSheet() async {
const double minFareSYP = 160;
const double minBillableKm = 0.3;
const double ladyFlatAddon = 20;
const double airportAddonSYP = 200;
const double damascusAirportBoundAddon = 1400;
const double electricPerKmUplift = 4;
const double electricFlatAddon = 10;
const double longSpeedThresholdKm = 40.0;
const double longSpeedPerKm = 26.0;
const double mediumDistThresholdKm = 25.0;
const double longDistThresholdKm = 35.0;
const double longTripPerMin = 6.0;
const int minuteCapMedium = 60;
const int minuteCapLong = 80;
const int freeMinutesLong = 10;
const double extraReduction100 = 0.07;
const double maxReductionCap = 0.35;
durationToAdd = Duration(seconds: durationToRide);
hours = durationToAdd.inHours;
minutes = (durationToAdd.inMinutes % 60).round();
final DateTime currentTime = DateTime.now();
newTime = currentTime.add(durationToAdd);
averageDuration = (durationToRide / 60) / distance;
final int waypointSurchargeMinutes = activeMenuWaypointCount * 5;
final int totalMinutes =
(durationToRide / 60).floor() + waypointSurchargeMinutes;
bool _isAirport(String s) {
final t = s.toLowerCase();
return t.contains('airport') ||
s.contains('مطار') ||
s.contains('المطار');
}
bool _isClub(String s) {
final t = s.toLowerCase();
return t.contains('club') ||
t.contains('nightclub') ||
t.contains('night club') ||
s.contains('ديسكو') ||
s.contains('ملهى ليلي');
}
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;
final double heavyPerMin = heavyPrice;
double _perMinuteByTime(DateTime now, bool clubCtx) {
final h = now.hour;
if (h >= 21 || h < 1) return latePerMin;
if (h >= 1 && h < 5) return clubCtx ? (latePerMin * 2) : latePerMin;
if (h >= 14 && h <= 17) return heavyPerMin;
return naturePerMin;
}
double _applyMinFare(double fare) =>
(fare < minFareSYP) ? minFareSYP : fare;
double _withCommission(double base) =>
(base * (1 + kazan / 100)).ceilToDouble();
final bool airportCtx =
_isAirport(startNameAddress) || _isAirport(endNameAddress);
final bool clubCtx = _isClub(startNameAddress) || _isClub(endNameAddress);
double destLat = 0.0;
double destLng = 0.0;
try {
destLat = myDestination.latitude;
destLng = myDestination.longitude;
} catch (_) {
if (locSearch.coordinatesWithoutEmpty.isNotEmpty) {
destLat = double.tryParse(
locSearch.coordinatesWithoutEmpty.last.split(',')[0]) ??
0.0;
destLng = double.tryParse(
locSearch.coordinatesWithoutEmpty.last.split(',')[1]) ??
0.0;
}
}
final bool damascusAirportBoundCtx =
_isInsideDamascusAirportBounds(destLat, destLng);
final bool isInDamascusAirportBoundCtx = _isInsideDamascusAirportBounds(
newMyLocation.latitude.toDouble(),
newMyLocation.longitude.toDouble(),
);
final double billableDistance =
(distance < minBillableKm) ? minBillableKm : distance;
final bool isLongSpeed = billableDistance > longSpeedThresholdKm;
final double perKmSpeedBaseFromServer = speedPrice;
final double perKmSpeed =
isLongSpeed ? longSpeedPerKm : perKmSpeedBaseFromServer;
double reductionPct40 = 0.0;
if (perKmSpeedBaseFromServer > 0) {
reductionPct40 = (1.0 - (longSpeedPerKm / perKmSpeedBaseFromServer))
.clamp(0.0, maxReductionCap);
}
final double reductionPct100 =
(reductionPct40 + extraReduction100).clamp(0.0, maxReductionCap);
double distanceReduction = 0.0;
if (billableDistance > 100.0) {
distanceReduction = reductionPct100;
} else if (billableDistance > 40.0) {
distanceReduction = reductionPct40;
}
double effectivePerMin = _perMinuteByTime(currentTime, clubCtx);
int billableMinutes = totalMinutes;
if (billableDistance > longDistThresholdKm) {
effectivePerMin = longTripPerMin;
final int capped =
(billableMinutes > minuteCapLong) ? minuteCapLong : billableMinutes;
billableMinutes = capped - freeMinutesLong;
if (billableMinutes < 0) billableMinutes = 0;
} else if (billableDistance > mediumDistThresholdKm) {
effectivePerMin = longTripPerMin;
billableMinutes = (billableMinutes > minuteCapMedium)
? minuteCapMedium
: billableMinutes;
}
final double perKmComfortRaw = comfortPrice;
final double perKmDelivery = deliveryPrice;
final double perKmVanRaw =
(familyPrice > 0 ? familyPrice : (speedPrice + 13));
final double perKmElectricRaw = perKmComfortRaw + electricPerKmUplift;
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);
final double perKmBalash = (perKmSpeed - 5).clamp(0, double.infinity);
double _oneWayFare({
required double perKm,
required bool isLady,
double flatAddon = 0,
}) {
double fare = billableDistance * perKm;
fare += billableMinutes * effectivePerMin;
fare += flatAddon;
if (isLady) fare += ladyFlatAddon;
if (airportCtx) fare += airportAddonSYP;
if (damascusAirportBoundCtx || isInDamascusAirportBoundCtx) {
fare += damascusAirportBoundAddon;
}
return _applyMinFare(fare);
}
double _roundTripFare({required double perKm}) {
double distPart =
(billableDistance * 2 * perKm) - ((billableDistance * perKm) * 0.4);
double timePart = (billableMinutes * 2) * effectivePerMin;
double fare = distPart + timePart;
if (airportCtx) fare += airportAddonSYP;
if (damascusAirportBoundCtx || isInDamascusAirportBoundCtx) {
fare += damascusAirportBoundAddon;
}
return _applyMinFare(fare);
}
final double costSpeed = _oneWayFare(perKm: perKmSpeed, isLady: false);
final double costBalash = _oneWayFare(perKm: perKmBalash, isLady: false);
final double costComfort = _oneWayFare(perKm: perKmComfort, isLady: false);
final double costElectric = _oneWayFare(
perKm: perKmElectric, isLady: false, flatAddon: electricFlatAddon);
final double costDelivery =
_oneWayFare(perKm: perKmDelivery, isLady: false);
final double costLady = _oneWayFare(perKm: perKmComfort, isLady: true);
final double costVan = _oneWayFare(perKm: perKmVan, isLady: false);
final double costRayehGai = _roundTripFare(perKm: perKmSpeed);
final double costRayehGaiComfort = _roundTripFare(perKm: perKmComfort);
final double costRayehGaiBalash = _roundTripFare(perKm: perKmBalash);
totalPassengerSpeed = _withCommission(costSpeed);
totalPassengerBalash = _withCommission(costBalash);
totalPassengerComfort = _withCommission(costComfort);
totalPassengerElectric = _withCommission(costElectric);
totalPassengerLady = _withCommission(costLady);
totalPassengerScooter = _withCommission(costDelivery);
totalPassengerVan = _withCommission(costVan);
totalPassengerRayehGai = _withCommission(costRayehGai);
totalPassengerRayehGaiComfort = _withCommission(costRayehGaiComfort);
totalPassengerRayehGaiBalash = _withCommission(costRayehGaiBalash);
totalPassenger = totalPassengerSpeed;
totalCostPassenger = totalPassenger;
try {
final walletStr = box.read(BoxName.passengerWalletTotal).toString();
final walletVal = double.tryParse(walletStr) ?? 0.0;
if (walletVal < 0) {
final neg = (-1) * walletVal;
totalPassenger += neg;
totalPassengerComfort += neg;
totalPassengerElectric += neg;
totalPassengerLady += neg;
totalPassengerBalash += neg;
totalPassengerScooter += neg;
totalPassengerRayehGai += neg;
totalPassengerRayehGaiComfort += neg;
totalPassengerRayehGaiBalash += neg;
totalPassengerVan += neg;
final res = await CRUD().post(link: AppLink.getPrices, payload: {
'distance': distance.toString(),
'durationToRide': durationToRide.toString(),
'startNameAddress': startNameAddress,
'endNameAddress': endNameAddress,
'destLat': myDestination.latitude.toString(),
'destLng': myDestination.longitude.toString(),
'passengerLat': newMyLocation.latitude.toString(),
'passengerLng': newMyLocation.longitude.toString(),
'walletVal': box.read(BoxName.passengerWalletTotal)?.toString() ?? '0',
'activeMenuWaypointCount': activeMenuWaypointCount.toString(),
'passenger_id': box.read(BoxName.passengerID) ?? '',
'country': box.read(BoxName.countryCode) ?? '',
});
if (res != 'failure') {
var response = jsonDecode(res);
if (response['status'] == 'success') {
var data = response['data'];
totalPassengerSpeed = data['totalPassengerSpeed']?.toString() ?? '0';
totalPassengerBalash = data['totalPassengerBalash']?.toString() ?? '0';
totalPassengerComfort = data['totalPassengerComfort']?.toString() ?? '0';
totalPassengerElectric = data['totalPassengerElectric']?.toString() ?? '0';
totalPassengerLady = data['totalPassengerLady']?.toString() ?? '0';
totalPassengerScooter = data['totalPassengerScooter']?.toString() ?? '0';
totalPassengerVan = data['totalPassengerVan']?.toString() ?? '0';
totalPassengerRayehGai = data['totalPassengerRayehGai']?.toString() ?? '0';
totalPassengerRayehGaiComfort = data['totalPassengerRayehGaiComfort']?.toString() ?? '0';
totalPassengerRayehGaiBalash = data['totalPassengerRayehGaiBalash']?.toString() ?? '0';
totalPassenger = totalPassengerSpeed;
totalCostPassenger = totalPassenger;
}
}
} catch (e) {
Log.print("Error: $e");
Log.print("Error fetching prices: $e");
}
update();
@@ -2694,7 +2426,7 @@ class RideLifecycleController extends GetxController {
"end_location": '${endLoc.latitude},${endLoc.longitude}',
"date": DateTime.now().toString(),
"time": DateTime.now().toString(),
"price": totalPassenger.toStringAsFixed(2),
"price": double.parse(totalPassenger.toString()).toStringAsFixed(2),
'passenger_id': box.read(BoxName.passengerID).toString(),
'status': 'waiting',
'carType': box.read(BoxName.carType),
@@ -2720,144 +2452,9 @@ class RideLifecycleController extends GetxController {
double familyPrice = 55;
double deliveryPrice = 1.2;
Future<void> getKazanPercent() async {
var res = await CRUD().get(
link: AppLink.getKazanPercent,
payload: {'country': box.read(BoxName.countryCode).toString()},
);
if (res != 'failure') {
var json = jsonDecode(res);
var dataList = json['data'] ?? json['message'];
if (dataList != null && dataList is List && dataList.isNotEmpty) {
var firstRow = dataList[0];
kazan = double.parse(firstRow['kazan'].toString());
naturePrice = double.parse(firstRow['naturePrice'].toString());
heavyPrice = double.parse(firstRow['heavyPrice'].toString());
latePrice = double.parse(firstRow['latePrice'].toString());
comfortPrice = double.parse(firstRow['comfortPrice'].toString());
speedPrice = double.parse(firstRow['speedPrice'].toString());
deliveryPrice = double.parse(firstRow['deliveryPrice'].toString());
mashwariPrice = double.parse(firstRow['freePrice'].toString());
familyPrice = double.parse(firstRow['familyPrice'].toString());
fuelPrice = double.parse(firstRow['fuelPrice'].toString());
}
}
}
Future<void> getPassengerRate() async {
var res = await CRUD().get(
link: AppLink.getPassengerRate,
payload: {'passenger_id': box.read(BoxName.passengerID)});
if (res != 'failure') {
var json = jsonDecode(res);
var message = json['data'] ?? json['message'];
if (message['rating'] == null) {
passengerRate = 5.0;
} else {
var rating = message['rating'];
if (rating is String) {
passengerRate = double.tryParse(rating) ?? 5.0;
} else if (rating is num) {
passengerRate = rating.toDouble();
} else {
passengerRate = 5.0;
}
}
} else {
passengerRate = 5.0;
}
}
Future<void> addFingerPrint() async {
String fingerPrint = await DeviceHelper.getDeviceFingerprint();
await CRUD().postWallet(link: AppLink.addFingerPrint, payload: {
'token': (box.read(BoxName.tokenFCM.toString())),
'passengerID': box.read(BoxName.passengerID).toString(),
"fingerPrint": fingerPrint
});
}
Future<void> firstTimeRunToGetCoupon() async {
if (box.read(BoxName.isFirstTime).toString() == '0' &&
box.read(BoxName.isInstall).toString() == '1' &&
box.read(BoxName.isGiftToken).toString() == '0') {
var promoCode, discount, validity;
var resPromo = await CRUD().get(link: AppLink.getPromoFirst, payload: {
"passengerID": box.read(BoxName.passengerID).toString(),
});
if (resPromo != 'failure') {
var d1 = jsonDecode(resPromo);
promoCode = d1['message']['promo_code'];
discount = d1['message']['amount'];
validity = d1['message']['validity_end_date'];
}
box.write(BoxName.isFirstTime, '1');
Get.dialog(
AlertDialog(
contentPadding: EdgeInsets.zero,
content: SizedBox(
width: 300,
child: PromoBanner(
promoCode: promoCode,
discountPercentage: discount,
validity: validity,
),
),
),
);
}
}
Future<void> detectAndCacheDeviceTier() async {
bool isHighEnd = await DevicePerformanceManager.isHighEndDevice();
Log.print("Device Analysis - Is Flagship/HighEnd? $isHighEnd");
box.write(BoxName.lowEndMode, !isHighEnd);
}
Future<void> initilizeGetStorage() async {
if (box.read(BoxName.addWork) == null) {
box.write(BoxName.addWork, 'addWork');
}
if (box.read(BoxName.addHome) == null) {
box.write(BoxName.addHome, 'addHome');
}
if (box.read(BoxName.lowEndMode) == null) {
detectAndCacheDeviceTier();
}
}
Future<void> selectDriverAndCarForMishwariTrip() async {
double latitudeOffset = 0.1;
double longitudeOffset = 0.12;
double southwestLat = passengerLocation.latitude - latitudeOffset;
double northeastLat = passengerLocation.latitude + latitudeOffset;
double southwestLon = passengerLocation.longitude - longitudeOffset;
double northeastLon = passengerLocation.longitude + longitudeOffset;
var payload = {
'southwestLat': southwestLat.toString(),
'northeastLat': northeastLat.toString(),
'southwestLon': southwestLon.toString(),
'northeastLon': northeastLon.toString(),
};
Future selectDriverAndCarForMishwariTrip() async {
try {
var res = await CRUD().get(
link: AppLink.selectDriverAndCarForMishwariTrip, payload: payload);
if (res != 'failure') {
try {
var d = jsonDecode(res);
driversForMishwari = d['message'];
Log.print('driversForMishwari: $driversForMishwari');
update();
} catch (e) {
Log.print("Error decoding JSON: $e");
}
}
// Logic for mishwari trip driver selection
} catch (e) {
Log.print("Error Mishwari select: $e");
}
@@ -4311,7 +3908,6 @@ class RideLifecycleController extends GetxController {
Future<void> _stagePricingAndState() async {
try {
await getKazanPercent();
} catch (e) {
Log.print("Error: $e");
}
@@ -4663,4 +4259,68 @@ class RideLifecycleController extends GetxController {
mapEngine.update();
update();
}
initilizeGetStorage() async {
if (box.read(BoxName.addWork) == null) {
box.write(BoxName.addWork, 'addWork');
}
if (box.read(BoxName.addHome) == null) {
box.write(BoxName.addHome, 'addHome');
}
}
getPassengerRate() async {
var res = await CRUD().get(
link: AppLink.getPassengerRate,
payload: {'passenger_id': box.read(BoxName.passengerID)});
if (res != 'failure') {
var json = jsonDecode(res);
var message = json['data'] ?? json['message'];
if (message['rating'] == null) {
passengerRate = 5.0; // Default rating
} else {
var rating = message['rating'];
if (rating is String) {
passengerRate = double.tryParse(rating) ?? 5.0;
} else if (rating is num) {
passengerRate = rating.toDouble();
} else {
passengerRate = 5.0;
}
}
} else {
passengerRate = 5.0;
}
}
firstTimeRunToGetCoupon() async {
if (box.read(BoxName.isFirstTime).toString() == '0' &&
box.read(BoxName.isInstall).toString() == '1' &&
box.read(BoxName.isGiftToken).toString() == '0') {
var promo, discount, validity;
var resPromo = await CRUD().get(link: AppLink.getPromoFirst, payload: {
"passengerID": box.read(BoxName.passengerID).toString(),
});
if (resPromo != 'failure') {
var d1 = jsonDecode(resPromo);
promo = d1['message']['promo_code'];
discount = d1['message']['amount'];
validity = d1['message']['validity_end_date'];
}
box.write(BoxName.isFirstTime, '1');
Get.dialog(
AlertDialog(
contentPadding: EdgeInsets.zero,
content: SizedBox(
width: 300,
child: PromoBanner(
promoCode: promo ?? '',
discountPercentage: discount ?? '',
validity: validity ?? '',
),
),
),
);
}
}
}

View File

@@ -21,6 +21,7 @@ import '../../functions/crud.dart';
import '../../functions/tts.dart';
import 'ride_lifecycle_controller.dart';
import 'location_search_controller.dart';
import '../../functions/country_logic.dart';
class UiInteractionsController extends GetxController {
TextEditingController sosPhonePassengerProfile = TextEditingController();
@@ -58,7 +59,8 @@ class UiInteractionsController extends GetxController {
MyTextForm(
controller: sosPhonePassengerProfile,
label: 'insert sos phone'.tr,
hint: 'e.g. 0912345678 (Default +963)'.tr,
hint: CountryLogic.getPhoneHint(
box.read(BoxName.countryCode) ?? 'Syria').tr,
type: TextInputType.phone,
),
const SizedBox(height: 10),
@@ -77,7 +79,7 @@ class UiInteractionsController extends GetxController {
if (sosFormKey.currentState!.validate()) {
Get.back();
var numberPhone =
formatSyrianPhoneNumber(sosPhonePassengerProfile.text);
CountryLogic.formatCurrentCountryPhone(sosPhonePassengerProfile.text);
await CRUD().post(
link: AppLink.updateprofile,
@@ -160,36 +162,7 @@ class UiInteractionsController extends GetxController {
'whatsapp', box.read(BoxName.sosPhonePassenger), message);
}
String formatSyrianPhone(String phone) {
phone = phone.replaceAll(' ', '').replaceAll('+', '');
if (phone.startsWith('00963')) {
phone = phone.replaceFirst('00963', '963');
}
if (phone.startsWith('0963')) {
phone = phone.replaceFirst('0963', '963');
}
if (phone.startsWith('963')) {
return phone;
}
if (phone.startsWith('09')) {
return '963' + phone.substring(1);
}
if (phone.startsWith('9') && phone.length == 9) {
return '963' + phone;
}
return phone;
}
String formatSyrianPhoneNumber(String phoneNumber) {
String trimmedPhone = phoneNumber.trim();
if (trimmedPhone.startsWith('09')) {
return '963${trimmedPhone.substring(1)}';
}
if (trimmedPhone.startsWith('963')) {
return trimmedPhone;
}
return '963$trimmedPhone';
}
// removed formatSyrianPhone and formatSyrianPhoneNumber
void sendSMS(String to) async {
final rideLifecycle = Get.find<RideLifecycleController>();
@@ -205,7 +178,7 @@ class UiInteractionsController extends GetxController {
void sendWhatsapp(String to) async {
final rideLifecycle = Get.find<RideLifecycleController>();
final locSearch = Get.find<LocationSearchController>();
String formattedPhone = formatSyrianPhone(to);
String formattedPhone = CountryLogic.formatCurrentCountryPhone(to);
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} ${rideLifecycle.passengerName}${' as the driver.'.tr} ${rideLifecycle.passengerName} \n${'is driving a '.tr}${rideLifecycle.model}\n${' with license plate '.tr}${rideLifecycle.licensePlate}.\n${' I am currently located at '.tr} https://www.google.com/maps/place/${locSearch.passengerLocation.latitude},${locSearch.passengerLocation.longitude}.\n${' If you need to reach me, please contact the driver directly at'.tr}\n\n ${rideLifecycle.driverPhone}.';
@@ -286,7 +259,7 @@ class UiInteractionsController extends GetxController {
return;
}
var numberPhone = formatSyrianPhoneNumber(storedPhone);
var numberPhone = CountryLogic.formatCurrentCountryPhone(storedPhone);
String trackingLink = rideLifecycle.generateTrackingLink(
rideLifecycle.rideId, rideLifecycle.driverId);
@@ -326,7 +299,7 @@ Thank you for using Siro!
Future getTokenForParent() async {
_ensureSosNumber(() async {
String storedPhone = box.read(BoxName.sosPhonePassenger)!;
var numberPhone = formatSyrianPhoneNumber(storedPhone);
var numberPhone = CountryLogic.formatCurrentCountryPhone(storedPhone);
Log.print("Searching for Parent Token with Phone: $numberPhone");
var res = await CRUD()
@@ -375,7 +348,7 @@ Thank you for using Siro!
Get.back();
var rawPhone = box.read(BoxName.sosPhonePassenger);
if (rawPhone == null) return;
var phone = formatSyrianPhoneNumber(rawPhone);
var phone = CountryLogic.formatCurrentCountryPhone(rawPhone);
var message = '''Dear Friend,

View File

@@ -1,4 +1,5 @@
// import 'dart:async';
// import 'package:siro_rider/constant/currency.dart';
import 'dart:async';
// import 'package:siro_rider/services/offline_map_service.dart';
// import 'package:siro_rider/services/emergency_signal_service.dart';
// import 'package:siro_rider/views/widgets/mycircular.dart';
@@ -6559,8 +6560,8 @@
// if (!promoFormKey.currentState!.validate()) return;
// // العتبات بالليرة السورية
// const double minPromoLowSYP = 172; // Speed / Balash
// const double minPromoHighSYP = 200; // Comfort / Electric / Lady
// const double minPromoLow${CurrencyHelper.currency} = 172; // Speed / Balash
// const double minPromoHigh${CurrencyHelper.currency} = 200; // Comfort / Electric / Lady
// try {
// final value = await CRUD().get(
@@ -6723,10 +6724,10 @@
// // if (data.isEmpty) return;
// // === إعدادات عامة ===
// const double minFareSYP = 160; // حد أدنى
// const double minFare${CurrencyHelper.currency} = 160; // حد أدنى
// const double minBillableKm = 0.3; // حد أدنى للمسافة المفوترة
// const double ladyFlatAddon = 20; // إضافة ثابتة لـ Lady
// const double airportAddonSYP = 200; // إضافة المطار
// const double airportAddon${CurrencyHelper.currency} = 200; // إضافة المطار
// // --- ⬇️ الإضافة الجديدة: إضافة حدود مطار دمشق ⬇️ ---
// const double damascusAirportBoundAddon = 1400; // إضافة المطار (حدود)
@@ -6814,7 +6815,7 @@
// // حد أدنى
// double _applyMinFare(double fare) =>
// (fare < minFareSYP) ? minFareSYP : fare;
// (fare < minFareSYP) ? minFare${CurrencyHelper.currency} : fare;
// // عمولة الراكب (kazan من السيرفر)
// double _withCommission(double base) =>
@@ -7341,7 +7342,7 @@
// double mashwariPrice = 40;
// double familyPrice = 55;
// double deliveryPrice = 1.2;
// double minFareSYP = 16000; // حد أدنى للأجرة (سوريا)
// double minFare${CurrencyHelper.currency} = 16000; // حد أدنى للأجرة (سوريا)
// double minBillableKm = 1.0; // حد أدنى للمسافة المفوترة
// double commissionPct = 15; // عمولة التطبيق % (راكب)

View File

@@ -302,18 +302,30 @@ ${'Download the Siro app now and enjoy your ride!'.tr}
'${'Claim your 20 LE gift for inviting'.tr} $passengerName!',
() async {
Get.back(); // Close dialog first
await Get.find<PaymentController>().addPassengersWallet('20');
await CRUD().post(
link: AppLink.updatePassengerGift,
payload: {'id': invitation['id']},
var response = await CRUD().post(
link: AppLink.claimInviteReward,
payload: {
'invite_id': invitation['id'].toString(),
'passenger_id': box.read(BoxName.passengerID).toString(),
'country_code': box.read(BoxName.countryCode).toString(),
},
);
NotificationCaptainController().addNotificationCaptain(
invitation['passengerInviterId'].toString(),
"You have got a gift for invitation".tr,
'${"You have earned 20".tr} ${'LE'}',
false,
);
fetchDriverStatsPassengers(); // Refresh list
if (response != 'failure') {
var data = jsonDecode(response);
if (data['status'] == 'success') {
NotificationCaptainController().addNotificationCaptain(
invitation['passengerInviterId'].toString(),
"You have got a gift for invitation".tr,
'${"You have earned 20".tr} ${'LE'}',
false,
);
fetchDriverStatsPassengers(); // Refresh list
} else {
Get.snackbar('Error'.tr, data['message'] ?? 'Claim failed'.tr, backgroundColor: AppColor.redColor);
}
}
},
);
} else {

View File

@@ -286,6 +286,8 @@ class MyTranslation extends Translations {
"you must insert token code": "لازم تدخل الكود",
"Syria": "سوريا",
"SYP": "ل.س",
"EGP": "ج.م",
"JOD": "د.أ",
"Order": "طلب",
"OrderVIP": "طلب VIP",
"Cancel Trip": "إلغاء المشوار",
@@ -1700,6 +1702,8 @@ class MyTranslation extends Translations {
"ar-main": {
"Syria": "‏سوريا",
"SYP": "ل.س",
"EGP": "ج.م",
"JOD": "د.أ",
"Order": "طلب",
"OrderVIP": "طلب VIP",
"Cancel Trip": "إلغاء الرحلة",
@@ -3127,6 +3131,8 @@ class MyTranslation extends Translations {
"ar-eg": {
"Syria": "سوريا",
"SYP": "ل.س",
"EGP": "ج.م",
"JOD": "د.أ",
"Order": "طلب",
"OrderVIP": "طلب VIP",
"Cancel Trip": "إلغاء المشوار",
@@ -4542,6 +4548,8 @@ class MyTranslation extends Translations {
"AR-Gulf": {
"Syria": "سوريا",
"SYP": "ل.س",
"EGP": "ج.م",
"JOD": "د.أ",
"Order": "طلب",
"OrderVIP": "طلب VIP",
"Cancel Trip": "إلغاء الرحلة",
@@ -5960,6 +5968,8 @@ class MyTranslation extends Translations {
"ar-ma": {
"Syria": "سوريا",
"SYP": "ل.س",
"EGP": "ج.م",
"JOD": "د.أ",
"Order": "طلب",
"OrderVIP": "طلب VIP",
"Cancel Trip": "إلغي الرحلة",
@@ -7571,6 +7581,8 @@ class MyTranslation extends Translations {
"you must insert token code": "you must insert token code",
"Syria": "Suriye",
"SYP": "SYP",
"EGP": "EGP",
"JOD": "JOD",
"Order": "Sipariş",
"OrderVIP": "VIP Sipariş",
"Cancel Trip": "Yolculuğu İptal Et",
@@ -9099,6 +9111,8 @@ class MyTranslation extends Translations {
"you must insert token code": "you must insert token code",
"Syria": "Syrie",
"SYP": "SYP",
"EGP": "EGP",
"JOD": "JOD",
"Order": "Commande",
"OrderVIP": "Commande VIP",
"Cancel Trip": "Annuler le trajet",
@@ -10669,6 +10683,8 @@ class MyTranslation extends Translations {
"you must insert token code": "you must insert token code",
"Syria": "Syrien",
"SYP": "SYP",
"EGP": "EGP",
"JOD": "JOD",
"Order": "Bestellung",
"OrderVIP": "VIP-Bestellung",
"Cancel Trip": "Fahrt stornieren",
@@ -12418,6 +12434,8 @@ class MyTranslation extends Translations {
"you must insert token code": "you must insert token code",
"Syria": "Siria",
"SYP": "SYP",
"EGP": "EGP",
"JOD": "JOD",
"Order": "Pedido",
"OrderVIP": "Pedido VIP",
"Cancel Trip": "Cancelar viaje",
@@ -14160,6 +14178,8 @@ class MyTranslation extends Translations {
"you must insert token code": "you must insert token code",
"Syria": "سوریه",
"SYP": "لیره سوریه",
"EGP": "EGP",
"JOD": "JOD",
"Order": "درخواست",
"OrderVIP": "درخواست VIP",
"Cancel Trip": "لغو سفر",
@@ -15666,6 +15686,8 @@ class MyTranslation extends Translations {
"you must insert token code": "you must insert token code",
"Syria": "Συρία",
"SYP": "SYP",
"EGP": "EGP",
"JOD": "JOD",
"Order": "Αίτημα",
"OrderVIP": "VIP Αίτημα",
"Cancel Trip": "Ακύρωση Διαδρομής",
@@ -17159,6 +17181,8 @@ class MyTranslation extends Translations {
"you must insert token code": "you must insert token code",
"Syria": "شام",
"SYP": "شامی پاؤن",
"EGP": "EGP",
"JOD": "JOD",
"Order": "آرڈر",
"OrderVIP": "VIP آرڈر",
"Cancel Trip": "سفر منسوخ کریں",
@@ -18721,6 +18745,8 @@ class MyTranslation extends Translations {
"you must insert token code": "you must insert token code",
"Syria": "भारत",
"SYP": "",
"EGP": "EGP",
"JOD": "JOD",
"Order": "ऑर्डर",
"OrderVIP": "VIP ऑर्डर",
"Cancel Trip": "ट्रिप रद्द करें",
@@ -20281,6 +20307,8 @@ class MyTranslation extends Translations {
"you must insert token code": "you must insert token code",
"Syria": "Сирия",
"SYP": "SYP",
"EGP": "EGP",
"JOD": "JOD",
"Order": "Заказ",
"OrderVIP": "VIP Заказ",
"Cancel Trip": "Отменить поездку",
@@ -21745,6 +21773,8 @@ class MyTranslation extends Translations {
"you must insert token code": "you must insert token code",
"Syria": "Siria",
"SYP": "SYP",
"EGP": "EGP",
"JOD": "JOD",
"Order": "Ordine",
"OrderVIP": "Ordine VIP",
"Cancel Trip": "Annulla corsa",
@@ -23244,6 +23274,8 @@ class MyTranslation extends Translations {
"you must insert token code": "you must insert token code",
"Syria": "叙利亚",
"SYP": "叙利亚镑",
"EGP": "EGP",
"JOD": "JOD",
"Order": "طلب",
"OrderVIP": "طلب VIP",
"Cancel Trip": "إلغاء المشوار",

View File

@@ -1,29 +1,21 @@
import 'dart:convert';
import 'package:siro_rider/constant/api_key.dart';
import 'package:siro_rider/constant/style.dart';
import 'package:siro_rider/controller/firebase/firbase_messge.dart';
import 'package:siro_rider/controller/payment/paymob/paymob_response.dart';
import 'package:siro_rider/views/home/map_page_passenger.dart';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:local_auth/local_auth.dart';
import 'package:siro_rider/controller/home/map/ride_lifecycle_controller.dart';
import 'package:siro_rider/controller/home/map/ride_state.dart';
import 'package:siro_rider/controller/home/map/ride_state.dart';
import 'package:webview_flutter/webview_flutter.dart';
import '../../constant/box_name.dart';
import '../../constant/colors.dart';
import '../../constant/info.dart';
import '../../constant/links.dart';
import '../../main.dart';
import '../../print.dart';
import '../firebase/notification_service.dart';
import '../functions/crud.dart';
import '../functions/encrypt_decrypt.dart';
import '../functions/toast.dart';
import 'paymob/e_cash_screen.dart';
import '../../views/home/my_wallet/payment_screen_mtn.dart';
import '../../views/home/my_wallet/payment_screen_cliq.dart';
class PaymentController extends GetxController {
bool isLoading = false;
@@ -34,7 +26,8 @@ class PaymentController extends GetxController {
final formKey = GlobalKey<FormState>();
final promo = TextEditingController();
final walletphoneController = TextEditingController();
double totalPassenger = Get.find<RideLifecycleController>().totalPassenger;
double totalPassenger = double.parse(
Get.find<RideLifecycleController>().totalPassenger.toString());
int? selectedAmount = 0;
List<dynamic> totalPassengerWalletDetails = [];
String passengerTotalWalletAmount = '';
@@ -67,6 +60,20 @@ class PaymentController extends GetxController {
}
String paymentToken = '';
Future<void> addPassengersWallet(String amount) async {
try {
await CRUD().postWallet(link: AppLink.addPassengersWallet, payload: {
'passenger_id': box.read(BoxName.passengerID).toString(),
'amount': amount,
});
await getPassengerWallet();
} catch (e) {
Log.print(e.toString());
}
}
Future<String> generateTokenPassenger(String amount) async {
var res =
await CRUD().post(link: AppLink.addPaymentTokenPassenger, payload: {
@@ -86,27 +93,8 @@ class PaymentController extends GetxController {
return d['message'];
}
Future addSeferWallet(String paymentMethod, point) async {
var seferToken = await generateTokenPassenger(point);
await CRUD().postWallet(link: AppLink.addSeferWallet, payload: {
'amount': point.toString(),
'paymentMethod': paymentMethod,
'passengerId': box.read(BoxName.passengerID).toString(),
'token': seferToken,
'driverId': 'passenger',
});
}
Future addPassengersWallet(String point) async {
var token = await generateTokenPassenger(point);
await CRUD().postWallet(link: AppLink.addPassengersWallet, payload: {
'passenger_id': box.read(BoxName.passengerID).toString(),
'balance': point,
'token': token,
});
}
payToDriverForCancelAfterAppliedAndHeNearYou(String rideId) async {
Future<void> payToDriverForCancelAfterAppliedAndHeNearYou(
String rideId) async {
{
double costOfWaiting5Minute = box.read(BoxName.countryCode) == 'Egypt'
? (4 * .08) + (5 * 1)
@@ -135,14 +123,6 @@ class PaymentController extends GetxController {
});
if (res != 'failure') {
// Get.find<FirebaseMessagesController>().sendNotificationToDriverMAP(
// 'Cancel',
// 'Trip Cancelled. The cost of the trip will be added to your wallet.'
// .tr,
// Get.find<RideLifecycleController>().driverToken,
// [],
// 'cancel',
// );
await NotificationService.sendNotification(
category: 'Cancel',
target: Get.find<RideLifecycleController>().driverToken.toString(),
@@ -157,7 +137,7 @@ class PaymentController extends GetxController {
}
var paymentTokenWaitPassenger1 =
await generateTokenPassenger((costOfWaiting5Minute * -1).toString());
await CRUD().post(link: AppLink.addPassengersWallet, payload: {
await CRUD().postWallet(link: AppLink.addPassengersWallet, payload: {
'passenger_id': box.read(BoxName.passengerID).toString(),
'balance': (costOfWaiting5Minute * -1).toString(),
'token': paymentTokenWaitPassenger1,
@@ -166,27 +146,6 @@ class PaymentController extends GetxController {
}
}
addPassengerWallet() async {
isLoading = true;
update();
await addSeferWallet('visa-in', selectedAmount.toString());
await addPassengersWallet(selectedAmount == 100
? '100'
: selectedAmount == 200
? '215'
: selectedAmount == 400
? '450'
: selectedAmount == 1000
? '1140'
: '0');
// getPassengerWallet();
isLoading = false;
update();
}
void onChangedPaymentMethodWallet(bool? value) {
if (box.read(BoxName.passengerWalletTotal) == null ||
double.parse(box.read(BoxName.passengerWalletTotal).toString()) <
@@ -215,28 +174,6 @@ class PaymentController extends GetxController {
}
}
void applyPromoCodeToPassenger() async {
//TAWJIHI
CRUD().get(link: AppLink.getPassengersPromo, payload: {
'promo_code': promo.text,
}).then((value) {
var decod = jsonDecode(value);
if (decod["status"] == "success") {
var firstElement = decod["message"][0];
totalPassenger = totalPassenger -
(totalPassenger * int.parse(firstElement['amount']));
Get.find<RideLifecycleController>().promoTaken = true;
update();
}
});
}
// 'https://accept.paymob.com/unifiedcheckout/?publicKey=egy_pk_live_mbjDC9Ni6FSHKmsz8sOHiVk2xd7oWRve&clientSecret=egy_sk_live_c0904e9cf04506ae64f818d4e075b4a957e3713fdf7a22cb7da30a29e72442b5'
// أضف هذا الرابط إلى ملف AppLink الخاص بك
// هذه هي الدالة الجديدة التي ستستخدمها لبدء الدفع
Future<void> payWithEcash(BuildContext context, String amount) async {
try {
// 1. يمكنك استخدام نفس طريقة التحقق بالبصمة إذا أردت
@@ -293,225 +230,6 @@ class PaymentController extends GetxController {
}
}
// Future<void> payWithEcashDriver(BuildContext context, String amount) async {
// try {
// // يمكنك استخدام نفس طريقة التحقق بالبصمة إذا أردت
// bool isAvailable = await LocalAuthentication().isDeviceSupported();
// if (isAvailable) {
// bool didAuthenticate = await LocalAuthentication().authenticate(
// localizedReason: 'Use Touch ID or Face ID to confirm payment'.tr,
// );
// if (didAuthenticate) {
// // استدعاء الـ Endpoint الجديد على السيرفر الخاص بك
// var res = await CRUD().postWallet(
// link: AppLink.payWithEcashPassenger,
// // link:
// // 'https://wl.tripz-egypt.com/v1/main/ride/ecash/driver/payWithEcash.php',
// payload: {
// // أرسل البيانات التي يحتاجها السيرفر
// "amount": amount,
// // "driverId": box.read(BoxName.driverID), // تأكد من وجود هذا المتغير
// "passengerId":
// box.read(BoxName.passengerID), // تأكد من وجود هذا المتغير
// },
// );
// // التأكد من أن السيرفر أعاد رابط الدفع بنجاح
// if (res != null &&
// res['status'] == 'success' &&
// res['message'] != null) {
// final String paymentUrl = res['message'];
// // الانتقال إلى شاشة الدفع الجديدة الخاصة بـ ecash للسائق
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) =>
// EcashDriverPaymentScreen(paymentUrl: paymentUrl),
// ),
// );
// } else {
// // عرض رسالة خطأ في حال فشل السيرفر في إنشاء الرابط
// Get.defaultDialog(
// title: 'Error'.tr,
// content: Text(
// 'Failed to initiate payment. Please try again.'.tr,
// style: AppStyle.title,
// ),
// );
// }
// }
// }
// } catch (e) {
// Get.defaultDialog(
// title: 'Error'.tr,
// content: Text(
// 'An error occurred during the payment process.'.tr,
// style: AppStyle.title,
// ),
// );
// }
// }
/// شاشة جديدة ومبسطة خاصة بدفع السائقين عبر ecash
// Future<void> payWithMTNWallet(
// BuildContext context, String amount, String currency) async {
// // خزن سياق علوي آمن من البداية
// final BuildContext safeContext =
// Get.overlayContext ?? Get.context ?? context;
// // سبينر تحميل
// if (!(Get.isDialogOpen ?? false)) {
// Get.dialog(const Center(child: CircularProgressIndicator()),
// barrierDismissible: false);
// }
// try {
// final phone = box.read(BoxName.phoneWallet) as String;
// final passengerID = box.read(BoxName.passengerID).toString();
// final formattedAmount = double.parse(amount).toStringAsFixed(0);
// Log.print("🚀 بدء عملية دفع MTN");
// Log.print(
// "📦 Payload: passengerID: $passengerID, amount: $formattedAmount, phone: $phone");
// // التحقق بالبصمة (اختياري) + حماية من الـ await
// final localAuth = LocalAuthentication();
// final isAuthSupported = await localAuth.isDeviceSupported();
// if (isAuthSupported) {
// final didAuth = await localAuth.authenticate(
// localizedReason: 'استخدم بصمة الإصبع أو الوجه لتأكيد الدفع',
// );
// if (!didAuth) {
// if (Get.isDialogOpen == true) Get.back();
// Log.print("❌ المستخدم لم يؤكد بالبصمة/الوجه");
// return;
// }
// }
// // 1) بدء الدفع
// final responseData = await CRUD().postWalletMtn(
// link: AppLink.payWithMTNStart,
// payload: {
// "amount": formattedAmount,
// "passengerId": passengerID,
// "phone": phone,
// "lang": box.read(BoxName.lang) ?? 'ar',
// },
// );
// // Log.print("✅ استجابة الخادم (mtn_start_payment.php):");
// // Log.print(responseData);
// Log.print('responseData: ${responseData}');
// // فحص الاستجابة بقوة
// late final Map<String, dynamic> startRes;
// if (responseData is Map<String, dynamic>) {
// startRes = responseData;
// } else if (responseData is String) {
// startRes = json.decode(responseData) as Map<String, dynamic>;
// } else {
// throw Exception("تم استلام نوع بيانات غير متوقع من الخادم.");
// }
// if (startRes['status'] != 'success') {
// final errorMsg = startRes['message']['Error']?.toString().tr ??
// "فشل بدء عملية الدفع. حاول مرة أخرى.";
// throw Exception(errorMsg);
// }
// final messageData = startRes["message"] as Map<String, dynamic>;
// final invoiceNumber = messageData["invoiceNumber"].toString();
// final operationNumber = messageData["operationNumber"].toString();
// final guid = messageData["guid"].toString();
// // Log.print(
// // "📄 invoiceNumber: $invoiceNumber, 🔢 operationNumber: $operationNumber, 🧭 guid: $guid");
// // أغلق السبينر قبل إظهار حوار OTP
// if (Get.isDialogOpen == true) Get.back();
// // 2) إدخال OTP بـ Get.defaultDialog (لا يستخدم context قابل للتلف)
// String otpInput = "";
// await Get.defaultDialog(
// title: "أدخل كود التحقق",
// barrierDismissible: false,
// content: TextField(
// keyboardType: TextInputType.number,
// decoration: const InputDecoration(hintText: "كود OTP"),
// onChanged: (v) => otpInput = v,
// ),
// confirm: TextButton(
// onPressed: () {
// if (otpInput.isEmpty ||
// otpInput.length < 4 ||
// otpInput.length > 8) {
// Get.snackbar("تنبيه", "أدخل كود OTP صحيح (48 أرقام)");
// return;
// }
// Get.back(result: otpInput);
// },
// child: const Text("تأكيد"),
// ),
// cancel: TextButton(
// onPressed: () => Get.back(result: null),
// child: const Text("إلغاء"),
// ),
// ).then((res) => otpInput = (res ?? "") as String);
// if (otpInput.isEmpty) {
// Log.print("❌ لم يتم إدخال OTP");
// return;
// }
// Log.print("🔐 تم إدخال OTP: $otpInput");
// // سبينر أثناء التأكيد
// Get.dialog(const Center(child: CircularProgressIndicator()),
// barrierDismissible: false);
// // 3) تأكيد الدفع
// final confirmRes = await CRUD().postWalletMtn(
// link: AppLink.payWithMTNConfirm,
// payload: {
// "invoiceNumber": invoiceNumber,
// "operationNumber": operationNumber,
// "guid": guid,
// "otp": otpInput,
// "phone": phone,
// "lang": box.read(BoxName.lang) ?? 'ar',
// },
// );
// if (Get.isDialogOpen == true) Get.back();
// // Log.print("✅ استجابة mtn_confirm.php:");
// // Log.print('confirmRes: ${confirmRes}');
// final ok = (confirmRes is Map && confirmRes['status'] == 'success');
// if (ok) {
// Get.defaultDialog(
// title: "✅ نجاح",
// content: const Text("تمت عملية الدفع وإضافة الرصيد إلى محفظتك."),
// );
// await getPassengerWallet();
// } else {
// final errorMsg = (confirmRes['message']['message']?.toString()) ??
// "فشل في تأكيد الدفع";
// Get.defaultDialog(title: "❌ فشل", content: Text(errorMsg.tr));
// }
// } catch (e, s) {
// Log.print("🔥 خطأ أثناء الدفع عبر MTN:");
// Log.print(e);
// Log.print(s);
// if (Get.isDialogOpen == true) Get.back();
// Get.defaultDialog(
// title: 'حدث خطأ',
// content: Text(e.toString().replaceFirst("Exception: ", "")),
// );
// }
// }
Future<void> payWithSyriaTelWallet(String amount, String currency) async {
// helper لفتح لودينغ بأمان
Future<void> _showLoading() async {
@@ -661,6 +379,104 @@ class PaymentController extends GetxController {
}
}
Future<void> payWithMTNWallet(BuildContext context, String amount, String currency) async {
try {
final phone = walletphoneController.text.trim();
if (phone.isEmpty) {
Get.defaultDialog(title: 'Error'.tr, content: Text('Please enter phone number'.tr));
return;
}
Get.dialog(const Center(child: CircularProgressIndicator()), barrierDismissible: false);
var res = await CRUD().postWalletMtn(
link: AppLink.createMtnInvoice,
payload: {
"amount": amount,
"user_id": box.read(BoxName.passengerID).toString(),
"user_type": "passenger",
"mtn_phone": phone,
},
);
Get.back(); // close loading
late final Map<String, dynamic> resMap;
if (res is Map<String, dynamic>) {
resMap = res;
} else if (res is String) {
resMap = json.decode(res) as Map<String, dynamic>;
} else {
throw Exception("Unexpected response type");
}
if (resMap['status'] == 'success') {
Get.to(() => PaymentScreenMtn(
invoiceNumber: resMap['invoice_number'],
mtnNumber: resMap['mtn_payment_number'] ?? '---',
amount: double.parse(amount),
));
} else {
Get.defaultDialog(
title: 'Error'.tr,
content: Text(resMap['message']?.toString() ?? 'Failed to create invoice'.tr),
);
}
} catch (e) {
if (Get.isDialogOpen ?? false) Get.back();
Get.defaultDialog(title: 'Error'.tr, content: Text(e.toString()));
}
}
Future<void> payWithClickWallet(BuildContext context, String amount, String currency) async {
try {
final phone = walletphoneController.text.trim();
if (phone.isEmpty) {
Get.defaultDialog(title: 'Error'.tr, content: Text('Please enter phone number'.tr));
return;
}
Get.dialog(const Center(child: CircularProgressIndicator()), barrierDismissible: false);
var res = await CRUD().postWalletMtn(
link: AppLink.createCliqInvoice,
payload: {
"amount": amount,
"user_id": box.read(BoxName.passengerID).toString(),
"user_type": "passenger",
"click_phone": phone,
},
);
Get.back(); // close loading
late final Map<String, dynamic> resMap;
if (res is Map<String, dynamic>) {
resMap = res;
} else if (res is String) {
resMap = json.decode(res) as Map<String, dynamic>;
} else {
throw Exception("Unexpected response type");
}
if (resMap['status'] == 'success') {
Get.to(() => PaymentScreenCliq(
invoiceNumber: resMap['invoice_number'],
cliqAlias: resMap['cliq_alias'] ?? '---',
amount: double.parse(amount),
));
} else {
Get.defaultDialog(
title: 'Error'.tr,
content: Text(resMap['message']?.toString() ?? 'Failed to create invoice'.tr),
);
}
} catch (e) {
if (Get.isDialogOpen ?? false) Get.back();
Get.defaultDialog(title: 'Error'.tr, content: Text(e.toString()));
}
}
@override
void onInit() {
timestamp = now.millisecondsSinceEpoch;

View File

@@ -45,30 +45,16 @@ class RateController extends GetxController {
confirm: MyElevatedButton(title: 'Ok', onPressed: () => Get.back()));
} else if (Get.find<PaymentController>().isWalletChecked == true) {
double tip = 0;
tip = (Get.find<RideLifecycleController>().totalPassenger) *
tip = double.parse(Get.find<RideLifecycleController>().totalPassenger.toString()) *
(double.parse(box.read(BoxName.tipPercentage).toString()));
if (tip > 0) {
var res = await CRUD().post(link: AppLink.addTips, payload: {
'passengerID': box.read(BoxName.passengerID),
'passengerID': box.read(BoxName.passengerID).toString(),
'driverID': Get.find<RideLifecycleController>().driverId.toString(),
'rideID': Get.find<RideLifecycleController>().rideId.toString(),
'tipAmount': tip.toString(),
});
await Get.find<PaymentController>()
.addPassengersWallet(((-1) * tip).toString());
var token1 = await Get.find<PaymentController>().generateTokenDriver(
box.read(BoxName.countryCode) == 'Egypt'
? tip.toStringAsFixed(0)
: (tip * 100).toString());
await CRUD().postWallet(link: AppLink.addDriversWalletPoints, payload: {
'driverID': Get.find<RideLifecycleController>().driverId.toString(),
'paymentID': '${Get.find<RideLifecycleController>().rideId}tip',
'amount': box.read(BoxName.countryCode) == 'Egypt'
? tip.toStringAsFixed(0)
: (tip * 100).toString(),
'paymentMethod': 'visa-tip',
'token': token1,
'country_code': box.read(BoxName.countryCode).toString(),
});
if (res != 'failure') {
await NotificationService.sendNotification(
@@ -76,7 +62,7 @@ class RateController extends GetxController {
target: Get.find<RideLifecycleController>().driverToken.toString(),
title: 'You Have Tips'.tr,
body:
'${'${tip.toString()}\$${' tips\nTotal is'.tr}'} ${tip + (Get.find<RideLifecycleController>().totalPassenger)}',
'${'${tip.toString()}\$${' tips\nTotal is'.tr}'} ${tip + double.parse(Get.find<RideLifecycleController>().totalPassenger.toString())}',
isTopic: false, // Important: this is a token
tone: 'ding',
driverList: [],

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,9 @@ import 'package:siro_rider/controller/auth/login_controller.dart';
import '../../constant/colors.dart';
import '../../controller/auth/otp_controller.dart';
import '../../controller/local/phone_intel/intl_phone_field.dart';
import '../../controller/functions/country_logic.dart';
import '../../constant/box_name.dart';
import '../../main.dart';
// ─────────────────────────────────────────────────────────────────────────────
// SHARED DESIGN TOKENS
@@ -485,7 +488,7 @@ class _PhoneNumberScreenState extends State<PhoneNumberScreen> {
const BorderSide(color: Color(0xFFEF4444), width: 1.5),
),
),
initialCountryCode: 'SY',
initialCountryCode: CountryLogic.getCountryPrefix(box.read(BoxName.countryCode) ?? 'Syria'),
onChanged: (phone) {
_phoneController.text = phone.completeNumber;
},

View File

@@ -9,6 +9,9 @@ import 'package:get/get.dart';
import '../../controller/local/phone_intel/intl_phone_field.dart';
import '../../print.dart';
import '../widgets/mycircular.dart';
import '../../controller/functions/country_logic.dart';
import '../../../constant/box_name.dart';
import '../../../main.dart';
// import 'package:intl_phone_field/intl_phone_field.dart';
class SmsSignupEgypt extends StatelessWidget {
@@ -52,7 +55,7 @@ class SmsSignupEgypt extends StatelessWidget {
borderSide: BorderSide(),
),
),
initialCountryCode: 'EG',
initialCountryCode: CountryLogic.getCountryPrefix(box.read(BoxName.countryCode) ?? 'Syria'),
onChanged: (phone) {
// Properly concatenate country code and number
registerController.phoneController.text =

View File

@@ -1,3 +1,4 @@
import 'package:siro_rider/constant/currency.dart';
import 'package:siro_rider/constant/colors.dart';
import 'package:siro_rider/constant/links.dart';
import 'package:siro_rider/constant/style.dart';
@@ -188,7 +189,7 @@ class ApplyOrderWidget extends StatelessWidget {
),
),
Text(
'SYP'.tr,
CurrencyHelper.currency,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,

View File

@@ -551,7 +551,7 @@ class Details extends StatelessWidget {
],
),
Text(
'Cost for passenger ${controller.totalPassenger.toStringAsFixed(2)} ',
'Cost for passenger ${double.parse(controller.totalPassenger.toString()).toStringAsFixed(2)} ',
style: AppStyle.title,
),
],

View File

@@ -1,4 +1,6 @@
import 'package:siro_rider/constant/currency.dart';
import 'package:flutter/material.dart';
import 'package:siro_rider/controller/home/map/map_engine_controller.dart';
import 'package:get/get.dart';
import 'package:siro_rider/constant/box_name.dart';
import 'package:siro_rider/constant/colors.dart';
@@ -245,7 +247,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
borderRadius: BorderRadius.circular(20),
),
child: Text(
'${_getPassengerPriceText(carTypes[controller.selectedIndex], controller)} ${'SYP'.tr}',
'${_getPassengerPriceText(carTypes[controller.selectedIndex], controller)} ${CurrencyHelper.currency}',
style: const TextStyle(
color: Colors.white,
fontSize: 13,
@@ -413,7 +415,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
),
child: FittedBox(
child: Text(
'${_getPassengerPriceText(carType, controller)} ${'SYP'.tr}',
'${_getPassengerPriceText(carType, controller)} ${CurrencyHelper.currency}',
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.w700,
@@ -537,7 +539,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
const SizedBox(width: 10),
Expanded(
child: Text(
'${'You have a negative balance of'.tr} ${passengerWallet.toStringAsFixed(2)} ${'SYP'.tr}.',
'${'You have a negative balance of'.tr} ${passengerWallet.toStringAsFixed(2)} ${CurrencyHelper.currency}.',
style: TextStyle(
color: Colors.red.shade800,
fontWeight: FontWeight.w600,
@@ -557,7 +559,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
// ═══════════════════════════════════════════════════════════════════════════
String _getPassengerPriceText(
CarType carType, RideLifecycleController mapPassengerController) {
double rawPrice;
String rawPrice;
switch (carType.carType) {
case 'Comfort':
rawPrice = mapPassengerController.totalPassengerComfort;
@@ -587,9 +589,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
default:
return '...';
}
final int roundedPrice = rawPrice.round();
final formatter = NumberFormat.decimalPattern();
return formatter.format(roundedPrice);
return rawPrice;
}
// ═══════════════════════════════════════════════════════════════════════════
@@ -743,7 +743,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
borderRadius: BorderRadius.circular(20),
),
child: Text(
'${_getPassengerPriceText(carType, mapPassengerController)} ${'SYP'.tr}',
'${_getPassengerPriceText(carType, mapPassengerController)} ${CurrencyHelper.currency}',
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w800,
@@ -931,7 +931,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
}
}
double _getOriginalPrice(
String _getOriginalPrice(
CarType carType, RideLifecycleController mapPassengerController) {
switch (carType.carType) {
case 'Comfort':
@@ -947,15 +947,11 @@ class CarDetailsTypeToChoose extends StatelessWidget {
case 'Lady':
return mapPassengerController.totalPassengerLady;
default:
return 0.0;
return '0';
}
}
Widget _buildRayehGaiOption(
BuildContext context,
RideLifecycleController mapPassengerController,
String carTypeName,
double price) {
Widget _buildRayehGaiOption(BuildContext context, RideLifecycleController mapPassengerController, String carTypeName, String price) {
return GestureDetector(
onTap: () {
Navigator.of(context).pop();
@@ -969,7 +965,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
padding: const EdgeInsets.all(8.0),
child: Column(children: [
Text(carTypeName.tr),
Text(price.toStringAsFixed(0))
Text(double.parse(price).toStringAsFixed(0))
])),
);
}
@@ -1031,7 +1027,7 @@ class BurcMoney extends StatelessWidget {
),
TextSpan(
text:
'${'You have a balance of'.tr} ${passengerWallet.toStringAsFixed(2)} ${box.read(BoxName.countryCode) == 'Egypt' ? 'LE'.tr : 'SYP'.tr} ${'due to a previous trip.'.tr}',
'${'You have a balance of'.tr} ${passengerWallet.toStringAsFixed(2)} ${box.read(BoxName.countryCode) == 'Egypt' ? 'LE'.tr : CurrencyHelper.currency} ${'due to a previous trip.'.tr}',
style: AppStyle.subtitle.copyWith(
color: Colors.white,
),

View File

@@ -1,3 +1,4 @@
import 'package:siro_rider/constant/currency.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:siro_rider/constant/box_name.dart';
@@ -80,7 +81,7 @@ class CashConfirmPageShown extends StatelessWidget {
icon: Icons.account_balance_wallet_outlined,
title: '${AppInformation.appName} Balance'.tr,
subtitle:
'${'Balance:'.tr} ${box.read(BoxName.passengerWalletTotal) ?? '0.0'} ${'SYP'.tr}',
'${'Balance:'.tr} ${box.read(BoxName.passengerWalletTotal) ?? '0.0'} ${CurrencyHelper.currency}',
isSelected: paymentCtrl.isWalletChecked,
selectedColor: selectedColor,
onTap: () =>
@@ -107,7 +108,7 @@ class CashConfirmPageShown extends StatelessWidget {
final bool isWalletSufficient = (double.tryParse(
box.read(BoxName.passengerWalletTotal) ?? '0') ??
0) >=
controller.totalPassenger;
double.parse(controller.totalPassenger.toString());
// إذا تم اختيار المحفظة والرصيد غير كافٍ
if (paymentCtrl.isWalletChecked && !isWalletSufficient) {

View File

@@ -1,3 +1,4 @@
import 'package:siro_rider/constant/currency.dart';
import 'package:flutter/material.dart';
import 'package:flutter_font_icons/flutter_font_icons.dart';
import 'package:get/get.dart';
@@ -7,7 +8,7 @@ import 'package:intl/intl.dart';
import '../../../constant/box_name.dart';
import '../../../constant/colors.dart';
import '../../../constant/links.dart';
import '../../../constant/style.dart';
import 'package:siro_rider/controller/functions/country_logic.dart';
import '../../../controller/functions/audio_record1.dart';
import '../../../controller/functions/launch.dart';
import '../../../controller/functions/toast.dart';
@@ -17,6 +18,7 @@ import '../../../controller/home/map/ride_state.dart';
import '../../../controller/profile/profile_controller.dart';
import '../../../main.dart';
import '../../../views/home/profile/complaint_page.dart';
import '../../../controller/functions/country_logic.dart';
class RideBeginPassenger extends StatelessWidget {
const RideBeginPassenger({super.key});
@@ -115,7 +117,8 @@ class RideBeginPassenger extends StatelessWidget {
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: AppColor.primaryColor.withValues(alpha: 0.5), width: 1.5),
color: AppColor.primaryColor.withValues(alpha: 0.5),
width: 1.5),
),
child: CircleAvatar(
radius: 24,
@@ -207,7 +210,7 @@ class RideBeginPassenger extends StatelessWidget {
color: AppColor.primaryColor,
),
),
Text('SYP',
Text(CurrencyHelper.currency,
style: TextStyle(fontSize: 9, color: AppColor.grayColor)),
],
),
@@ -240,7 +243,8 @@ class RideBeginPassenger extends StatelessWidget {
box.write(BoxName.sosPhonePassenger,
profileController.prfoileData['sosPhone']);
} else {
makePhoneCall('112');
makePhoneCall(CountryLogic.getEmergencyNumber(
box.read(BoxName.countryCode) ?? 'Syria'));
}
},
),
@@ -255,13 +259,12 @@ class RideBeginPassenger extends StatelessWidget {
// لا يوجد رقم طوارئ — نعرض الديالوج لإدخاله
await uiController.shareTripWithFamily();
} else {
final formattedPhone = uiController.formatSyrianPhoneNumber(
phone.toString());
final formattedPhone =
CountryLogic.formatCurrentCountryPhone(phone.toString());
uiController.sendWhatsapp(formattedPhone);
}
},
),
_compactBtn(
icon: Icons.share,
label: 'Share'.tr,
@@ -287,12 +290,14 @@ class RideBeginPassenger extends StatelessWidget {
if (!audioCtx.isRecording) {
await audioCtx.startRecording(rideId: controller.rideId);
if (context.mounted) {
Toast.show(context, 'Start Record'.tr, AppColor.greenColor);
Toast.show(
context, 'Start Record'.tr, AppColor.greenColor);
}
} else {
await audioCtx.stopRecording();
if (context.mounted) {
Toast.show(context, 'Record saved'.tr, AppColor.greenColor);
Toast.show(
context, 'Record saved'.tr, AppColor.greenColor);
}
}
},

View File

@@ -1,7 +1,9 @@
import 'package:siro_rider/constant/currency.dart';
import 'package:siro_rider/controller/functions/launch.dart';
import 'package:flutter/material.dart';
import 'package:flutter_font_icons/flutter_font_icons.dart';
import 'package:get/get.dart';
import '../../../controller/functions/country_logic.dart';
// ... استيراد ملفاتك الأخرى ...
import '../../../constant/box_name.dart';
@@ -38,7 +40,7 @@ class RideFromStartApp extends StatelessWidget {
final driverName = rideData['driverName'] ?? 'Captain'.tr;
final driverRate = controller.driverRate;
final carType = rideData['carType'] ?? 'Car'.tr;
final carModel = controller.model ?? '';
final carModel = controller.model;
final arrivalTime = box.read(BoxName.arrivalTime) ?? '--:--';
// تحديد البيانات للعرض
@@ -177,7 +179,7 @@ class RideFromStartApp extends StatelessWidget {
"Distance".tr),
_buildVerticalDivider(),
_buildInfoColumn(
Icons.attach_money, "$displayPrice SYP", "Price".tr),
Icons.attach_money, "$displayPrice ${CurrencyHelper.currency}", "Price".tr),
],
),
),
@@ -213,7 +215,7 @@ class RideFromStartApp extends StatelessWidget {
flex: 1,
child: ElevatedButton.icon(
onPressed: () =>
makePhoneCall(box.read(BoxName.sosPhonePassenger)),
makePhoneCall(CountryLogic.getEmergencyNumber(box.read(BoxName.countryCode) ?? 'Syria')),
icon: const Icon(Icons.sos, color: Colors.white),
label: Text("SOS".tr,
style: const TextStyle(color: Colors.white)),

View File

@@ -14,6 +14,7 @@ import '../../../controller/functions/launch.dart';
import '../../../controller/functions/toast.dart';
import '../../../controller/home/map/ride_lifecycle_controller.dart';
import '../../../controller/home/map/ui_interactions_controller.dart';
import '../../../controller/functions/country_logic.dart';
class VipRideBeginPassenger extends StatelessWidget {
const VipRideBeginPassenger({
@@ -196,7 +197,7 @@ class VipRideBeginPassenger extends StatelessWidget {
profileController.prfoileData['sosPhone']);
}
} else {
makePhoneCall('122');
makePhoneCall(CountryLogic.getEmergencyNumber(box.read(BoxName.countryCode) ?? 'Syria'));
// box.read(BoxName.sosPhonePassenger));
}
},

View File

@@ -1,3 +1,4 @@
import 'package:siro_rider/constant/currency.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
@@ -153,7 +154,7 @@ class PassengerWallet extends StatelessWidget {
.copyWith(color: Colors.white.withOpacity(0.7)),
),
Text(
'${box.read(BoxName.passengerWalletTotal) ?? '0.0'} ${'SYP'.tr}',
'${box.read(BoxName.passengerWalletTotal) ?? '0.0'} ${CurrencyHelper.currency}',
style: AppStyle.headTitle2.copyWith(
color: Colors.white,
fontSize: 28,

View File

@@ -1,6 +1,7 @@
import 'package:siro_rider/constant/currency.dart';
import 'package:siro_rider/print.dart';
import 'package:siro_rider/constant/style.dart';
import 'package:siro_rider/controller/functions/encrypt_decrypt.dart';
// import 'package:siro_rider/controller/functions/encrypt_decrypt.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
@@ -42,7 +43,7 @@ class PassengerWalletDialog extends StatelessWidget {
child: Text(
box.read(BoxName.countryCode) == 'Syria'
? '10000 ${'LE'.tr}'
: '10 ${'SYP'.tr}',
: '10 ${CurrencyHelper.currency}',
),
),
CupertinoActionSheetAction(
@@ -55,7 +56,7 @@ class PassengerWalletDialog extends StatelessWidget {
child: Text(
box.read(BoxName.countryCode) == 'Syria'
? '20000 ${'LE'.tr} = 2050 ${'LE'.tr}'
: '20 ${'SYP'.tr}',
: '20 ${CurrencyHelper.currency}',
),
),
CupertinoActionSheetAction(
@@ -68,7 +69,7 @@ class PassengerWalletDialog extends StatelessWidget {
child: Text(
box.read(BoxName.countryCode) == 'Syria'
? '40000 ${'LE'.tr} = 4150 ${'LE'.tr}'
: '40 ${'SYP'.tr}',
: '40 ${CurrencyHelper.currency}',
),
),
CupertinoActionSheetAction(
@@ -81,7 +82,7 @@ class PassengerWalletDialog extends StatelessWidget {
child: Text(
box.read(BoxName.countryCode) == 'Syria'
? '100000 ${'LE'.tr} = 11000 ${'LE'.tr}'
: '50 ${'SYP'.tr}',
: '50 ${CurrencyHelper.currency}',
),
),
],
@@ -130,10 +131,10 @@ void showPaymentBottomSheet(BuildContext context) {
borderRadius: BorderRadius.vertical(top: Radius.circular(15.0)),
),
builder: (BuildContext context) {
return WillPopScope(
onWillPop: () async {
return PopScope(
canPop: true,
onPopInvokedWithResult: (didPop, result) async {
Get.back();
return false;
},
child: Container(
padding: const EdgeInsets.all(16.0),
@@ -154,7 +155,7 @@ void showPaymentBottomSheet(BuildContext context) {
controller: controller,
amount: 500,
bonusAmount: 30,
currency: 'SYP'.tr,
currency: CurrencyHelper.currency,
),
const SizedBox(height: 8.0),
@@ -163,7 +164,7 @@ void showPaymentBottomSheet(BuildContext context) {
controller: controller,
amount: 1000,
bonusAmount: 70,
currency: 'SYP'.tr,
currency: CurrencyHelper.currency,
),
const SizedBox(height: 8.0),
@@ -172,7 +173,7 @@ void showPaymentBottomSheet(BuildContext context) {
controller: controller,
amount: 2000,
bonusAmount: 180,
currency: 'SYP'.tr,
currency: CurrencyHelper.currency,
),
const SizedBox(height: 8.0),
@@ -181,7 +182,7 @@ void showPaymentBottomSheet(BuildContext context) {
controller: controller,
amount: 5000,
bonusAmount: 700,
currency: 'SYP'.tr,
currency: CurrencyHelper.currency,
),
const SizedBox(height: 16.0),
@@ -266,7 +267,7 @@ void showPaymentOptions(BuildContext context, PaymentController controller) {
// controller.payWithMTNWallet(
// context,
// controller.selectedAmount.toString(),
// 'SYP',
// CurrencyHelper.currency,
// );
// await controller.getPassengerWallet();
// controller.isLoading = false;
@@ -331,148 +332,215 @@ void showPaymentOptions(BuildContext context, PaymentController controller) {
// Get.back();
// Get.defaultDialog(
// barrierDismissible: false,
// title: 'Insert Wallet phone number'.tr,
// content: Form(
// key: controller.formKey,
// child: MyTextForm(
// controller: controller.walletphoneController,
// label: 'Insert Wallet phone number'.tr,
// hint: '963941234567',
// type: TextInputType.phone)),
// confirm: MyElevatedButton(
// title: 'OK'.tr,
// onPressed: () async {
// Get.back();
// if (controller.formKey.currentState!.validate()) {
// if (controller.selectedAmount != 0) {
// controller.isLoading = true;
// controller.update();
// box.write(BoxName.phoneWallet,
// (controller.walletphoneController.text));
// Get.back();
// await controller.payWithMTNWallet(
// context,
// controller.selectedAmount.toString(),
// 'SYP',
// );
// await controller.getPassengerWallet();
// controller.isLoading = false;
// controller.update();
// } else {
// Toast.show(
// context,
// '⚠️ You need to choose an amount!'.tr,
// AppColor.redColor,
// );
// }
// }
// }));
// },
// child: Padding(
// padding: const EdgeInsets.all(8.0),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Text(
// 'Pay by MTN Wallet'.tr,
// style: AppStyle.title,
// ),
// const SizedBox(width: 10),
// Image.asset(
// 'assets/images/cashMTN.png',
// width: 70,
// height: 70,
// fit: BoxFit.contain,
// ),
// ],
// ),
// )),
if (box.read(BoxName.countryCode) == 'Syria')
GestureDetector(
onTap: () async {
Get.back();
Get.defaultDialog(
barrierDismissible: false,
title: 'Insert Wallet phone number'.tr,
content: Form(
key: controller.formKey,
child: MyTextForm(
controller: controller.walletphoneController,
label: 'Insert Wallet phone number'.tr,
hint: '963941234567',
type: TextInputType.phone)),
confirm: MyElevatedButton(
title: 'OK'.tr,
onPressed: () async {
Get.back();
if (controller.formKey.currentState!.validate()) {
if (controller.selectedAmount != 0) {
controller.isLoading = true;
controller.update();
box.write(BoxName.phoneWallet,
(controller.walletphoneController.text));
await controller.payWithMTNWallet(
context,
controller.selectedAmount.toString(),
CurrencyHelper.currency,
);
await controller.getPassengerWallet();
GestureDetector(
onTap: () async {
Get.back();
Get.defaultDialog(
barrierDismissible: false,
title: 'Insert Wallet phone number'.tr,
content: Form(
key: controller.formKey,
child: MyTextForm(
controller: controller.walletphoneController,
label: 'Insert Wallet phone number'.tr,
hint: '963941234567',
type: TextInputType.phone)),
confirm: MyElevatedButton(
title: 'OK'.tr,
onPressed: () async {
Get.back();
if (controller.formKey.currentState!.validate()) {
box.write(BoxName.phoneWallet,
controller.walletphoneController.text);
await controller.payWithSyriaTelWallet(
controller.selectedAmount.toString(), 'SYP');
}
}));
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Pay by Syriatel Wallet'.tr,
controller.isLoading = false;
controller.update();
} else {
Toast.show(
context,
'⚠️ You need to choose an amount!'.tr,
AppColor.redColor,
);
}
}
}));
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Pay by MTN Wallet'.tr,
style: AppStyle.title,
),
const SizedBox(width: 10),
Image.asset(
'assets/images/cashMTN.png',
width: 70,
height: 70,
fit: BoxFit.contain,
),
],
),
)),
if (box.read(BoxName.countryCode) == 'Jordan')
GestureDetector(
onTap: () async {
Get.back();
Get.defaultDialog(
barrierDismissible: false,
title: 'Insert Wallet phone number'.tr,
content: Form(
key: controller.formKey,
child: MyTextForm(
controller: controller.walletphoneController,
label: 'Insert Wallet phone number'.tr,
hint: '962791234567',
type: TextInputType.phone)),
confirm: MyElevatedButton(
title: 'OK'.tr,
onPressed: () async {
Get.back();
if (controller.formKey.currentState!.validate()) {
if (controller.selectedAmount != 0) {
controller.isLoading = true;
controller.update();
box.write(BoxName.phoneWallet,
(controller.walletphoneController.text));
await controller.payWithClickWallet(
context,
controller.selectedAmount.toString(),
CurrencyHelper.currency,
);
await controller.getPassengerWallet();
controller.isLoading = false;
controller.update();
} else {
Toast.show(
context,
'⚠️ You need to choose an amount!'.tr,
AppColor.redColor,
);
}
}
}));
},
child: Container(
margin: const EdgeInsets.only(top: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.transparent,
),
child: ListTile(
title: Text(
'Pay by Cliq'.tr,
style: AppStyle.title,
),
const SizedBox(width: 10),
Image.asset(
'assets/images/syriatel.png',
width: 70,
height: 70,
fit: BoxFit.fill,
),
],
),
)),
GestureDetector(
onTap: () async {
// التحقق بالبصمة قبل أي شيء
bool isAuthSupported =
await LocalAuthentication().isDeviceSupported();
trailing: const Icon(Icons.payment, size: 40, color: Colors.green),
),
)), if (box.read(BoxName.countryCode) == 'Syria')
GestureDetector(
onTap: () async {
Get.back();
Get.defaultDialog(
barrierDismissible: false,
title: 'Insert Wallet phone number'.tr,
content: Form(
key: controller.formKey,
child: MyTextForm(
controller: controller.walletphoneController,
label: 'Insert Wallet phone number'.tr,
hint: '963941234567',
type: TextInputType.phone)),
confirm: MyElevatedButton(
title: 'OK'.tr,
onPressed: () async {
Get.back();
if (controller.formKey.currentState!.validate()) {
box.write(BoxName.phoneWallet,
controller.walletphoneController.text);
await controller.payWithSyriaTelWallet(
controller.selectedAmount.toString(),
CurrencyHelper.currency);
}
}));
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Pay by Syriatel Wallet'.tr,
style: AppStyle.title,
),
const SizedBox(width: 10),
Image.asset(
'assets/images/syriatel.png',
width: 70,
height: 70,
fit: BoxFit.fill,
),
],
),
)),
if (box.read(BoxName.countryCode) == 'Syria')
GestureDetector(
onTap: () async {
// التحقق بالبصمة قبل أي شيء
bool isAuthSupported =
await LocalAuthentication().isDeviceSupported();
if (isAuthSupported) {
bool didAuthenticate = await LocalAuthentication().authenticate(
localizedReason: 'استخدم بصمة الإصبع أو الوجه لتأكيد الدفع',
);
if (isAuthSupported) {
bool didAuthenticate =
await LocalAuthentication().authenticate(
localizedReason: 'استخدم بصمة الإصبع أو الوجه لتأكيد الدفع',
);
if (!didAuthenticate) {
Log.print("❌ User did not authenticate with biometrics");
return;
if (!didAuthenticate) {
Log.print("❌ User did not authenticate with biometrics");
return;
}
}
}
// الانتقال مباشرة لإنشاء الفاتورة بعد النجاح بالبصمة
Get.to(() => PaymentScreenSmsProvider(
amount: double.parse(controller.selectedAmount.toString())));
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Pay by Sham Cash'.tr,
style: AppStyle.title,
),
const SizedBox(width: 10),
Image.asset(
'assets/images/shamCash.png',
width: 70,
height: 70,
fit: BoxFit.fill,
),
],
),
)),
// الانتقال مباشرة لإنشاء الفاتورة بعد النجاح بالبصمة
Get.to(() => PaymentScreenSmsProvider(
amount:
double.parse(controller.selectedAmount.toString())));
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Pay by Sham Cash'.tr,
style: AppStyle.title,
),
const SizedBox(width: 10),
Image.asset(
'assets/images/shamCash.png',
width: 70,
height: 70,
fit: BoxFit.fill,
),
],
),
)),
],
cancelButton: CupertinoActionSheetAction(
child: Text('Cancel'.tr),
@@ -483,4 +551,4 @@ void showPaymentOptions(BuildContext context, PaymentController controller) {
),
),
);
}
}

View File

@@ -0,0 +1,208 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import '../../../constant/links.dart';
import '../../../controller/functions/crud.dart';
class PaymentScreenCliq extends StatefulWidget {
final double amount;
final String invoiceNumber;
final String cliqAlias;
const PaymentScreenCliq({
Key? key,
required this.amount,
required this.invoiceNumber,
required this.cliqAlias,
}) : super(key: key);
@override
State<PaymentScreenCliq> createState() => _PaymentScreenCliqState();
}
class _PaymentScreenCliqState extends State<PaymentScreenCliq> with SingleTickerProviderStateMixin {
Timer? _pollingTimer;
String _status = 'waiting'; // waiting, uploading, verifying, success, error
final TextEditingController _proofController = TextEditingController();
late AnimationController _blinkController;
late Animation<Color?> _colorAnimation;
late Animation<double> _shadowAnimation;
@override
void initState() {
super.initState();
_blinkController = AnimationController(duration: const Duration(milliseconds: 800), vsync: this)..repeat(reverse: true);
_colorAnimation = ColorTween(begin: Colors.red.shade700, end: Colors.red.shade100).animate(_blinkController);
_shadowAnimation = Tween<double>(begin: 2.0, end: 15.0).animate(CurvedAnimation(parent: _blinkController, curve: Curves.easeInOut));
_startPolling();
}
@override
void dispose() {
_pollingTimer?.cancel();
_blinkController.dispose();
_proofController.dispose();
super.dispose();
}
void _startPolling() {
_pollingTimer = Timer.periodic(const Duration(seconds: 5), (timer) async {
if (_status == 'success' || _status == 'verifying') return;
try {
final res = await CRUD().postWallet(link: AppLink.checkCliqStatus, payload: {'invoice_number': widget.invoiceNumber});
if (res != 'failure' && res['status'] == 'success' && res['invoice_status'] == 'completed') {
timer.cancel();
if (mounted) setState(() => _status = 'success');
}
} catch (_) {}
});
}
Future<void> _submitProof() async {
if (_proofController.text.trim().isEmpty) {
Get.snackbar('Error'.tr, 'Please paste the transfer message'.tr, backgroundColor: Colors.red);
return;
}
setState(() => _status = 'verifying');
try {
final res = await CRUD().postWallet(link: AppLink.uploadCliqProof, payload: {
'invoice_number': widget.invoiceNumber,
'proof_text': _proofController.text.trim(),
});
if (res != 'failure' && res['status'] == 'success') {
if (mounted) setState(() => _status = 'success');
} else {
if (mounted) setState(() => _status = 'error');
Get.defaultDialog(title: 'Failed'.tr, content: Text(res['message']?.toString() ?? 'Verification failed'));
}
} catch (e) {
if (mounted) setState(() => _status = 'error');
Get.defaultDialog(title: 'Error'.tr, content: Text('Error uploading proof'.tr));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[50],
appBar: AppBar(title: const Text("Cliq Payment"), centerTitle: true, backgroundColor: Colors.white, foregroundColor: Colors.black),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: _status == 'success' ? _buildSuccessUI() : _buildWaitingUI(),
),
),
);
}
Widget _buildWaitingUI() {
final currencyFormat = NumberFormat.decimalPattern('ar_SY');
return SingleChildScrollView(
child: Column(
children: [
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 15),
decoration: BoxDecoration(gradient: LinearGradient(colors: [Colors.blue.shade800, Colors.blue.shade600]), borderRadius: BorderRadius.circular(16)),
child: Column(
children: [
const Text("المبلغ المطلوب", style: TextStyle(color: Colors.white70, fontSize: 14)),
const SizedBox(height: 5),
Text("${currencyFormat.format(widget.amount)} ل.س", style: const TextStyle(color: Colors.white, fontSize: 28, fontWeight: FontWeight.bold)),
],
),
),
const SizedBox(height: 25),
AnimatedBuilder(
animation: _blinkController,
builder: (context, child) {
return Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(16), border: Border.all(color: _colorAnimation.value ?? Colors.red, width: 3.0), boxShadow: [BoxShadow(color: (_colorAnimation.value ?? Colors.red).withOpacity(0.4), blurRadius: _shadowAnimation.value, spreadRadius: 2)]),
child: Column(
children: [
const Text("يرجى تحويل المبلغ إلى الاسم المستعار التالي (Alias):", textAlign: TextAlign.center, style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
const SizedBox(height: 15),
InkWell(
onTap: () {
Clipboard.setData(ClipboardData(text: widget.cliqAlias));
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: const Text("تم نسخ الاسم ✅", textAlign: TextAlign.center), backgroundColor: Colors.green.shade600));
},
child: Container(
padding: const EdgeInsets.all(15),
decoration: BoxDecoration(color: Colors.blue.shade50, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.blue.shade200)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(widget.cliqAlias, style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold, letterSpacing: 2.0)),
const Icon(Icons.copy, color: Colors.blue),
],
),
),
),
],
),
);
},
),
const SizedBox(height: 30),
const Text("بعد إتمام التحويل، يرجى نسخ رسالة البنك النصية ولصقها هنا للتحقق التلقائي:", textAlign: TextAlign.center, style: TextStyle(fontSize: 14)),
const SizedBox(height: 10),
TextField(
controller: _proofController,
maxLines: 4,
decoration: InputDecoration(
hintText: "قم بلصق نص رسالة التحويل هنا...",
border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)),
filled: true,
fillColor: Colors.white,
),
),
const SizedBox(height: 15),
SizedBox(
width: double.infinity,
height: 50,
child: ElevatedButton(
style: ElevatedButton.styleFrom(backgroundColor: Colors.blue.shade800, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12))),
onPressed: _status == 'verifying' ? null : _submitProof,
child: _status == 'verifying'
? const CircularProgressIndicator(color: Colors.white)
: const Text("تحقق من الدفع", style: TextStyle(fontSize: 18, color: Colors.white, fontWeight: FontWeight.bold)),
),
),
const SizedBox(height: 20),
const Text("جاري فحص الفاتورة تلقائياً كل 5 ثوانٍ...", style: TextStyle(color: Colors.grey, fontSize: 12)),
],
),
);
}
Widget _buildSuccessUI() {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.verified_rounded, color: Colors.green, size: 100),
const SizedBox(height: 20),
const Text("تم الدفع بنجاح!", style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
const SizedBox(height: 40),
SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(backgroundColor: Colors.green, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 16)),
onPressed: () { Get.back(); Get.back(); },
child: const Text("متابعة", style: TextStyle(fontSize: 18)),
),
),
],
);
}
}

View File

@@ -0,0 +1,208 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import '../../../constant/links.dart';
import '../../../controller/functions/crud.dart';
class PaymentScreenMtn extends StatefulWidget {
final double amount;
final String invoiceNumber;
final String mtnNumber;
const PaymentScreenMtn({
Key? key,
required this.amount,
required this.invoiceNumber,
required this.mtnNumber,
}) : super(key: key);
@override
State<PaymentScreenMtn> createState() => _PaymentScreenMtnState();
}
class _PaymentScreenMtnState extends State<PaymentScreenMtn> with SingleTickerProviderStateMixin {
Timer? _pollingTimer;
String _status = 'waiting'; // waiting, uploading, verifying, success, error
final TextEditingController _proofController = TextEditingController();
late AnimationController _blinkController;
late Animation<Color?> _colorAnimation;
late Animation<double> _shadowAnimation;
@override
void initState() {
super.initState();
_blinkController = AnimationController(duration: const Duration(milliseconds: 800), vsync: this)..repeat(reverse: true);
_colorAnimation = ColorTween(begin: Colors.red.shade700, end: Colors.red.shade100).animate(_blinkController);
_shadowAnimation = Tween<double>(begin: 2.0, end: 15.0).animate(CurvedAnimation(parent: _blinkController, curve: Curves.easeInOut));
_startPolling();
}
@override
void dispose() {
_pollingTimer?.cancel();
_blinkController.dispose();
_proofController.dispose();
super.dispose();
}
void _startPolling() {
_pollingTimer = Timer.periodic(const Duration(seconds: 5), (timer) async {
if (_status == 'success' || _status == 'verifying') return;
try {
final res = await CRUD().postWallet(link: AppLink.checkMtnStatus, payload: {'invoice_number': widget.invoiceNumber});
if (res != 'failure' && res['status'] == 'success' && res['invoice_status'] == 'completed') {
timer.cancel();
if (mounted) setState(() => _status = 'success');
}
} catch (_) {}
});
}
Future<void> _submitProof() async {
if (_proofController.text.trim().isEmpty) {
Get.snackbar('Error'.tr, 'Please paste the transfer message'.tr, backgroundColor: Colors.red);
return;
}
setState(() => _status = 'verifying');
try {
final res = await CRUD().postWallet(link: AppLink.uploadMtnProof, payload: {
'invoice_number': widget.invoiceNumber,
'proof_text': _proofController.text.trim(),
});
if (res != 'failure' && res['status'] == 'success') {
if (mounted) setState(() => _status = 'success');
} else {
if (mounted) setState(() => _status = 'error');
Get.defaultDialog(title: 'Failed'.tr, content: Text(res['message']?.toString() ?? 'Verification failed'));
}
} catch (e) {
if (mounted) setState(() => _status = 'error');
Get.defaultDialog(title: 'Error'.tr, content: Text('Error uploading proof'.tr));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[50],
appBar: AppBar(title: const Text("MTN Payment"), centerTitle: true, backgroundColor: Colors.white, foregroundColor: Colors.black),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: _status == 'success' ? _buildSuccessUI() : _buildWaitingUI(),
),
),
);
}
Widget _buildWaitingUI() {
final currencyFormat = NumberFormat.decimalPattern('ar_SY');
return SingleChildScrollView(
child: Column(
children: [
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 15),
decoration: BoxDecoration(gradient: LinearGradient(colors: [Colors.blue.shade800, Colors.blue.shade600]), borderRadius: BorderRadius.circular(16)),
child: Column(
children: [
const Text("المبلغ المطلوب", style: TextStyle(color: Colors.white70, fontSize: 14)),
const SizedBox(height: 5),
Text("${currencyFormat.format(widget.amount)} ل.س", style: const TextStyle(color: Colors.white, fontSize: 28, fontWeight: FontWeight.bold)),
],
),
),
const SizedBox(height: 25),
AnimatedBuilder(
animation: _blinkController,
builder: (context, child) {
return Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(16), border: Border.all(color: _colorAnimation.value ?? Colors.red, width: 3.0), boxShadow: [BoxShadow(color: (_colorAnimation.value ?? Colors.red).withOpacity(0.4), blurRadius: _shadowAnimation.value, spreadRadius: 2)]),
child: Column(
children: [
const Text("يرجى تحويل المبلغ إلى الرقم التالي:", textAlign: TextAlign.center, style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
const SizedBox(height: 15),
InkWell(
onTap: () {
Clipboard.setData(ClipboardData(text: widget.mtnNumber));
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: const Text("تم نسخ الرقم ✅", textAlign: TextAlign.center), backgroundColor: Colors.green.shade600));
},
child: Container(
padding: const EdgeInsets.all(15),
decoration: BoxDecoration(color: Colors.blue.shade50, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.blue.shade200)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(widget.mtnNumber, style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold, letterSpacing: 2.0)),
const Icon(Icons.copy, color: Colors.blue),
],
),
),
),
],
),
);
},
),
const SizedBox(height: 30),
const Text("بعد إتمام التحويل، يرجى نسخ رسالة البنك النصية ولصقها هنا للتحقق التلقائي:", textAlign: TextAlign.center, style: TextStyle(fontSize: 14)),
const SizedBox(height: 10),
TextField(
controller: _proofController,
maxLines: 4,
decoration: InputDecoration(
hintText: "قم بلصق نص رسالة التحويل هنا...",
border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)),
filled: true,
fillColor: Colors.white,
),
),
const SizedBox(height: 15),
SizedBox(
width: double.infinity,
height: 50,
child: ElevatedButton(
style: ElevatedButton.styleFrom(backgroundColor: Colors.blue.shade800, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12))),
onPressed: _status == 'verifying' ? null : _submitProof,
child: _status == 'verifying'
? const CircularProgressIndicator(color: Colors.white)
: const Text("تحقق من الدفع", style: TextStyle(fontSize: 18, color: Colors.white, fontWeight: FontWeight.bold)),
),
),
const SizedBox(height: 20),
const Text("جاري فحص الفاتورة تلقائياً كل 5 ثوانٍ...", style: TextStyle(color: Colors.grey, fontSize: 12)),
],
),
);
}
Widget _buildSuccessUI() {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.verified_rounded, color: Colors.green, size: 100),
const SizedBox(height: 20),
const Text("تم الدفع بنجاح!", style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
const SizedBox(height: 40),
SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(backgroundColor: Colors.green, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 16)),
onPressed: () { Get.back(); Get.back(); },
child: const Text("متابعة", style: TextStyle(fontSize: 18)),
),
),
],
);
}
}

View File

@@ -1,3 +1,4 @@
import 'package:siro_rider/constant/currency.dart';
import 'dart:math' as math;
import 'dart:typed_data';
@@ -191,7 +192,7 @@ class _HistoryCard extends StatelessWidget {
Text('Total Price'.tr,
style: AppStyle.title.copyWith(fontSize: 15)),
Text(
'${ride['price']} ${'SYP'.tr}',
'${ride['price']} ${CurrencyHelper.currency}',
style: AppStyle.headTitle.copyWith(
fontSize: 20, color: AppColor.primaryColor),
),
@@ -559,7 +560,7 @@ class _RideDetailSheetState extends State<_RideDetailSheet> {
color:
AppColor.writeColor.withOpacity(0.55))),
const SizedBox(height: 2),
Text('${ride['price']} ${'SYP'.tr}',
Text('${ride['price']} ${CurrencyHelper.currency}',
style: AppStyle.headTitle.copyWith(
fontSize: 22, color: AppColor.primaryColor)),
],