use super::step_advance::conditions::ManualStepCondition;
use super::step_advance::{SerializableStepAdvanceCondition, StepAdvanceCondition};
use crate::algorithms::distance_between_locations;
use crate::deviation_detection::{RouteDeviation, RouteDeviationTracking};
use crate::models::{RouteStep, SpokenInstruction, UserLocation, VisualInstruction, Waypoint};
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
#[cfg(feature = "wasm-bindgen")]
use tsify::Tsify;
#[derive(Clone)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
pub struct NavState {
trip_state: TripState,
step_advance_condition: Arc<dyn StepAdvanceCondition>,
}
impl NavState {
pub fn new(
trip_state: TripState,
step_advance_condition: Arc<dyn StepAdvanceCondition>,
) -> Self {
Self {
trip_state,
step_advance_condition,
}
}
pub fn idle(user_location: Option<UserLocation>) -> Self {
Self {
trip_state: TripState::Idle { user_location },
step_advance_condition: Arc::new(ManualStepCondition {}), }
}
pub fn complete(user_location: UserLocation, last_summary: TripSummary) -> Self {
Self {
trip_state: TripState::Complete {
user_location,
summary: TripSummary {
ended_at: Some(Utc::now()),
..last_summary
},
},
step_advance_condition: Arc::new(ManualStepCondition {}), }
}
#[inline]
pub fn trip_state(&self) -> TripState {
self.trip_state.clone()
}
#[inline]
pub fn step_advance_condition(&self) -> Arc<dyn StepAdvanceCondition> {
self.step_advance_condition.clone()
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
#[cfg_attr(feature = "wasm-bindgen", derive(Tsify))]
#[cfg_attr(feature = "wasm-bindgen", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "wasm-bindgen", tsify(into_wasm_abi, from_wasm_abi))]
pub struct SerializableNavState {
pub(crate) trip_state: TripState,
pub(crate) step_advance_condition: SerializableStepAdvanceCondition,
}
impl From<SerializableNavState> for NavState {
fn from(value: SerializableNavState) -> Self {
Self {
trip_state: value.trip_state,
step_advance_condition: value.step_advance_condition.into(),
}
}
}
impl From<NavState> for SerializableNavState {
fn from(value: NavState) -> Self {
Self {
trip_state: value.trip_state,
step_advance_condition: value.step_advance_condition.to_js(),
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
#[cfg_attr(feature = "wasm-bindgen", derive(Tsify))]
#[cfg_attr(any(feature = "wasm-bindgen", test), serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "wasm-bindgen", tsify(into_wasm_abi, from_wasm_abi))]
pub struct TripProgress {
pub distance_to_next_maneuver: f64,
pub distance_remaining: f64,
pub duration_remaining: f64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
#[cfg_attr(feature = "wasm-bindgen", derive(Tsify))]
#[cfg_attr(any(feature = "wasm-bindgen", test), serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "wasm-bindgen", tsify(into_wasm_abi, from_wasm_abi))]
pub struct TripSummary {
pub distance_traveled: f64,
pub snapped_distance_traveled: f64,
#[cfg_attr(feature = "wasm-bindgen", tsify(type = "Date"))]
pub started_at: DateTime<Utc>,
#[cfg_attr(feature = "wasm-bindgen", tsify(type = "Date | null"))]
pub ended_at: Option<DateTime<Utc>>,
}
impl TripSummary {
pub(crate) fn update(
&self,
previous_location: &UserLocation,
current_location: &UserLocation,
previous_snapped_location: &UserLocation,
current_snapped_location: &UserLocation,
) -> Self {
let distance_increment = distance_between_locations(previous_location, current_location);
let snapped_distance_increment =
distance_between_locations(previous_snapped_location, current_snapped_location);
TripSummary {
distance_traveled: self.distance_traveled + distance_increment,
snapped_distance_traveled: self.snapped_distance_traveled + snapped_distance_increment,
started_at: self.started_at,
ended_at: self.ended_at,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
#[cfg_attr(feature = "wasm-bindgen", derive(Tsify))]
#[cfg_attr(feature = "wasm-bindgen", tsify(into_wasm_abi, from_wasm_abi))]
#[allow(clippy::large_enum_variant)]
pub enum TripState {
Idle { user_location: Option<UserLocation> },
#[cfg_attr(feature = "wasm-bindgen", serde(rename_all = "camelCase"))]
Navigating {
current_step_geometry_index: Option<u64>,
user_location: UserLocation,
snapped_user_location: UserLocation,
remaining_steps: Vec<RouteStep>,
remaining_waypoints: Vec<Waypoint>,
progress: TripProgress,
summary: TripSummary,
deviation: RouteDeviation,
visual_instruction: Option<VisualInstruction>,
spoken_instruction: Option<SpokenInstruction>,
annotation_json: Option<String>,
},
Complete {
user_location: UserLocation,
summary: TripSummary,
},
}
impl TripState {
pub(crate) fn user_location(&self) -> Option<UserLocation> {
match self {
TripState::Navigating { user_location, .. } => Some(*user_location),
_ => None,
}
}
pub(crate) fn snapped_user_location(&self) -> Option<UserLocation> {
match self {
TripState::Navigating {
snapped_user_location,
..
} => Some(*snapped_user_location),
_ => None,
}
}
pub(crate) fn current_step(&self) -> Option<RouteStep> {
match self {
TripState::Navigating {
remaining_steps, ..
} => remaining_steps.first().cloned(),
_ => None,
}
}
pub(crate) fn next_step(&self) -> Option<RouteStep> {
self.get_step(1)
}
pub(crate) fn get_step(&self, index: usize) -> Option<RouteStep> {
match self {
TripState::Navigating {
remaining_steps, ..
} => remaining_steps.get(index).cloned(),
_ => None,
}
}
pub(crate) fn deviation(&self) -> Option<RouteDeviation> {
match self {
TripState::Navigating { deviation, .. } => Some(*deviation),
_ => None,
}
}
}
#[allow(clippy::large_enum_variant)]
pub enum StepAdvanceStatus {
Advanced { step: RouteStep },
EndOfRoute,
}
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
#[cfg_attr(feature = "wasm-bindgen", derive(Tsify))]
#[cfg_attr(feature = "wasm-bindgen", tsify(from_wasm_abi))]
pub enum CourseFiltering {
SnapToRoute,
Raw,
}
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
#[cfg_attr(feature = "wasm-bindgen", derive(Tsify))]
#[cfg_attr(feature = "wasm-bindgen", tsify(from_wasm_abi))]
pub enum WaypointAdvanceMode {
WaypointWithinRange(f64),
WaypointAlongAdvancingStep(f64),
}
#[derive(Clone)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
pub struct NavigationControllerConfig {
pub waypoint_advance: WaypointAdvanceMode,
pub step_advance_condition: Arc<dyn StepAdvanceCondition>,
pub arrival_step_advance_condition: Arc<dyn StepAdvanceCondition>,
pub route_deviation_tracking: RouteDeviationTracking,
pub snapped_location_course_filtering: CourseFiltering,
}
#[derive(Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "wasm-bindgen", derive(Tsify))]
#[cfg_attr(feature = "wasm-bindgen", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "wasm-bindgen", tsify(from_wasm_abi))]
pub struct SerializableNavigationControllerConfig {
pub waypoint_advance: WaypointAdvanceMode,
pub step_advance_condition: SerializableStepAdvanceCondition,
pub arrival_step_advance_condition: SerializableStepAdvanceCondition,
pub route_deviation_tracking: RouteDeviationTracking,
pub snapped_location_course_filtering: CourseFiltering,
}
impl From<SerializableNavigationControllerConfig> for NavigationControllerConfig {
fn from(js_config: SerializableNavigationControllerConfig) -> Self {
Self {
waypoint_advance: js_config.waypoint_advance,
step_advance_condition: js_config.step_advance_condition.into(),
arrival_step_advance_condition: js_config.arrival_step_advance_condition.into(),
route_deviation_tracking: js_config.route_deviation_tracking,
snapped_location_course_filtering: js_config.snapped_location_course_filtering,
}
}
}
impl From<NavigationControllerConfig> for SerializableNavigationControllerConfig {
fn from(config: NavigationControllerConfig) -> Self {
Self {
waypoint_advance: config.waypoint_advance,
step_advance_condition: config.step_advance_condition.to_js(),
arrival_step_advance_condition: config.arrival_step_advance_condition.to_js(),
route_deviation_tracking: config.route_deviation_tracking,
snapped_location_course_filtering: config.snapped_location_course_filtering,
}
}
}