telegram_webapp_sdk/webapp/navigation.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::webapp::{TelegramWebApp, types::OpenLinkOptions};
9
10impl TelegramWebApp {
11 /// Call `WebApp.openLink(url)`.
12 ///
13 /// # Examples
14 /// ```no_run
15 /// # use telegram_webapp_sdk::webapp::TelegramWebApp;
16 /// # let app = TelegramWebApp::instance().unwrap();
17 /// app.open_link("https://example.com", None).unwrap();
18 /// ```
19 pub fn open_link(&self, url: &str, options: Option<&OpenLinkOptions>) -> Result<(), JsValue> {
20 let f = Reflect::get(&self.inner, &"openLink".into())?;
21 let func = f
22 .dyn_ref::<Function>()
23 .ok_or_else(|| JsValue::from_str("openLink is not a function"))?;
24 match options {
25 Some(opts) => {
26 let value = to_value(opts).map_err(|err| JsValue::from_str(&err.to_string()))?;
27 func.call2(&self.inner, &url.into(), &value)?;
28 }
29 None => {
30 func.call1(&self.inner, &url.into())?;
31 }
32 }
33 Ok(())
34 }
35
36 /// Call `WebApp.openTelegramLink(url)`.
37 ///
38 /// # Examples
39 /// ```no_run
40 /// # use telegram_webapp_sdk::webapp::TelegramWebApp;
41 /// # let app = TelegramWebApp::instance().unwrap();
42 /// app.open_telegram_link("https://t.me/telegram").unwrap();
43 /// ```
44 pub fn open_telegram_link(&self, url: &str) -> Result<(), JsValue> {
45 Reflect::get(&self.inner, &"openTelegramLink".into())?
46 .dyn_into::<Function>()?
47 .call1(&self.inner, &url.into())?;
48 Ok(())
49 }
50
51 /// Call `WebApp.switchInlineQuery(query, choose_chat_types)`.
52 ///
53 /// # Examples
54 /// ```no_run
55 /// # use telegram_webapp_sdk::webapp::TelegramWebApp;
56 /// # let app = TelegramWebApp::instance().unwrap();
57 /// app.switch_inline_query("query", None).unwrap();
58 /// ```
59 ///
60 /// # Errors
61 /// Returns [`JsValue`] if the underlying JS call fails.
62 pub fn switch_inline_query(
63 &self,
64 query: &str,
65 choose_chat_types: Option<&JsValue>
66 ) -> Result<(), JsValue> {
67 let f = Reflect::get(&self.inner, &"switchInlineQuery".into())?;
68 let func = f
69 .dyn_ref::<Function>()
70 .ok_or_else(|| JsValue::from_str("switchInlineQuery is not a function"))?;
71 match choose_chat_types {
72 Some(types) => func.call2(&self.inner, &query.into(), types)?,
73 None => func.call1(&self.inner, &query.into())?
74 };
75 Ok(())
76 }
77
78 /// Call `WebApp.shareMessage(msg_id, callback)`.
79 ///
80 /// # Examples
81 /// ```no_run
82 /// # use telegram_webapp_sdk::webapp::TelegramWebApp;
83 /// # let app = TelegramWebApp::instance().unwrap();
84 /// app.share_message("id123", |sent| {
85 /// let _ = sent;
86 /// })
87 /// .unwrap();
88 /// ```
89 ///
90 /// # Errors
91 /// Returns [`JsValue`] if the underlying JS call fails.
92 pub fn share_message<F>(&self, msg_id: &str, callback: F) -> Result<(), JsValue>
93 where
94 F: 'static + Fn(bool)
95 {
96 let cb = Closure::<dyn FnMut(JsValue)>::new(move |v: JsValue| {
97 callback(v.as_bool().unwrap_or(false));
98 });
99 let f = Reflect::get(&self.inner, &"shareMessage".into())?;
100 let func = f
101 .dyn_ref::<Function>()
102 .ok_or_else(|| JsValue::from_str("shareMessage is not a function"))?;
103 func.call2(&self.inner, &msg_id.into(), cb.as_ref().unchecked_ref())?;
104 cb.forget();
105 Ok(())
106 }
107
108 /// Call `WebApp.shareToStory(media_url, params)`.
109 ///
110 /// # Examples
111 /// ```no_run
112 /// # use js_sys::Object;
113 /// # use telegram_webapp_sdk::webapp::TelegramWebApp;
114 /// # let app = TelegramWebApp::instance().unwrap();
115 /// let params = Object::new();
116 /// app.share_to_story("https://example.com/image.png", Some(¶ms.into()))
117 /// .unwrap();
118 /// ```
119 ///
120 /// # Errors
121 /// Returns [`JsValue`] if the underlying JS call fails.
122 pub fn share_to_story(
123 &self,
124 media_url: &str,
125 params: Option<&JsValue>
126 ) -> Result<(), JsValue> {
127 let f = Reflect::get(&self.inner, &"shareToStory".into())?;
128 let func = f
129 .dyn_ref::<Function>()
130 .ok_or_else(|| JsValue::from_str("shareToStory is not a function"))?;
131 match params {
132 Some(p) => func.call2(&self.inner, &media_url.into(), p)?,
133 None => func.call1(&self.inner, &media_url.into())?
134 };
135 Ok(())
136 }
137
138 /// Call `WebApp.shareURL(url, text)`.
139 ///
140 /// # Examples
141 /// ```no_run
142 /// # use telegram_webapp_sdk::webapp::TelegramWebApp;
143 /// # let app = TelegramWebApp::instance().unwrap();
144 /// app.share_url("https://example.com", Some("Check this"))
145 /// .unwrap();
146 /// ```
147 ///
148 /// # Errors
149 /// Returns [`JsValue`] if the underlying JS call fails.
150 pub fn share_url(&self, url: &str, text: Option<&str>) -> Result<(), JsValue> {
151 let f = Reflect::get(&self.inner, &"shareURL".into())?;
152 let func = f
153 .dyn_ref::<Function>()
154 .ok_or_else(|| JsValue::from_str("shareURL is not a function"))?;
155 match text {
156 Some(t) => func.call2(&self.inner, &url.into(), &t.into())?,
157 None => func.call1(&self.inner, &url.into())?
158 };
159 Ok(())
160 }
161
162 /// Call `WebApp.joinVoiceChat(chat_id, invite_hash)`.
163 ///
164 /// # Examples
165 /// ```no_run
166 /// # use telegram_webapp_sdk::webapp::TelegramWebApp;
167 /// # let app = TelegramWebApp::instance().unwrap();
168 /// app.join_voice_chat("chat", None).unwrap();
169 /// ```
170 ///
171 /// # Errors
172 /// Returns [`JsValue`] if the underlying JS call fails.
173 pub fn join_voice_chat(
174 &self,
175 chat_id: &str,
176 invite_hash: Option<&str>
177 ) -> Result<(), JsValue> {
178 let f = Reflect::get(&self.inner, &"joinVoiceChat".into())?;
179 let func = f
180 .dyn_ref::<Function>()
181 .ok_or_else(|| JsValue::from_str("joinVoiceChat is not a function"))?;
182 match invite_hash {
183 Some(hash) => func.call2(&self.inner, &chat_id.into(), &hash.into())?,
184 None => func.call1(&self.inner, &chat_id.into())?
185 };
186 Ok(())
187 }
188
189 /// Call `WebApp.addToHomeScreen()` and return whether the prompt was shown.
190 ///
191 /// # Examples
192 /// ```no_run
193 /// # use telegram_webapp_sdk::webapp::TelegramWebApp;
194 /// # let app = TelegramWebApp::instance().unwrap();
195 /// let _shown = app.add_to_home_screen().unwrap();
196 /// ```
197 pub fn add_to_home_screen(&self) -> Result<bool, JsValue> {
198 let f = Reflect::get(&self.inner, &"addToHomeScreen".into())?;
199 let func = f
200 .dyn_ref::<Function>()
201 .ok_or_else(|| JsValue::from_str("addToHomeScreen is not a function"))?;
202 let result = func.call0(&self.inner)?;
203 Ok(result.as_bool().unwrap_or(false))
204 }
205
206 /// Call `WebApp.checkHomeScreenStatus(callback)`.
207 ///
208 /// # Examples
209 /// ```no_run
210 /// # use telegram_webapp_sdk::webapp::TelegramWebApp;
211 /// # let app = TelegramWebApp::instance().unwrap();
212 /// app.check_home_screen_status(|status| {
213 /// let _ = status;
214 /// })
215 /// .unwrap();
216 /// ```
217 pub fn check_home_screen_status<F>(&self, callback: F) -> Result<(), JsValue>
218 where
219 F: 'static + Fn(String)
220 {
221 let cb = Closure::<dyn FnMut(JsValue)>::new(move |status: JsValue| {
222 callback(status.as_string().unwrap_or_default());
223 });
224 let f = Reflect::get(&self.inner, &"checkHomeScreenStatus".into())?;
225 let func = f
226 .dyn_ref::<Function>()
227 .ok_or_else(|| JsValue::from_str("checkHomeScreenStatus is not a function"))?;
228 func.call1(&self.inner, cb.as_ref().unchecked_ref())?;
229 cb.forget();
230 Ok(())
231 }
232}