2026-03-13-2

This commit is contained in:
Hamza-Ayed
2026-03-13 22:43:46 +03:00
parent fdfea5582a
commit e2341b104f
4 changed files with 1007 additions and 330 deletions

View File

@@ -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) {