Update: 2026-06-19 01:47:48

This commit is contained in:
Hamza-Ayed
2026-06-19 01:47:48 +03:00
parent f13faa8c31
commit a003bf78c4
34 changed files with 6207 additions and 13499 deletions

View File

@@ -6,6 +6,7 @@ import 'location_search_controller.dart';
import 'nearby_drivers_controller.dart';
import 'ride_lifecycle_controller.dart';
import 'ui_interactions_controller.dart';
import 'ride_simulation.dart';
class MapScreenBinding extends Bindings {
@override
@@ -21,5 +22,8 @@ class MapScreenBinding extends Bindings {
// 3. Lifecycle and UI Interaction Controllers
Get.lazyPut(() => RideLifecycleController());
Get.lazyPut(() => UiInteractionsController(), fenix: true);
// 4. Simulation Controller (for development/testing)
Get.lazyPut(() => RideSimulationController(), fenix: true);
}
}

View File

@@ -2137,17 +2137,21 @@ class RideLifecycleController extends GetxController {
polyLines = polyLines
.where((p) =>
!p.polylineId.value.startsWith('driver_route') &&
p.polylineId.value != 'main_route' &&
p.polylineId.value != 'route_primary' &&
p.polylineId.value != 'route_direct')
.toSet();
if (statusRide == 'Begin' ||
currentRideState.value == RideState.inProgress) {
// لا نرسم أي شيء في حالة البدء لأنه وصل
polyLines = polyLines
.where((p) => !p.polylineId.value.startsWith('driver_route'))
.toSet();
polyLines = {
...polyLines.where((p) => !p.polylineId.value.startsWith('driver_route')),
Polyline(
polylineId: const PolylineId('main_route'),
points: remainingPoints,
color: const Color(0xFF2196F3),
width: 6,
),
};
} else {
polyLines = {
...polyLines,
@@ -4263,6 +4267,11 @@ class RideLifecycleController extends GetxController {
return segments;
}
// Call this externally when passengerLocation changes to refresh walk line
void updatePassengerWalkLine() {
_updatePassengerWalkLine();
}
// تحديث الخط المنقط ومكان أيقونة المشي للراكب
void _updatePassengerWalkLine() {
polyLines.removeWhere(

View File

@@ -0,0 +1,438 @@
import 'dart:async';
import 'dart:math' show cos, pi, sin;
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intaleq_maps/intaleq_maps.dart';
import '../../../print.dart';
import 'map_engine_controller.dart';
import 'map_socket_controller.dart';
import 'nearby_drivers_controller.dart';
import 'ride_lifecycle_controller.dart';
import 'ride_state.dart';
import 'location_search_controller.dart';
class RideSimulationController extends GetxController {
Timer? _simulationTimer;
int _step = 0;
bool _isSimulating = false;
List<LatLng> _simulatedRoute = [];
int _driverRouteIndex = 0;
String get simulationStatus => _isSimulating
? 'Simulating... Step $_step'
: 'Idle';
// آمود نقاط المسار (Jordan area: Amman center ~ 31.95, 35.91)
static const double _centerLat = 31.95;
static const double _centerLng = 35.91;
static const double _routeDelta = 0.03;
static const int _routePointCount = 100;
void _generateRoutePoints() {
_simulatedRoute = [];
for (int i = 0; i < _routePointCount; i++) {
double fraction = i / (_routePointCount - 1);
double lat = _centerLat + fraction * _routeDelta;
double lng = _centerLng + fraction * _routeDelta +
0.005 * sin(fraction * pi * 2);
_simulatedRoute.add(LatLng(lat, lng));
}
}
void startFullSimulation() {
if (_isSimulating) return;
_isSimulating = true;
_step = 0;
_driverRouteIndex = 0;
_generateRoutePoints();
Log.print('=' * 70);
Log.print('🚀 RIDE SIMULATION STARTED — Full lifecycle test');
Log.print('=' * 70);
_simulationTimer = Timer.periodic(const Duration(seconds: 2), (timer) {
switch (_step) {
case 0:
_simulateSearchingState();
break;
case 1:
_simulateDriverAppliedState();
break;
case 2:
_simulateDriverEnRoute(isFirst: true);
break;
case 3:
_simulateDriverEnRoute(isFirst: false);
break;
case 4:
_simulateDriverArrivedState();
break;
case 5:
_simulateRideBeginState();
break;
case 6:
_simulateRideInProgress();
break;
case 7:
_simulateRideFinishedState();
timer.cancel();
_isSimulating = false;
Log.print('=' * 70);
Log.print('✅ RIDE SIMULATION COMPLETED');
Log.print('=' * 70);
break;
}
_step++;
update();
});
}
void stopSimulation() {
_simulationTimer?.cancel();
_simulationTimer = null;
_isSimulating = false;
_step = 0;
_driverRouteIndex = 0;
Log.print('🛑 Simulation stopped');
update();
}
void _logPolylineState(String stage) {
final mapEngine = Get.find<MapEngineController>();
Log.print('');
Log.print('╔══ Polyline State [$stage] ══╗');
if (mapEngine.polyLines.isEmpty) {
Log.print(' ║ (no polylines)');
}
for (final p in mapEngine.polyLines) {
String colorStr;
if (p.color == Colors.amber) {
colorStr = 'AMBER';
} else if (p.color.value == 0xFF2196F3) {
colorStr = 'BLUE';
} else if (p.color == Colors.blueGrey) {
colorStr = 'BLUE_GREY';
} else {
colorStr = '#${p.color.value.toRadixString(16).padLeft(8, '0')}';
}
Log.print(' ║ • ${p.polylineId.value}: ${p.points.length} pts, '
'color: $colorStr, w: ${p.width}');
}
Log.print('╠══ Markers [$stage] ══╣');
if (mapEngine.markers.isEmpty) {
Log.print(' ║ (no markers)');
}
for (final m in mapEngine.markers) {
Log.print(' ║ • ${m.markerId.value}: '
'(${m.position.latitude.toStringAsFixed(5)}, '
'${m.position.longitude.toStringAsFixed(5)}), '
'heading: ${m.rotation.toStringAsFixed(1)}');
}
Log.print('╚══════════════════════╝');
Log.print('');
}
void _verifyPolylineCondition(bool condition, String description) {
if (!condition) {
Log.print(' ❌ VERIFY FAILED: $description');
} else {
Log.print(' ✅ VERIFY PASSED: $description');
}
}
LatLng _interpolateRoutePoint(double fraction) {
if (_simulatedRoute.isEmpty) return LatLng(_centerLat, _centerLng);
int total = _simulatedRoute.length;
double exactIdx = fraction * (total - 1);
int idx = exactIdx.floor();
if (idx >= total - 1) return _simulatedRoute.last;
double t = exactIdx - idx;
return LatLng(
_simulatedRoute[idx].latitude +
t * (_simulatedRoute[idx + 1].latitude - _simulatedRoute[idx].latitude),
_simulatedRoute[idx].longitude +
t * (_simulatedRoute[idx + 1].longitude - _simulatedRoute[idx].longitude),
);
}
void _simulateSearchingState() {
Log.print('🟡 [Step $_step] STATE: SEARCHING');
final ride = Get.find<RideLifecycleController>();
final locSearch = Get.find<LocationSearchController>();
ride.currentRideState.value = RideState.searching;
ride.rideId = 'sim_ride_001';
ride.isSearchingWindow = true;
// آمود موقع الراكب
LatLng passengerLoc = _simulatedRoute.isNotEmpty
? _simulatedRoute.first
: LatLng(_centerLat, _centerLng);
locSearch.passengerLocation = passengerLoc;
ride.passengerLocation = passengerLoc;
ride.update();
_logPolylineState('searching');
_verifyPolylineCondition(
Get.find<MapEngineController>().polyLines.isEmpty,
'No route polylines during searching');
Log.print('');
}
void _simulateDriverAppliedState() {
Log.print('🟢 [Step $_step] STATE: DRIVER APPLIED');
final ride = Get.find<RideLifecycleController>();
final nearbyDrivers = Get.find<NearbyDriversController>();
final locSearch = Get.find<LocationSearchController>();
ride.currentRideState.value = RideState.driverApplied;
ride.statusRide = 'Apply';
ride.isSearchingWindow = false;
// آمود معلومات السائق
ride.driverId = 'sim_driver_001';
ride.driverName = 'Simulated Captain';
ride.make = 'Toyota';
ride.model = 'Corolla';
ride.carColor = 'White';
ride.licensePlate = 'SIM-123';
ride.driverRate = '4.8';
ride.driverPhone = '+9627XXXXXXXX';
ride.driverToken = 'sim_token_001';
// آمود مواقع البداية والنهاية
ride.passengerLocation = _simulatedRoute.first;
ride.myDestination = _simulatedRoute.last;
locSearch.passengerLocation = _simulatedRoute.first;
locSearch.myDestination = _simulatedRoute.last;
// محاكاة موقع السائق (45% على طول المسار)
LatLng driverPos = _interpolateRoutePoint(0.45);
nearbyDrivers.driverCarsLocationToPassengerAfterApplied = [driverPos];
// رسم مسار السائق إلى الراكب
ride.calculateDriverToPassengerRoute(driverPos, ride.passengerLocation);
// وضع ماركر السائق على الخريطة
ride.updateDriverMarker(driverPos, 45.0);
ride.update();
_logPolylineState('driver_applied');
// التحقق من وجود الخطوط المطلوبة
final polylines = Get.find<MapEngineController>().polyLines;
_verifyPolylineCondition(
polylines.any((p) => p.polylineId.value == 'driver_route_solid'),
'driver_route_solid (amber solid line) exists');
_verifyPolylineCondition(
polylines.any((p) => p.polylineId.value.startsWith('passenger_walk_line')),
'passenger_walk_line (dashed walk line) exists');
_verifyPolylineCondition(
polylines.any((p) => p.color == Colors.amber),
'Amber-colored polyline exists (driver route)');
_verifyPolylineCondition(
polylines.any((p) => p.color == Colors.blueGrey),
'BlueGrey-colored polyline exists (walk dashes)');
Log.print('');
}
void _simulateDriverEnRoute({required bool isFirst}) {
String label = isFirst ? '1' : '2';
Log.print('🔵 [Step $_step] STATE: DRIVER APPROACHING (update #$label)');
final ride = Get.find<RideLifecycleController>();
final nearbyDrivers = Get.find<NearbyDriversController>();
_driverRouteIndex += 18;
if (_driverRouteIndex > _routePointCount - 1) {
_driverRouteIndex = _routePointCount - 1;
}
LatLng newPos = _simulatedRoute[_driverRouteIndex];
// تحديث موقع السائق
nearbyDrivers.driverCarsLocationToPassengerAfterApplied = [newPos];
ride.updateDriverMarker(newPos, 50.0);
ride.updateRemainingRoute(newPos);
ride.update();
_logPolylineState('driver_en_route_$label');
// التحقق: driver_route_solid يبقى موجود ويتقلص
final polylines = Get.find<MapEngineController>().polyLines;
_verifyPolylineCondition(
polylines.any((p) => p.polylineId.value == 'driver_route_solid'),
'driver_route_solid still exists (shrinking)');
_verifyPolylineCondition(
polylines.any((p) => p.polylineId.value.startsWith('passenger_walk_line')),
'passenger_walk_line still exists');
Log.print('');
}
void _simulateDriverArrivedState() {
Log.print('🟣 [Step $_step] STATE: DRIVER ARRIVED');
final ride = Get.find<RideLifecycleController>();
ride.currentRideState.value = RideState.driverArrived;
ride.statusRide = 'Arrived';
// محاكاة وصول السائق: تحديد الموقع كآخر نقطة طريق
LatLng driverPos = _simulatedRoute.first;
// تطبيق arrived logic
ride.polyLines = ride.polyLines
.where((p) =>
p.polylineId.value != 'main_route' &&
p.polylineId.value != 'route_direct' &&
!p.polylineId.value.startsWith('driver_route'))
.toSet();
// رسم المسار الجديد (من السائق إلى الوجهة النهائية)
ride.calculateDriverToPassengerRoute(driverPos, ride.myDestination,
isBeginPhase: true);
ride.update();
_logPolylineState('driver_arrived');
final polylines = Get.find<MapEngineController>().polyLines;
// في حالة الوصول: يجب أن يظهر main_route (أزرق) بدلاً من driver_route_solid
_verifyPolylineCondition(
!polylines.any((p) => p.polylineId.value == 'driver_route_solid'),
'driver_route_solid (amber) has been cleared');
_verifyPolylineCondition(
polylines.any((p) => p.polylineId.value == 'main_route'),
'main_route (blue) has been drawn to destination');
Log.print('');
}
void _simulateRideBeginState() {
Log.print('🔴 [Step $_step] STATE: RIDE IN PROGRESS (Begin)');
final ride = Get.find<RideLifecycleController>();
ride.currentRideState.value = RideState.inProgress;
ride.statusRide = 'Begin';
LatLng driverPos = _simulatedRoute.first;
// محاكاة processRideBegin: مسح الخطوط القديمة ورسم الخط الجديد
ride.polyLines = ride.polyLines
.where((p) =>
p.polylineId.value != 'main_route' &&
p.polylineId.value != 'route_direct' &&
!p.polylineId.value.startsWith('driver_route'))
.toSet();
ride.calculateDriverToPassengerRoute(driverPos, ride.myDestination,
isBeginPhase: true);
ride.rideIsBeginPassengerTimer();
ride.update();
_logPolylineState('ride_begin');
final polylines = Get.find<MapEngineController>().polyLines;
_verifyPolylineCondition(
polylines.any((p) => p.polylineId.value == 'main_route'),
'main_route (blue) exists for trip');
_verifyPolylineCondition(
!polylines.any((p) => p.polylineId.value.startsWith('driver_route')),
'No driver_route* polylines remain');
_verifyPolylineCondition(
polylines.any((p) => p.color.value == 0xFF2196F3),
'Blue polyline (main route) is present');
Log.print('');
}
void _simulateRideInProgress() {
Log.print('📱 [Step $_step] STATE: CAR MOVING (remaining route update)');
final ride = Get.find<RideLifecycleController>();
final nearbyDrivers = Get.find<NearbyDriversController>();
_driverRouteIndex += 30;
if (_driverRouteIndex > _routePointCount - 1) {
_driverRouteIndex = _routePointCount - 1;
}
LatLng newPos = _simulatedRoute[_driverRouteIndex];
nearbyDrivers.driverCarsLocationToPassengerAfterApplied = [newPos];
ride.updateDriverMarker(newPos, 70.0);
ride.updateRemainingRoute(newPos, updateEta: true);
ride.update();
_logPolylineState('ride_in_progress');
final polylines = Get.find<MapEngineController>().polyLines;
_verifyPolylineCondition(
polylines.any((p) => p.polylineId.value == 'main_route'),
'main_route (blue) exists with remaining points');
_verifyPolylineCondition(
!polylines.any((p) => p.polylineId.value.startsWith('driver_route')),
'No driver_route* polylines remain');
Log.print('');
}
void _simulateRideFinishedState() {
Log.print('🏁 [Step $_step] STATE: RIDE FINISHED');
final ride = Get.find<RideLifecycleController>();
final mapEngine = Get.find<MapEngineController>();
ride.currentRideState.value = RideState.finished;
ride.statusRide = 'Finished';
ride.isSearchingWindow = false;
ride.stopAllTimers();
mapEngine.clearPolyline();
mapEngine.markers = {};
ride.update();
_logPolylineState('ride_finished');
_verifyPolylineCondition(
Get.find<MapEngineController>().polyLines.isEmpty,
'All polylines cleared');
_verifyPolylineCondition(
Get.find<MapEngineController>().markers.isEmpty,
'All markers removed');
Log.print('');
}
// Simulate a single WebSocket location update event
void simulateSocketLocationUpdate(LatLng position, double heading) {
final ride = Get.find<RideLifecycleController>();
final nearbyDrivers = Get.find<NearbyDriversController>();
final mapSocket = Get.find<MapSocketController>();
Log.print('📡 Simulating socket location update: '
'(${position.latitude.toStringAsFixed(5)}, ${position.longitude.toStringAsFixed(5)})');
nearbyDrivers.driverCarsLocationToPassengerAfterApplied = [position];
ride.driverCarsLocationToPassengerAfterApplied = [position];
ride.checkAndRecalculateIfDeviated(
position,
heading: heading,
speed: 30.0,
);
final mapEngine = Get.find<MapEngineController>();
if (mapEngine.mapController != null) {
mapEngine.mapController!
.animateCamera(CameraUpdate.newLatLngZoom(position, 16.5));
}
ride.updateDriverMarker(position, heading);
ride.updateRemainingRoute(position);
ride.update();
}
@override
void onClose() {
_simulationTimer?.cancel();
super.onClose();
}
}