2026-03-3-1

This commit is contained in:
Hamza-Ayed
2026-03-03 02:07:55 +03:00
parent 76c04702cd
commit 9de4cb0a84
13 changed files with 969 additions and 575 deletions

View File

@@ -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();
}
// -----------------------------------------------------------------------------------------
// 🛑 دالة الخطأ القاتل (تغلق كل شيء وتعيد المستخدم للخريطة)
// -----------------------------------------------------------------------------------------

View File

@@ -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.":