Update: 2026-07-09 01:55:25

This commit is contained in:
Hamza-Ayed
2026-07-09 01:55:25 +03:00
parent ac0c343f18
commit 7dff7b6973
12 changed files with 374 additions and 28 deletions
@@ -159,6 +159,9 @@ class FirebaseMessagesController extends GetxController {
'DriverList': myList,
'body': body,
'is_destination_match': message.data['is_destination_match'] ?? '0',
// 🆕 "أرباحك أعلى" — يُرسَل فقط عند وجود فرق إيجابي حقيقي
'driver_earnings_extra': message.data['driver_earnings_extra'],
'driver_earnings_currency': message.data['driver_earnings_currency'],
});
}
break;
@@ -411,6 +411,9 @@ class LocationController extends GetxController with WidgetsBindingObserver {
'DriverList': driverList,
'body': 'New Trip Request via Socket ⚡',
'is_destination_match': rideData['is_destination_match'] ?? '0',
// 🆕 "أرباحك أعلى" — نفس الحقل الجاي من FCM، متوفر أيضاً عبر السوكيت
'driver_earnings_extra': rideData['driver_earnings_extra'],
'driver_earnings_currency': rideData['driver_earnings_currency'],
});
} else {
Log.print(
@@ -65,6 +65,10 @@ class OrderRequestController extends GetxController
String tripPrice = "--";
bool isDestinationMatch = false; // 🆕 Destination Match flag
// 🆕 Driver Earnings Advantage — "أرباحك أعلى" badge
double? driverEarningsExtra;
String driverEarningsCurrency = 'ل.س';
String timeToPassenger = "Calculating...".tr;
String distanceToPassenger = "--";
@@ -165,6 +169,7 @@ class OrderRequestController extends GetxController
args['is_destination_match'] == true) {
isDestinationMatch = true;
}
_parseEarningsData(args);
}
// ب) هل هي قادمة من Socket بالمفاتيح الرقمية ("0", "1", ...)؟
else {
@@ -175,6 +180,7 @@ class OrderRequestController extends GetxController
args['is_destination_match'] == true) {
isDestinationMatch = true;
}
_parseEarningsData(args);
}
}
}
@@ -189,6 +195,21 @@ class OrderRequestController extends GetxController
"📍 Parsed Coordinates: Pax($latPassenger, $lngPassenger) -> Dest($latDestination, $lngDestination)");
}
/// 🆕 يقرأ حقل "أرباحك أعلى" من بيانات الطلب (FCM أو Socket) إن وُجد
void _parseEarningsData(Map args) {
final rawExtra = args['driver_earnings_extra'];
if (rawExtra != null) {
final parsed = double.tryParse(rawExtra.toString());
if (parsed != null && parsed > 0) {
driverEarningsExtra = parsed;
}
}
final rawCurrency = args['driver_earnings_currency'];
if (rawCurrency != null && rawCurrency.toString().isNotEmpty) {
driverEarningsCurrency = rawCurrency.toString();
}
}
/// 🔥 دالة ذكية تجلب القيمة سواء كانت البيانات في List أو Map
dynamic _getValueAt(int index) {
// الأولوية للقائمة
@@ -24,6 +24,10 @@ class OrderData {
final String? rawStartCoordinates;
final String? rawEndCoordinates;
// 🆕 "أرباحك أعلى" — الفرق الإيجابي بأجرة السائق مقارنة بالمنافس (إن وُجد)
final double? driverEarningsExtra;
final String? driverEarningsCurrency;
OrderData({
required this.customerName,
required this.customerToken,
@@ -40,6 +44,8 @@ class OrderData {
required this.passengerRate,
this.rawStartCoordinates,
this.rawEndCoordinates,
this.driverEarningsExtra,
this.driverEarningsCurrency,
});
// --- NEW: Factory constructor to create an instance from a Map ---
@@ -74,6 +80,8 @@ class OrderData {
// For nullable strings, direct access is fine as it returns null if the key doesn't exist
rawStartCoordinates: map['rawStartCoordinates'],
rawEndCoordinates: map['rawEndCoordinates'],
driverEarningsExtra: (map['driverEarningsExtra'] as num?)?.toDouble(),
driverEarningsCurrency: map['driverEarningsCurrency']?.toString(),
);
}
@@ -118,6 +126,15 @@ class OrderData {
rawStartCoordinates: list.isNotEmpty ? list[0].toString() : null,
rawEndCoordinates: list.length > 1 ? list[1].toString() : null,
// 🆕 Index 35/36: "أرباحك أعلى"
driverEarningsExtra: list.length > 35 && list[35].toString().isNotEmpty
? double.tryParse(list[35].toString())
: null,
driverEarningsCurrency:
list.length > 36 && list[36].toString().isNotEmpty
? list[36].toString()
: null,
);
}
@@ -182,6 +199,8 @@ class OrderData {
'passengerRate': passengerRate,
'rawStartCoordinates': rawStartCoordinates,
'rawEndCoordinates': rawEndCoordinates,
'driverEarningsExtra': driverEarningsExtra,
'driverEarningsCurrency': driverEarningsCurrency,
};
}
}
@@ -529,6 +529,40 @@ class _OrderOverlayState extends State<OrderOverlay>
),
],
),
// 🆕 "أرباحك أعلى" — يظهر فقط إذا في فرق إيجابي حقيقي من الباك اند
if (order.driverEarningsExtra != null &&
order.driverEarningsExtra! > 0) ...[
const SizedBox(height: 10),
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
decoration: BoxDecoration(
color: AppColors.priceHighlight.withOpacity(0.12),
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: AppColors.priceHighlight.withOpacity(0.35),
width: 1),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.trending_up_rounded,
color: AppColors.priceHighlight, size: 16),
const SizedBox(width: 6),
Text(
"أرباحك أعلى بـ ${order.driverEarningsExtra!.toStringAsFixed(2)} ${order.driverEarningsCurrency ?? ''} من التطبيقات الثانية"
.tr,
style: const TextStyle(
color: AppColors.priceHighlight,
fontSize: 11.5,
fontWeight: FontWeight.w700,
),
textAlign: TextAlign.center,
),
],
),
),
],
const SizedBox(height: 12),
Divider(color: AppColors.gray.withOpacity(0.2), thickness: 1),
const SizedBox(height: 12),
@@ -238,14 +238,16 @@ class OrderRequestPage extends StatelessWidget {
),
// ── Earnings Compare Badge ──────────────────
// يتم جلبه من API مشابه أو يمكن ربطه ببيانات الكنترولر لاحقاً.
// نتركه متاحاً للتحديث عبر الكنترولر (controller.driverBadgeText, controller.extraEarnings).
// سنستخدم قيم افتراضية للتأكد من الريندر (UI render) الآن
// سيتم تفعيله من الباك إند
// مصدر البيانات: driver_earnings_extra/currency القادمة من add_ride.php
// (عبر FCM أو Socket) — controller.driverEarningsExtra يبقى null إذا
// ما في فرق إيجابي حقيقي، فالويدجت نفسه بيختفي تلقائياً.
const SizedBox(height: 5),
const DriverEarningsBadge(
earningsLabel: "أرباحك أعلى هنا مقارنة بـ المنافسين",
extraAmount: 2.50, // القيمة هنا ستُسحب من الـ Socket / API قريباً
DriverEarningsBadge(
earningsLabel: controller.driverEarningsExtra != null
? "أرباحك أعلى هنا مقارنة بـ المنافسين"
: null,
extraAmount: controller.driverEarningsExtra,
currency: controller.driverEarningsCurrency,
),
const SizedBox(height: 15),
@@ -110,6 +110,13 @@ class RideAvailableCard extends StatelessWidget {
const RideAvailableCard({Key? key, required this.rideInfo}) : super(key: key);
/// يحوّل driver_earnings_extra (نص من الـ Socket) إلى double، أو null إن لم يوجد
double? get _earningsExtra {
final raw = rideInfo['driver_earnings_extra'];
if (raw == null) return null;
return double.tryParse(raw.toString());
}
@override
Widget build(BuildContext context) {
return Card(
@@ -128,10 +135,16 @@ class RideAvailableCard extends StatelessWidget {
const Divider(height: 24, thickness: 0.5),
_buildRideDetails(),
const SizedBox(height: 12),
// ── إضافة شارة الأرباح هنا ──
const DriverEarningsBadge(
earningsLabel: "أرباحك أعلى هنا مقارنة بـ المنافسين",
extraAmount: 2.50, // القيمة هنا ستُسحب من الـ Socket / API قريباً
// ── شارة الأرباح — مصدرها rideInfo['driver_earnings_extra'] القادم
// من add_ride.php (broadcastRideToMarket عبر Socket). ملاحظة: الرحلات
// المجلوبة من الجلب الأولي (getRideWaiting.php) ما زالت لا تحمل هذا
// الحقل، فالشارة بتختفي تلقائياً لحد ما تُحدَّث تلك النقطة لاحقاً.
DriverEarningsBadge(
earningsLabel: _earningsExtra != null
? "أرباحك أعلى هنا مقارنة بـ المنافسين"
: null,
extraAmount: _earningsExtra,
currency: rideInfo['driver_earnings_currency']?.toString() ?? 'ل.س',
),
const SizedBox(height: 12),
_buildAcceptButton(),