2026-03-3-1
This commit is contained in:
@@ -765,6 +765,7 @@ class MapPassengerController extends GetxController {
|
||||
IosLiveActivityService.endRideActivity(); // ✅ أضف هذا السطر
|
||||
_isCancelProcessed = false;
|
||||
currentRideState.value = RideState.noRide;
|
||||
resetAllMapStates();
|
||||
Get.offAll(() => const MapPagePassenger());
|
||||
|
||||
Get.defaultDialog(
|
||||
@@ -2116,20 +2117,18 @@ class MapPassengerController extends GetxController {
|
||||
update();
|
||||
} else {
|
||||
var res = placesDestination[index];
|
||||
|
||||
// استخراج الاسم من displayName.text أو بديله
|
||||
hintTextDestinationPoint = res['displayName']?['text'] ??
|
||||
res['formattedAddress'] ??
|
||||
'Unknown Place';
|
||||
|
||||
// استخراج الإحداثيات
|
||||
double? lat = res['location']?['latitude'];
|
||||
double? lng = res['location']?['longitude'];
|
||||
|
||||
if (lat != null && lng != null) {
|
||||
newMyLocation = LatLng(lat, lng);
|
||||
// 🔥 الحل: تحريك الكاميرا فوراً للهدف حتى لا يتم مسحه عند إغلاق الكيبورد 🔥
|
||||
mapController
|
||||
?.animateCamera(CameraUpdate.newLatLngZoom(newMyLocation, 16));
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
}
|
||||
@@ -2141,6 +2140,8 @@ class MapPassengerController extends GetxController {
|
||||
double lng = recentLocations[index]['longitude'];
|
||||
newMyLocation = LatLng(lat, lng);
|
||||
|
||||
// 🔥 تحريك الكاميرا فوراً 🔥
|
||||
mapController?.animateCamera(CameraUpdate.newLatLngZoom(newMyLocation, 16));
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -2517,7 +2518,7 @@ class MapPassengerController extends GetxController {
|
||||
// 1. تحديث الآيفون (Live Activity): يمكن تحديثه كل 5 ثواني لأنه "تحديث صامت" للشاشة فقط ولا يصدر صوتاً
|
||||
if (remainingSeconds % 5 == 0 || remainingSeconds == 0) {
|
||||
IosLiveActivityService.updateRideActivity(
|
||||
status: 'inProgress', // الحالة تتغير هنا إلى جارية
|
||||
status: 'ongoing', // ['waiting', 'ongoing']
|
||||
driverName: driverName ?? '',
|
||||
carDetails: '$make • $model • $carColor',
|
||||
etaText: stringRemainingTimeRideBegin,
|
||||
@@ -2734,7 +2735,7 @@ class MapPassengerController extends GetxController {
|
||||
|
||||
// إيقاف التايمرات
|
||||
stopAllTimers();
|
||||
|
||||
resetAllMapStates();
|
||||
clearPolyline();
|
||||
clearMarkersExceptStartEnd();
|
||||
markers.clear();
|
||||
@@ -4862,12 +4863,12 @@ Intaleq Team''';
|
||||
}
|
||||
|
||||
// 3. التنظيف المحلي الفوري (UX Optimization)
|
||||
// نقوم بتنظيف الواجهة فوراً ليشعر المستخدم بالاستجابة السريعة
|
||||
Get.back(); // إغلاق الـ BottomSheet
|
||||
changeCancelRidePageShow(); // إخفاء زر الإلغاء إن وجد
|
||||
clearPlacesDestination();
|
||||
clearPolyline();
|
||||
data = [];
|
||||
if (isCancelRidePageShown)
|
||||
changeCancelRidePageShow(); // إخفاء زر الإلغاء إن وجد
|
||||
|
||||
// 🔥 استدعاء دالة التنظيف الشاملة هنا 🔥
|
||||
resetAllMapStates();
|
||||
|
||||
// إيقاف جميع التايمرات
|
||||
// إيقاف جميع التايمرات
|
||||
@@ -5551,7 +5552,7 @@ Intaleq Team''';
|
||||
|
||||
// تحديث الكاميرا بثروتل
|
||||
void onCameraMoveThrottled(CameraPosition pos) {
|
||||
if (_camThrottle?.isActive ?? false) return;
|
||||
_camThrottle?.cancel();
|
||||
_camThrottle = Timer(const Duration(milliseconds: 160), () {
|
||||
// ضع فقط المنطق الضروري هنا لتقليل الحمل
|
||||
int waypointsLength = Get.find<WayPointController>().wayPoints.length;
|
||||
@@ -6405,7 +6406,6 @@ Intaleq Team''';
|
||||
// 🛑 الفحص الأمني (Sanity Check) - Updated for new format
|
||||
// ============================================================
|
||||
|
||||
// البيانات الآن داخل routes[0]
|
||||
if (responseData['routes'] == null || responseData['routes'].isEmpty) {
|
||||
if (attemptCount < 2) {
|
||||
await _retryProcess(origin, destination, waypoints, attemptCount);
|
||||
@@ -6426,7 +6426,6 @@ Intaleq Team''';
|
||||
double aerialDistance =
|
||||
Geolocator.distanceBetween(startLat, startLng, latDest, lngDest);
|
||||
|
||||
// الشرط: مسافة السيرفر صفرية أو صغيرة جداً بينما الحقيقية كبيرة
|
||||
if (apiDistanceMeters < 50.0 && aerialDistance > 200.0) {
|
||||
Log.print(
|
||||
"⚠️ Suspicious Route detected! Server: $apiDistanceMeters m | Aerial: $aerialDistance m");
|
||||
@@ -6452,18 +6451,15 @@ Intaleq Team''';
|
||||
box.remove(BoxName.tripData);
|
||||
box.write(BoxName.tripData, routeData);
|
||||
|
||||
// duration and distance من routes[0]
|
||||
durationToRide =
|
||||
((routeData['duration'] as num) * kDurationScalar).toInt();
|
||||
double distanceOfTrip = (routeData['distance'] as num) / 1000.0;
|
||||
distance = distanceOfTrip;
|
||||
|
||||
// steps الآن داخل legs[0].steps
|
||||
data = routeData['legs'] != null && routeData['legs'].isNotEmpty
|
||||
? (routeData['legs'][0]['steps'] ?? [])
|
||||
: [];
|
||||
|
||||
// معالجة الرسم (Polyline) - الحقل الآن اسمه geometry بدلاً من polyline
|
||||
String pointsString = routeData['geometry'] ?? "";
|
||||
List<LatLng> decodedPoints = [];
|
||||
|
||||
@@ -6471,7 +6467,6 @@ Intaleq Team''';
|
||||
decodedPoints = await compute(decodePolylineIsolate, pointsString);
|
||||
}
|
||||
|
||||
// حماية إضافية: لو البولي لاين فارغ رغم أن المسافة سليمة
|
||||
if (decodedPoints.isEmpty) {
|
||||
_handleFatalError("Map Error".tr, "Received empty route data.".tr);
|
||||
return;
|
||||
@@ -6507,7 +6502,6 @@ Intaleq Team''';
|
||||
maxLng == null ? point.longitude : max(maxLng, point.longitude);
|
||||
}
|
||||
|
||||
// إغلاق شاشة التحميل بنجاح
|
||||
if (Get.isBottomSheetOpen ?? false) Get.back();
|
||||
isDrawingRoute = false;
|
||||
isLoading = false;
|
||||
@@ -6543,33 +6537,23 @@ Intaleq Team''';
|
||||
'$distance ${'KM'.tr} ⌛ ${hours > 0 ? '$hours H $minutes m' : '$minutes m'}'),
|
||||
));
|
||||
|
||||
// 7. رسم الخط (فقط في حال النجاح)
|
||||
// 7. رسم الخط (النظام الجديد لجميع الأجهزة)
|
||||
if (polyLines.isNotEmpty) clearPolyline();
|
||||
bool isLowEndDevice = box.read(BoxName.lowEndMode) ?? true;
|
||||
|
||||
if (isLowEndDevice) {
|
||||
polyLines.add(Polyline(
|
||||
polylineId: const PolylineId('route_solid'),
|
||||
points: polylineCoordinates,
|
||||
width: 6,
|
||||
color: AppColor.primaryColor,
|
||||
endCap: Cap.roundCap,
|
||||
startCap: Cap.roundCap,
|
||||
jointType: JointType.round,
|
||||
));
|
||||
} else {
|
||||
polyLines.addAll(_createGradientPolylines(polylineCoordinates,
|
||||
const Color(0xFF00E5FF), const Color(0xFFFF4081)));
|
||||
}
|
||||
|
||||
rideConfirm = false;
|
||||
isMarkersShown = true;
|
||||
update();
|
||||
update(); // تحديث أولي لإظهار الخريطة والماركرز
|
||||
|
||||
// إظهار الباتم شيت للسعر
|
||||
bottomSheet();
|
||||
} catch (e) {
|
||||
// محاولة أخيرة عند حدوث Exception
|
||||
|
||||
// تشغيل الأنيميشن الخفيف لومضات المسار
|
||||
_playRouteAnimation(polylineCoordinates);
|
||||
} catch (e, stackTrace) {
|
||||
// 🚨 هذا السطر سيفضح المشكلة الحقيقية! 🚨
|
||||
print('🚨 CRITICAL ERROR IN getDirectionMap: $e');
|
||||
print('🚨 STACKTRACE: $stackTrace');
|
||||
|
||||
if (attemptCount < 2) {
|
||||
await _retryProcess(origin, destination, waypoints, attemptCount);
|
||||
} else {
|
||||
@@ -6579,6 +6563,64 @@ Intaleq Team''';
|
||||
}
|
||||
}
|
||||
|
||||
// --- دالة الأنيميشن الجديدة ---
|
||||
Future<void> _playRouteAnimation(List<LatLng> coords) async {
|
||||
const String routeId = 'route_solid';
|
||||
|
||||
// الألوان المطلوبة (بإمكانك تغيير AppColor.primaryColor إلى ما يناسبك)
|
||||
Color finalColor =
|
||||
AppColor.primaryColor; // اللون النهائي الثابت (مثل الأزرق)
|
||||
Color lightColor = Colors.grey.shade400; // لون التحديث الفاتح (رمادي)
|
||||
Color darkColor = Colors.grey.shade700; // لون التحديث الغامق (رمادي غامق)
|
||||
|
||||
// تكرار العملية 4 مرات لإعطاء تأثير التحميل والتحديث
|
||||
for (int i = 0; i < 4; i++) {
|
||||
// الحالة 1: لون فاتح وعرض أقل
|
||||
polyLines.removeWhere((p) => p.polylineId.value == routeId);
|
||||
polyLines.add(Polyline(
|
||||
polylineId: const PolylineId(routeId),
|
||||
points: coords,
|
||||
width: 5,
|
||||
color: lightColor,
|
||||
endCap: Cap.roundCap,
|
||||
startCap: Cap.roundCap,
|
||||
jointType: JointType.round,
|
||||
zIndex: 1,
|
||||
));
|
||||
update();
|
||||
await Future.delayed(const Duration(milliseconds: 250));
|
||||
|
||||
// الحالة 2: لون غامق وعرض أكبر
|
||||
polyLines.removeWhere((p) => p.polylineId.value == routeId);
|
||||
polyLines.add(Polyline(
|
||||
polylineId: const PolylineId(routeId),
|
||||
points: coords,
|
||||
width: 6,
|
||||
color: darkColor,
|
||||
endCap: Cap.roundCap,
|
||||
startCap: Cap.roundCap,
|
||||
jointType: JointType.round,
|
||||
zIndex: 2,
|
||||
));
|
||||
update();
|
||||
await Future.delayed(const Duration(milliseconds: 250));
|
||||
}
|
||||
|
||||
// بعد الانتهاء من الأنيميشن، يتم تثبيت المسار على اللون الأساسي للتطبيق
|
||||
polyLines.removeWhere((p) => p.polylineId.value == routeId);
|
||||
polyLines.add(Polyline(
|
||||
polylineId: const PolylineId(routeId),
|
||||
points: coords,
|
||||
width: 6,
|
||||
color: finalColor,
|
||||
endCap: Cap.roundCap,
|
||||
startCap: Cap.roundCap,
|
||||
jointType: JointType.round,
|
||||
zIndex: 3,
|
||||
));
|
||||
update();
|
||||
}
|
||||
|
||||
// --- دالة المساعدة لإعادة المحاولة ---
|
||||
Future<void> _retryProcess(String origin, String dest, List<String> waypoints,
|
||||
int currentAttempt) async {
|
||||
@@ -6588,6 +6630,38 @@ Intaleq Team''';
|
||||
getDirectionMap(origin, dest, waypoints, currentAttempt + 1);
|
||||
}
|
||||
|
||||
// --- دالة جديدة لتنظيف الخريطة بالكامل ومنع تداخل الرحلات ---
|
||||
void resetAllMapStates() {
|
||||
Log.print('🧹 Resetting all map states to prevent sticky location bug');
|
||||
|
||||
clearPlacesDestination();
|
||||
clearPlacesStart();
|
||||
clearPolyline();
|
||||
data = [];
|
||||
|
||||
passengerStartLocationFromMap = false;
|
||||
startLocationFromMap = false;
|
||||
isPickerShown = false;
|
||||
workLocationFromMap = false;
|
||||
homeLocationFromMap = false;
|
||||
isAnotherOreder = false;
|
||||
isWhatsAppOrder = false;
|
||||
|
||||
// ✅ أضف هذا: reset الوجهة لموقع الراكب حتى لا تبقى قيمة الرحلة القديمة
|
||||
myDestination = passengerLocation;
|
||||
hintTextDestinationPoint = 'Select your destination'.tr;
|
||||
|
||||
placeDestinationController.clear();
|
||||
placeStartController.clear();
|
||||
|
||||
rideConfirm = false;
|
||||
shouldFetch = false;
|
||||
isDrawingRoute = false;
|
||||
isLoading = false;
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
// 🛑 دالة الخطأ القاتل (تغلق كل شيء وتعيد المستخدم للخريطة)
|
||||
// -----------------------------------------------------------------------------------------
|
||||
|
||||
@@ -1424,6 +1424,19 @@ class MyTranslation extends Translations {
|
||||
"We Are Sorry That we dont have cars in your Location!":
|
||||
"نأسف لعدم توفر سيارات في موقعك!",
|
||||
"Choose from Map": "اختر من الخريطة",
|
||||
'Destination Set': "تم تعيين الوجهة",
|
||||
'Now move the map to your pickup point':
|
||||
"الآن حرك الخريطة إلى نقطة الانطلاق الخاصة بك",
|
||||
'Move map to your pickup point':
|
||||
"حرك الخريطة إلى نقطة الانطلاق الخاصة بك",
|
||||
'Move map to set start location': "حرك الخريطة لتعيين موقع الانطلاق",
|
||||
'Move map to your work location': "حرك الخريطة إلى موقع عملك",
|
||||
'Move map to your home location': "حرك الخريطة إلى موقع منزلك",
|
||||
'Move map to select destination': "حرك الخريطة لاختيار الوجهة",
|
||||
'Confirm Pickup Location': "تأكيد موقع الانطلاق",
|
||||
'Open': "فتح",
|
||||
'Set Destination': "تعيين الوجهة",
|
||||
'Tap to search your destination': "اضغط للبحث عن وجهتك",
|
||||
"Pick your ride location on the map - Tap to confirm":
|
||||
"اختر موقع رحلتك على الخريطة - اضغط للتأكيد",
|
||||
"Intaleq is the ride-hailing app that is safe, reliable, and accessible.":
|
||||
|
||||
Reference in New Issue
Block a user