telegram_webapp_sdk/webapp/permissions.rs
1// SPDX-FileCopyrightText: 2025 RAprogramm <andrey.rozanov.vl@gmail.com>
2// SPDX-License-Identifier: MIT
3
4use js_sys::{Function, Reflect};
5use serde_wasm_bindgen::to_value;
6use wasm_bindgen::{JsCast, JsValue, prelude::Closure};
7
8use crate::{core::types::download_file_params::DownloadFileParams, webapp::TelegramWebApp};
9
10impl TelegramWebApp {
11 /// Call `WebApp.requestWriteAccess(callback)`.
12 ///
13 /// # Examples
14 /// ```no_run
15 /// # use telegram_webapp_sdk::webapp::TelegramWebApp;
16 /// # let app = TelegramWebApp::instance().unwrap();
17 /// app.request_write_access(|granted| {
18 /// let _ = granted;
19 /// })
20 /// .unwrap();
21 /// ```
22 ///
23 /// # Errors
24 /// Returns [`JsValue`] if the underlying JS call fails.
25 pub fn request_write_access<F>(&self, callback: F) -> Result<(), JsValue>
26 where
27 F: 'static + Fn(bool)
28 {
29 let cb = Closure::<dyn FnMut(JsValue)>::new(move |v: JsValue| {
30 callback(v.as_bool().unwrap_or(false));
31 });
32 self.call1("requestWriteAccess", cb.as_ref().unchecked_ref())?;
33 cb.forget();
34 Ok(())
35 }
36
37 /// Call `WebApp.requestEmojiStatusAccess(callback)`.
38 ///
39 /// # Examples
40 /// ```no_run
41 /// # use telegram_webapp_sdk::webapp::TelegramWebApp;
42 /// # let app = TelegramWebApp::instance().unwrap();
43 /// app.request_emoji_status_access(|granted| {
44 /// let _ = granted;
45 /// })
46 /// .unwrap();
47 /// ```
48 ///
49 /// # Errors
50 /// Returns [`JsValue`] if the underlying JS call fails.
51 pub fn request_emoji_status_access<F>(&self, callback: F) -> Result<(), JsValue>
52 where
53 F: 'static + Fn(bool)
54 {
55 let cb = Closure::<dyn FnMut(JsValue)>::new(move |v: JsValue| {
56 callback(v.as_bool().unwrap_or(false));
57 });
58 let f = Reflect::get(&self.inner, &"requestEmojiStatusAccess".into())?;
59 let func = f
60 .dyn_ref::<Function>()
61 .ok_or_else(|| JsValue::from_str("requestEmojiStatusAccess is not a function"))?;
62 func.call1(&self.inner, cb.as_ref().unchecked_ref())?;
63 cb.forget();
64 Ok(())
65 }
66
67 /// Call `WebApp.setEmojiStatus(status, callback)`.
68 ///
69 /// # Examples
70 /// ```no_run
71 /// # use js_sys::Object;
72 /// # use js_sys::Reflect;
73 /// # use telegram_webapp_sdk::webapp::TelegramWebApp;
74 /// # let app = TelegramWebApp::instance().unwrap();
75 /// let status = Object::new();
76 /// let _ = Reflect::set(&status, &"custom_emoji_id".into(), &"123".into());
77 /// app.set_emoji_status(&status.into(), |success| {
78 /// let _ = success;
79 /// })
80 /// .unwrap();
81 /// ```
82 ///
83 /// # Errors
84 /// Returns [`JsValue`] if the underlying JS call fails.
85 pub fn set_emoji_status<F>(&self, status: &JsValue, callback: F) -> Result<(), JsValue>
86 where
87 F: 'static + Fn(bool)
88 {
89 let cb = Closure::<dyn FnMut(JsValue)>::new(move |v: JsValue| {
90 callback(v.as_bool().unwrap_or(false));
91 });
92 let f = Reflect::get(&self.inner, &"setEmojiStatus".into())?;
93 let func = f
94 .dyn_ref::<Function>()
95 .ok_or_else(|| JsValue::from_str("setEmojiStatus is not a function"))?;
96 func.call2(&self.inner, status, cb.as_ref().unchecked_ref())?;
97 cb.forget();
98 Ok(())
99 }
100
101 /// Call `WebApp.openInvoice(url, callback)`.
102 ///
103 /// # Examples
104 /// ```no_run
105 /// # use telegram_webapp_sdk::webapp::TelegramWebApp;
106 /// # let app = TelegramWebApp::instance().unwrap();
107 /// app.open_invoice("https://invoice", |status| {
108 /// let _ = status;
109 /// })
110 /// .unwrap();
111 /// ```
112 pub fn open_invoice<F>(&self, url: &str, callback: F) -> Result<(), JsValue>
113 where
114 F: 'static + Fn(String)
115 {
116 let cb = Closure::<dyn FnMut(JsValue)>::new(move |status: JsValue| {
117 callback(status.as_string().unwrap_or_default());
118 });
119 Reflect::get(&self.inner, &"openInvoice".into())?
120 .dyn_into::<Function>()?
121 .call2(&self.inner, &url.into(), cb.as_ref().unchecked_ref())?;
122 cb.forget();
123 Ok(())
124 }
125
126 /// Call `WebApp.downloadFile(params, callback)`.
127 ///
128 /// # Examples
129 /// ```no_run
130 /// # use telegram_webapp_sdk::core::types::download_file_params::DownloadFileParams;
131 /// # use telegram_webapp_sdk::webapp::TelegramWebApp;
132 /// # let app = TelegramWebApp::instance().unwrap();
133 /// let params = DownloadFileParams {
134 /// url: "https://example.com/file",
135 /// file_name: None,
136 /// mime_type: None
137 /// };
138 /// app.download_file(params, |file_id| {
139 /// let _ = file_id;
140 /// })
141 /// .unwrap();
142 /// ```
143 ///
144 /// # Errors
145 /// Returns [`JsValue`] if the underlying JS call fails or the parameters
146 /// fail to serialize.
147 pub fn download_file<F>(
148 &self,
149 params: DownloadFileParams<'_>,
150 callback: F
151 ) -> Result<(), JsValue>
152 where
153 F: 'static + Fn(String)
154 {
155 let js_params =
156 to_value(¶ms).map_err(|e| JsValue::from_str(&format!("serialize params: {e}")))?;
157 let cb = Closure::<dyn FnMut(JsValue)>::new(move |v: JsValue| {
158 callback(v.as_string().unwrap_or_default());
159 });
160 Reflect::get(&self.inner, &"downloadFile".into())?
161 .dyn_into::<Function>()?
162 .call2(&self.inner, &js_params, cb.as_ref().unchecked_ref())?;
163 cb.forget();
164 Ok(())
165 }
166
167 /// Call `WebApp.readTextFromClipboard(callback)`.
168 ///
169 /// # Examples
170 /// ```no_run
171 /// # use telegram_webapp_sdk::webapp::TelegramWebApp;
172 /// # let app = TelegramWebApp::instance().unwrap();
173 /// app.read_text_from_clipboard(|text| {
174 /// let _ = text;
175 /// })
176 /// .unwrap();
177 /// ```
178 ///
179 /// # Errors
180 /// Returns [`JsValue`] if the underlying JS call fails.
181 pub fn read_text_from_clipboard<F>(&self, callback: F) -> Result<(), JsValue>
182 where
183 F: 'static + Fn(String)
184 {
185 let cb = Closure::<dyn FnMut(JsValue)>::new(move |text: JsValue| {
186 callback(text.as_string().unwrap_or_default());
187 });
188 let f = Reflect::get(&self.inner, &"readTextFromClipboard".into())?;
189 let func = f
190 .dyn_ref::<Function>()
191 .ok_or_else(|| JsValue::from_str("readTextFromClipboard is not a function"))?;
192 func.call1(&self.inner, cb.as_ref().unchecked_ref())?;
193 cb.forget();
194 Ok(())
195 }
196}