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(&params).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}