Files
Siro/siro_driver/lib/controller/food_delivery/food_location_broadcaster.dart
T

80 lines
3.0 KiB
Dart

// 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<int> orderIds) {
box.write(BoxName.foodActiveOrders, jsonEncode(orderIds));
}
static List<int> 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<void> 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;
}
}
}