Files
Siro/knowledge/ride_simulation_report.md
2026-06-19 01:47:48 +03:00

11 KiB
Raw Blame History

تقرير محاكاة دورة حياة الرحلة — 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 مسح الكل لا شيء

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