Files
Siro/siro_rider/lib/views/home/route_planner/rp_actions.dart
T

272 lines
10 KiB
Dart

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<LocationSearchController>();
static MapEngineController get _map => Get.find<MapEngineController>();
static RideLifecycleController get _ride =>
Get.find<RideLifecycleController>();
// ── Destination ─────────────────────────────────────────────────────────
static void pickDestinationOnMap() {
_map.changeMainBottomMenuMap();
_map.changePickerShown();
}
static Future<void> 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<String, dynamic>.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<void> 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<void> 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<void> goToStoredPlace(dynamic place) async {
await _s.getLocation();
await _ride.getDirectionMap(
'${_s.passengerLocation.latitude},${_s.passengerLocation.longitude}',
'${place['latitude']},${place['longitude']}',
);
_ride.showBottomSheet1();
}
}