dioxus_std/geolocation/
use_geolocation.rs

1//! Provides an initialization and use_geolocation hook.
2
3use super::core::{Error, Event, Geocoordinates, Geolocator, PowerMode, Status};
4use dioxus::{
5    prelude::{
6        provide_context, try_consume_context, use_coroutine, use_hook, use_signal, Signal,
7        UnboundedReceiver,
8    },
9    signals::{Readable, Writable},
10};
11use futures_util::stream::StreamExt;
12use std::sync::Once;
13
14static INIT: Once = Once::new();
15
16/// Provides the latest geocoordinates. Good for navigation-type apps.
17pub fn use_geolocation() -> Result<Geocoordinates, Error> {
18    // Store the coords
19    let mut coords: Signal<Result<Geocoordinates, Error>> =
20        use_signal(|| Err(Error::NotInitialized));
21    let Some(geolocator) = try_consume_context::<Signal<Result<Geolocator, Error>>>() else {
22        return Err(Error::NotInitialized);
23    };
24    let geolocator = geolocator.read();
25
26    // Get geolocator
27    let Ok(geolocator) = geolocator.as_ref() else {
28        return Err(Error::NotInitialized);
29    };
30
31    // Initialize the handler of events
32    let listener = use_coroutine(|mut rx: UnboundedReceiver<Event>| async move {
33        while let Some(event) = rx.next().await {
34            match event {
35                Event::NewGeocoordinates(new_coords) => {
36                    *coords.write() = Ok(new_coords);
37                }
38                Event::StatusChanged(Status::Disabled) => {
39                    *coords.write() = Err(Error::AccessDenied);
40                }
41                _ => {}
42            }
43        }
44    });
45
46    // Start listening
47    INIT.call_once(|| {
48        geolocator.listen(listener).ok();
49    });
50
51    // Get the result and return a clone
52    coords.read_unchecked().clone()
53}
54
55/// Must be called before any use of the geolocation abstraction.
56pub fn init_geolocator(power_mode: PowerMode) -> Signal<Result<Geolocator, Error>> {
57    use_hook(|| {
58        let geolocator = Signal::new(Geolocator::new(power_mode));
59        provide_context(geolocator)
60    })
61}