Update: 2026-06-19 14:01:15

This commit is contained in:
Hamza-Ayed
2026-06-19 14:01:15 +03:00
parent a0495147c4
commit 017bec86fa
3 changed files with 120 additions and 8 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -177,12 +177,68 @@ _cameraFollowTimer = Timer.periodic(const Duration(seconds: 8), (timer) { ... })
## 4. نظام الملاحة التفاعلي ورسم المسارات (Interactive Navigation & Mapping) ## 4. نظام الملاحة التفاعلي ورسم المسارات (Interactive Navigation & Mapping)
<div dir="rtl" align="right"> <div dir="rtl" align="right">
يعتمد تطبيق السائق على خرائط انطلق المبنية على محرك مابليبرا (MapLibre)، ويتم استدعاء مسار الملاحة من سيرفر SaaS عبر الدالة يعتمد تطبيق السائق على خرائط انطلق المبنية على محرك مابليبرا (MapLibre)، ويتم استدعاء ورسم مسارات الملاحة التفاعلية في تطبيق السائق بدقة وتفصيل عالية عبر الفئات والأساليب التالية:
</div>
### أ. رسم المسارات المزدوجة ونوافذ المعلومات في شاشة طلب الرحلة (Dual-Route & Info Windows in Order Request)
<div dir="rtl" align="right">
في شاشة استقبال الطلب
</div>
[OrderRequestController](file:///Users/hamzaaleghwairyeen/development/App/Siro/siro_driver/lib/controller/home/captin/order_request_controller.dart)
<div dir="rtl" align="right">
يقوم التطبيق بالاستعلام ورسم مسارين جغرافيين في نفس الوقت عبر الدالة
</div>
[_calculateFullJourney](file:///Users/hamzaaleghwairyeen/development/App/Siro/siro_driver/lib/controller/home/captin/order_request_controller.dart#L226)
<div dir="rtl" align="right">
حيث يستدعي:
1. مسار الانطلاق (Pickup Route): من موقع السائق الحالي إلى موقع الراكب (يرسم باللون الأصفر/الذهبي).
2. مسار الرحلة الرئيسي (Trip Route): من موقع الراكب إلى الوجهة النهائية (يرسم باللون الأسود/الأزرق).
ولعرض تفاصيل المسافة والوقت كصندوق معلومات عائم (Info Window) مباشرة فوق الخريطة، يتم استدعاء الدالة
</div>
[_updateMarkers](file:///Users/hamzaaleghwairyeen/development/App/Siro/siro_driver/lib/controller/home/captin/order_request_controller.dart#L468)
<div dir="rtl" align="right">
والتي تقوم بطلب مولد الماركرز
</div>
[MarkerGenerator.createCustomMarkerBitmap](file:///Users/hamzaaleghwairyeen/development/App/Siro/siro_driver/lib/views/home/Captin/orderCaptin/marker_generator.dart)
<div dir="rtl" align="right">
لتوليد صور ماركر مخصصة ديناميكياً تحتوي على الوقت والمسافة كصندوق معلومات يعلو الخريطة فوق نقطة الركوب (أقرب مسافة وزمن وصول للسائق) ونقطة الوصول (المسافة والزمن المقدرين للرحلة الكلية للراكب).
</div>
### ب. تسلسل رسم وحذف المسارات أثناء دورة حياة الرحلة (Lifecycle Route Transitions)
<div dir="rtl" align="right">
تخضع مسارات الخريطة لعملية تحديث وحذف دورية أثناء الرحلة في الكنترولر
</div>
[MapDriverController](file:///Users/hamzaaleghwairyeen/development/App/Siro/siro_driver/lib/controller/home/captin/map_driver_controller.dart)
<div dir="rtl" align="right">
وفق التسلسل التالي:
1. **عند قبول الطلب**: يتم مسح خط الوجهة، ورسم خط الملاحة الجاري باتجاه الراكب (باللون الأصفر) عبر استدعاء
</div> </div>
[getRoute](file:///Users/hamzaaleghwairyeen/development/App/Siro/siro_driver/lib/controller/home/captin/map_driver_controller.dart#L1885) [getRoute](file:///Users/hamzaaleghwairyeen/development/App/Siro/siro_driver/lib/controller/home/captin/map_driver_controller.dart#L1885)
### أ. تفادي انهيار الخرائط عند المسافات الصفرية (Same-Device Crash Protection) <div dir="rtl" align="right">
2. **عند وصول السائق لموقع الراكب**: بمجرد ضغط السائق على زر "وصلت" وتأكيده، يتم استدعاء الدالة
</div>
[clearPolyline](file:///Users/hamzaaleghwairyeen/development/App/Siro/siro_driver/lib/controller/home/captin/map_driver_controller.dart#L422)
<div dir="rtl" align="right">
والتي تقوم بمسح وحذف المسار الجاري الأول (الخط الأصفر الموصل للراكب) بالكامل من الخريطة لتنظيف الشاشة.
3. **عند بدء الرحلة الفعلي**: يتم الاستعلام ورسم المسار الأزرق/الأسود الجديد المؤدي للوجهة النهائية مباشرة باتجاه وجهة الراكب عبر إعادة استدعاء دالة المسار `getRoute` للوجهة.
</div>
### ج. تفادي انهيار الخرائط عند المسافات الصفرية (Same-Device Crash Protection)
<div dir="rtl" align="right"> <div dir="rtl" align="right">
عند تشغيل اختبارات الرحلة وكون موقع السائق والراكب متطابقين تماماً (مسافة أقل من 10 أمتار)، ينهار محرك الملاحة المكتوب بلغة C++ بسبب إحداثيات الصندوق المحيط (Bounds) ذات العرض الصفرى مطلقةً استثناء `std::domain_error`. لمنع ذلك، يقوم الكود بفحص المسافة، وفي حال كانت متطابقة يقوم بإظهار نافذة تنبيه عند تشغيل اختبارات الرحلة وكون موقع السائق والراكب متطابقين تماماً (مسافة أقل من 10 أمتار)، ينهار محرك الملاحة المكتوب بلغة C++ بسبب إحداثيات الصندوق المحيط (Bounds) ذات العرض الصفرى مطلقةً استثناء `std::domain_error`. لمنع ذلك، يقوم الكود بفحص المسافة، وفي حال كانت متطابقة يقوم بإظهار نافذة تنبيه
</div> </div>
@@ -193,7 +249,7 @@ _cameraFollowTimer = Timer.periodic(const Duration(seconds: 8), (timer) { ... })
ثم الانتقال قسرياً لتطبيق زوم تقريبي آمن بدلاً من احتواء الحدود الصفرية. ثم الانتقال قسرياً لتطبيق زوم تقريبي آمن بدلاً من احتواء الحدود الصفرية.
</div> </div>
### ب. تحديث المسار المقطوع بنظام النافذة المنزلقة (Bidirectional Sliding Window) ### د. تحديث المسار المقطوع بنظام النافذة المنزلقة (Bidirectional Sliding Window)
<div dir="rtl" align="right"> <div dir="rtl" align="right">
لمنع إعادة رسم كامل خط المسار (Polyline) عند كل إرسال للموقع، يتم استخدام نافذة بحث منزلقة ثنائية الاتجاه تتكون من 60 نقطة (30 للخلف و 30 للأمام) في الدالة لمنع إعادة رسم كامل خط المسار (Polyline) عند كل إرسال للموقع، يتم استخدام نافذة بحث منزلقة ثنائية الاتجاه تتكون من 60 نقطة (30 للخلف و 30 للأمام) في الدالة
</div> </div>
@@ -204,7 +260,7 @@ _cameraFollowTimer = Timer.periodic(const Duration(seconds: 8), (timer) { ... })
تحدد الدالة أقرب نقطة لموقع السائق الحالي على المسار المخزن، وتقوم بقطع الـ Polyline إلى جزأين: مسار مقطوع بلون رمادي ومسار متبقي بلون أزرق/أصفر، وتحديث الخريطة فقط عند تجاوز إزاحة تزيد عن 50 متراً. تحدد الدالة أقرب نقطة لموقع السائق الحالي على المسار المخزن، وتقوم بقطع الـ Polyline إلى جزأين: مسار مقطوع بلون رمادي ومسار متبقي بلون أزرق/أصفر، وتحديث الخريطة فقط عند تجاوز إزاحة تزيد عن 50 متراً.
</div> </div>
### ج. رسم خطوط المشي المنقطة (Passenger Walk Dotted Line) ### هـ. رسم خطوط المشي المنقطة (Passenger Walk Dotted Line)
<div dir="rtl" align="right"> <div dir="rtl" align="right">
عندما يكون موقع الراكب الفعلي بعيداً عن أقرب طريق إسفلتي متاح للسيارات، يتم استدعاء الدالة عندما يكون موقع الراكب الفعلي بعيداً عن أقرب طريق إسفلتي متاح للسيارات، يتم استدعاء الدالة
</div> </div>

View File

@@ -1317,7 +1317,7 @@
<!-- Passenger Marker --> <!-- Passenger Marker -->
<div class="marker" id="marker-pax" style="top: 250px; left: 450px; display: none;"> <div class="marker" id="marker-pax" style="top: 250px; left: 450px; display: none;">
<div class="marker-label">Mahmoud (Pickup)</div> <div class="marker-label" id="pax-label">Mahmoud (Pickup)</div>
<div class="marker-dot marker-pax"> <div class="marker-dot marker-pax">
<i data-lucide="user" style="width: 14px; height: 14px; color: #000;"></i> <i data-lucide="user" style="width: 14px; height: 14px; color: #000;"></i>
</div> </div>
@@ -1325,7 +1325,7 @@
<!-- Destination Marker --> <!-- Destination Marker -->
<div class="marker" id="marker-dest" style="top: 450px; left: 450px; display: none;"> <div class="marker" id="marker-dest" style="top: 450px; left: 450px; display: none;">
<div class="marker-label">Mezzeh (Destination)</div> <div class="marker-label" id="dest-label">Mezzeh (Destination)</div>
<div class="marker-dot marker-dest"> <div class="marker-dot marker-dest">
<i data-lucide="flag" style="width: 14px; height: 14px; color: #fff;"></i> <i data-lucide="flag" style="width: 14px; height: 14px; color: #fff;"></i>
</div> </div>
@@ -1784,6 +1784,17 @@
fillEl.style.strokeDashoffset = '0'; fillEl.style.strokeDashoffset = '0';
document.getElementById('txt-overlay-timer').innerText = overlayTimer; document.getElementById('txt-overlay-timer').innerText = overlayTimer;
// Draw BOTH routes on the map during the Order Request view
drawRoute(driverPos, paxPos, 'both');
// Show both markers on map
document.getElementById('marker-pax').style.display = 'flex';
document.getElementById('marker-dest').style.display = 'flex';
// Update markers to act as dynamic Info Windows (Time & Distance)
document.getElementById('pax-label').innerHTML = `Mahmoud (Pickup)<br><span style="color:var(--accent-gold); font-weight:bold; font-size:0.7rem;">2.1 km | 5 min</span>`;
document.getElementById('dest-label').innerHTML = `Mezzeh (Destination)<br><span style="color:var(--accent-blue); font-weight:bold; font-size:0.7rem;">12.5 km | 20 min</span>`;
overlayInterval = setInterval(() => { overlayInterval = setInterval(() => {
overlayTimer--; overlayTimer--;
document.getElementById('txt-overlay-timer').innerText = overlayTimer; document.getElementById('txt-overlay-timer').innerText = overlayTimer;
@@ -1798,6 +1809,11 @@
addLog("Order Request timed out. Missed count incremented.", "error"); addLog("Order Request timed out. Missed count incremented.", "error");
orderOverlay.style.display = 'none'; orderOverlay.style.display = 'none';
driverState = 'ONLINE'; driverState = 'ONLINE';
// Clear map state
document.getElementById('marker-pax').style.display = 'none';
document.getElementById('marker-dest').style.display = 'none';
ctx.clearRect(0, 0, routeCanvas.width, routeCanvas.height);
} }
}, 1000); }, 1000);
} }
@@ -1842,11 +1858,13 @@
document.getElementById('panel-online').style.display = 'none'; document.getElementById('panel-online').style.display = 'none';
document.getElementById('panel-ride-active').style.display = 'flex'; document.getElementById('panel-ride-active').style.display = 'flex';
// Show passenger marker and hide destination marker initially
document.getElementById('marker-pax').style.display = 'flex'; document.getElementById('marker-pax').style.display = 'flex';
document.getElementById('marker-dest').style.display = 'flex'; document.getElementById('marker-dest').style.display = 'none'; // Clear destination marker
document.getElementById('pax-label').innerHTML = `Mahmoud (Pickup)`; // Restore default label
document.getElementById('radar-pulse').style.display = 'none'; document.getElementById('radar-pulse').style.display = 'none';
// Draw route on map // Draw ONLY the yellow route to passenger
drawRoute(driverPos, paxPos, 'yellow'); drawRoute(driverPos, paxPos, 'yellow');
// Update TBT instructions Panel // Update TBT instructions Panel
@@ -1858,6 +1876,37 @@
// Draw lines on canvas // Draw lines on canvas
function drawRoute(start, end, type = 'yellow') { function drawRoute(start, end, type = 'yellow') {
ctx.clearRect(0, 0, routeCanvas.width, routeCanvas.height); ctx.clearRect(0, 0, routeCanvas.width, routeCanvas.height);
if (type === 'both') {
// 1. Draw yellow route (driver to passenger)
ctx.beginPath();
ctx.lineWidth = 6;
ctx.strokeStyle = '#eab308'; // Amber
ctx.moveTo(start.x, start.y);
ctx.lineTo(end.x, start.y);
ctx.lineTo(end.x, end.y);
ctx.stroke();
// Draw dotted walk line from road (corner) to actual offroad pax position
ctx.beginPath();
ctx.lineWidth = 3;
ctx.strokeStyle = '#94a3b8';
ctx.setLineDash([6, 6]);
ctx.moveTo(end.x, start.y);
ctx.lineTo(end.x + 20, end.y - 30);
ctx.stroke();
ctx.setLineDash([]);
// 2. Draw blue route (passenger to destination)
ctx.beginPath();
ctx.lineWidth = 6;
ctx.strokeStyle = '#3b82f6'; // Blue
ctx.moveTo(end.x, end.y);
ctx.lineTo(destPos.x, destPos.y);
ctx.stroke();
return;
}
ctx.beginPath(); ctx.beginPath();
ctx.lineWidth = 6; ctx.lineWidth = 6;
ctx.strokeStyle = type === 'yellow' ? '#eab308' : '#3b82f6'; ctx.strokeStyle = type === 'yellow' ? '#eab308' : '#3b82f6';
@@ -1920,6 +1969,9 @@
addLog("Driver marked Arrived. Waiting compensation timer started.", "info"); addLog("Driver marked Arrived. Waiting compensation timer started.", "info");
document.getElementById('btn-arrive-action').style.display = 'none'; document.getElementById('btn-arrive-action').style.display = 'none';
// Clear route line (deletes the first yellow polyline)
ctx.clearRect(0, 0, routeCanvas.width, routeCanvas.height);
// Update badge // Update badge
document.getElementById('txt-lifecycle-phase').innerHTML = ` document.getElementById('txt-lifecycle-phase').innerHTML = `
<div class="status-dot" style="background-color: var(--accent-emerald); box-shadow: 0 0 8px var(--accent-emerald);"></div> <div class="status-dot" style="background-color: var(--accent-emerald); box-shadow: 0 0 8px var(--accent-emerald);"></div>
@@ -2025,6 +2077,10 @@
document.getElementById('marker-driver').style.left = driverPos.x + 'px'; document.getElementById('marker-driver').style.left = driverPos.x + 'px';
document.getElementById('marker-driver').style.top = driverPos.y + 'px'; document.getElementById('marker-driver').style.top = driverPos.y + 'px';
// Show destination marker on map
document.getElementById('marker-dest').style.display = 'flex';
document.getElementById('dest-label').innerHTML = `Mezzeh (Destination)`;
// Draw Trip Route (solid blue/black) // Draw Trip Route (solid blue/black)
drawRoute(driverPos, destPos, 'blue'); drawRoute(driverPos, destPos, 'blue');