2026-04-03-maplibra come next

This commit is contained in:
Hamza-Ayed
2026-04-03 16:23:14 +03:00
parent c6b27d06d4
commit e325405dff
13 changed files with 363 additions and 830 deletions

View File

@@ -4,6 +4,7 @@ import 'dart:math';
import 'package:Intaleq/constant/api_key.dart';
import 'package:Intaleq/controller/firebase/firbase_messge.dart';
import 'package:Intaleq/views/auth/otp_page.dart';
import 'package:Intaleq/views/widgets/error_snakbar.dart';
import 'package:http/http.dart' as http;
import 'package:Intaleq/constant/info.dart';
@@ -276,37 +277,47 @@ class LoginController extends GetxController {
// مهم: تأكد من passengerID في الـ box
box.write(BoxName.passengerID, passengerID);
// 4) نفّذ عمليات مكلفة بالتوازي: getTokens + fingerprint
// 4) تنفيذ العمليات بالتوازي: getTokens + fingerprint محلي
final results = await Future.wait([
CRUD().get(link: AppLink.getTokens, payload: {
'passengerID': passengerID, // FIX: لا تستخدم box هنا
}),
CRUD().get(
link: AppLink.getTokens, payload: {'passengerID': passengerID}),
DeviceHelper.getDeviceFingerprint(),
]);
await box.write(BoxName.firstTimeLoadKey, 'false');
final tokenResp = results[0];
final fingerPrint = (results[1] ?? '').toString();
await storage.write(key: BoxName.fingerPrint, value: fingerPrint);
final tokenResp = results[0];
final localFP = (results[1] ?? '').toString();
await storage.write(key: BoxName.fingerPrint, value: localFP);
await box.write(BoxName.firstTimeLoadKey, 'false');
// ── 5. المقارنة: FCM token + fingerprint ──────────────────────
if (email != '962798583052@intaleqapp.com' && tokenResp != 'failure') {
final tokenJson = jsonDecode(tokenResp);
final serverToken = tokenJson['message']?['token']?.toString() ?? '';
// Log.print('serverToken: ${serverToken}');
final localFcm = (box.read(BoxName.tokenFCM) ?? '').toString();
// Log.print('localFcm: ${localFcm}');
final serverData = tokenJson['message'] as Map?; // null = أول تسجيل
// 5) اختلاف الجهاز -> تحقّق OTP
if (serverToken.isNotEmpty && serverToken != localFcm) {
final goVerify = await _confirmDeviceChangeDialog();
if (goVerify == true) {
if (serverData != null) {
final serverFCM = serverData['token']?.toString() ?? '';
final serverFP = serverData['fingerPrint']?.toString() ?? '';
final localFCM = (box.read(BoxName.tokenFCM) ?? '').toString();
// ── اختلاف أي منهما = جهاز مختلف أو تثبيت جديد ─────────
final fcmChanged = serverFCM.isNotEmpty && serverFCM != localFCM;
final fpChanged = serverFP.isNotEmpty && serverFP != localFP;
if (fcmChanged || fpChanged) {
// final goVerify = await _confirmDeviceChangeDialog();
// if (goVerify == true) {
mySnackbarInfo('Device Change Detected'.tr);
//
await Get.to(() => OtpVerificationPage(
phone: data['phone'].toString(),
deviceToken: fingerPrint,
token: tokenResp.toString(),
ptoken: serverToken,
deviceToken: localFP,
token: tokenResp,
ptoken: serverFCM, // نمرر FCM القديم للـ OTP controller
));
// بعد العودة من OTP (نجح/فشل)، أخرج من الميثود كي لا يحصل offAll مرتين
return;
return; // لا تكمل — الـ OTP controller يتولى الانتقال
// }
}
}
}
@@ -359,18 +370,18 @@ class LoginController extends GetxController {
}
}
Future<bool?> _confirmDeviceChangeDialog() {
return Get.defaultDialog<bool>(
barrierDismissible: false,
title: 'Device Change Detected'.tr,
middleText: 'Please verify your identity'.tr,
textConfirm: 'Verify'.tr,
confirmTextColor: Colors.white,
onConfirm: () => Get.back(result: true),
textCancel: 'Cancel'.tr,
onCancel: () => Get.back(result: false),
);
}
// Future<bool?> _confirmDeviceChangeDialog() {
// return Get.defaultDialog<bool>(
// barrierDismissible: false,
// title: 'Device Change Detected'.tr,
// middleText: 'Please verify your identity'.tr,
// textConfirm: 'Verify'.tr,
// confirmTextColor: Colors.white,
// onConfirm: () => Get.back(result: true),
// textCancel: 'Cancel'.tr,
// onCancel: () => Get.back(result: false),
// );
// }
void login() async {
isloading = true;

View File

@@ -45,7 +45,7 @@ import '../../main.dart';
import '../../models/model/locations.dart';
import '../../models/model/painter_copoun.dart';
import '../../print.dart';
import '../../services/ride_tracking_native.dart';
import '../../services/pip_service.dart';
import '../../views/home/map_widget.dart/cancel_raide_page.dart';
import '../../views/home/map_widget.dart/car_details_widget_to_go.dart';
import '../../views/home/map_widget.dart/select_driver_mishwari.dart';
@@ -357,49 +357,83 @@ class MapPassengerController extends GetxController {
.setTransports(['websocket'])
.disableAutoConnect()
.setQuery({'id': passengerId})
// ✅ [FIX] إعادة اتصال شبه-لانهائية (999 محاولة) بدلاً من 20
.setReconnectionAttempts(20)
.setReconnectionDelay(2400)
// ✅ أضف هذا السطر لحل مشكلة الـ Heartbeat مع PHPSocketIO
// ✅ [FIX] تأخير أقل (1.5 ثانية) مع حد أقصى (8 ثواني) للتسريع
.setReconnectionDelay(1500)
.setReconnectionDelayMax(8000)
.enableReconnection()
.setExtraHeaders({'Connection': 'Upgrade'})
.build(),
);
socket.connect();
// ✅ إضافة النبضة (Heartbeat) لمنع السيرفر من قطع الاتصال
_heartbeatTimer?.cancel(); // إيقاف أي نبضة قديمة
_heartbeatTimer = Timer.periodic(const Duration(seconds: 25), (timer) {
if (isSocketConnected && socket != null && socket!.connected) {
socket!.emit('heartbeat', {'passenger_id': passengerId});
// Log.print("💓 Socket Heartbeat sent"); // اختياري للتأكد أنه يعمل
} else {
timer.cancel(); // إيقاف النبضة إذا انقطع السوكيت
}
});
// ✅ معالج الاتصال
// ✅ معالج الاتصال الأول
socket.onConnect((_) {
Log.print("✅ Socket Connected Successfully");
isSocketConnected = true;
_reconnectAttempts = 0;
_startHeartbeat(); // ← أضف هذا
_startHeartbeat();
// ✅ [FIX] الاشتراك مجدداً في أحداث الرحلة عند كل اتصال
if (rideId != null && rideId != 'yet' && driverId.isNotEmpty) {
socket.emit('subscribe_driver_location', {
'ride_id': rideId,
'driver_id': driverId,
});
Log.print("📡 Re-subscribed to driver location after connect");
}
update();
});
// دالة منفصلة للـ heartbeat
// ⚠️ معالج الانقطاع
socket.onDisconnect((_) {
Log.print("⚠️ Socket Disconnected");
Log.print("⚠️ Socket Disconnected — Auto-Reconnect will handle it");
isSocketConnected = false;
// تفعيل Polling أسرع كـ Fallback
// تفعيل Polling أسرع كـ Fallback مؤقت (سيتم إيقافه عند عودة الاتصال)
if (_isActiveRideState()) {
Log.print("🔄 Switching to Fast Polling Mode (6s interval)");
Log.print("🔄 Enabling Fast Polling Fallback (4s) until reconnect...");
_startMasterTimerWithInterval(4);
}
update();
});
// 🔁 [FIX] معالج إعادة الاتصال الناجحة
socket.onReconnect((_) {
Log.print("🔁 Socket Reconnected Successfully!");
isSocketConnected = true;
_reconnectAttempts = 0;
// استئناف النبضة فوراً
_startHeartbeat();
// إعادة الاشتراك في أحداث الرحلة
if (rideId != null && rideId != 'yet' && driverId.isNotEmpty) {
socket.emit('subscribe_driver_location', {
'ride_id': rideId,
'driver_id': driverId,
});
Log.print("📡 Re-subscribed to driver location after reconnect");
}
// ✅ [FIX] إيقاف الـ Fast Polling لأن السوكيت عاد
if (_isActiveRideState()) {
Log.print("✅ Socket back online — stopping Fast Polling Fallback");
_masterTimer?.cancel();
_masterTimer = null;
}
update();
});
// 🔄 [FIX] معالج محاولات إعادة الاتصال (للتشخيص)
socket.onReconnectAttempt((attemptNumber) {
Log.print("🔄 Socket Reconnect Attempt #$attemptNumber...");
});
// ❌ معالج الأخطاء
socket.onError((error) {
Log.print("❌ Socket Error: $error");
@@ -724,6 +758,7 @@ class MapPassengerController extends GetxController {
if (Get.isDialogOpen == true) Get.back();
await RideLiveNotification.cancel();
IosLiveActivityService.endRideActivity(); // ✅ أضف هذا السطر
PipService.disablePip(); // ✅ إيقاف PiP عند انتهاء الرحلة
if (Get.isDialogOpen == true) Get.back();
await RideLiveNotification.cancel();
Get.defaultDialog(
@@ -771,6 +806,7 @@ class MapPassengerController extends GetxController {
stopAllTimers();
await RideLiveNotification.cancel();
IosLiveActivityService.endRideActivity(); // ✅ أضف هذا السطر
PipService.disablePip(); // ✅ إيقاف PiP
_isCancelProcessed = false;
currentRideState.value = RideState.noRide;
resetAllMapStates();
@@ -959,6 +995,7 @@ class MapPassengerController extends GetxController {
'tone1',
);
IosLiveActivityService.endRideActivity();
PipService.disablePip(); // ✅ إيقاف PiP
await RideLiveNotification.cancel();
// 5. استخراج البيانات والانتقال
if (driverList.length >= 4) {
@@ -1272,20 +1309,24 @@ class MapPassengerController extends GetxController {
timeToPassengerFromDriverAfterApplied; // مثلاً من السيرفر
final double distanceDriverToPassengerMeters =
double.parse(distanceByPassenger);
await RideTrackingNative.updateRideTracking(
driverName: driverName,
driverPhone: driverPhone,
carDetails: '$make$carColor$licensePlate',
driverLat: driverCarsLocationToPassengerAfterApplied.last.latitude,
driverLng: driverCarsLocationToPassengerAfterApplied.last.longitude,
passengerLat: passengerLocation.latitude,
passengerLng: passengerLocation.longitude,
destLat: myDestination.latitude,
destLng: myDestination.longitude,
rideState: 'waiting', // يعني السائق بالطريق للراكب
estimatedTimeMinutes: (timeToPassengerSeconds / 60).round(),
totalDistanceMeters: distanceDriverToPassengerMeters,
);
// [PiP] تم تعطيل الإشعار المستمر القديم (Foreground Service) واستبداله بـ PiP
// await RideTrackingNative.updateRideTracking(
// driverName: driverName,
// driverPhone: driverPhone,
// carDetails: '$make • $carColor • $licensePlate',
// driverLat: driverCarsLocationToPassengerAfterApplied.last.latitude,
// driverLng: driverCarsLocationToPassengerAfterApplied.last.longitude,
// passengerLat: passengerLocation.latitude,
// passengerLng: passengerLocation.longitude,
// destLat: myDestination.latitude,
// destLng: myDestination.longitude,
// rideState: 'waiting',
// estimatedTimeMinutes: (timeToPassengerSeconds / 60).round(),
// totalDistanceMeters: distanceDriverToPassengerMeters,
// );
// [PiP] تفعيل PiP عند بدء الرحلة (سيدخل وضع النافذة العائمة عند خروج المستخدم)
PipService.enablePip();
// 6. بدء تتبع الموقع الدوري (Polling Backup + Smart Rerouting)
// سيبدأ العمل بعد 6 ثواني
@@ -1918,21 +1959,21 @@ class MapPassengerController extends GetxController {
durationToRide; // موجود عندك من التايمر
final double totalDistanceMeters = double.parse(distanceByPassenger);
// 2) استدعاء خدمة الأندرويد لتحديث الإشعار لحالة "inProgress"
await RideTrackingNative.updateRideTracking(
driverName: driverName,
driverPhone: driverPhone,
carDetails: carDetails,
driverLat: driverLat,
driverLng: driverLng,
passengerLat: passengerLat,
passengerLng: passengerLng,
destLat: destLat,
destLng: destLng,
rideState: 'inProgress',
estimatedTimeMinutes: (timeToDestinationSeconds / 60).round(),
totalDistanceMeters: totalDistanceMeters,
);
// [PiP] تم تعطيل الإشعار المستمر القديم (Foreground Service) واستبداله بـ PiP
// await RideTrackingNative.updateRideTracking(
// driverName: driverName,
// driverPhone: driverPhone,
// carDetails: carDetails,
// driverLat: driverLat,
// driverLng: driverLng,
// passengerLat: passengerLat,
// passengerLng: passengerLng,
// destLat: destLat,
// destLng: destLng,
// rideState: 'inProgress',
// estimatedTimeMinutes: (timeToDestinationSeconds / 60).round(),
// totalDistanceMeters: totalDistanceMeters,
// );
// 3) بدء التايمر الداخلي الخاص بك (للـ ETA داخل التطبيق نفسه)
rideIsBeginPassengerTimer();
@@ -4894,6 +4935,7 @@ Intaleq Team''';
currentRideState.value = RideState.cancelled;
await RideLiveNotification.cancel(); // إغلاق أندرويد
IosLiveActivityService.endRideActivity(); // ✅ إغلاق iOS
PipService.disablePip(); // ✅ إيقاف PiP عند الإلغاء
// 4. الاتصال بالسيرفر لإلغاء الرحلة وإبلاغ السائق
if (rideId != 'yet' && rideId != null) {