2026-03-13-2
This commit is contained in:
@@ -263,6 +263,14 @@ class MapPassengerController extends GetxController {
|
||||
bool currentLocationToFormPlaces3 = false;
|
||||
bool currentLocationToFormPlaces4 = false;
|
||||
List currentLocationToFormPlacesAll = [];
|
||||
|
||||
// ── Multi-Waypoint (max 2 stops) ──────────────────────────────────────────
|
||||
List<LatLng?> menuWaypoints = [null, null];
|
||||
List<String> menuWaypointNames = ['', ''];
|
||||
int activeMenuWaypointCount = 0;
|
||||
bool isPickingWaypoint = false;
|
||||
int pickingWaypointIndex = -1;
|
||||
|
||||
late String driverToken = '';
|
||||
int carsOrder = 0;
|
||||
int wayPointIndex = 0;
|
||||
@@ -4906,6 +4914,82 @@ Intaleq Team''';
|
||||
update();
|
||||
}
|
||||
|
||||
// ── Multi-Waypoint Methods ──────────────────────────────────────────────────
|
||||
void addMenuWaypoint() {
|
||||
if (activeMenuWaypointCount >= 2) return;
|
||||
activeMenuWaypointCount++;
|
||||
// Increase expanded bottom menu height to accommodate new waypoint row
|
||||
mainBottomMenuMapHeight = Get.height * .6 + (activeMenuWaypointCount * 56);
|
||||
update();
|
||||
}
|
||||
|
||||
void removeMenuWaypoint(int index) {
|
||||
if (index < 0 || index >= 2) return;
|
||||
// Shift items if removing first waypoint while second exists
|
||||
if (index == 0 && activeMenuWaypointCount == 2) {
|
||||
menuWaypoints[0] = menuWaypoints[1];
|
||||
menuWaypointNames[0] = menuWaypointNames[1];
|
||||
}
|
||||
menuWaypoints[activeMenuWaypointCount - 1] = null;
|
||||
menuWaypointNames[activeMenuWaypointCount - 1] = '';
|
||||
activeMenuWaypointCount--;
|
||||
mainBottomMenuMapHeight = Get.height * .6 + (activeMenuWaypointCount * 56);
|
||||
update();
|
||||
}
|
||||
|
||||
void clearAllMenuWaypoints() {
|
||||
menuWaypoints = [null, null];
|
||||
menuWaypointNames = ['', ''];
|
||||
activeMenuWaypointCount = 0;
|
||||
isPickingWaypoint = false;
|
||||
pickingWaypointIndex = -1;
|
||||
update();
|
||||
}
|
||||
|
||||
void startPickingWaypointOnMap(int index) {
|
||||
pickingWaypointIndex = index;
|
||||
isPickingWaypoint = true;
|
||||
isPickerShown = true;
|
||||
heightPickerContainer = 150;
|
||||
// Close the expanded menu to show the map picker
|
||||
isMainBottomMenuMap = true;
|
||||
mainBottomMenuMapHeight = Get.height * .22;
|
||||
update();
|
||||
}
|
||||
|
||||
void setMenuWaypointFromMap(int index, LatLng position) {
|
||||
if (index < 0 || index >= 2) return;
|
||||
menuWaypoints[index] = position;
|
||||
menuWaypointNames[index] =
|
||||
'${position.latitude.toStringAsFixed(4)}, ${position.longitude.toStringAsFixed(4)}';
|
||||
isPickingWaypoint = false;
|
||||
pickingWaypointIndex = -1;
|
||||
isPickerShown = false;
|
||||
// Re-open expanded menu
|
||||
isMainBottomMenuMap = false;
|
||||
mainBottomMenuMapHeight = Get.height * .6 + (activeMenuWaypointCount * 56);
|
||||
update();
|
||||
}
|
||||
|
||||
void setMenuWaypointFromSearch(int index, LatLng pos, String name) {
|
||||
if (index < 0 || index >= 2) return;
|
||||
menuWaypoints[index] = pos;
|
||||
menuWaypointNames[index] = name;
|
||||
update();
|
||||
}
|
||||
|
||||
/// Build OSRM waypoint coordinate string for the route URL
|
||||
String _buildOsrmWaypointCoords() {
|
||||
String coords = '';
|
||||
for (int i = 0; i < activeMenuWaypointCount; i++) {
|
||||
final wp = menuWaypoints[i];
|
||||
if (wp != null) {
|
||||
coords += ';${wp.longitude},${wp.latitude}';
|
||||
}
|
||||
}
|
||||
return coords;
|
||||
}
|
||||
|
||||
void changeHeightPointsPageForRider() {
|
||||
isPointsPageForRider = !isPointsPageForRider;
|
||||
heightPointsPageForRider = isPointsPageForRider == true ? Get.height : 0;
|
||||
@@ -6375,10 +6459,12 @@ Intaleq Team''';
|
||||
double lngDest = double.parse(coordDestination[1]);
|
||||
myDestination = LatLng(latDest, lngDest);
|
||||
|
||||
// 2. الاتصال بالسيرفر - New OSRM format
|
||||
// 2. الاتصال بالسيرفر - New OSRM format (with multi-waypoint support)
|
||||
var originCoords = origin.split(',');
|
||||
// Build waypoint coordinates for OSRM (inserted between origin and destination)
|
||||
String waypointCoords = _buildOsrmWaypointCoords();
|
||||
String dynamicApiUrl =
|
||||
'${AppLink.routesOsm}/route/v1/driving/${originCoords[1]},${originCoords[0]};$lngDest,$latDest';
|
||||
'${AppLink.routesOsm}/route/v1/driving/${originCoords[1]},${originCoords[0]}$waypointCoords;$lngDest,$latDest';
|
||||
|
||||
var uri = Uri.parse('$dynamicApiUrl?steps=false&overview=full');
|
||||
Log.print('Requesting Route URI (Attempt: ${attemptCount + 1}): $uri');
|
||||
@@ -6506,14 +6592,6 @@ Intaleq Team''';
|
||||
isDrawingRoute = false;
|
||||
isLoading = false;
|
||||
|
||||
if (minLat != null) {
|
||||
LatLngBounds boundsData = LatLngBounds(
|
||||
northeast: LatLng(maxLat!, maxLng!),
|
||||
southwest: LatLng(minLat!, minLng!));
|
||||
mapController
|
||||
?.animateCamera(CameraUpdate.newLatLngBounds(boundsData, 100));
|
||||
}
|
||||
|
||||
// 6. إضافة الماركرز
|
||||
durationToAdd = Duration(seconds: durationToRide);
|
||||
hours = durationToAdd.inHours;
|
||||
@@ -6537,6 +6615,25 @@ Intaleq Team''';
|
||||
'$distance ${'KM'.tr} ⌛ ${hours > 0 ? '$hours H $minutes m' : '$minutes m'}'),
|
||||
));
|
||||
|
||||
// 6b. Add waypoint markers (amber for stop 1, deep purple for stop 2)
|
||||
for (int i = 0; i < activeMenuWaypointCount; i++) {
|
||||
final wp = menuWaypoints[i];
|
||||
if (wp != null) {
|
||||
markers.add(Marker(
|
||||
markerId: MarkerId('waypoint_$i'),
|
||||
position: wp,
|
||||
icon: BitmapDescriptor.defaultMarkerWithHue(
|
||||
i == 0
|
||||
? BitmapDescriptor.hueOrange
|
||||
: BitmapDescriptor.hueViolet,
|
||||
),
|
||||
infoWindow: InfoWindow(
|
||||
title: '${'Stop'.tr} ${i + 1}',
|
||||
snippet: menuWaypointNames[i]),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// 7. رسم الخط (النظام الجديد لجميع الأجهزة)
|
||||
if (polyLines.isNotEmpty) clearPolyline();
|
||||
|
||||
@@ -6547,8 +6644,16 @@ Intaleq Team''';
|
||||
// إظهار الباتم شيت للسعر
|
||||
bottomSheet();
|
||||
|
||||
// تشغيل الأنيميشن الخفيف لومضات المسار
|
||||
_playRouteAnimation(polylineCoordinates);
|
||||
// 8. Compute bounds from all polyline points
|
||||
LatLngBounds? boundsData;
|
||||
if (minLat != null) {
|
||||
boundsData = LatLngBounds(
|
||||
northeast: LatLng(maxLat!, maxLng!),
|
||||
southwest: LatLng(minLat!, minLng!));
|
||||
}
|
||||
|
||||
// تشغيل الأنيميشن الخفيف لومضات المسار + fit camera after
|
||||
_playRouteAnimation(polylineCoordinates, boundsData);
|
||||
} catch (e, stackTrace) {
|
||||
// 🚨 هذا السطر سيفضح المشكلة الحقيقية! 🚨
|
||||
print('🚨 CRITICAL ERROR IN getDirectionMap: $e');
|
||||
@@ -6563,25 +6668,28 @@ Intaleq Team''';
|
||||
}
|
||||
}
|
||||
|
||||
// --- دالة الأنيميشن الجديدة ---
|
||||
Future<void> _playRouteAnimation(List<LatLng> coords) async {
|
||||
const String routeId = 'route_solid';
|
||||
// --- دالة الأنيميشن مع ألوان مختلفة لكل قطعة ---
|
||||
Future<void> _playRouteAnimation(
|
||||
List<LatLng> coords, LatLngBounds? bounds) async {
|
||||
// Segment colors matching UI dots: green → amber → purple → red
|
||||
const List<Color> segmentColors = [
|
||||
Color(0xFF109642), // Green (start → stop 1)
|
||||
Color(0xFFF59E0B), // Amber (stop 1 → stop 2)
|
||||
Color(0xFF7C3AED), // Purple (last segment → dest)
|
||||
Color(0xFFEF4444), // Red (fallback)
|
||||
];
|
||||
|
||||
// الألوان المطلوبة (بإمكانك تغيير AppColor.primaryColor إلى ما يناسبك)
|
||||
Color finalColor =
|
||||
AppColor.primaryColor; // اللون النهائي الثابت (مثل الأزرق)
|
||||
Color lightColor = Colors.grey.shade400; // لون التحديث الفاتح (رمادي)
|
||||
Color darkColor = Colors.grey.shade700; // لون التحديث الغامق (رمادي غامق)
|
||||
// Loading animation (4 flashes)
|
||||
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.removeWhere((p) => p.polylineId.value.startsWith('route_'));
|
||||
polyLines.add(Polyline(
|
||||
polylineId: const PolylineId(routeId),
|
||||
polylineId: const PolylineId('route_solid'),
|
||||
points: coords,
|
||||
width: 5,
|
||||
color: lightColor,
|
||||
color: i.isEven ? lightColor : darkColor,
|
||||
endCap: Cap.roundCap,
|
||||
startCap: Cap.roundCap,
|
||||
jointType: JointType.round,
|
||||
@@ -6589,36 +6697,76 @@ Intaleq Team''';
|
||||
));
|
||||
update();
|
||||
await Future.delayed(const Duration(milliseconds: 250));
|
||||
}
|
||||
|
||||
// الحالة 2: لون غامق وعرض أكبر
|
||||
polyLines.removeWhere((p) => p.polylineId.value == routeId);
|
||||
// After animation: draw coloured segments if we have waypoints
|
||||
polyLines.removeWhere((p) => p.polylineId.value.startsWith('route_'));
|
||||
|
||||
if (activeMenuWaypointCount > 0) {
|
||||
// Find split indices: closest polyline point to each active waypoint
|
||||
List<int> splitIndices = [];
|
||||
for (int w = 0; w < activeMenuWaypointCount; w++) {
|
||||
final wp = menuWaypoints[w];
|
||||
if (wp == null) continue;
|
||||
int bestIdx = 0;
|
||||
double bestDist = double.infinity;
|
||||
for (int j = 0; j < coords.length; j++) {
|
||||
final dx = coords[j].latitude - wp.latitude;
|
||||
final dy = coords[j].longitude - wp.longitude;
|
||||
final d = dx * dx + dy * dy;
|
||||
if (d < bestDist) {
|
||||
bestDist = d;
|
||||
bestIdx = j;
|
||||
}
|
||||
}
|
||||
splitIndices.add(bestIdx);
|
||||
}
|
||||
splitIndices.sort();
|
||||
|
||||
// Build segments: [0..split0], [split0..split1], ..., [splitN..end]
|
||||
List<int> boundaries = [0, ...splitIndices, coords.length - 1];
|
||||
for (int s = 0; s < boundaries.length - 1; s++) {
|
||||
int from = boundaries[s];
|
||||
int to = boundaries[s + 1] + 1; // inclusive end
|
||||
if (to > coords.length) to = coords.length;
|
||||
if (from >= to - 1) continue; // skip empty
|
||||
final segCoords = coords.sublist(from, to);
|
||||
if (segCoords.length < 2) continue;
|
||||
final color = segmentColors[s % segmentColors.length];
|
||||
polyLines.add(Polyline(
|
||||
polylineId: PolylineId('route_seg_$s'),
|
||||
points: segCoords,
|
||||
width: 6,
|
||||
color: color,
|
||||
endCap: Cap.roundCap,
|
||||
startCap: Cap.roundCap,
|
||||
jointType: JointType.round,
|
||||
zIndex: 3 + s,
|
||||
));
|
||||
}
|
||||
} else {
|
||||
// Single leg: solid primary color
|
||||
polyLines.add(Polyline(
|
||||
polylineId: const PolylineId(routeId),
|
||||
polylineId: const PolylineId('route_solid'),
|
||||
points: coords,
|
||||
width: 6,
|
||||
color: darkColor,
|
||||
color: AppColor.primaryColor,
|
||||
endCap: Cap.roundCap,
|
||||
startCap: Cap.roundCap,
|
||||
jointType: JointType.round,
|
||||
zIndex: 2,
|
||||
zIndex: 3,
|
||||
));
|
||||
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();
|
||||
|
||||
// Fit camera to full route bounds AFTER polylines are drawn
|
||||
if (bounds != null) {
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
try {
|
||||
mapController
|
||||
?.animateCamera(CameraUpdate.newLatLngBounds(bounds, 100));
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
// --- دالة المساعدة لإعادة المحاولة ---
|
||||
@@ -7341,7 +7489,9 @@ Intaleq Team''';
|
||||
final DateTime currentTime = DateTime.now();
|
||||
newTime = currentTime.add(durationToAdd);
|
||||
averageDuration = (durationToRide / 60) / distance;
|
||||
final int totalMinutes = (durationToRide / 60).floor();
|
||||
// +5 minutes per waypoint stop surcharge
|
||||
final int waypointSurchargeMinutes = activeMenuWaypointCount * 5;
|
||||
final int totalMinutes = (durationToRide / 60).floor() + waypointSurchargeMinutes;
|
||||
|
||||
// ====== أدوات مساعدة ======
|
||||
bool _isAirport(String s) {
|
||||
|
||||
Reference in New Issue
Block a user