telegram_webapp_sdk/webapp/
permissions.rs1use js_sys::{Function, Reflect};
5use serde_wasm_bindgen::to_value;
6use wasm_bindgen::{JsCast, JsValue, prelude::Closure};
7
8use crate::{
9 core::types::download_file_params::DownloadFileParams,
10 webapp::{
11 TelegramWebApp,
12 core::{await_one_shot, one_shot_promise}
13 }
14};
15
16impl TelegramWebApp {
17 pub fn request_write_access_with_callback<F>(&self, callback: F) -> Result<(), JsValue>
22 where
23 F: 'static + FnOnce(bool)
24 {
25 let cb = Closure::once_into_js(move |v: JsValue| {
26 callback(v.as_bool().unwrap_or(false));
27 });
28 self.call1("requestWriteAccess", &cb)
29 }
30
31 pub async fn request_write_access(&self) -> Result<bool, JsValue> {
50 let webapp = self.inner.clone();
51 let promise = one_shot_promise(move |resolve, _reject| {
52 let cb = Closure::once_into_js(move |granted: JsValue| {
53 let _ = resolve.call1(&JsValue::NULL, &granted);
54 });
55 let f = Reflect::get(&webapp, &"requestWriteAccess".into())?;
56 let func = f
57 .dyn_ref::<Function>()
58 .ok_or_else(|| JsValue::from_str("requestWriteAccess is not a function"))?;
59 func.call1(&webapp, &cb)?;
60 Ok(())
61 });
62 let value = await_one_shot(promise).await?;
63 Ok(value.as_bool().unwrap_or(false))
64 }
65
66 pub fn request_emoji_status_access_with_callback<F>(&self, callback: F) -> Result<(), JsValue>
71 where
72 F: 'static + FnOnce(bool)
73 {
74 let cb = Closure::once_into_js(move |v: JsValue| {
75 callback(v.as_bool().unwrap_or(false));
76 });
77 let f = Reflect::get(&self.inner, &"requestEmojiStatusAccess".into())?;
78 let func = f
79 .dyn_ref::<Function>()
80 .ok_or_else(|| JsValue::from_str("requestEmojiStatusAccess is not a function"))?;
81 func.call1(&self.inner, &cb)?;
82 Ok(())
83 }
84
85 pub async fn request_emoji_status_access(&self) -> Result<bool, JsValue> {
90 let webapp = self.inner.clone();
91 let promise = one_shot_promise(move |resolve, _reject| {
92 let cb = Closure::once_into_js(move |granted: JsValue| {
93 let _ = resolve.call1(&JsValue::NULL, &granted);
94 });
95 let f = Reflect::get(&webapp, &"requestEmojiStatusAccess".into())?;
96 let func = f
97 .dyn_ref::<Function>()
98 .ok_or_else(|| JsValue::from_str("requestEmojiStatusAccess is not a function"))?;
99 func.call1(&webapp, &cb)?;
100 Ok(())
101 });
102 let value = await_one_shot(promise).await?;
103 Ok(value.as_bool().unwrap_or(false))
104 }
105
106 pub fn set_emoji_status_with_callback<F>(
111 &self,
112 status: &JsValue,
113 callback: F
114 ) -> Result<(), JsValue>
115 where
116 F: 'static + FnOnce(bool)
117 {
118 let cb = Closure::once_into_js(move |v: JsValue| {
119 callback(v.as_bool().unwrap_or(false));
120 });
121 let f = Reflect::get(&self.inner, &"setEmojiStatus".into())?;
122 let func = f
123 .dyn_ref::<Function>()
124 .ok_or_else(|| JsValue::from_str("setEmojiStatus is not a function"))?;
125 func.call2(&self.inner, status, &cb)?;
126 Ok(())
127 }
128
129 pub async fn set_emoji_status(&self, status: &JsValue) -> Result<bool, JsValue> {
134 let webapp = self.inner.clone();
135 let status = status.clone();
136 let promise = one_shot_promise(move |resolve, _reject| {
137 let cb = Closure::once_into_js(move |v: JsValue| {
138 let _ = resolve.call1(&JsValue::NULL, &v);
139 });
140 let f = Reflect::get(&webapp, &"setEmojiStatus".into())?;
141 let func = f
142 .dyn_ref::<Function>()
143 .ok_or_else(|| JsValue::from_str("setEmojiStatus is not a function"))?;
144 func.call2(&webapp, &status, &cb)?;
145 Ok(())
146 });
147 let value = await_one_shot(promise).await?;
148 Ok(value.as_bool().unwrap_or(false))
149 }
150
151 pub fn open_invoice_with_callback<F>(&self, url: &str, callback: F) -> Result<(), JsValue>
153 where
154 F: 'static + FnOnce(String)
155 {
156 let cb = Closure::once_into_js(move |status: JsValue| {
157 callback(status.as_string().unwrap_or_default());
158 });
159 Reflect::get(&self.inner, &"openInvoice".into())?
160 .dyn_into::<Function>()?
161 .call2(&self.inner, &url.into(), &cb)?;
162 Ok(())
163 }
164
165 pub async fn open_invoice(&self, url: &str) -> Result<String, JsValue> {
171 let webapp = self.inner.clone();
172 let url = url.to_owned();
173 let promise = one_shot_promise(move |resolve, _reject| {
174 let cb = Closure::once_into_js(move |status: JsValue| {
175 let _ = resolve.call1(&JsValue::NULL, &status);
176 });
177 Reflect::get(&webapp, &"openInvoice".into())?
178 .dyn_into::<Function>()?
179 .call2(&webapp, &url.into(), &cb)?;
180 Ok(())
181 });
182 let value = await_one_shot(promise).await?;
183 Ok(value.as_string().unwrap_or_default())
184 }
185
186 pub fn download_file_with_callback<F>(
192 &self,
193 params: DownloadFileParams<'_>,
194 callback: F
195 ) -> Result<(), JsValue>
196 where
197 F: 'static + FnOnce(String)
198 {
199 let js_params =
200 to_value(¶ms).map_err(|e| JsValue::from_str(&format!("serialize params: {e}")))?;
201 let cb = Closure::once_into_js(move |v: JsValue| {
202 callback(v.as_string().unwrap_or_default());
203 });
204 Reflect::get(&self.inner, &"downloadFile".into())?
205 .dyn_into::<Function>()?
206 .call2(&self.inner, &js_params, &cb)?;
207 Ok(())
208 }
209
210 pub async fn download_file(&self, params: DownloadFileParams<'_>) -> Result<String, JsValue> {
217 let js_params =
218 to_value(¶ms).map_err(|e| JsValue::from_str(&format!("serialize params: {e}")))?;
219 let webapp = self.inner.clone();
220 let promise = one_shot_promise(move |resolve, _reject| {
221 let cb = Closure::once_into_js(move |v: JsValue| {
222 let _ = resolve.call1(&JsValue::NULL, &v);
223 });
224 Reflect::get(&webapp, &"downloadFile".into())?
225 .dyn_into::<Function>()?
226 .call2(&webapp, &js_params, &cb)?;
227 Ok(())
228 });
229 let value = await_one_shot(promise).await?;
230 Ok(value.as_string().unwrap_or_default())
231 }
232
233 pub fn read_text_from_clipboard_with_callback<F>(&self, callback: F) -> Result<(), JsValue>
238 where
239 F: 'static + FnOnce(String)
240 {
241 let cb = Closure::once_into_js(move |text: JsValue| {
242 callback(text.as_string().unwrap_or_default());
243 });
244 let f = Reflect::get(&self.inner, &"readTextFromClipboard".into())?;
245 let func = f
246 .dyn_ref::<Function>()
247 .ok_or_else(|| JsValue::from_str("readTextFromClipboard is not a function"))?;
248 func.call1(&self.inner, &cb)?;
249 Ok(())
250 }
251
252 pub async fn read_text_from_clipboard(&self) -> Result<String, JsValue> {
257 let webapp = self.inner.clone();
258 let promise = one_shot_promise(move |resolve, _reject| {
259 let cb = Closure::once_into_js(move |text: JsValue| {
260 let _ = resolve.call1(&JsValue::NULL, &text);
261 });
262 let f = Reflect::get(&webapp, &"readTextFromClipboard".into())?;
263 let func = f
264 .dyn_ref::<Function>()
265 .ok_or_else(|| JsValue::from_str("readTextFromClipboard is not a function"))?;
266 func.call1(&webapp, &cb)?;
267 Ok(())
268 });
269 let value = await_one_shot(promise).await?;
270 Ok(value.as_string().unwrap_or_default())
271 }
272}