* *Option 3:* `feat: add tourist landmarks support with UI sheets, data models
306 lines
9.5 KiB
Dart
306 lines
9.5 KiB
Dart
import 'package:equatable/equatable.dart';
|
|
import 'package:intaleq_maps/intaleq_maps.dart';
|
|
import '../../../data/models/route_model.dart';
|
|
import '../../../data/models/place_model.dart';
|
|
|
|
enum NavigationStatus {
|
|
initial,
|
|
loading,
|
|
mapReady,
|
|
routePreview,
|
|
navigating,
|
|
arrived,
|
|
error,
|
|
}
|
|
|
|
enum MapThemeType {
|
|
vectorLight,
|
|
vectorDark,
|
|
satellite,
|
|
}
|
|
|
|
class NavigationState extends Equatable {
|
|
final NavigationStatus status;
|
|
final LatLng? myLocation;
|
|
final double altitude; // Altitude AMSL in meters (defaults to 0.0)
|
|
final double heading;
|
|
final double speed;
|
|
final List<RouteData> routes;
|
|
final int selectedRouteIndex;
|
|
final LatLng? destination;
|
|
final String destinationTitle;
|
|
final String originTitle;
|
|
final List<Map<String, dynamic>> routeSteps;
|
|
final int currentStepIndex;
|
|
final String currentInstruction;
|
|
final String nextInstruction;
|
|
final double distanceToNextStep;
|
|
final double remainingDistance;
|
|
final double remainingDuration;
|
|
final int currentManeuverModifier;
|
|
final String arrivalTime;
|
|
final bool isMuted;
|
|
final bool isCameraLocked;
|
|
final MapThemeType mapTheme;
|
|
final Set<Marker> markers;
|
|
final Set<Polyline> polylines;
|
|
final List<PlaceModel> searchResults;
|
|
final bool isSelectingLocationOnMap;
|
|
final String? activePickerMode;
|
|
final LatLng? pickedLocation;
|
|
final bool isOnline;
|
|
final String? errorMessage;
|
|
final int selectedVehicleColor;
|
|
final String selectedVehicleStyle;
|
|
final double vehicleScale;
|
|
final List<String> recentSearches;
|
|
final bool isSearching;
|
|
final bool isOrbiting;
|
|
final double orbitSpeed;
|
|
final bool isSunPlaying;
|
|
final int sunTimeMinutes;
|
|
final double terrainExaggeration;
|
|
final double cameraTilt;
|
|
final bool showBuildings;
|
|
final bool showContours;
|
|
final bool showHillshading;
|
|
final bool isTouristModeEnabled;
|
|
final String? selectedLandmarkId;
|
|
|
|
const NavigationState({
|
|
this.status = NavigationStatus.initial,
|
|
this.myLocation,
|
|
this.altitude = 0.0,
|
|
this.heading = 0.0,
|
|
this.speed = 0.0,
|
|
this.routes = const [],
|
|
this.selectedRouteIndex = 0,
|
|
this.destination,
|
|
this.destinationTitle = '',
|
|
this.originTitle = 'موقعي الحالي',
|
|
this.routeSteps = const [],
|
|
this.currentStepIndex = 0,
|
|
this.currentInstruction = '',
|
|
this.nextInstruction = '',
|
|
this.distanceToNextStep = 0.0,
|
|
this.remainingDistance = 0.0,
|
|
this.remainingDuration = 0.0,
|
|
this.currentManeuverModifier = 0,
|
|
this.arrivalTime = '--:--',
|
|
this.isMuted = false,
|
|
this.isCameraLocked = true,
|
|
this.mapTheme = MapThemeType.vectorLight,
|
|
this.markers = const {},
|
|
this.polylines = const {},
|
|
this.searchResults = const [],
|
|
this.isSelectingLocationOnMap = false,
|
|
this.activePickerMode,
|
|
this.pickedLocation,
|
|
this.isOnline = true,
|
|
this.errorMessage,
|
|
this.selectedVehicleColor = 0xFF007AFF,
|
|
this.selectedVehicleStyle = 'car',
|
|
this.vehicleScale = 1.8,
|
|
this.recentSearches = const [],
|
|
this.isSearching = false,
|
|
this.isOrbiting = false,
|
|
this.orbitSpeed = 1.0,
|
|
this.isSunPlaying = false,
|
|
this.sunTimeMinutes = 1110,
|
|
this.terrainExaggeration = 2.0,
|
|
this.cameraTilt = 55.0,
|
|
this.showBuildings = true,
|
|
this.showContours = true,
|
|
this.showHillshading = true,
|
|
this.isTouristModeEnabled = false,
|
|
this.selectedLandmarkId,
|
|
});
|
|
|
|
RouteData? get currentRoute =>
|
|
routes.isNotEmpty && selectedRouteIndex < routes.length
|
|
? routes[selectedRouteIndex]
|
|
: null;
|
|
|
|
bool get isNavigating => status == NavigationStatus.navigating;
|
|
|
|
String get formattedRemainingDistance {
|
|
if (remainingDistance >= 1000) {
|
|
return '${(remainingDistance / 1000).toStringAsFixed(1)} كم';
|
|
}
|
|
return '${remainingDistance.round()} م';
|
|
}
|
|
|
|
String get formattedRemainingDuration {
|
|
final int minutes = (remainingDuration / 60).round();
|
|
if (minutes >= 60) {
|
|
final int hours = minutes ~/ 60;
|
|
final int remMin = minutes % 60;
|
|
return '$hours س $remMin د';
|
|
}
|
|
return '$minutes دقيقة';
|
|
}
|
|
|
|
String get formattedDistanceToStep {
|
|
if (distanceToNextStep >= 1000) {
|
|
return '${(distanceToNextStep / 1000).toStringAsFixed(1)} كم';
|
|
}
|
|
if (distanceToNextStep > 0) {
|
|
return '${distanceToNextStep.round()} م';
|
|
}
|
|
return '';
|
|
}
|
|
|
|
NavigationState copyWith({
|
|
NavigationStatus? status,
|
|
LatLng? myLocation,
|
|
double? altitude,
|
|
double? heading,
|
|
double? speed,
|
|
List<RouteData>? routes,
|
|
int? selectedRouteIndex,
|
|
LatLng? destination,
|
|
String? destinationTitle,
|
|
String? originTitle,
|
|
List<Map<String, dynamic>>? routeSteps,
|
|
int? currentStepIndex,
|
|
String? currentInstruction,
|
|
String? nextInstruction,
|
|
double? distanceToNextStep,
|
|
double? remainingDistance,
|
|
double? remainingDuration,
|
|
int? currentManeuverModifier,
|
|
String? arrivalTime,
|
|
bool? isMuted,
|
|
bool? isCameraLocked,
|
|
MapThemeType? mapTheme,
|
|
Set<Marker>? markers,
|
|
Set<Polyline>? polylines,
|
|
List<PlaceModel>? searchResults,
|
|
bool? isSelectingLocationOnMap,
|
|
String? activePickerMode,
|
|
bool clearActivePickerMode = false,
|
|
LatLng? pickedLocation,
|
|
bool clearPickedLocation = false,
|
|
bool? isOnline,
|
|
String? errorMessage,
|
|
int? selectedVehicleColor,
|
|
String? selectedVehicleStyle,
|
|
double? vehicleScale,
|
|
List<String>? recentSearches,
|
|
bool? isSearching,
|
|
bool? isOrbiting,
|
|
double? orbitSpeed,
|
|
bool? isSunPlaying,
|
|
int? sunTimeMinutes,
|
|
double? terrainExaggeration,
|
|
double? cameraTilt,
|
|
bool? showBuildings,
|
|
bool? showContours,
|
|
bool? showHillshading,
|
|
bool? isTouristModeEnabled,
|
|
String? selectedLandmarkId,
|
|
bool clearSelectedLandmark = false,
|
|
}) {
|
|
return NavigationState(
|
|
status: status ?? this.status,
|
|
myLocation: myLocation ?? this.myLocation,
|
|
altitude: altitude ?? this.altitude,
|
|
heading: heading ?? this.heading,
|
|
speed: speed ?? this.speed,
|
|
routes: routes ?? this.routes,
|
|
selectedRouteIndex: selectedRouteIndex ?? this.selectedRouteIndex,
|
|
destination: destination ?? this.destination,
|
|
destinationTitle: destinationTitle ?? this.destinationTitle,
|
|
originTitle: originTitle ?? this.originTitle,
|
|
routeSteps: routeSteps ?? this.routeSteps,
|
|
currentStepIndex: currentStepIndex ?? this.currentStepIndex,
|
|
currentInstruction: currentInstruction ?? this.currentInstruction,
|
|
nextInstruction: nextInstruction ?? this.nextInstruction,
|
|
distanceToNextStep: distanceToNextStep ?? this.distanceToNextStep,
|
|
remainingDistance: remainingDistance ?? this.remainingDistance,
|
|
remainingDuration: remainingDuration ?? this.remainingDuration,
|
|
currentManeuverModifier:
|
|
currentManeuverModifier ?? this.currentManeuverModifier,
|
|
arrivalTime: arrivalTime ?? this.arrivalTime,
|
|
isMuted: isMuted ?? this.isMuted,
|
|
isCameraLocked: isCameraLocked ?? this.isCameraLocked,
|
|
mapTheme: mapTheme ?? this.mapTheme,
|
|
markers: markers ?? this.markers,
|
|
polylines: polylines ?? this.polylines,
|
|
searchResults: searchResults ?? this.searchResults,
|
|
isSelectingLocationOnMap:
|
|
isSelectingLocationOnMap ?? this.isSelectingLocationOnMap,
|
|
activePickerMode: clearActivePickerMode ? null : (activePickerMode ?? this.activePickerMode),
|
|
pickedLocation: clearPickedLocation ? null : (pickedLocation ?? this.pickedLocation),
|
|
isOnline: isOnline ?? this.isOnline,
|
|
errorMessage: errorMessage ?? this.errorMessage,
|
|
selectedVehicleColor: selectedVehicleColor ?? this.selectedVehicleColor,
|
|
selectedVehicleStyle: selectedVehicleStyle ?? this.selectedVehicleStyle,
|
|
vehicleScale: vehicleScale ?? this.vehicleScale,
|
|
recentSearches: recentSearches ?? this.recentSearches,
|
|
isSearching: isSearching ?? this.isSearching,
|
|
isOrbiting: isOrbiting ?? this.isOrbiting,
|
|
orbitSpeed: orbitSpeed ?? this.orbitSpeed,
|
|
isSunPlaying: isSunPlaying ?? this.isSunPlaying,
|
|
sunTimeMinutes: sunTimeMinutes ?? this.sunTimeMinutes,
|
|
terrainExaggeration: terrainExaggeration ?? this.terrainExaggeration,
|
|
cameraTilt: cameraTilt ?? this.cameraTilt,
|
|
showBuildings: showBuildings ?? this.showBuildings,
|
|
showContours: showContours ?? this.showContours,
|
|
showHillshading: showHillshading ?? this.showHillshading,
|
|
isTouristModeEnabled: isTouristModeEnabled ?? this.isTouristModeEnabled,
|
|
selectedLandmarkId: clearSelectedLandmark ? null : (selectedLandmarkId ?? this.selectedLandmarkId),
|
|
);
|
|
}
|
|
|
|
@override
|
|
List<Object?> get props => [
|
|
status,
|
|
myLocation,
|
|
altitude,
|
|
heading,
|
|
speed,
|
|
routes,
|
|
selectedRouteIndex,
|
|
destination,
|
|
destinationTitle,
|
|
originTitle,
|
|
routeSteps,
|
|
currentStepIndex,
|
|
currentInstruction,
|
|
nextInstruction,
|
|
distanceToNextStep,
|
|
remainingDistance,
|
|
remainingDuration,
|
|
currentManeuverModifier,
|
|
arrivalTime,
|
|
isMuted,
|
|
isCameraLocked,
|
|
mapTheme,
|
|
markers,
|
|
polylines,
|
|
searchResults,
|
|
isSelectingLocationOnMap,
|
|
activePickerMode,
|
|
pickedLocation,
|
|
isOnline,
|
|
errorMessage,
|
|
selectedVehicleColor,
|
|
selectedVehicleStyle,
|
|
vehicleScale,
|
|
recentSearches,
|
|
isSearching,
|
|
isOrbiting,
|
|
orbitSpeed,
|
|
isSunPlaying,
|
|
sunTimeMinutes,
|
|
terrainExaggeration,
|
|
cameraTilt,
|
|
showBuildings,
|
|
showContours,
|
|
showHillshading,
|
|
isTouristModeEnabled,
|
|
selectedLandmarkId,
|
|
];
|
|
}
|