Fixes & Updates - 2026-06-01: Integrate Back-End v3 updates, fix call/connection issues across apps
This commit is contained in:
809
lib/controller/home/map/map_engine_controller.dart
Normal file
809
lib/controller/home/map/map_engine_controller.dart
Normal file
@@ -0,0 +1,809 @@
|
||||
import 'dart:async';
|
||||
import 'dart:math' show cos, max, min, pi, pow, sqrt;
|
||||
import 'dart:typed_data';
|
||||
import 'package:Intaleq/controller/home/map/ride_lifecycle_controller.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intaleq_maps/intaleq_maps.dart';
|
||||
import 'package:image/image.dart' as img;
|
||||
|
||||
import '../../../constant/colors.dart';
|
||||
// contains global 'box'
|
||||
import '../../../print.dart';
|
||||
import '../../../views/home/map_widget.dart/cancel_raide_page.dart';
|
||||
import 'location_search_controller.dart';
|
||||
import 'nearby_drivers_controller.dart';
|
||||
import 'ride_lifecycle_controller.dart';
|
||||
import '../points_for_rider_controller.dart';
|
||||
import '../../../constant/univeries_polygon.dart';
|
||||
|
||||
class MapEngineController extends GetxController {
|
||||
IntaleqMapController? mapController;
|
||||
bool isStyleLoaded = false;
|
||||
bool isIconsLoaded = false;
|
||||
|
||||
Set<Marker> markers = {};
|
||||
Set<Polyline> polyLines = {};
|
||||
List<LatLng> polylineCoordinates = [];
|
||||
Set<Polygon> polygons = {};
|
||||
Set<Circle> circles = {};
|
||||
|
||||
LatLngBounds? lastComputedBounds;
|
||||
bool mapType = false;
|
||||
bool mapTrafficON = false;
|
||||
bool isMarkersShown = false;
|
||||
|
||||
String markerIcon = "marker_icon";
|
||||
String tripIcon = "trip_icon";
|
||||
String startIcon = "start_icon";
|
||||
String endIcon = "end_icon";
|
||||
String carIcon = "car_icon";
|
||||
String motoIcon = "moto_icon";
|
||||
String ladyIcon = "lady_icon";
|
||||
|
||||
double height = 150;
|
||||
double heightMenu = 0;
|
||||
double widthMenu = 0;
|
||||
double heightPickerContainer = 90;
|
||||
double heightPointsPageForRider = 0;
|
||||
double mainBottomMenuMapHeight = Get.height * .2;
|
||||
double wayPointSheetHeight = 0;
|
||||
bool heightMenuBool = false;
|
||||
bool isPickerShown = false;
|
||||
bool isPointsPageForRider = false;
|
||||
bool isBottomSheetShown = false;
|
||||
bool reloadStartApp = false;
|
||||
bool isCancelRidePageShown = false;
|
||||
bool isCashConfirmPageShown = false;
|
||||
bool isPaymentMethodPageShown = false;
|
||||
bool isRideFinished = false;
|
||||
bool rideConfirm = false;
|
||||
bool isMainBottomMenuMap = true;
|
||||
|
||||
bool isWayPointSheet = false;
|
||||
bool isWayPointStopsSheet = false;
|
||||
bool isWayPointStopsSheetUtilGetMap = false;
|
||||
double heightBottomSheetShown = 0;
|
||||
double cashConfirmPageShown = 250;
|
||||
double widthMapTypeAndTraffic = 50;
|
||||
double paymentPageShown = Get.height * .6;
|
||||
|
||||
bool isAnotherOreder = false;
|
||||
bool isWhatsAppOrder = false;
|
||||
|
||||
Map<String, Timer> _animationTimers = {};
|
||||
final int updateIntervalMs = 100;
|
||||
final double minMovementThreshold = 1.0;
|
||||
|
||||
void onMapCreated(IntaleqMapController controller) {
|
||||
mapController = controller;
|
||||
update();
|
||||
}
|
||||
|
||||
void onStyleLoaded() async {
|
||||
Log.print('🗺️ Intaleq Map Style Loaded. Initializing...');
|
||||
isStyleLoaded = true;
|
||||
await _loadMapIcons();
|
||||
|
||||
final locationSearch = Get.find<LocationSearchController>();
|
||||
Get.find<RideLifecycleController>().reinit();
|
||||
|
||||
if (mapController != null) {
|
||||
if (markers.isNotEmpty && lastComputedBounds != null) {
|
||||
await _safeAnimateCameraBounds(lastComputedBounds);
|
||||
} else {
|
||||
mapController!.animateCamera(
|
||||
CameraUpdate.newLatLng(locationSearch.passengerLocation),
|
||||
);
|
||||
}
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
Future<void> _safeAnimateCameraBounds(LatLngBounds? bounds,
|
||||
{double left = 60,
|
||||
double top = 60,
|
||||
double right = 60,
|
||||
double bottom = 60}) async {
|
||||
if (bounds == null || mapController == null) return;
|
||||
|
||||
try {
|
||||
if (bounds.northeast.latitude == bounds.southwest.latitude &&
|
||||
bounds.northeast.longitude == bounds.southwest.longitude) {
|
||||
Log.print(
|
||||
'⚠️ _safeAnimateCameraBounds: Bounds are a single point, zooming to point instead.');
|
||||
await mapController
|
||||
?.animateCamera(CameraUpdate.newLatLngZoom(bounds.northeast, 15));
|
||||
return;
|
||||
}
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
|
||||
await mapController?.animateCamera(
|
||||
CameraUpdate.newLatLngBounds(
|
||||
bounds,
|
||||
left: left,
|
||||
top: top,
|
||||
right: right,
|
||||
bottom: bottom,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
Log.print('❌ _safeAnimateCameraBounds CRASH PREVENTED: $e');
|
||||
try {
|
||||
await mapController
|
||||
?.animateCamera(CameraUpdate.newLatLngZoom(bounds.northeast, 14));
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _loadMapIcons() async {
|
||||
isIconsLoaded = false;
|
||||
for (int i = 0; i < 15; i++) {
|
||||
if (mapController != null && isStyleLoaded) break;
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
}
|
||||
|
||||
if (mapController == null || !isStyleLoaded) {
|
||||
Log.print(
|
||||
'⚠️ _loadMapIcons: mapController or style not ready. Icons may not load.');
|
||||
}
|
||||
|
||||
await _addMapImage(startIcon, 'assets/images/A.png');
|
||||
await _addMapImage(endIcon, 'assets/images/b.png');
|
||||
await _addMapImage(carIcon, 'assets/images/car.png');
|
||||
await _addMapImage(motoIcon, 'assets/images/moto.png');
|
||||
await _addMapImage(ladyIcon, 'assets/images/lady.png');
|
||||
await _addMapImage('picker_icon', 'assets/images/picker.png');
|
||||
await _addMapImage('orange_marker', 'assets/images/moto1.png');
|
||||
await _addMapImage('violet_marker', 'assets/images/lady1.png');
|
||||
|
||||
isIconsLoaded = true;
|
||||
markers = markers.map((m) => m.copyWith()).toSet();
|
||||
update();
|
||||
|
||||
if (Get.isRegistered<NearbyDriversController>()) {
|
||||
Get.find<NearbyDriversController>()
|
||||
.getCarsLocationByPassengerAndReloadMarker();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _addMapImage(String id, String path) async {
|
||||
try {
|
||||
final ByteData bytes = await rootBundle.load(path);
|
||||
final size = _getImageSize(id);
|
||||
if (size != null && (id == carIcon || id == motoIcon || id == ladyIcon)) {
|
||||
final resized = await _resizeImage(bytes.buffer.asUint8List(), size);
|
||||
await mapController?.addImage(id, resized);
|
||||
Log.print(
|
||||
'delimited: successfully added resized map image: $id (${size}x${size})');
|
||||
} else {
|
||||
await mapController?.addImage(id, bytes.buffer.asUint8List());
|
||||
Log.print('delimited: successfully added map image: $id');
|
||||
}
|
||||
} catch (e) {
|
||||
Log.print('❌ Error loading map icon $id: $e');
|
||||
}
|
||||
}
|
||||
|
||||
int? _getImageSize(String id) {
|
||||
if (id == carIcon || id == motoIcon || id == ladyIcon) return 120;
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<Uint8List> _resizeImage(Uint8List bytes, int size) async {
|
||||
return await compute((Uint8List data) {
|
||||
final image = img.decodeImage(data);
|
||||
if (image == null) return data;
|
||||
final resized = img.copyResize(image, width: size, height: size);
|
||||
return Uint8List.fromList(img.encodePng(resized));
|
||||
}, bytes);
|
||||
}
|
||||
|
||||
void clearPolyline() {
|
||||
polyLines.clear();
|
||||
update();
|
||||
}
|
||||
|
||||
LatLngBounds calculateBounds(double lat, double lng, double radiusInMeters) {
|
||||
const double earthRadius = 6378137.0;
|
||||
|
||||
double latDelta = (radiusInMeters / earthRadius) * (180 / pi);
|
||||
double lngDelta =
|
||||
(radiusInMeters / (earthRadius * cos(pi * lat / 180))) * (180 / pi);
|
||||
|
||||
double minLat = lat - latDelta;
|
||||
double maxLat = lat + latDelta;
|
||||
|
||||
double minLng = lng - lngDelta;
|
||||
double maxLng = lng + lngDelta;
|
||||
|
||||
minLat = max(-90.0, minLat);
|
||||
maxLat = min(90.0, maxLat);
|
||||
|
||||
minLng = (minLng + 180) % 360 - 180;
|
||||
maxLng = (maxLng + 180) % 360 - 180;
|
||||
|
||||
if (minLng > maxLng) {
|
||||
double temp = minLng;
|
||||
minLng = maxLng;
|
||||
maxLng = temp;
|
||||
}
|
||||
|
||||
return LatLngBounds(
|
||||
southwest: LatLng(minLat, minLng),
|
||||
northeast: LatLng(maxLat, maxLng),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> playRouteAnimation(
|
||||
List<LatLng> coords, LatLngBounds? bounds) async {
|
||||
const List<Color> segmentColors = [
|
||||
Color(0xFF109642), // Green
|
||||
Color(0xFFF59E0B), // Amber
|
||||
Color(0xFF7C3AED), // Purple
|
||||
Color(0xFFEF4444), // Red
|
||||
];
|
||||
|
||||
Set<Polyline> newPolylines = {};
|
||||
final locationSearch = Get.find<LocationSearchController>();
|
||||
|
||||
if (locationSearch.activeMenuWaypointCount > 0) {
|
||||
List<int> splitIndices = [];
|
||||
for (int w = 0; w < locationSearch.activeMenuWaypointCount; w++) {
|
||||
final wp = locationSearch.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();
|
||||
|
||||
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;
|
||||
if (to > coords.length) to = coords.length;
|
||||
if (from >= to - 1) continue;
|
||||
final segCoords = coords.sublist(from, to);
|
||||
if (segCoords.length < 2) continue;
|
||||
final color = segmentColors[s % segmentColors.length];
|
||||
|
||||
newPolylines.add(Polyline(
|
||||
polylineId: PolylineId('segment_$s'),
|
||||
points: segCoords,
|
||||
color: color,
|
||||
width: 6,
|
||||
));
|
||||
}
|
||||
} else {
|
||||
newPolylines.add(Polyline(
|
||||
polylineId: const PolylineId('route_primary'),
|
||||
points: coords,
|
||||
color: AppColor.primaryColor,
|
||||
width: 6,
|
||||
));
|
||||
}
|
||||
|
||||
polyLines = newPolylines;
|
||||
update();
|
||||
|
||||
Log.print(
|
||||
'🗺️ Drawing ${markers.length} markers + ${polyLines.length} polylines on map');
|
||||
|
||||
if (bounds != null) {
|
||||
await _safeAnimateCameraBounds(bounds);
|
||||
}
|
||||
}
|
||||
|
||||
void _fitCameraToPoints(LatLng p1, LatLng p2) async {
|
||||
if (mapController == null) return;
|
||||
|
||||
if (p1.latitude == p2.latitude && p1.longitude == p2.longitude) {
|
||||
try {
|
||||
mapController?.animateCamera(CameraUpdate.newLatLngZoom(p1, 17));
|
||||
} catch (e) {
|
||||
Log.print("Error animating to single point: $e");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
double minLat = min(p1.latitude, p2.latitude);
|
||||
double maxLat = max(p1.latitude, p2.latitude);
|
||||
double minLng = min(p1.longitude, p2.longitude);
|
||||
double maxLng = max(p1.longitude, p2.longitude);
|
||||
|
||||
if ((maxLat - minLat).abs() < 0.002 && (maxLng - minLng).abs() < 0.002) {
|
||||
try {
|
||||
mapController?.animateCamera(CameraUpdate.newLatLngZoom(p1, 16));
|
||||
} catch (e) {
|
||||
Log.print("Error animating to single point: $e");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
double padding = 50.0;
|
||||
|
||||
try {
|
||||
await mapController?.animateCamera(
|
||||
CameraUpdate.newLatLngBounds(
|
||||
LatLngBounds(
|
||||
southwest: LatLng(minLat, minLng),
|
||||
northeast: LatLng(maxLat, maxLng),
|
||||
),
|
||||
left: padding,
|
||||
top: padding,
|
||||
right: padding,
|
||||
bottom: padding,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
Log.print("Error animating bounds: $e");
|
||||
try {
|
||||
LatLng center = LatLng((minLat + maxLat) / 2, (minLng + maxLng) / 2);
|
||||
mapController?.animateCamera(CameraUpdate.newLatLngZoom(center, 14));
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
void fitCameraToPoints(LatLng p1, LatLng p2) {
|
||||
_fitCameraToPoints(p1, p2);
|
||||
}
|
||||
|
||||
void clearMarkersExceptStartEndAndDriver() {
|
||||
const String currentDriverMarkerId = 'assigned_driver_marker';
|
||||
markers.removeWhere((marker) {
|
||||
String id = marker.markerId.value;
|
||||
if (id == 'start') return false;
|
||||
if (id == 'end') return false;
|
||||
if (id == currentDriverMarkerId) return false;
|
||||
return true;
|
||||
});
|
||||
update();
|
||||
}
|
||||
|
||||
void clearMarkersExceptStartEnd() {
|
||||
markers.removeWhere((marker) {
|
||||
String id = marker.markerId.value;
|
||||
return id != 'start' && id != 'end';
|
||||
});
|
||||
update();
|
||||
}
|
||||
|
||||
void _updateMarkerPosition(
|
||||
LatLng newPosition, double newHeading, String icon) {
|
||||
const String markerId = 'driverToPassengers';
|
||||
final mId = MarkerId(markerId);
|
||||
final existingMarker = markers.cast<Marker?>().firstWhere(
|
||||
(m) => m?.markerId == mId,
|
||||
orElse: () => null,
|
||||
);
|
||||
|
||||
if (existingMarker != null) {
|
||||
_smoothlyUpdateMarker(existingMarker, newPosition, newHeading, icon);
|
||||
} else {
|
||||
markers = {
|
||||
...markers,
|
||||
Marker(
|
||||
markerId: mId,
|
||||
position: newPosition,
|
||||
rotation: newHeading,
|
||||
icon: InlqBitmap.fromStyleImage(icon),
|
||||
anchor: const Offset(0.5, 0.5),
|
||||
),
|
||||
};
|
||||
update();
|
||||
}
|
||||
mapController?.animateCamera(CameraUpdate.newLatLng(newPosition));
|
||||
}
|
||||
|
||||
void updateMarkerPosition(
|
||||
LatLng newPosition, double newHeading, String icon) {
|
||||
_updateMarkerPosition(newPosition, newHeading, icon);
|
||||
}
|
||||
|
||||
void _smoothlyUpdateMarker(
|
||||
Marker oldMarker, LatLng newPosition, double newHeading, String icon) {
|
||||
double distance = Geolocator.distanceBetween(
|
||||
oldMarker.position.latitude,
|
||||
oldMarker.position.longitude,
|
||||
newPosition.latitude,
|
||||
newPosition.longitude);
|
||||
|
||||
if (distance < 2.0) return;
|
||||
|
||||
final MarkerId markerIdKey = oldMarker.markerId;
|
||||
_animationTimers[markerIdKey.value]?.cancel();
|
||||
|
||||
int ticks = 0;
|
||||
const int totalSteps = 20;
|
||||
const int stepDuration = 50;
|
||||
|
||||
double latStep =
|
||||
(newPosition.latitude - oldMarker.position.latitude) / totalSteps;
|
||||
double lngStep =
|
||||
(newPosition.longitude - oldMarker.position.longitude) / totalSteps;
|
||||
double headingStep = (newHeading - oldMarker.rotation) / totalSteps;
|
||||
|
||||
LatLng currentPos = oldMarker.position;
|
||||
double currentHeading = oldMarker.rotation;
|
||||
|
||||
_animationTimers[markerIdKey.value] =
|
||||
Timer.periodic(const Duration(milliseconds: stepDuration), (timer) {
|
||||
ticks++;
|
||||
|
||||
currentPos =
|
||||
LatLng(currentPos.latitude + latStep, currentPos.longitude + lngStep);
|
||||
currentHeading += headingStep;
|
||||
|
||||
final updatedMarker = oldMarker.copyWith(
|
||||
position: currentPos,
|
||||
rotation: currentHeading,
|
||||
icon: InlqBitmap.fromStyleImage(icon),
|
||||
);
|
||||
|
||||
markers = {
|
||||
...markers.where((m) => m.markerId != markerIdKey),
|
||||
updatedMarker,
|
||||
};
|
||||
|
||||
if (mapController != null) {
|
||||
mapController!.animateCamera(CameraUpdate.newLatLng(currentPos));
|
||||
}
|
||||
|
||||
update();
|
||||
|
||||
if (ticks >= totalSteps) {
|
||||
timer.cancel();
|
||||
_animationTimers.remove(markerIdKey.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// تحديث موقع العلامة (Marker) واتجاهها بسلاسة على الخريطة.
|
||||
// تحسب الدالة المسافة بين الموقع الحالي والجديد؛ وإذا كانت أكبر من مترين،
|
||||
// تقوم بتقسيم الحركة والدوران إلى 20 خطوة متباعدة بـ 50 مللي ثانية (إجمالي ثانية واحدة).
|
||||
// يتم تحديث موضع العلامة وتحريك الكاميرا تدريجياً لتبدو حركة السيارة انسيابية.
|
||||
void smoothlyUpdateMarker(
|
||||
Marker oldMarker, LatLng newPosition, double newHeading, String icon) {
|
||||
_smoothlyUpdateMarker(oldMarker, newPosition, newHeading, icon);
|
||||
}
|
||||
|
||||
void changeBottomSheetShown({bool? forceValue}) {
|
||||
if (forceValue != null) {
|
||||
isBottomSheetShown = forceValue;
|
||||
} else {
|
||||
isBottomSheetShown = !isBottomSheetShown;
|
||||
}
|
||||
heightBottomSheetShown = isBottomSheetShown == true ? 250 : 0;
|
||||
update();
|
||||
}
|
||||
|
||||
void changeCashConfirmPageShown() {
|
||||
isCashConfirmPageShown = !isCashConfirmPageShown;
|
||||
final rideLife = Get.find<RideLifecycleController>();
|
||||
rideLife.isCashSelectedBeforeConfirmRide = true;
|
||||
cashConfirmPageShown = isCashConfirmPageShown == true ? 250 : 0;
|
||||
update();
|
||||
rideLife.update();
|
||||
}
|
||||
|
||||
void changePaymentMethodPageShown() {
|
||||
isPaymentMethodPageShown = !isPaymentMethodPageShown;
|
||||
paymentPageShown = isPaymentMethodPageShown == true ? Get.height * .6 : 0;
|
||||
update();
|
||||
}
|
||||
|
||||
void changeMapType() {
|
||||
mapType = !mapType;
|
||||
update();
|
||||
}
|
||||
|
||||
void changeMapTraffic() {
|
||||
mapTrafficON = !mapTrafficON;
|
||||
update();
|
||||
}
|
||||
|
||||
void changeisAnotherOreder(bool val) {
|
||||
isAnotherOreder = val;
|
||||
update();
|
||||
}
|
||||
|
||||
void changeIsWhatsAppOrder(bool val) {
|
||||
isWhatsAppOrder = val;
|
||||
update();
|
||||
}
|
||||
|
||||
void changeCancelRidePageShow() {
|
||||
showCancelRideBottomSheet();
|
||||
isCancelRidePageShown = !isCancelRidePageShown;
|
||||
update();
|
||||
if (Get.isRegistered<RideLifecycleController>()) {
|
||||
Get.find<RideLifecycleController>().update();
|
||||
}
|
||||
}
|
||||
|
||||
void getDrawerMenu() {
|
||||
heightMenuBool = !heightMenuBool;
|
||||
widthMapTypeAndTraffic = heightMenuBool == true ? 0 : 50;
|
||||
heightMenu = heightMenuBool == true ? 80 : 0;
|
||||
widthMenu = heightMenuBool == true ? 110 : 0;
|
||||
update();
|
||||
}
|
||||
|
||||
void changeMainBottomMenuMap() {
|
||||
if (isWayPointStopsSheetUtilGetMap == true) {
|
||||
changeWayPointSheet();
|
||||
} else {
|
||||
isMainBottomMenuMap = !isMainBottomMenuMap;
|
||||
mainBottomMenuMapHeight =
|
||||
isMainBottomMenuMap == true ? Get.height * .22 : Get.height * .6;
|
||||
isWayPointSheet = false;
|
||||
if (heightMenuBool == true) {
|
||||
getDrawerMenu();
|
||||
}
|
||||
Get.find<RideLifecycleController>().initilizeGetStorage();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void downPoints() {
|
||||
if (Get.find<WayPointController>().wayPoints.length < 2) {
|
||||
isWayPointStopsSheetUtilGetMap = false;
|
||||
isWayPointSheet = false;
|
||||
wayPointSheetHeight = isWayPointStopsSheet ? Get.height * .45 : 0;
|
||||
update();
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void changeWayPointSheet() {
|
||||
isWayPointSheet = !isWayPointSheet;
|
||||
wayPointSheetHeight = isWayPointSheet == false ? 0 : Get.height * .45;
|
||||
update();
|
||||
}
|
||||
|
||||
void changeWayPointStopsSheet() {
|
||||
final locationSearch = Get.find<LocationSearchController>();
|
||||
if (locationSearch.wayPointIndex > -1) {
|
||||
isWayPointStopsSheet = true;
|
||||
isWayPointStopsSheetUtilGetMap = true;
|
||||
}
|
||||
isWayPointStopsSheet = !isWayPointStopsSheet;
|
||||
wayPointSheetHeight = isWayPointStopsSheet ? Get.height * .45 : 0;
|
||||
update();
|
||||
}
|
||||
|
||||
void changeHeightPlaces() {
|
||||
final locationSearch = Get.find<LocationSearchController>();
|
||||
if (locationSearch.placesDestination.isEmpty) {
|
||||
height = 0;
|
||||
update();
|
||||
} else {
|
||||
height = 150;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void changeHeightStartPlaces() {
|
||||
final locationSearch = Get.find<LocationSearchController>();
|
||||
if (locationSearch.placesStart.isEmpty) {
|
||||
height = 0;
|
||||
update();
|
||||
} else {
|
||||
height = 150;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void changeHeightPlacesAll(int index) {
|
||||
final locationSearch = Get.find<LocationSearchController>();
|
||||
if (locationSearch.placeListResponseAll[index].isEmpty) {
|
||||
height = 0;
|
||||
update();
|
||||
} else {
|
||||
height = 150;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void changeHeightPlaces1() {
|
||||
final locationSearch = Get.find<LocationSearchController>();
|
||||
if (locationSearch.wayPoint1.isEmpty) {
|
||||
height = 0;
|
||||
update();
|
||||
} else {
|
||||
height = 150;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void changeHeightPlaces2() {
|
||||
final locationSearch = Get.find<LocationSearchController>();
|
||||
if (locationSearch.wayPoint2.isEmpty) {
|
||||
height = 0;
|
||||
update();
|
||||
} else {
|
||||
height = 150;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void changeHeightPlaces3() {
|
||||
final locationSearch = Get.find<LocationSearchController>();
|
||||
if (locationSearch.wayPoint3.isEmpty) {
|
||||
height = 0;
|
||||
update();
|
||||
} else {
|
||||
height = 150;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void changeHeightPlaces4() {
|
||||
final locationSearch = Get.find<LocationSearchController>();
|
||||
if (locationSearch.wayPoint4.isEmpty) {
|
||||
height = 0;
|
||||
update();
|
||||
} else {
|
||||
height = 150;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void hidePlaces() {
|
||||
height = 0;
|
||||
update();
|
||||
}
|
||||
|
||||
void changePickerShown() {
|
||||
isPickerShown = !isPickerShown;
|
||||
heightPickerContainer = isPickerShown == true ? 150 : 90;
|
||||
update();
|
||||
}
|
||||
|
||||
void _initializePolygons() {
|
||||
List<List<LatLng>> universityPolygons =
|
||||
UniversitiesPolygons.universityPolygons;
|
||||
|
||||
for (int i = 0; i < universityPolygons.length; i++) {
|
||||
Polygon polygon = Polygon(
|
||||
polygonId: PolygonId('univ_$i'),
|
||||
points: universityPolygons[i],
|
||||
fillColor: Colors.blueAccent.withOpacity(0.2),
|
||||
strokeColor: Colors.blueAccent,
|
||||
strokeWidth: 2,
|
||||
);
|
||||
polygons.add(polygon);
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void _applyLowEndModeIfNeeded() {
|
||||
// Placeholder comment from original
|
||||
}
|
||||
|
||||
Future<void> _initMinimalIcons() async {
|
||||
// Icons are loaded dynamically
|
||||
}
|
||||
|
||||
Future<void> _playRouteAnimation(
|
||||
List<LatLng> coords, LatLngBounds? bounds) async {
|
||||
const List<Color> segmentColors = [
|
||||
Color(0xFF109642), // Green
|
||||
Color(0xFFF59E0B), // Amber
|
||||
Color(0xFF7C3AED), // Purple
|
||||
Color(0xFFEF4444), // Red
|
||||
];
|
||||
|
||||
Set<Polyline> newPolylines = {};
|
||||
final locSearch = Get.find<LocationSearchController>();
|
||||
|
||||
if (locSearch.activeMenuWaypointCount > 0) {
|
||||
List<int> splitIndices = [];
|
||||
for (int w = 0; w < locSearch.activeMenuWaypointCount; w++) {
|
||||
final wp = locSearch.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();
|
||||
|
||||
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;
|
||||
if (to > coords.length) to = coords.length;
|
||||
if (from >= to - 1) continue;
|
||||
final segCoords = coords.sublist(from, to);
|
||||
if (segCoords.length < 2) continue;
|
||||
final color = segmentColors[s % segmentColors.length];
|
||||
|
||||
newPolylines.add(Polyline(
|
||||
polylineId: PolylineId('segment_$s'),
|
||||
points: segCoords,
|
||||
color: color,
|
||||
width: 6,
|
||||
));
|
||||
}
|
||||
} else {
|
||||
newPolylines.add(Polyline(
|
||||
polylineId: const PolylineId('route_primary'),
|
||||
points: coords,
|
||||
color: AppColor.primaryColor,
|
||||
width: 6,
|
||||
));
|
||||
}
|
||||
|
||||
polyLines = newPolylines;
|
||||
update();
|
||||
|
||||
Log.print(
|
||||
'🗺️ Drawing ${markers.length} markers + ${polyLines.length} polylines on map');
|
||||
|
||||
update();
|
||||
|
||||
if (bounds != null) {
|
||||
await _safeAnimateCameraBounds(bounds);
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
isPickerShown = false;
|
||||
isPointsPageForRider = false;
|
||||
isBottomSheetShown = false;
|
||||
isCancelRidePageShown = false;
|
||||
isCashConfirmPageShown = false;
|
||||
isPaymentMethodPageShown = false;
|
||||
isRideFinished = false;
|
||||
rideConfirm = false;
|
||||
isMainBottomMenuMap = true;
|
||||
|
||||
isWayPointSheet = false;
|
||||
isWayPointStopsSheet = false;
|
||||
isWayPointStopsSheetUtilGetMap = false;
|
||||
|
||||
heightBottomSheetShown = 0;
|
||||
mainBottomMenuMapHeight = Get.height * 0.22;
|
||||
wayPointSheetHeight = 0;
|
||||
|
||||
markers.clear();
|
||||
polyLines.clear();
|
||||
polylineCoordinates.clear();
|
||||
|
||||
_animationTimers.forEach((key, timer) => timer.cancel());
|
||||
_animationTimers.clear();
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
_animationTimers.forEach((key, timer) => timer.cancel());
|
||||
_animationTimers.clear();
|
||||
mapController = null;
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user