import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:intaleq_maps/intaleq_maps.dart'; import '../../../constant/colors.dart'; import '../../../constant/table_names.dart'; import '../../../controller/functions/toast.dart'; import '../../../controller/home/map/location_search_controller.dart'; import '../../../controller/home/map/map_engine_controller.dart'; import '../../../controller/home/map/ride_lifecycle_controller.dart'; import '../../../main.dart'; import '../../../print.dart'; import '../../widgets/mydialoug.dart'; import 'rp_theme.dart'; /// All controller side-effects for the route planner live here, so the /// widgets stay declarative. This is a faithful port of the behavior that /// previously lived inside `form_search_*.dart` and `main_bottom_Menu_map`. /// /// No controller is modified — this only *calls* their existing API. class RpActions { RpActions._(); static LocationSearchController get _s => Get.find(); static MapEngineController get _map => Get.find(); static RideLifecycleController get _ride => Get.find(); // ── Destination ───────────────────────────────────────────────────────── static void pickDestinationOnMap() { _map.changeMainBottomMenuMap(); _map.changePickerShown(); } static Future selectDestination(int index, dynamic res) async { final lat = res['latitude']; final lng = res['longitude']; if (lat == null || lng == null) { Toast.show(Get.context!, 'Invalid location data', AppColor.redColor); return; } final String title = (res['name_ar'] ?? res['name'] ?? 'Unknown Place').toString(); await sql.insertMapLocation({ 'latitude': lat, 'longitude': lng, 'name': title, 'rate': 'N/A', 'createdAt': DateTime.now().toIso8601String(), }, TableName.recentLocations); final dest = LatLng(double.parse(lat.toString()), double.parse(lng.toString())); if (_ride.isAnotherOreder) { _s.myDestination = dest; _s.clearPlacesDestination(); await _ride.getDirectionMap( '${_s.passengerLocation.latitude},${_s.passengerLocation.longitude}', '${_s.myDestination.latitude},${_s.myDestination.longitude}'); _map.isPickerShown = false; _s.passengerStartLocationFromMap = false; _map.changeMainBottomMenuMap(); _ride.showBottomSheet1(); } else { _s.passengerLocation = _s.newMyLocation; _s.myDestination = dest; _s.convertHintTextDestinationNewPlaces(index); _s.clearPlacesDestination(); _map.changeMainBottomMenuMap(); _s.passengerStartLocationFromMap = true; _map.isPickerShown = true; _map.mapController?.animateCamera( CameraUpdate.newLatLngZoom(_s.passengerLocation, 16), ); } } // ── Origin / pickup ─────────────────────────────────────────────────────── /// Map-pick for the *other person's* pickup (order-for-someone-else mode). static void pickOtherPickupOnMap() { _s.passengerStartLocationFromMap = true; _map.changeMainBottomMenuMap(); _map.changePickerShown(); } /// Map-pick for my own start point (updates the pickup without re-routing). static void pickMyStartOnMap() { _s.startLocationFromMap = true; _map.changeMainBottomMenuMap(); _map.changePickerShown(); } /// Selecting a searched start point (other person's pickup). static void selectStart(dynamic res) { final lat = res['latitude']; final lng = res['longitude']; if (lat == null || lng == null) return; final String title = (res['name_ar'] ?? res['name'] ?? 'Unknown Place').toString(); _s.passengerLocation = LatLng(double.parse(lat.toString()), double.parse(lng.toString())); _s.placeStartController.text = title; _s.clearPlacesStart(); _s.update(); } // ── Gate Selection (Bottom Sheet) ────────────────────────────────────────── static void handleLocationSelection( BuildContext context, int index, dynamic place, bool isOrigin) { final hasGates = place['gates'] != null && place['gates'] is List && (place['gates'] as List).isNotEmpty; if (!hasGates) { if (isOrigin) { selectStart(place); } else { selectDestination(index, place); } return; } final List gates = place['gates']; final bool isArabic = Get.locale?.languageCode == 'ar'; showModalBottomSheet( context: context, backgroundColor: Colors.transparent, isScrollControlled: true, builder: (context) { return Container( padding: const EdgeInsets.only(top: 12, left: 16, right: 16, bottom: 24), decoration: BoxDecoration( color: RP.sheetElevated, borderRadius: const BorderRadius.vertical(top: Radius.circular(RP.rSheet)), ), child: Column( mainAxisSize: MainAxisSize.min, children: [ RP.grabber(), const SizedBox(height: 16), Text( 'Select Gate'.tr, style: RP.title, ), const SizedBox(height: 16), ...gates.map((gate) { final String gateName = isArabic ? (gate['name_ar'] ?? gate['name_en'] ?? 'Gate'.tr) : (gate['name_en'] ?? gate['name_ar'] ?? 'Gate'.tr); return ListTile( contentPadding: EdgeInsets.zero, leading: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: AppColor.primaryColor.withOpacity(0.1), shape: BoxShape.circle, ), child: const Icon(Icons.door_sliding_outlined, color: AppColor.primaryColor, size: 20), ), title: Text(gateName, style: RP.fieldValue), subtitle: gate['is_main_gate'] == true ? Text('Main Gate'.tr, style: RP.body) : null, onTap: () { Navigator.pop(context); final modifiedPlace = Map.from(place); modifiedPlace['latitude'] = gate['latitude']; modifiedPlace['longitude'] = gate['longitude']; modifiedPlace['name_ar'] = '${place['name_ar'] ?? place['name'] ?? ''} - $gateName'; modifiedPlace['name'] = '${place['name'] ?? place['name_ar'] ?? ''} - $gateName'; if (isOrigin) { selectStart(modifiedPlace); } else { selectDestination(index, modifiedPlace); } }, ); }), ], ), ); }, ); } // ── Stops (menu waypoints) ──────────────────────────────────────────────── static void addStop() => _s.addMenuWaypoint(); static void removeStop(int index) => _s.removeMenuWaypoint(index); static void pickStopOnMap(int index) => _s.startPickingWaypointOnMap(index); // ── Home / Work quick actions ───────────────────────────────────────────── static void pickHomeOrWork({required bool isWork}) { if (isWork) { _s.workLocationFromMap = true; } else { _s.homeLocationFromMap = true; } _map.changeMainBottomMenuMap(); _map.changePickerShown(); } static void changeHomeOrWork({required bool isWork}) { MyDialog().getDialog( isWork ? 'Change Work location ?'.tr : 'Change Home location ?'.tr, '', () => pickHomeOrWork(isWork: isWork), ); } /// Navigate to a saved Home/Work location and open the ride sheet. static Future goToSaved(String boxName, String hint) async { try { final locationString = box.read(boxName).toString(); final parts = locationString.split(','); final latLng = LatLng(double.parse(parts[0].trim()), double.parse(parts[1].trim())); _s.hintTextDestinationPoint = hint.tr; _map.changeMainBottomMenuMap(); await _ride.getDirectionMap( '${_s.passengerLocation.latitude},${_s.passengerLocation.longitude}', '${latLng.latitude},${latLng.longitude}', ); _s.currentLocationToFormPlaces = false; _s.clearPlacesDestination(); _s.passengerStartLocationFromMap = false; _map.isPickerShown = false; _ride.showBottomSheet1(); } catch (e) { Log.print('RpActions.goToSaved error: $e'); Toast.show(Get.context!, 'Failed to get location'.tr, AppColor.redColor); } } // ── Favorites / recents ─────────────────────────────────────────────────── static Future addFavorite( BuildContext context, dynamic lat, dynamic lng, String title) async { if (lat == null || lng == null) { Toast.show(context, 'Invalid location data', AppColor.redColor); return; } await sql.insertMapLocation({ 'latitude': lat, 'longitude': lng, 'name': title, 'rate': 'N/A', }, TableName.placesFavorite); if (!context.mounted) return; Toast.show( context, '$title ${'Saved Successfully'.tr}', AppColor.primaryColor); } /// Route to a stored place (recent or favorite) after confirmation. static Future goToStoredPlace(dynamic place) async { await _s.getLocation(); await _ride.getDirectionMap( '${_s.passengerLocation.latitude},${_s.passengerLocation.longitude}', '${place['latitude']},${place['longitude']}', ); _ride.showBottomSheet1(); } }