irox_winlocation_api/
lib.rs1#[cfg(target_os = "windows")]
6pub use crate::windows::*;
7
8#[cfg(target_os = "windows")]
9mod windows {
10 use log::{error, info, trace, warn};
11 use windows::Devices::Geolocation::{
12 GeolocationAccessStatus, Geolocator, PositionChangedEventArgs, StatusChangedEventArgs,
13 };
14 use windows::Foundation::TypedEventHandler;
15 type EventRegistrationToken = i64;
16
17 pub use crate::data::*;
18 pub use crate::error::*;
19
20 pub struct WindowsLocationAPI {
21 locator: Geolocator,
22 }
23
24 impl WindowsLocationAPI {
25 pub fn connect() -> Result<WindowsLocationAPI, Error> {
26 let locator = Geolocator::new()?;
27 trace!("Geolocator created.");
28
29 if let Err(e) = locator.AllowFallbackToConsentlessPositions() {
30 warn!("Error requesting fallback to consentless positions: {e:?}")
31 }
32
33 let access = Geolocator::RequestAccessAsync()?;
34 let access_results = access.get()?;
35 match access_results {
36 GeolocationAccessStatus::Allowed => {
37 info!("User granted geolocation access.");
38 }
39 GeolocationAccessStatus::Denied => {
40 warn!("User denied geolocation access.");
41 }
42 _ => {
43 warn!("Unknown result from geolocation access request.");
44 }
45 }
46
47 Ok(WindowsLocationAPI { locator })
48 }
49
50 pub fn get_location(&self) -> Result<WindowsCoordinate, Error> {
51 let res = self.locator.GetGeopositionAsync()?;
52 let res = res.get()?;
53 let res = &(res.Coordinate()?);
54 let out: WindowsCoordinate = res.into();
55 trace!("WindowsLocation: {out:?}");
56 Ok(out)
57 }
58
59 pub fn get_status(&self) -> Result<PositionStatus, Error> {
62 Ok(self.locator.LocationStatus()?.0.into())
63 }
64
65 pub fn on_location_changed<T: FnMut(WindowsCoordinate) + Send + 'static>(
70 &self,
71 mut cb: T,
72 ) -> Result<LocationHandler, Error> {
73 let handler = TypedEventHandler::new(
74 move |_sender: &Option<Geolocator>, result: &Option<PositionChangedEventArgs>| {
75 let Some(args) = result else {
76 error!("No position changed args received.");
77 return Ok(());
78 };
79 if let Ok(pos) = args.Position() {
80 if let Ok(coord) = pos.Coordinate() {
81 let out: WindowsCoordinate = (&coord).into();
82 cb(out);
83 }
84 }
85
86 Ok(())
87 },
88 );
89 let res = self.locator.PositionChanged(&handler)?;
90 trace!("Location handler registered.");
91 Ok(LocationHandler {
92 locator: &self.locator,
93 token: res,
94 })
95 }
96 pub fn on_status_changed<T: FnMut(PositionStatus) + Send + 'static>(
97 &self,
98 mut cb: T,
99 ) -> Result<StatusHandler, Error> {
100 let handler = TypedEventHandler::new(
101 move |_sender: &Option<Geolocator>, result: &Option<StatusChangedEventArgs>| {
102 let Some(args) = result else {
103 error!("No status changed args received.");
104 return Ok(());
105 };
106 if let Ok(status) = args.Status() {
107 let out: PositionStatus = status.0.into();
108 cb(out);
109 }
110 Ok(())
111 },
112 );
113 let res = self.locator.StatusChanged(&handler)?;
114 Ok(StatusHandler {
115 locator: &self.locator,
116 token: res,
117 })
118 }
119 }
120
121 pub struct LocationHandler<'a> {
122 locator: &'a Geolocator,
123 token: EventRegistrationToken,
124 }
125
126 impl Drop for LocationHandler<'_> {
127 fn drop(&mut self) {
128 let _res = self.locator.RemovePositionChanged(self.token);
129 trace!("Dropped location handler.");
130 }
131 }
132
133 pub struct StatusHandler<'a> {
134 locator: &'a Geolocator,
135 token: EventRegistrationToken,
136 }
137
138 impl Drop for StatusHandler<'_> {
139 fn drop(&mut self) {
140 let _res = self.locator.RemoveStatusChanged(self.token);
141 trace!("Dropped location handler.");
142 }
143 }
144}
145
146#[cfg(target_os = "windows")]
147mod data;
148#[cfg(target_os = "windows")]
149mod error;