Update codebase
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
// food_overlay_bridge.dart — نافذة عرض التوصيل العائمة (أندرويد) ونتيجتها
|
||||
//
|
||||
// لماذا جسر مستقل عن كنترولر التوصيل:
|
||||
// العرض قد يصل والتطبيق في الخلفية وشاشة التوصيل مغلقة — بل وقد يصل من العزلة
|
||||
// الخلفية حيث لا وجود لأي كنترولر. فالاشتراك في نتيجة النافذة يجب أن يكون
|
||||
// عالمياً ويعيش طوال عمر التطبيق، ويردّ على الخادم بنفسه بلا انتظار شاشة.
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:get/get.dart';
|
||||
import 'package:trip_overlay_plugin/trip_overlay_plugin.dart';
|
||||
|
||||
import '../../print.dart';
|
||||
import '../../views/food_delivery/food_task_details_page.dart';
|
||||
import '../../views/widgets/error_snakbar.dart';
|
||||
import 'food_delivery_models.dart';
|
||||
import 'food_delivery_service.dart';
|
||||
|
||||
class FoodOverlayBridge {
|
||||
FoodOverlayBridge._();
|
||||
|
||||
static StreamSubscription<String>? _acceptSub;
|
||||
static StreamSubscription<String>? _rejectSub;
|
||||
|
||||
/// تُنادى مرة واحدة عند إقلاع التطبيق
|
||||
static void attach() {
|
||||
if (!TripOverlayPlugin.isSupported) return; // أندرويد فقط
|
||||
if (_acceptSub != null) return;
|
||||
|
||||
TripOverlayPlugin.initialize();
|
||||
|
||||
_acceptSub = TripOverlayPlugin.onFoodOrderAccepted.listen(_onAccepted);
|
||||
_rejectSub = TripOverlayPlugin.onFoodOrderRejected.listen(_onRejected);
|
||||
Log.print('🍔 [FoodOverlay] جاهز لاستقبال نتائج النافذة العائمة');
|
||||
}
|
||||
|
||||
static Future<void> _onAccepted(String orderIdRaw) async {
|
||||
final orderId = int.tryParse(orderIdRaw) ?? 0;
|
||||
if (orderId == 0) return;
|
||||
|
||||
Log.print('🍔 [FoodOverlay] قبول من النافذة — طلب #$orderId');
|
||||
|
||||
// القبول يتم هنا لا في الشاشة: النافذة تُغلق فوراً والخادم لا ينتظر
|
||||
// فتح واجهة. لو تأخّرنا حتى تُبنى الشاشة قد تنتهي مهلة العرض.
|
||||
final res = await FoodDeliveryService.respondToOffer(orderId, true);
|
||||
|
||||
if (res.success) {
|
||||
mySnackbarSuccess('تم قبول طلب التوصيل');
|
||||
Get.to(() => FoodTaskDetailsPage(orderId: orderId));
|
||||
} else {
|
||||
mySnackbarWarning(res.message);
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> _onRejected(String orderIdRaw) async {
|
||||
final orderId = int.tryParse(orderIdRaw) ?? 0;
|
||||
if (orderId == 0) return;
|
||||
|
||||
// الرفض الصريح يُبلَّغ الخادم ليعرض الطلب على سائق آخر فوراً بدل انتظار
|
||||
// انتهاء المهلة. انتهاء المهلة يصل بنفس الحدث، والخادم يتعامل مع الحالتين
|
||||
// بأمان (يرفض إن لم يعد العرض قائماً).
|
||||
Log.print('🍔 [FoodOverlay] رفض/انتهاء مهلة — طلب #$orderId');
|
||||
await FoodDeliveryService.respondToOffer(orderId, false);
|
||||
}
|
||||
|
||||
/// عرض النافذة لعرض توصيل وارد — تُنادى حين يكون التطبيق في الخلفية
|
||||
static Future<bool> show(FoodDeliveryOffer offer, {String? distanceText}) {
|
||||
return TripOverlayPlugin.showFoodOverlay(
|
||||
FoodOrderOverlayData(
|
||||
orderId: offer.orderId.toString(),
|
||||
merchantName: offer.merchantNameAr,
|
||||
merchantAddress: offer.merchantAddress ?? '',
|
||||
// التنسيق يتم هنا لا في Kotlin — العملة والوحدة الصغرى منطق تطبيق
|
||||
deliveryFeeText: foodFormatPrice(offer.deliveryFee),
|
||||
cashToCollectText:
|
||||
offer.cashToCollect > 0 ? foodFormatPrice(offer.cashToCollect) : '',
|
||||
distanceText: distanceText ?? '',
|
||||
itemsCount: offer.itemsCount,
|
||||
isCash: offer.isCash,
|
||||
),
|
||||
autoCloseSeconds: offer.secondsRemaining.clamp(5, 20),
|
||||
);
|
||||
}
|
||||
|
||||
static Future<void> hide() => TripOverlayPlugin.hideOverlay();
|
||||
|
||||
static void detach() {
|
||||
_acceptSub?.cancel();
|
||||
_rejectSub?.cancel();
|
||||
_acceptSub = null;
|
||||
_rejectSub = null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user