use crate::{Location, LocationError, Timestamp};
#[swift_bridge::bridge]
mod ffi {
#[swift_bridge(swift_repr = "struct")]
struct LocationData {
latitude: f64,
longitude: f64,
altitude: f64,
horizontal_accuracy: f64,
vertical_accuracy: f64,
timestamp_ms: i64,
}
enum LocationResult {
Success(LocationData),
PermissionDenied,
ServiceDisabled,
Timeout,
NotAvailable,
}
extern "Swift" {
fn get_current_location(callback: Box<dyn FnOnce(LocationResult) -> ()>);
}
}
pub async fn get_location() -> Result<Location, LocationError> {
let (sender, receiver) = futures::channel::oneshot::channel();
ffi::get_current_location(Box::new(move |result| {
let _ = sender.send(result);
}));
let result = receiver
.await
.map_err(|_| LocationError::Platform("location callback dropped".into()))?;
match result {
ffi::LocationResult::Success(data) => {
let timestamp = Timestamp::from_millisecond(data.timestamp_ms)
.map_err(|e| LocationError::Platform(e.to_string()))?;
let mut location = Location::from_degrees(data.latitude, data.longitude, timestamp)?;
if data.vertical_accuracy >= 0.0 {
location = location
.with_altitude(data.altitude)
.with_vertical_accuracy(data.vertical_accuracy);
}
if data.horizontal_accuracy >= 0.0 {
location = location.with_horizontal_accuracy(data.horizontal_accuracy);
}
Ok(location)
}
ffi::LocationResult::PermissionDenied => Err(LocationError::PermissionDenied),
ffi::LocationResult::ServiceDisabled => Err(LocationError::ServiceDisabled),
ffi::LocationResult::Timeout => Err(LocationError::Timeout),
ffi::LocationResult::NotAvailable => Err(LocationError::NotAvailable),
}
}