// food_location_broadcaster.dart — بثّ موقع السائق للزبون أثناء التوصيل // // لماذا هنا ولا في الخدمة الخلفية (background_service.dart): // قاعدة معمارية مثبّتة في المشروع تمنع أي تدفّق GPS ثانٍ في العزلة الخلفية — // `LocationController` هو المصدر الوحيد، وهو يبقى حياً في الخلفية أصلاً عبر // enableBackgroundMode. فتح تدفّق ثانٍ هناك يعني مستمعَي GPS متوازيين واستنزاف // بطارية وتجميد أجهزة (موثّق في driver_lifecycle.md). فالبثّ يركب على النبضة // القائمة في LocationController بدل إنشاء مصدر جديد — وهو ما يجعله يستمر بعد // إغلاق شاشة التوصيل، وهو المطلوب فعلاً. // // المهام النشطة تُحفظ في التخزين المحلي، فلا يحتاج هذا الملف كنترولر التوصيل // ولا يموت بموته. import 'dart:convert'; import '../../constant/box_name.dart'; import '../../main.dart'; import '../../print.dart'; import 'food_delivery_service.dart'; class FoodLocationBroadcaster { FoodLocationBroadcaster._(); static const Duration _minInterval = Duration(seconds: 7); static DateTime? _lastSentAt; static bool _inFlight = false; /// تُخزَّن من كنترولر التوصيل عند كل تحديث للمهام static void setActiveOrders(List orderIds) { box.write(BoxName.foodActiveOrders, jsonEncode(orderIds)); } static List get activeOrders { try { final raw = box.read(BoxName.foodActiveOrders); if (raw == null) return const []; return (jsonDecode(raw.toString()) as List) .map((e) => int.tryParse(e.toString()) ?? 0) .where((e) => e != 0) .toList(); } catch (_) { return const []; } } static void clear() => box.remove(BoxName.foodActiveOrders); /// يُنادى من LocationController على كل تحديث موقع — يخرج فوراً إن لم تكن /// هناك مهمة توصيل، فلا يكلّف شيئاً في الحالة الغالبة. static Future maybeSend({ required double lat, required double lng, double? heading, }) async { final orders = activeOrders; if (orders.isEmpty) return; if (lat == 0 && lng == 0) return; if (_inFlight) return; final now = DateTime.now(); if (_lastSentAt != null && now.difference(_lastSentAt!) < _minInterval) return; _lastSentAt = now; _inFlight = true; try { for (final orderId in orders) { await FoodDeliveryService.sendLocation( orderId: orderId, lat: lat, lng: lng, heading: heading, ); } } catch (e) { Log.print('🍔 [FoodLocation] تعذّر بثّ الموقع: $e'); } finally { _inFlight = false; } } }