80 lines
3.0 KiB
Dart
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;
|
|
}
|
|
}
|
|
}
|