Files
tripz-llc/apps/driver-archive-cubit/lib/features/home/data/driver_location_service.dart
T
Hamza-AyedandClaude Opus 5 9909d9b4c1 chore: أرشفة تطبيقات ولوحات تريبز التي سيحلّ محلها كود سيرو
استكمال قرار 2026-07-27 (كوميت fff76c9 أرشف الباك إند):
  apps/rider          → apps/rider-archive-cubit
  apps/driver         → apps/driver-archive-cubit
  dashboards/admin-web    → dashboards/admin-web-archive
  dashboards/service-web  → dashboards/service-web-archive

إعادة تسمية بلا تعديل محتوى. rider/driver كانا إعادة بناء Cubit مبنية على
عقد NestJS المؤرشف. admin-web و service-web نموذجان بملف HTML واحد (164 و
128 سطراً) — يحلّ محلهما siro_admin و siro_service المكتملان.

يُحمل من المؤرشف ولا يُعاد اكتشافه: عقد map-saas المثبَّت بالتجربة في
apps/rider-archive-cubit/lib/core/api/ (x-api-key ترويسة، reverse مصفوفة،
route في points) ودرس مسار FCM.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 05:12:04 +03:00

92 lines
2.5 KiB
Dart

import 'dart:async';
import 'package:geolocator/geolocator.dart';
/// خدمة موقع السائق — تتبع الموقع في الخلفية وإرساله للسيرفر.
///
/// تتبع 3 ثوانٍ عند التنشيط، ثم إرسال كل دقيقتين (docs/23 §10).
/// تراعي حالة البطارية وتتوقف عند انخفاضها.
class DriverLocationService {
final Future<void> Function(double lat, double lng, {double? heading, double? speed})
_onLocationUpdate;
StreamSubscription<Position>? _positionSub;
Timer? _heartbeatTimer;
bool _active = false;
DriverLocationService(this._onLocationUpdate);
bool get isActive => _active;
/// بدء التتبع.
Future<void> start() async {
if (_active) return;
// تحقق من صلاحية الموقع.
var permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied ||
permission == LocationPermission.deniedForever) {
return;
}
}
_active = true;
// أرسل الموقع فوراً.
_sendCurrentLocation();
// استمع لتحديثات الموقع كل 3 ثوانٍ.
_positionSub = Geolocator.getPositionStream(
locationSettings: const LocationSettings(
accuracy: LocationAccuracy.high,
distanceFilter: 15, // تحديث عند تغيير 15 متر
),
).listen((pos) {
_onLocationUpdate(
pos.latitude,
pos.longitude,
heading: pos.heading,
speed: pos.speed,
);
});
// دفعة كل دقيقتين كحد أقصى.
_heartbeatTimer = Timer.periodic(const Duration(minutes: 2), (_) {
_sendCurrentLocation();
});
}
/// إيقاف التتبع.
void stop() {
_active = false;
_positionSub?.cancel();
_positionSub = null;
_heartbeatTimer?.cancel();
_heartbeatTimer = null;
}
/// إرسال الموقع الحالي مرة واحدة.
Future<void> _sendCurrentLocation() async {
try {
final pos = await Geolocator.getCurrentPosition(
locationSettings: const LocationSettings(
accuracy: LocationAccuracy.high,
),
);
await _onLocationUpdate(
pos.latitude,
pos.longitude,
heading: pos.heading,
speed: pos.speed,
);
} catch (_) {
// خطأ صامت — سيحاول مرة أخرى مع الدقيقة التالية.
}
}
void dispose() {
stop();
}
}