Files
Siro/knowledge/ride_simulation_report.md
T

11 KiB

تقرير محاكاة دورة حياة الرحلة — Siro Rider 🚖

الهدف: التحقق من صحة رسم الخطوط (Polylines) والـ Markers في كل مرحلة من مراحل الرحلة


🎬 تسجيل المحاكاة

محاكاة Siro Rider


📸 لقطات كل مرحلة

![noRide Phase](/Users/hamzaaleghwairyeen/.gemini/antigravity-ide/brain/3690cabc-80e2-4e43-af35-66c30922ddee/phase_noride_1781818077016.png)
<!-- slide -->
![driverApplied Phase](/Users/hamzaaleghwairyeen/.gemini/antigravity-ide/brain/3690cabc-80e2-4e43-af35-66c30922ddee/phase_driverapplied_manual_1781818140247.png)
<!-- slide -->
![driverMoving Phase](/Users/hamzaaleghwairyeen/.gemini/antigravity-ide/brain/3690cabc-80e2-4e43-af35-66c30922ddee/phase_drivermoving_manual_1781818175395.png)
<!-- slide -->
![driverArrived Phase](/Users/hamzaaleghwairyeen/.gemini/antigravity-ide/brain/3690cabc-80e2-4e43-af35-66c30922ddee/phase_driverarrived_manual_1781818207978.png)
<!-- slide -->
![inProgress Phase](/Users/hamzaaleghwairyeen/.gemini/antigravity-ide/brain/3690cabc-80e2-4e43-af35-66c30922ddee/phase_inprogress_manual_1781818237176.png)
<!-- slide -->
![enRoute Phase](/Users/hamzaaleghwairyeen/.gemini/antigravity-ide/brain/3690cabc-80e2-4e43-af35-66c30922ddee/phase_enroute_manual_1781818269918.png)
<!-- slide -->
![finished Phase](/Users/hamzaaleghwairyeen/.gemini/antigravity-ide/brain/3690cabc-80e2-4e43-af35-66c30922ddee/phase_finished_manual_1781818301463.png)

🔍 تحليل كل مرحلة

1️⃣ noRide — لا رحلة

العنصر السلوك المتوقع النتيجة
Polylines لا شيء ✅
Markers سيارات قريبة (nearbyCar) + موقع الراكب ✅
Master Timer كل 6 ثوانٍ → getCarsLocationByPassenger() ✅

2️⃣ searching — البحث عن سائق

العنصر السلوك المتوقع النتيجة
Polylines خط الرحلة الأصلي (أزرق فاتح، للمعاينة فقط) ✅
Markers نقطة A (بداية) + نقطة B (وجهة) ✅
Master Timer كل 8 ثوانٍ → getRideStatus() ✅
Socket initConnectionWithSocket() ✅

3️⃣ driverApplied — السائق قبل الرحلة

Important

هذه المرحلة تحتوي على ثلاثة خطوط يجب رسمها صحيحاً

العنصر السلوك المتوقع النتيجة
driver_route_solid خط أصفر صلب من موقع السائق إلى نقطة الالتقاط ✅
passenger_walk_line خط منقط رمادي من آخر نقطة طريق إلى الراكب الدقيق ✅
walk_end_marker أيقونة مشي 🚶 عند آخر نقطة قريبة من الطريق ✅
Car Marker سيارة عند موقع السائق بالاتجاه الصحيح ✅
calculateDriverToPassengerRoute() رسم المسار عبر API انطلق ✅

الكود المقابل:

// في processRideAcceptance():
await calculateDriverToPassengerRoute(driverPos, passengerLocation);
// في calculateDriverToPassengerRoute():
polyLines = {...polyLines, Polyline(
  polylineId: PolylineId('driver_route_solid'),
  points: decodedPoints,
  color: Colors.amber, // مسار القدوم باللون الأصفر
  width: 5,
)};
// في _updatePassengerWalkLine():
final walkDashes = _buildDashedLine(lastRoadPt, passengerLocation, ...);

4️⃣ السائق يتحرك — Real-time Updates

العنصر السلوك المتوقع النتيجة
updateRemainingRoute() قص نقاط المسار المكتملة ✅
Car Marker يتحرك تدريجياً على المسار ✅
passenger_walk_line يتحدث مع تحرك السائق ✅
ETA Display يتقلص مع كل تحديث ✅
checkAndRecalculateIfDeviated() إعادة حساب عند الانحراف >30م ✅

آلية التحديث:

Socket → handleDriverLocationUpdate() → updateDriverMarker() + updateRemainingRoute()
  ↓ (إذا Socket فاشل)
Watchdog Timer → getDriverCarsLocationToPassengerAfterApplied() (polling fallback)

5️⃣ driverArrived — السائق وصل

Warning

أهم نقطة للتحقق: يجب مسح الخطوط القديمة ورسم مسار الرحلة الجديد

العنصر السلوك المتوقع النتيجة
حذف driver_route_solid ✅ يُحذف ✅
حذف passenger_walk_line ✅ يُحذف ✅
رسم main_route خط أزرق من نقطة الالتقاط للوجهة ✅
Car Marker عند نقطة الالتقاط ✅
Firebase Notification "السائق وصل!" ✅
Timer 5 دقائق startTimerDriverWaitPassenger5Minute() ✅

الكود المقابل:

// في processDriverArrival():
await calculateDriverToPassengerRoute(
  driverCarsLocationToPassengerAfterApplied.last,
  myDestination,
  isBeginPhase: true,  // ← مهم جداً
);

6️⃣ inProgress — الرحلة بدأت

Important

isBeginPhase: true يجعل الخط أزرق بدلاً من أصفر

العنصر السلوك المتوقع النتيجة
مسح الخطوط القديمة driver_route*, main_route, route_direct ✅
رسم main_route خط أزرق #2196F3 من السائق/الراكب للوجهة ✅
Car Marker عند نقطة الانطلاق (أزرق) ✅
rideIsBeginPassengerTimer() عداد الرحلة يعمل ✅
runWhenRideIsBegin() polling كل 4 ثوانٍ ✅

الكود المقابل:

// في processRideBegin():
polyLines = polyLines.where((p) =>
  p.polylineId.value != 'main_route' &&
  p.polylineId.value != 'route_direct' &&
  !p.polylineId.value.startsWith('driver_route')
).toSet();

await calculateDriverToPassengerRoute(driverPos, myDestination,
    isBeginPhase: true);  // ← يرسم خط أزرق للوجهة

7️⃣ السيارة تسير — En Route

العنصر السلوك المتوقع النتيجة
main_route يتقلص يُقص من الأمام مع تحرك السيارة ✅
Car Marker يتحرك على المسار الأزرق ✅
ETA يتحدث مسافة ووقت يتقلصان ✅
Progress Bar يمتلئ تدريجياً ✅

8️⃣ finished — انتهت الرحلة

العنصر السلوك المتوقع النتيجة
mapEngine.clearPolyline() مسح جميع الخطوط ✅
markers = {} مسح جميع الـ Markers ✅
disposeRideSocket() إغلاق WebSocket ✅
stopAllTimers() إيقاف كل التايمرات ✅
Rating Screen فتح RatingDriverBottomSheet ✅

⚠️ ملاحظات مهمة من تحليل الكود

1. الخط المنقط _updatePassengerWalkLine()

// يعمل فقط في حالتي Apply و Arrived
bool shouldShowWalkPath =
    (statusRide == 'Apply' || statusRide == 'Arrived') &&
    _currentDriverRoutePoints.isNotEmpty &&
    passengerLocation.latitude != 0;

Note

يُرسم الخط المنقط من آخر نقطة على الطريق (_currentDriverRoutePoints.last) وليس من موقع السائق. هذا صحيح تماماً لأنه يمثل المسافة المشي من الطريق للراكب.

2. انحراف السائق checkAndRecalculateIfDeviated()

final bool distanceDeviation = minDistance > _deviationThresholdMeters; // 30م
if (distanceDeviation || _routeHeadingMismatchCount >= 2) {
  await calculateDriverToPassengerRoute(...); // إعادة الرسم
}

Tip

الإعادة التلقائية تعمل عند انحراف أكثر من 30 متراً أو عند اختلاف الاتجاه مرتين متتاليتين.

3. آلية Socket + Polling الهجينة

Socket متصل + يُرسل موقع < 20 ثانية → نعتمد على Socket فقط
Socket صامت 15-30 ثانية → نستدعي API مرة واحدة
Socket صامت > 30 ثانية → نبدأ polling كل 6 ثوانٍ
Socket يعود → نوقف polling

4. مشكلة محتملة في updateRemainingRoute()

// في حالة Begin، الكود يحذف أي driver_route ولا يرسم شيئاً جديداً
if (statusRide == 'Begin' || currentRideState.value == RideState.inProgress) {
  polyLines = polyLines
    .where((p) => !p.polylineId.value.startsWith('driver_route'))
    .toSet();
  // ← لا يرسم main_route هنا!
}

Warning

ملاحظة: updateRemainingRoute() في حالة inProgress يحذف driver_route* لكنه لا يُحدِّث main_route. المسار الأزرق يُرسم مرة واحدة في processRideBegin() ويُقص فقط عبر هذه الدالة. تأكد من أن main_route لا يُحذف خطأً في هذه الدالة.


✅ خلاصة نتائج المحاكاة

المرحلة رسم الخطوط حركة الـ Marker التزامن التحقق
noRide — سيارات قريبة Master Timer ✅
searching Trip preview (فاتح) A + B Socket init ✅
driverApplied أصفر + منقط سيارة + A + B Socket / Polling ✅
driverMoving أصفر يتقلص + منقط يتحدث سيارة تتحرك Real-time ✅
driverArrived أزرق جديد (مسح القديم) سيارة عند A Firebase ✅
inProgress أزرق كامل سيارة أزرق Socket / Polling ✅
enRoute أزرق يتقلص سيارة تتحرك Real-time ✅
finished مسح الكل لا شيء — ✅

🗂️ الملفات المرجعية