leptos_use/
use_permission.rs1use leptos::prelude::*;
2use leptos::reactive::wrappers::read::Signal;
3use std::fmt::Display;
4
5pub fn use_permission(permission_name: &str) -> Signal<PermissionState> {
29 let (state, set_state) = signal(PermissionState::Unknown);
30
31 #[cfg(not(feature = "ssr"))]
32 {
33 use crate::use_event_listener;
34 use std::cell::RefCell;
35 use std::rc::Rc;
36
37 let permission_status = Rc::new(RefCell::new(None::<web_sys::PermissionStatus>));
38
39 let on_change = {
40 let permission_status = Rc::clone(&permission_status);
41
42 move || {
43 if let Some(permission_status) = permission_status.borrow().as_ref() {
44 set_state.set(PermissionState::from(permission_status.state()));
45 }
46 }
47 };
48
49 leptos::task::spawn_local({
50 let permission_name = permission_name.to_owned();
51
52 async move {
53 if let Ok(status) = query_permission(permission_name).await {
54 let _ = use_event_listener(status.clone(), leptos::ev::change, {
55 let on_change = on_change.clone();
56 move |_| on_change()
57 });
58 permission_status.replace(Some(status));
59 on_change();
60 } else {
61 set_state.set(PermissionState::Prompt);
62 }
63 }
64 });
65 }
66
67 #[cfg(feature = "ssr")]
68 {
69 let _ = set_state;
70 let _ = permission_name;
71 }
72
73 state.into()
74}
75
76#[derive(Copy, Clone, Default, Eq, PartialEq)]
78pub enum PermissionState {
79 #[default]
81 Unknown,
82
83 Granted,
85
86 Prompt,
88
89 Denied,
91}
92
93impl Display for PermissionState {
94 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95 match *self {
96 PermissionState::Unknown => write!(f, "unknown"),
97 PermissionState::Granted => write!(f, "granted"),
98 PermissionState::Prompt => write!(f, "prompt"),
99 PermissionState::Denied => write!(f, "denied"),
100 }
101 }
102}
103
104impl From<web_sys::PermissionState> for PermissionState {
105 fn from(permission_state: web_sys::PermissionState) -> Self {
106 match permission_state {
107 web_sys::PermissionState::Granted => PermissionState::Granted,
108 web_sys::PermissionState::Prompt => PermissionState::Prompt,
109 web_sys::PermissionState::Denied => PermissionState::Denied,
110 _ => PermissionState::Unknown,
111 }
112 }
113}
114
115#[cfg(not(feature = "ssr"))]
116async fn query_permission(
117 permission: String,
118) -> Result<web_sys::PermissionStatus, wasm_bindgen::JsValue> {
119 use crate::{js, js_fut};
120 use wasm_bindgen::JsCast;
121
122 let permission_object = js_sys::Object::new();
123 js!(permission_object["name"] = permission);
124
125 let permission_state: web_sys::PermissionStatus = js_fut!(window()
126 .navigator()
127 .permissions()?
128 .query(&permission_object)?)
129 .await?
130 .unchecked_into();
131
132 Ok(permission_state)
133}