Update: 2026-06-10 18:11:50

This commit is contained in:
Hamza-Ayed
2026-06-10 18:11:50 +03:00
parent a0473a8b0f
commit 977adfe99d
27 changed files with 3946 additions and 206 deletions

View File

@@ -9,7 +9,6 @@ import 'package:flutter_overlay_window/flutter_overlay_window.dart';
import 'package:socket_io_client/socket_io_client.dart' as IO;
import 'package:flutter_overlay_window/flutter_overlay_window.dart' as Overlay;
import 'package:get_storage/get_storage.dart';
import 'package:geolocator/geolocator.dart' as geo;
import '../../constant/box_name.dart';
import '../firebase/local_notification.dart';
@@ -129,40 +128,21 @@ Future<bool> onStart(ServiceInstance service) async {
service.stopSelf();
});
// 🔥 Location management in background isolate (Using Geolocator)
geo.Position? latestPos;
// Listen to location changes continuously in the background
geo.Geolocator.getPositionStream(
locationSettings: geo.AndroidSettings(
accuracy: geo.LocationAccuracy.high,
distanceFilter: 10,
intervalDuration: const Duration(seconds: 10),
),
).listen((pos) {
latestPos = pos;
});
// 🔥 MERCY HEARTBEAT: Send location every 2 minutes to keep driver active in 'raids'
Timer.periodic(const Duration(minutes: 2), (timer) async {
if (socket != null && socket.connected && latestPos != null) {
try {
socket.emit('update_location', {
'driver_id': driverId,
'lat': latestPos!.latitude,
'lng': latestPos!.longitude,
'heading': latestPos!.heading,
'speed': latestPos!.speed * 3.6,
'status': box.read(BoxName.statusDriverLocation) ?? 'on',
'source': 'background_heartbeat'
});
print(
"💓 Background Mercy Heartbeat Sent: ${latestPos!.latitude}, ${latestPos!.longitude}");
} catch (e) {
print("❌ Background Heartbeat Error: $e");
}
}
});
// 🚫 [Architecture Rule] NO redundant GPS stream in background service!
// LocationController is the SINGLE SOURCE OF TRUTH for all location GPS updates.
// It already uses location.enableBackgroundMode(enable: true) to keep the GPS
// stream alive even when the app is in the background. The main socket in
// LocationController handles all emitLocationToSocket() calls including heartbeat.
//
// The background service is ONLY responsible for:
// 1. Keeping the socket connection alive for receiving 'new_ride_request'
// and 'cancel_ride' events while the main isolate is paused on Android.
// 2. Showing the Android Overlay UI for incoming ride requests.
// 3. Notifications for iOS background state.
//
// Location data is not sent from the background isolate — it would conflict
// with LocationController's stream and cause duplicate GPS listeners,
// battery drain, and device freeze (as documented in driver_lifecycle.md).
Timer.periodic(const Duration(seconds: 30), (timer) async {
if (service is AndroidServiceInstance) {

View File

@@ -19,6 +19,7 @@ import '../firebase/local_notification.dart';
import '../home/captin/home_captain_controller.dart';
import '../home/captin/map_driver_controller.dart';
import '../home/payment/captain_wallet_controller.dart';
import '../home/navigation/navigation_controller.dart';
import 'background_service.dart';
import 'crud.dart';
@@ -539,6 +540,16 @@ class LocationController extends GetxController with WidgetsBindingObserver {
}
}
if (Get.isRegistered<MapDriverController>()) {
final mapCtrl = Get.find<MapDriverController>();
mapCtrl.handleLocationUpdateFromCentral(pos, speed, heading);
}
if (Get.isRegistered<NavigationController>()) {
final navCtrl = Get.find<NavigationController>();
navCtrl.handleLocationUpdateFromCentral(pos, speed, heading);
}
await _saveBehaviorIfMoved(pos, now, currentSpeed: speed);
}, onError: (e) => Log.print('❌ Location Stream Error: $e'));
}