Update codebase

This commit is contained in:
Hamza-Ayed
2026-08-09 16:56:13 +03:00
parent 95e2e4f35d
commit b64debaa88
1058 changed files with 164327 additions and 113928 deletions
@@ -2,22 +2,22 @@ import 'package:get/get.dart';
List<OnBoardingModel> onBoardingList = [
OnBoardingModel(
title: 'Welcome to Tripz!'.tr,
title: 'Welcome to Siro!'.tr,
image: 'assets/images/on1.png',
body:
'Tripz is the ride-hailing app that is safe, reliable, and accessible.'
'Siro is the ride-hailing app that is safe, reliable, and accessible.'
.tr,
),
OnBoardingModel(
title: 'Get to your destination quickly and easily.'.tr,
image: 'assets/images/on2.png',
body: 'With Tripz, you can get a ride to your destination in minutes.'.tr,
body: 'With Siro, you can get a ride to your destination in minutes.'.tr,
),
OnBoardingModel(
title: 'Enjoy a safe and comfortable ride.'.tr,
image: 'assets/images/on3.png',
body:
'Tripz is committed to safety, and all of our captains are carefully screened and background checked.'
'Siro is committed to safety, and all of our captains are carefully screened and background checked.'
.tr,
),
];
@@ -28,7 +28,32 @@ class OrderData {
final double? driverEarningsExtra;
final String? driverEarningsCurrency;
/// نوع الطلب: 'exclusive' خلال السبق الحصري، 'public' بعده، و null في
/// وضع البثّ الحر (عندها لا تُعرض شارة ويعمل المؤقّت بمدته العادية).
final String? offerType;
/// ثواني السبق الحصري كما حددها الخادم (DISPATCH_HEAD_START_SECONDS).
final int offerExpiresIn;
/// رحلة محجوزة مسبقاً — موعد مضبوط لا طلب فوري.
final bool isScheduled;
/// موعد الانطلاق كما حجزه الراكب. فارغ في الرحلات العادية.
final String scheduledAt;
/// طلب وصل عبر رسالة نصية — الراكب بلا إنترنت.
///
/// ليست تفصيلاً تجميلياً: هذا الراكب لن يصله شات ولا إشعار ولن يرى
/// السائق على الخريطة. الاتصال الهاتفي هو القناة الوحيدة، والسائق
/// الذي لا يعرف ذلك سينتظر رداً لن يأتي ثم يُلغي.
final bool isSmsRide;
OrderData({
this.offerType,
this.offerExpiresIn = 0,
this.isScheduled = false,
this.scheduledAt = '',
this.isSmsRide = false,
required this.customerName,
required this.customerToken,
required this.tripDistanceKm,
@@ -135,9 +160,95 @@ class OrderData {
list.length > 36 && list[36].toString().isNotEmpty
? list[36].toString()
: null,
// ‏مسار FCM لا يحمل هذين اليوم — يبقيان محايدَين فلا تظهر شارة.
offerType: list.length > 37 && list[37].toString().isNotEmpty
? list[37].toString()
: null,
offerExpiresIn:
list.length > 38 ? (int.tryParse(list[38].toString()) ?? 0) : 0,
// ‏الفهرسان 39/40 — يضيفهما add_ride.php للرحلات المحجوزة.
isScheduled: list.length > 39 &&
(list[39].toString() == '1' || list[39].toString() == 'true'),
scheduledAt: list.length > 40 ? list[40].toString() : '',
// ‏الفهرس 41 — طلب بالرسائل النصية.
isSmsRide: list.length > 41 &&
(list[41].toString() == '1' || list[41].toString() == 'true'),
);
}
/// بناء من حمولة السوكِت (خريطة). أسماء الحقول تطابق buildMarketPayload()
/// في backend/ride/rides/add_ride.php — أي تغيير هناك يجب أن ينعكس هنا.
///
/// ملاحظة: حمولة السوق لا تحمل اسم الراكب ولا توكنه عمداً (تصل سائقين لن
/// يقودوا الرحلة)، فتبقى القيم الافتراضية حتى يُقبل الطلب.
factory OrderData.fromSocketMap(Map<dynamic, dynamic> map) {
String str(String key, [String fallback = '']) =>
map[key]?.toString().isNotEmpty == true ? map[key].toString() : fallback;
final distanceToPassengerMeters =
double.tryParse(str('distanceToPassenger', '0')) ?? 0.0;
return OrderData(
customerName: str('passengerName', 'Unknown Customer'),
customerToken: str('passengerToken', 'Unknown token'),
tripDistanceKm: double.tryParse(str('distance', '0')) ?? 0.0,
price: str('price', '0').split('.')[0],
startLocationAddress: str('startName', 'Unknown Address'),
endLocationAddress: str('endName', 'Unknown Address'),
distanceToPassengerKm: distanceToPassengerMeters / 1000.0,
tripDurationMinutes: _secondsToRoundedUpMinutes(str('duration', '0')),
durationToPassengerMinutes:
_secondsToRoundedUpMinutes(str('durationToPassenger', '0')),
rideType: _getRideType(str('carType', 'Unknown')),
orderId: str('id', 'N/A'),
passengerId: str('passengerId', 'N/A'),
passengerRate: str('passengerRate', 'N/A'),
rawStartCoordinates: str('start_location').isNotEmpty
? str('start_location')
: (str('start_lat').isNotEmpty
? '${str('start_lat')},${str('start_lng')}'
: null),
rawEndCoordinates: str('end_location').isNotEmpty
? str('end_location')
: (str('end_lat').isNotEmpty
? '${str('end_lat')},${str('end_lng')}'
: null),
driverEarningsExtra: double.tryParse(str('driver_earnings_extra')),
driverEarningsCurrency: str('driver_earnings_currency').isNotEmpty
? str('driver_earnings_currency')
: null,
offerType: str('offer_type').isNotEmpty ? str('offer_type') : null,
offerExpiresIn: int.tryParse(str('offer_expires_in', '0')) ?? 0,
isScheduled: str('is_scheduled') == '1' || str('is_scheduled') == 'true',
scheduledAt: str('scheduled_at'),
isSmsRide: str('is_sms') == '1' || str('is_sms') == 'true',
);
}
/// الموحِّد: FCM يصل قائمةً مفهرسة، والسوكِت يصل خريطة JSON. النافذة
/// الواحدة تخدم المسارين، فالتمييز يتم هنا لا في كل مستدعٍ.
/// يرجع null على أي شكل غير معروف بدل أن يرمي — النافذة تبقى صامتة
/// بدل أن تنهار على حمولة غريبة.
static OrderData? fromAny(dynamic event) {
if (event is List) return OrderData.fromList(event);
if (event is Map) {
// ‏خريطتان مختلفتان تصلان هنا: حمولة السوكِت (أسماء الخادم: id،
// ‏carType، startName) وخريطة toMap() الداخلية (orderId، rideType).
// ‏نميّز بالمفتاح لا بالنوع، وإلا قرأنا إحداهما بقواعد الأخرى فخرجت
// ‏كل الحقول فارغة بصمت.
if (event.containsKey('orderId') || event.containsKey('rideType')) {
return OrderData.fromMap(Map<String, dynamic>.from(event));
}
return OrderData.fromSocketMap(event);
}
return null;
}
static String _getRideType(String type) {
switch (type) {
case 'Comfort':