|
|
|
|
@@ -16,6 +16,7 @@ import 'package:trip_overlay_plugin/trip_overlay_plugin.dart';
|
|
|
|
|
import '../../constant/box_name.dart';
|
|
|
|
|
import '../../constant/links.dart';
|
|
|
|
|
import '../../main.dart';
|
|
|
|
|
import '../../print.dart';
|
|
|
|
|
import '../home/captin/home_captain_controller.dart';
|
|
|
|
|
import '../home/captin/map_driver_controller.dart';
|
|
|
|
|
import '../home/payment/captain_wallet_controller.dart';
|
|
|
|
|
@@ -74,7 +75,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|
|
|
|
@override
|
|
|
|
|
Future<void> onInit() async {
|
|
|
|
|
super.onInit();
|
|
|
|
|
print('🚀 LocationController Starting...');
|
|
|
|
|
Log.print('🚀 LocationController Starting...');
|
|
|
|
|
|
|
|
|
|
// 1. Register Lifecycle Observer
|
|
|
|
|
WidgetsBinding.instance.addObserver(this);
|
|
|
|
|
@@ -83,7 +84,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|
|
|
|
// مراقب الحالة (Status Watcher)
|
|
|
|
|
box.listenKey(BoxName.statusDriverLocation, (value) {
|
|
|
|
|
if (value == 'blocked') {
|
|
|
|
|
print("⛔ Driver is Blocked: Force Stopping Location Updates.");
|
|
|
|
|
Log.print("⛔ Driver is Blocked: Force Stopping Location Updates.");
|
|
|
|
|
stopLocationUpdates();
|
|
|
|
|
if (socket != null && socket!.connected) {
|
|
|
|
|
socket!.emit('update_location', {
|
|
|
|
|
@@ -113,7 +114,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|
|
|
|
await startLocationUpdates();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
print('✅ LocationController Initialized.');
|
|
|
|
|
Log.print('✅ LocationController Initialized.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
@@ -133,7 +134,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|
|
|
|
@override
|
|
|
|
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
|
|
|
|
if (state == AppLifecycleState.resumed) {
|
|
|
|
|
print("📱 Lifecycle: App is in FOREGROUND");
|
|
|
|
|
Log.print("📱 Lifecycle: App is in FOREGROUND");
|
|
|
|
|
box.write(BoxName.isAppInForeground, true);
|
|
|
|
|
|
|
|
|
|
// إيقاف خدمة الخلفية لأننا في الواجهة الآن
|
|
|
|
|
@@ -141,7 +142,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|
|
|
|
|
|
|
|
|
// التأكد من أن السوكيت متصل، وإذا لا، نعيد الاتصال فوراً
|
|
|
|
|
if (socket == null || !socket!.connected) {
|
|
|
|
|
print("🔄 Socket disconnected in background. Reconnecting now...");
|
|
|
|
|
Log.print("🔄 Socket disconnected in background. Reconnecting now...");
|
|
|
|
|
initSocket();
|
|
|
|
|
} else {
|
|
|
|
|
// إذا كان متصلاً، ننعش المستمعين فقط للتأكد
|
|
|
|
|
@@ -149,7 +150,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|
|
|
|
}
|
|
|
|
|
} else if (state == AppLifecycleState.paused ||
|
|
|
|
|
state == AppLifecycleState.detached) {
|
|
|
|
|
print("📱 Lifecycle: App is in BACKGROUND");
|
|
|
|
|
Log.print("📱 Lifecycle: App is in BACKGROUND");
|
|
|
|
|
box.write(BoxName.isAppInForeground, false);
|
|
|
|
|
|
|
|
|
|
// تشغيل خدمة الخلفية لضمان بقاء التطبيق حياً
|
|
|
|
|
@@ -186,14 +187,15 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|
|
|
|
// 1. إذا كان السوكيت موجوداً، فقط تأكد من اتصاله
|
|
|
|
|
if (socket != null) {
|
|
|
|
|
if (!socket!.connected) {
|
|
|
|
|
print("🟡 Socket exists but disconnected. Reconnecting...");
|
|
|
|
|
Log.print("🟡 Socket exists but disconnected. Reconnecting...");
|
|
|
|
|
socket!.connect();
|
|
|
|
|
}
|
|
|
|
|
_setupSocketListeners(); // تحديث المستمعين
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
print("🟡 [LocationController] Creating NEW Socket for Driver: $driverId");
|
|
|
|
|
Log.print(
|
|
|
|
|
"🟡 [LocationController] Creating NEW Socket for Driver: $driverId");
|
|
|
|
|
|
|
|
|
|
// 2. إنشاء الاتصال
|
|
|
|
|
socket = IO.io(
|
|
|
|
|
@@ -222,20 +224,27 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|
|
|
|
socket!.off('ride_cancelled');
|
|
|
|
|
|
|
|
|
|
socket!.onConnect((_) {
|
|
|
|
|
print('✅ Socket Connected! ID: ${socket?.id}');
|
|
|
|
|
Log.print('✅ Socket Connected! ID: ${socket?.id}');
|
|
|
|
|
isSocketConnected = true;
|
|
|
|
|
_startHeartbeat();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
socket!.onDisconnect((_) {
|
|
|
|
|
print('❌ Socket Disconnected');
|
|
|
|
|
Log.print('❌ Socket Disconnected');
|
|
|
|
|
isSocketConnected = false;
|
|
|
|
|
_stopHeartbeat();
|
|
|
|
|
});
|
|
|
|
|
socket!.onConnectError((err) {
|
|
|
|
|
Log.print('❌ Socket Connect Error: $err');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
socket!.onError((err) {
|
|
|
|
|
Log.print('❌ Socket General Error: $err');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 🔥 الاستماع للطلبات الجديدة
|
|
|
|
|
socket!.on('new_ride_request', (data) {
|
|
|
|
|
print("🔔 Socket: New Ride Request Arrived!");
|
|
|
|
|
Log.print("🔔 Socket: New Ride Request Arrived!");
|
|
|
|
|
|
|
|
|
|
// نستخدم Future.microtask لضمان عدم حظر الـ UI Thread
|
|
|
|
|
Future.microtask(() {
|
|
|
|
|
@@ -259,7 +268,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|
|
|
|
handleIncomingOrder(convertedMap, "Socket");
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
print("❌ Error processing socket data: $e");
|
|
|
|
|
Log.print("❌ Error processing socket data: $e");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
@@ -267,7 +276,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|
|
|
|
|
|
|
|
|
// 🔥 الاستماع للإلغاء
|
|
|
|
|
socket!.on('cancel_ride', (data) {
|
|
|
|
|
print("🚫 Socket: Ride Cancelled Event Received");
|
|
|
|
|
Log.print("🚫 Socket: Ride Cancelled Event Received");
|
|
|
|
|
String reason = data['reason'] ?? 'No reason provided';
|
|
|
|
|
if (Get.isRegistered<MapDriverController>()) {
|
|
|
|
|
Get.find<MapDriverController>()
|
|
|
|
|
@@ -280,13 +289,13 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|
|
|
|
|
|
|
|
|
Future<void> handleIncomingOrder(
|
|
|
|
|
Map<String, dynamic> rideData, String source) async {
|
|
|
|
|
print("📦 Socket Order Received from ($source)");
|
|
|
|
|
Log.print("📦 Socket Order Received from ($source)");
|
|
|
|
|
|
|
|
|
|
// 🔴 1. التحقق من حالة التطبيق قبل أي شيء 🔴
|
|
|
|
|
bool isAppInForeground = box.read(BoxName.isAppInForeground) ?? false;
|
|
|
|
|
|
|
|
|
|
if (!isAppInForeground) {
|
|
|
|
|
print(
|
|
|
|
|
Log.print(
|
|
|
|
|
"🛑 التطبيق في الخلفية. السوكيت سيتجاهل التوجيه ويترك المهمة للـ Overlay.");
|
|
|
|
|
return; // 👈 هذا السطر يمنع السوكيت من إكمال العمل وفتح الصفحة
|
|
|
|
|
}
|
|
|
|
|
@@ -294,7 +303,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|
|
|
|
try {
|
|
|
|
|
// 2. التحقق من صحة البيانات
|
|
|
|
|
if (rideData.isEmpty || !rideData.containsKey('16')) {
|
|
|
|
|
print("❌ Socket Error: Invalid Ride Data.");
|
|
|
|
|
Log.print("❌ Socket Error: Invalid Ride Data.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -311,25 +320,26 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|
|
|
|
// 4. إغلاق النافذة (إن وجدت بالخطأ) والتنقل
|
|
|
|
|
try {
|
|
|
|
|
if (await TripOverlayPlugin.isOverlayActive()) {
|
|
|
|
|
print("📲 Closing Overlay because App took control via Socket");
|
|
|
|
|
Log.print("📲 Closing Overlay because App took control via Socket");
|
|
|
|
|
await TripOverlayPlugin.hideOverlay();
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
print("Overlay check error: $e");
|
|
|
|
|
Log.print("Overlay check error: $e");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Get.currentRoute != '/OrderRequestPage') {
|
|
|
|
|
print("🚀 Socket: Navigating to OrderRequestPage...");
|
|
|
|
|
Log.print("🚀 Socket: Navigating to OrderRequestPage...");
|
|
|
|
|
Get.toNamed('/OrderRequestPage', arguments: {
|
|
|
|
|
'myListString': jsonEncode(driverList),
|
|
|
|
|
'DriverList': driverList,
|
|
|
|
|
'body': 'New Trip Request via Socket ⚡'
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
print("⚠️ User is already on OrderRequestPage. Skipping navigation.");
|
|
|
|
|
Log.print(
|
|
|
|
|
"⚠️ User is already on OrderRequestPage. Skipping navigation.");
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
print("❌ Socket Navigation Error: $e");
|
|
|
|
|
Log.print("❌ Socket Navigation Error: $e");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -374,8 +384,8 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Debug print to verify
|
|
|
|
|
// print('🚀 Emitting Location: $payload');
|
|
|
|
|
// DebugLog.print to verify
|
|
|
|
|
//Log.print('🚀 Emitting Location: $payload');
|
|
|
|
|
|
|
|
|
|
if (socket != null && socket!.connected) {
|
|
|
|
|
socket!.emit('update_location', payload);
|
|
|
|
|
@@ -437,11 +447,11 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|
|
|
|
update();
|
|
|
|
|
emitLocationToSocket(pos, heading, speed);
|
|
|
|
|
await _saveBehaviorIfMoved(pos, now, currentSpeed: speed);
|
|
|
|
|
}, onError: (e) => print('❌ Location Stream Error: $e'));
|
|
|
|
|
}, onError: (e) => Log.print('❌ Location Stream Error: $e'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> stopLocationUpdates() async {
|
|
|
|
|
print("🛑 Stopping Location Updates...");
|
|
|
|
|
Log.print("🛑 Stopping Location Updates...");
|
|
|
|
|
|
|
|
|
|
_locSub?.cancel();
|
|
|
|
|
_locSub = null;
|
|
|
|
|
@@ -525,7 +535,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|
|
|
|
payload: {'driver_id': driverId, 'batch_data': jsonEncode(batch)},
|
|
|
|
|
);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
print('❌ Failed to upload batch: $e');
|
|
|
|
|
Log.print('❌ Failed to upload batch: $e');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -559,7 +569,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|
|
|
|
}, TableName.behavior);
|
|
|
|
|
_lastSqlLoc = pos;
|
|
|
|
|
} catch (e) {
|
|
|
|
|
print('SQLite Error: $e');
|
|
|
|
|
Log.print('SQLite Error: $e');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -594,7 +604,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|
|
|
|
interval: 1000,
|
|
|
|
|
distanceFilter: 10);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
print("Warning: $e");
|
|
|
|
|
Log.print("Warning: $e");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -633,7 +643,7 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|
|
|
|
return await location.getLocation();
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
print('❌ FAILED to get single location: $e');
|
|
|
|
|
Log.print('❌ FAILED to get single location: $e');
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|