use crate::{OptionLocalRwSignal, UseGeolocationOptions, UseGeolocationReturn};
use leptos::prelude::*;
pub fn use_geolocation()
-> UseGeolocationReturn<impl Fn() + Clone + Send + Sync, impl Fn() + Clone + Send + Sync> {
use_geolocation_with_options(UseGeolocationOptions::default())
}
pub fn use_geolocation_with_options(
options: UseGeolocationOptions,
) -> UseGeolocationReturn<impl Fn() + Clone + Send + Sync, impl Fn() + Clone + Send + Sync> {
let (located_at, set_located_at) = signal(None::<f64>);
let error = OptionLocalRwSignal::<web_sys::PositionError>::new();
let coords = OptionLocalRwSignal::<web_sys::Coordinates>::new();
let resume;
let pause;
#[cfg(feature = "ssr")]
{
resume = || ();
pause = || ();
let _ = options;
let _ = set_located_at;
let _ = error;
let _ = coords;
}
#[cfg(not(feature = "ssr"))]
{
use crate::{sendwrap_fn, use_window};
use std::sync::{Arc, Mutex};
use wasm_bindgen::prelude::*;
let update_position = move |position: web_sys::Position| {
set_located_at.set(Some(position.timestamp()));
coords.set(Some(position.coords()));
error.set(None);
};
let on_error = move |err: web_sys::PositionError| {
error.set(Some(err));
};
let watch_handle = Arc::new(Mutex::new(None::<i32>));
resume = {
let watch_handle = Arc::clone(&watch_handle);
let position_options = options.as_position_options();
sendwrap_fn!(move || {
let navigator = use_window().navigator();
if let Some(navigator) = navigator
&& let Ok(geolocation) = navigator.geolocation()
{
if let Some(handle) = watch_handle.lock().unwrap().take() {
geolocation.clear_watch(handle);
}
let update_position =
Closure::wrap(Box::new(update_position) as Box<dyn Fn(web_sys::Position)>);
let on_error =
Closure::wrap(Box::new(on_error) as Box<dyn Fn(web_sys::PositionError)>);
let handle = geolocation.watch_position_with_error_callback_and_options(
update_position.as_ref().unchecked_ref(),
Some(on_error.as_ref().unchecked_ref()),
&position_options,
);
#[cfg(web_sys_unstable_apis)]
let handle = Some(handle);
#[cfg(not(web_sys_unstable_apis))]
let handle = handle.ok();
*watch_handle.lock().unwrap() = handle;
update_position.forget();
on_error.forget();
}
})
};
if options.immediate {
resume();
}
pause = {
let watch_handle = Arc::clone(&watch_handle);
sendwrap_fn!(move || {
let navigator = use_window().navigator();
if let Some(navigator) = navigator
&& let Some(handle) = *watch_handle.lock().unwrap()
&& let Ok(geolocation) = navigator.geolocation()
{
geolocation.clear_watch(handle);
}
})
};
on_cleanup({
let pause = pause.clone();
move || {
pause();
}
});
}
UseGeolocationReturn {
coords: coords.read_only(),
located_at: located_at.into(),
error: error.read_only(),
resume,
pause,
}
}