2026-02-28-1

This commit is contained in:
Hamza-Ayed
2026-02-28 01:12:28 +03:00
parent 33f34f7c50
commit 76c04702cd
409 changed files with 2858 additions and 1090 deletions

View File

@@ -5,6 +5,7 @@ import 'dart:math' show Random, atan2, cos, max, min, pi, pow, sin, sqrt;
import 'dart:math' as math;
import 'dart:ui';
import 'dart:convert';
import 'package:Intaleq/services/ride_live_notification.dart';
import 'package:crypto/crypto.dart';
import 'package:Intaleq/views/Rate/rate_captain.dart';
import 'package:Intaleq/views/Rate/rating_driver_bottom.dart';
@@ -44,6 +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 '../../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';
@@ -61,6 +63,7 @@ import '../payment/payment_controller.dart';
import 'decode_polyline_isolate.dart';
import 'deep_link_controller.dart';
import 'device_performance.dart';
import 'ios_live_activity_service.dart';
import 'vip_waitting_page.dart';
enum RideState {
@@ -333,6 +336,7 @@ class MapPassengerController extends GetxController {
// ==============================================================================
// 1. الدالة الرئيسية لتأسيس الاتصال (تستدعى عند بدء البحث startSearchingForDriver)
// ==============================================================================
Timer? _heartbeatTimer;
void initConnectionWithSocket() {
if (isSocketConnected && socket != null) return;
@@ -345,21 +349,36 @@ class MapPassengerController extends GetxController {
.setTransports(['websocket'])
.disableAutoConnect()
.setQuery({'id': passengerId})
.setReconnectionAttempts(5)
.setReconnectionDelay(2000)
.setReconnectionAttempts(20)
.setReconnectionDelay(2400)
// ✅ أضف هذا السطر لحل مشكلة الـ Heartbeat مع PHPSocketIO
.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; // إعادة تعيين عداد المحاولات
_reconnectAttempts = 0;
_startHeartbeat(); // ← أضف هذا
update();
});
// دالة منفصلة للـ heartbeat
// ⚠️ معالج الانقطاع
socket.onDisconnect((_) {
Log.print("⚠️ Socket Disconnected");
@@ -391,6 +410,16 @@ class MapPassengerController extends GetxController {
});
}
void _startHeartbeat() {
_heartbeatTimer?.cancel();
_heartbeatTimer = Timer.periodic(const Duration(seconds: 25), (timer) {
if (isSocketConnected && socket.connected) {
socket.emit('heartbeat',
{'passenger_id': box.read(BoxName.passengerID).toString()});
}
});
}
// دالة مساعدة
bool _isActiveRideState() {
return currentRideState.value == RideState.searching ||
@@ -515,7 +544,7 @@ class MapPassengerController extends GetxController {
// 1. تجهيز الرابط (نفس API الـ Direction)
// نستخدم overview=full للحصول على الرسمة، و steps=false لتخفيف البيانات
String dynamicApiUrl =
'https://routesjo.intaleq.xyz/route/v1/driving/${driverPos.longitude},${driverPos.latitude};${passengerPos.longitude},${passengerPos.latitude}';
'${AppLink.routesOsm}/route/v1/driving/${driverPos.longitude},${driverPos.latitude};${passengerPos.longitude},${passengerPos.latitude}';
var uri = Uri.parse('$dynamicApiUrl?steps=false&overview=full');
Log.print('📍 Calculating Driver Route: $uri');
@@ -678,13 +707,17 @@ class MapPassengerController extends GetxController {
///
/// تستدعى من [Socket] أو [FCM] عند قيام السائق بإلغاء الرحلة.
/// تضمن عدم تضارب الإشعارات وتوحد تجربة المستخدم.
void processRideCancelledByDriver(dynamic data, {String source = "Unknown"}) {
Future<void> processRideCancelledByDriver(dynamic data,
{String source = "Unknown"}) async {
if (_isCancelProcessed) return;
_isCancelProcessed = true;
stopAllTimers();
if (Get.isDialogOpen == true) Get.back();
await RideLiveNotification.cancel();
IosLiveActivityService.endRideActivity(); // ✅ أضف هذا السطر
if (Get.isDialogOpen == true) Get.back();
await RideLiveNotification.cancel();
Get.defaultDialog(
title: "Sorry 😔".tr, // استخدام المفتاح الإنجليزي
titleStyle:
@@ -726,8 +759,10 @@ class MapPassengerController extends GetxController {
);
}
void handleNoDriverFound() {
Future<void> handleNoDriverFound() async {
stopAllTimers();
await RideLiveNotification.cancel();
IosLiveActivityService.endRideActivity(); // ✅ أضف هذا السطر
_isCancelProcessed = false;
currentRideState.value = RideState.noRide;
Get.offAll(() => const MapPagePassenger());
@@ -789,7 +824,7 @@ class MapPassengerController extends GetxController {
};
var response = await CRUD().post(
link: "${AppLink.ride}/rides/retry_search_drivers.php",
link: "${AppLink.rideServerSide}/rides/retry_search_drivers.php",
payload: payload,
);
@@ -813,11 +848,12 @@ class MapPassengerController extends GetxController {
///
/// يبدأ عداداً (مثلاً 90 ثانية). إذا لم يتم قبول الرحلة خلال هذه المدة،
/// يتم إنهاء البحث واستدعاء [handleNoDriverFound].
void startSearchingTimer() {
Future<void> startSearchingTimer() async {
_searchTimer?.cancel();
int seconds = 0;
Log.print("⏳ Search Timer Started (90s)...");
await RideLiveNotification.showSearching(driversStatusForSearchWindow);
_searchTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
seconds++;
@@ -850,7 +886,7 @@ class MapPassengerController extends GetxController {
/// 3. **تفعيل الواجهة:** تظهر ديالوج "السائق وصل" وتبدأ عداد الانتظار المجاني (5 دقائق).
///
/// * [source] : نص يوضح مصدر الاستدعاء (مثل "Socket" أو "FCM") لأغراض التتبع (Logging).
void processDriverArrival(String source) {
Future<void> processDriverArrival(String source) async {
// 1. الحارس: إذا تم التنفيذ سابقاً، توقف
if (currentRideState.value == RideState.driverArrived ||
_isArrivalProcessed) {
@@ -864,6 +900,7 @@ class MapPassengerController extends GetxController {
// 2. تحديث الحالة
currentRideState.value = RideState.driverArrived;
statusRide = 'Arrived';
await RideLiveNotification.showDriverArrived(driverName ?? '');
// 3. تشغيل واجهة الوصول والعداد
driverArrivePassengerDialoge();
@@ -881,8 +918,8 @@ class MapPassengerController extends GetxController {
/// تقوم بإغلاق السوكيت، إيقاف التتبع، والانتقال لشاشة التقييم والدفع.
///
/// * [driverList]: قائمة البيانات [driverId, rideId, token, price].
void processRideFinished(List<dynamic> driverList,
{String source = "Unknown"}) {
Future<void> processRideFinished(List<dynamic> driverList,
{String source = "Unknown"}) async {
// 1. الحارس: منع التكرار
if (currentRideState.value == RideState.finished || _isFinishProcessed) {
Log.print("✋ Ignored Finish Request from $source. Already Finished.");
@@ -912,7 +949,8 @@ class MapPassengerController extends GetxController {
"Please make sure not to leave any personal belongings in the car.".tr,
'tone1',
);
IosLiveActivityService.endRideActivity();
await RideLiveNotification.cancel();
// 5. استخراج البيانات والانتقال
if (driverList.length >= 4) {
String price = driverList[3].toString();
@@ -1185,9 +1223,24 @@ class MapPassengerController extends GetxController {
Log.print("⚠️ No Data in Payload. Fallback to API.");
await getUpdatedRideForDriverApply(rideId);
}
// أضف هذا بعد السطر الذي تستدعي فيه RideTrackingNative
await IosLiveActivityService.startRideActivity(
rideId: rideId,
driverName: driverName ?? 'السائق',
carDetails: '$make$carColor',
etaText: stringRemainingTimeToPassenger,
progress: 0.0,
);
// إشعارات (الأسعار، الأمان...)
_showRideStartNotifications();
final etaText = stringRemainingTimeToPassenger; // مثال: "8 دقائق"
final carInfo = '$make$model$licensePlate';
await RideLiveNotification.showDriverOnWay(
driverName: driverName,
etaText: etaText,
carInfo: carInfo,
);
update(); // تحديث الواجهة لإظهار بيانات السائق
@@ -1206,6 +1259,24 @@ class MapPassengerController extends GetxController {
// ج) تشغيل التايمر المحلي (للعد التنازلي فقط)
startTimerFromDriverToPassengerAfterApplied();
}
final int timeToPassengerSeconds =
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,
);
// 6. بدء تتبع الموقع الدوري (Polling Backup + Smart Rerouting)
// سيبدأ العمل بعد 6 ثواني
@@ -1350,7 +1421,7 @@ class MapPassengerController extends GetxController {
break;
}
_noRideSearchCount++;
Log.print('_noRideSearchCount: ${_noRideSearchCount}');
Log.print('_noRideSearchCount: $_noRideSearchCount');
_noRideNextAllowed = now.add(Duration(seconds: _noRideIntervalSec));
String currentCarType = box.read(BoxName.carType) ?? 'yet';
getCarsLocationByPassengerAndReloadMarker();
@@ -1805,40 +1876,57 @@ class MapPassengerController extends GetxController {
///
/// تستدعى عند استلام حدث بدء الرحلة سواء من السوكيت أو FCM.
/// تضمن انتقال التطبيق لحالة [RideState.inProgress] مرة واحدة فقط.
void processRideBegin({String source = "Unknown"}) {
// 1. الحارس: إذا بدأت الرحلة مسبقاً، تجاهل
Future<void> processRideBegin({String source = "Unknown"}) async {
// منطقك الحالي
if (currentRideState.value == RideState.inProgress ||
_isRideStartedProcessed) {
Log.print("✋ Ignored Start Request from $source. Already Started.");
return;
}
// شرط إضافي: يجب أن نكون في حالة "وصل السائق" أو "تم القبول" لبدء الرحلة
if (currentRideState.value != RideState.driverArrived &&
currentRideState.value != RideState.driverApplied) {
Log.print(
"⚠️ Start Request ignored due to invalid previous state: ${currentRideState.value}");
// يمكن السماح بها كحالة استثنائية (Fail-safe) إذا انقطع الاتصال سابقاً
// return;
}
_isRideStartedProcessed = true;
Log.print("🚀 Ride Started via $source! Processing...");
// 2. إغلاق أي ديالوج مفتوح (مثل ديالوج السائق وصل)
if (Get.isDialogOpen == true) Get.back();
// 3. تحديث الحالة
currentRideState.value = RideState.inProgress;
statusRide = 'Begin';
// 4. تصفير وإيقاف عدادات الانتظار
// إيقاف مؤقت الانتظار
remainingTimeDriverWaitPassenger5Minute = 0;
_stopWaitPassengerTimer(); // دالة إيقاف تايمر الانتظار
_stopWaitPassengerTimer();
// 5. بدء عداد وقت الرحلة الفعلي
// 1) بيانات السائق والرحلة
final driverName = this.driverName ?? 'السائق';
final driverPhone = this.driverPhone ?? '';
final carBrand = this.make ?? '';
final carColor = this.carColor ?? '';
final carPlate = this.licensePlate ?? '';
final carDetails = '$carBrand$carColor$carPlate';
final driverLat = driverCarsLocationToPassengerAfterApplied.last.latitude;
final driverLng = driverCarsLocationToPassengerAfterApplied.last.longitude;
final passengerLat = passengerLocation.latitude;
final passengerLng = passengerLocation.longitude;
final destLat = myDestination.latitude ?? 0.0;
final destLng = myDestination.longitude ?? 0.0;
final int timeToDestinationSeconds =
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,
);
// 3) بدء التايمر الداخلي الخاص بك (للـ ETA داخل التطبيق نفسه)
rideIsBeginPassengerTimer();
update();
}
@@ -2057,8 +2145,13 @@ class MapPassengerController extends GetxController {
}
// final mainBottomMenuMap = GlobalKey<AnimatedContainer>();
void changeBottomSheetShown() {
isBottomSheetShown = !isBottomSheetShown;
void changeBottomSheetShown({bool? forceValue}) {
if (forceValue != null) {
isBottomSheetShown = forceValue;
} else {
isBottomSheetShown = !isBottomSheetShown;
}
heightBottomSheetShown = isBottomSheetShown == true ? 250 : 0;
update();
}
@@ -2239,7 +2332,28 @@ class MapPassengerController extends GetxController {
int seconds = remainingTimeToPassengerFromDriverAfterApplied % 60;
stringRemainingTimeToPassenger =
'$minutes:${seconds.toString().padLeft(2, '0')}';
// تحويل الوقت أو المسافة إلى نسبة من 0.0 إلى 1.0
double currentProgress = 1 -
(remainingTimeToPassengerFromDriverAfterApplied /
timeToPassengerFromDriverAfterApplied);
// 🔴 التعديل هنا: نحدث الآيفون كل 5 ثواني فقط للحفاظ على البطارية وتجنب حظر أبل
if (secondsElapsed % 5 == 0) {
double currentProgress = 1 -
(remainingTimeToPassengerFromDriverAfterApplied /
(timeToPassengerFromDriverAfterApplied == 0
? 1
: timeToPassengerFromDriverAfterApplied));
IosLiveActivityService.updateRideActivity(
status: 'waiting',
driverName: driverName ?? 'السائق',
carDetails:
'$make$model$carColor', // من الأفضل إظهار اللون أيضاً
etaText: stringRemainingTimeToPassenger,
progress: currentProgress.clamp(0.0, 1.0),
);
}
// جلب موقع السائق كل 4 ثواني (Polling) ما دامت الرحلة نشطة
if (secondsElapsed % beginRideInterval == 0) {
// 2. تحديث موقع الراكب للسائق
@@ -2365,7 +2479,8 @@ class MapPassengerController extends GetxController {
Log.print("⏳ Ride Timer Started. Duration: $durationToRide sec");
// 3. بدء التايمر الدوري
_rideProgressTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
_rideProgressTimer =
Timer.periodic(const Duration(seconds: 1), (timer) async {
// أ) شرط الإيقاف الحاسم: إذا انتهت الرحلة أو ألغيت
if (currentRideState.value != RideState.inProgress) {
timer.cancel();
@@ -2392,15 +2507,42 @@ class MapPassengerController extends GetxController {
stringRemainingTimeRideBegin =
'$minutes:${seconds.toString().padLeft(2, '0')}';
// د) منطق الإشعارات (ربع الوقت)
// نحول progressTimerRideBegin (0..1) إلى نسبة (0..100)
final percent = (progressTimerRideBegin * 100).clamp(0, 100).toInt();
// ==============================================================
// 🔔 د) تحديث الإشعارات (هنا تم حل مشكلة الإزعاج)
// ==============================================================
// 1. تحديث الآيفون (Live Activity): يمكن تحديثه كل 5 ثواني لأنه "تحديث صامت" للشاشة فقط ولا يصدر صوتاً
if (remainingSeconds % 5 == 0 || remainingSeconds == 0) {
IosLiveActivityService.updateRideActivity(
status: 'inProgress', // الحالة تتغير هنا إلى جارية
driverName: driverName ?? '',
carDetails: '$make$model$carColor',
etaText: stringRemainingTimeRideBegin,
progress: progressTimerRideBegin.clamp(0.0, 1.0),
);
}
// 2. تحديث إشعار الهاتف العادي (RideLiveNotification):
// نحدثه كل دقيقة (60 ثانية) بدلاً من 5 ثواني حتى لا يزعج الراكب بالرنين المستمر!
if (remainingSeconds % 60 == 0 || remainingSeconds == 0) {
await RideLiveNotification.showTripInProgress(
percentage: percent,
etaText: stringRemainingTimeRideBegin,
);
}
// ==============================================================
// هـ) منطق الإشعارات لمنتصف الرحلة (يصدر تنبيه مرة واحدة فقط)
if (progressTimerRideBegin >= 0.25 &&
progressTimerRideBegin < 0.26 &&
!_hasShownSpeedWarning) {
// يمكن إضافة منطق إشعار منتصف الرحلة هنا
}
// هـ) مراقبة السرعة (Speed Check)
// نستخدم المتغير _hasShownSpeedWarning لمنع تكرار الديالوج بشكل مزعج
// و) مراقبة السرعة (Speed Check)
if (speed > 100 && !_hasShownSpeedWarning) {
_hasShownSpeedWarning = true; // ✅ قفل التنبيه حتى لا يتكرر
_triggerSpeedWarning();
@@ -2411,7 +2553,7 @@ class MapPassengerController extends GetxController {
_hasShownSpeedWarning = false;
}
// و) إنهاء التايمر إذا انتهى الوقت
// ز) إنهاء التايمر إذا انتهى الوقت
if (remainingSeconds <= 0) {
timer.cancel();
}
@@ -2640,7 +2782,7 @@ class MapPassengerController extends GetxController {
link: AppLink.getRideStatusFromStartApp,
payload: {'passenger_id': box.read(BoxName.passengerID)});
// print(res);
Log.print('rideStatusFromStartApp: ${res}');
Log.print('rideStatusFromStartApp: $res');
// print('1070');
if (res == 'failure') {
rideStatusFromStartApp = {
@@ -2796,60 +2938,66 @@ class MapPassengerController extends GetxController {
}));
}
Map<String, double>? extractCoordinatesFromLink(String link) {
Future<Map<String, double>?> extractCoordinatesFromLinkAsync(
String link) async {
try {
// Extract the URL part from the link by finding the first occurrence of "http"
// 1. استخراج الرابط فقط من النص (في حال كان هناك نص مع الرابط في الواتساب)
int urlStartIndex = link.indexOf(RegExp(r'https?://'));
if (urlStartIndex == -1) {
throw const FormatException('No URL found in the provided link.');
}
if (urlStartIndex == -1) return null;
String cleanLink = link.substring(urlStartIndex).trim();
// Extract the URL and clean it
link = link.substring(urlStartIndex).trim();
Uri uri = Uri.parse(cleanLink);
String finalUrl = cleanLink;
Uri uri = Uri.parse(link);
// Common coordinate query parameters
List<String> coordinateParams = ['q', 'cp', 'll'];
// Try to extract coordinates from query parameters
for (var param in coordinateParams) {
String? value = uri.queryParameters[param];
if (value != null && (value.contains(',') || value.contains('~'))) {
List<String> coordinates =
value.contains(',') ? value.split(',') : value.split('~');
if (coordinates.length == 2) {
double? latitude = double.tryParse(coordinates[0].trim());
double? longitude = double.tryParse(coordinates[1].trim());
if (latitude != null && longitude != null) {
return {
'latitude': latitude,
'longitude': longitude,
};
}
}
// 2. فك الروابط المختصرة (Unshorten URLs)
if (cleanLink.contains('goo.gl') ||
cleanLink.contains('maps.app.goo.gl')) {
try {
// نقوم بطلب HTTP عادي، وhttp يتبع التوجيه التلقائي (Redirects)
var response = await http.get(uri);
// نأخذ الرابط النهائي بعد التوجيه
finalUrl = response.request?.url.toString() ?? cleanLink;
} catch (e) {
Log.print('Failed to follow redirect: $e');
}
}
// Try to extract coordinates from the path
List<String> pathSegments = uri.pathSegments;
for (var segment in pathSegments) {
if (segment.contains(',')) {
List<String> coordinates = segment.split(',');
if (coordinates.length == 2) {
double? latitude = double.tryParse(coordinates[0].trim());
double? longitude = double.tryParse(coordinates[1].trim());
if (latitude != null && longitude != null) {
return {
'latitude': latitude,
'longitude': longitude,
};
}
}
}
Log.print('Final Unshortened URL: $finalUrl');
// 3. استخراج الإحداثيات باستخدام تعبيرات نمطية (Regex) قوية تغطي خرائط جوجل وغيرها
// النمط الأول: @lat,lng (الأكثر شيوعاً في خرائط جوجل)
RegExp regexAt = RegExp(r'@(-?\d+\.\d+),(-?\d+\.\d+)');
var matchAt = regexAt.firstMatch(finalUrl);
if (matchAt != null) {
return {
'latitude': double.parse(matchAt.group(1)!),
'longitude': double.parse(matchAt.group(2)!),
};
}
// النمط الثاني: q=lat,lng أو ll=lat,lng أو query=lat,lng
RegExp regexQuery =
RegExp(r'(?:q|ll|query)=(-?\d+\.\d+)[,~](-?\d+\.\d+)');
var matchQuery = regexQuery.firstMatch(finalUrl);
if (matchQuery != null) {
return {
'latitude': double.parse(matchQuery.group(1)!),
'longitude': double.parse(matchQuery.group(2)!),
};
}
// النمط الثالث: search/lat,lng (موجود في بعض أشكال خرائط جوجل)
RegExp regexSearch = RegExp(r'search/(-?\d+\.\d+),(-?\d+\.\d+)');
var matchSearch = regexSearch.firstMatch(finalUrl);
if (matchSearch != null) {
return {
'latitude': double.parse(matchSearch.group(1)!),
'longitude': double.parse(matchSearch.group(2)!),
};
}
} catch (e) {
print('Error parsing location link: $e');
Log.print('Error parsing location link: $e');
}
return null;
@@ -2857,8 +3005,9 @@ class MapPassengerController extends GetxController {
double latitudeWhatsApp = 0;
double longitudeWhatsApp = 0;
void handleWhatsAppLink(String link) {
Map<String, double>? coordinates = extractCoordinatesFromLink(link);
void handleWhatsAppLink(String link) async {
Map<String, double>? coordinates =
await extractCoordinatesFromLinkAsync(link);
if (coordinates != null) {
latitudeWhatsApp = coordinates['latitude']!;
@@ -3019,7 +3168,7 @@ class MapPassengerController extends GetxController {
"step3": placesCoordinate.length > 3 ? placesCoordinate[3] : "",
"step4": placesCoordinate.length > 4 ? placesCoordinate[4] : "",
};
Log.print('payload add_ride: ${payload}');
Log.print('payload add_ride: $payload');
try {
// الاتصال بـ add_ride.php
@@ -3412,7 +3561,7 @@ class MapPassengerController extends GetxController {
Future<String> getRideStatus(String rideId) async {
final response = await CRUD().get(
link: "${AppLink.ride}/ride/rides/getRideStatus.php",
link: "${AppLink.rideServerSide}/ride/rides/getRideStatus.php",
payload: {'id': rideId});
print(response);
print('2176');
@@ -3731,27 +3880,27 @@ class MapPassengerController extends GetxController {
box.write(BoxName.countryCode, 'Jordan');
// يمكنك تعيين AppLink.endPoint هنا إذا كان منطقك الداخلي لا يزال يعتمد عليه
box.write(BoxName.serverChosen,
AppLink.IntaleqSyriaServer); // مثال: اختر سيرفر سوريا للبيانات
AppLink.server); // مثال: اختر سيرفر سوريا للبيانات
return 'Jordan';
}
// 2. فحص سوريا
if (isPointInPolygon(passengerPoint, CountryPolygons.syriaBoundary)) {
box.write(BoxName.countryCode, 'Syria');
box.write(BoxName.serverChosen, AppLink.IntaleqSyriaServer);
box.write(BoxName.serverChosen, AppLink.server);
return 'Syria';
}
// 3. فحص مصر
if (isPointInPolygon(passengerPoint, CountryPolygons.egyptBoundary)) {
box.write(BoxName.countryCode, 'Egypt');
box.write(BoxName.serverChosen, AppLink.IntaleqAlexandriaServer);
box.write(BoxName.serverChosen, AppLink.server);
return 'Egypt';
}
// 4. الافتراضي (إذا كان خارج المناطق المخدومة)
box.write(BoxName.countryCode, 'Jordan');
box.write(BoxName.serverChosen, AppLink.IntaleqSyriaServer);
box.write(BoxName.serverChosen, AppLink.server);
return 'Unknown Location (Defaulting to Jordan)';
}
@@ -4574,7 +4723,7 @@ Intaleq Team''';
_timer?.cancel();
_masterTimer?.cancel(); // (أضف المؤقت الرئيسي)
_camThrottle?.cancel(); // (أضف مؤقت الكاميرا)
_heartbeatTimer?.cancel();
if (isSocketConnected) {
socket.emit('unsubscribe_all',
{'passenger_id': box.read(BoxName.passengerID).toString()});
@@ -4720,9 +4869,12 @@ Intaleq Team''';
clearPolyline();
data = [];
// إيقاف جميع التايمرات
// إيقاف جميع التايمرات
stopAllTimers();
currentRideState.value = RideState.cancelled;
await RideLiveNotification.cancel(); // إغلاق أندرويد
IosLiveActivityService.endRideActivity(); // ✅ إغلاق iOS
// 4. الاتصال بالسيرفر لإلغاء الرحلة وإبلاغ السائق
if (rideId != 'yet' && rideId != null) {
@@ -6143,7 +6295,7 @@ Intaleq Team''';
// Waypoints غير مدعومة حالياً في OSRM، لذلك تم تجاهلها
var uri = Uri.parse(
'$dynamicApiUrl?origin=$origin&destination=$destination&steps=false&overview=false');
Log.print('uri: ${uri}');
Log.print('uri: $uri');
// 3. إرسال الطلب مع الهيدر
http.Response response;
@@ -6169,7 +6321,7 @@ Intaleq Team''';
isDrawingRoute = false; // Reset state
responseData = json.decode(response.body);
Log.print('responseData: ${responseData}');
Log.print('responseData: $responseData');
if (responseData['status'] != 'ok') {
print('API returned an error: ${responseData['message']}');
@@ -6225,10 +6377,10 @@ Intaleq Team''';
// 2. الاتصال بالسيرفر - New OSRM format
var originCoords = origin.split(',');
String dynamicApiUrl =
'https://routesjo.intaleq.xyz/route/v1/driving/${originCoords[1]},${originCoords[0]};${lngDest},${latDest}';
'${AppLink.routesOsm}/route/v1/driving/${originCoords[1]},${originCoords[0]};$lngDest,$latDest';
var uri = Uri.parse('$dynamicApiUrl?steps=false&overview=full');
Log.print('Requesting Route URI (Attempt: ${attemptCount + 1}): ${uri}');
Log.print('Requesting Route URI (Attempt: ${attemptCount + 1}): $uri');
http.Response response;
Map<String, dynamic> responseData;
@@ -7344,7 +7496,7 @@ Intaleq Team''';
} catch (_) {}
update();
changeBottomSheetShown();
changeBottomSheetShown(forceValue: true);
}
List<LatLng> polylineCoordinate = [];
@@ -7779,27 +7931,59 @@ Intaleq Team''';
// --- دالة جديدة للاستماع ومعالجة الرابط ---
void _listenForDeepLink() {
// استمع إلى أي تغيير في الإحداثيات القادمة من الرابط
ever(_deepLinkController.deepLinkLatLng, (LatLng? latLng) {
if (latLng != null) {
print('MapPassengerController detected deep link LatLng: $latLng');
// عندما يتم استلام إحداثيات جديدة، عينها كوجهة
myDestination = latLng;
ever(_deepLinkController.rawDeepLink, (String? link) async {
if (link != null && link.isNotEmpty) {
Log.print('📍 MapPassengerController processing link: $link');
// قم بتشغيل المنطق الخاص بك لعرض المسار
// (تأكد من أن `passengerLocation` لديها قيمة أولاً)
if (passengerLocation != null) {
getDirectionMap(
'${passengerLocation.latitude},${passengerLocation.longitude}',
'${myDestination.latitude},${myDestination.longitude}');
// 1. استخراج الإحداثيات باستخدام الدالة الموجودة لديك مسبقاً
Map<String, double>? coordinates =
await extractCoordinatesFromLinkAsync(link);
if (coordinates != null) {
double destLat = coordinates['latitude']!;
double destLng = coordinates['longitude']!;
myDestination = LatLng(destLat, destLng);
// 2. التحقق من موقع الراكب الحالي
if (passengerLocation == null ||
(passengerLocation.latitude == 0 &&
passengerLocation.longitude == 0)) {
Log.print('⏳ Waiting for current location to calculate route...');
await getLocation(); // جلب موقع الراكب إذا لم يكن متاحاً
}
if (passengerLocation != null) {
String originStr =
'${passengerLocation.latitude},${passengerLocation.longitude}';
String destStr = '$destLat,$destLng';
Log.print(
'🚀 Drawing route from Deep Link: $originStr to $destStr');
// 3. مسح أي مسارات سابقة
clearPolyline();
// 4. استدعاء دالة رسم المسار وحساب التكلفة التي برمجتها
await getDirectionMap(originStr, destStr);
// 5. إظهار الواجهة السفلية للرحلة ليكون الطلب جاهزاً بنقرة واحدة
isBottomSheetShown = true;
heightBottomSheetShown = 250;
update();
Get.snackbar(
'Location Received'.tr,
'Route and prices have been calculated successfully!'.tr,
backgroundColor: AppColor.greenColor,
colorText: Colors.white,
);
}
} else {
// يمكنك إظهار رسالة للمستخدم لتمكين الموقع أولاً
print(
'Cannot process deep link route yet, passenger location is null.');
Log.print('⚠️ Could not extract valid coordinates from link: $link');
}
// إعادة تعيين القيمة إلى null لمنع التشغيل مرة أخرى عند إعادة بناء الواجهة
_deepLinkController.deepLinkLatLng.value = null;
// تفريغ الرابط بعد معالجته حتى لا يتم استدعاؤه مرة أخرى بالخطأ
_deepLinkController.rawDeepLink.value = null;
}
});
}