Skip to main content

telegram_webapp_sdk/leptos/
settings_button.rs

1// SPDX-FileCopyrightText: 2025-2026 RAprogramm <andrey.rozanov.vl@gmail.com>
2// SPDX-License-Identifier: MIT
3
4use std::cell::RefCell;
5
6use leptos::prelude::*;
7
8use crate::{
9    logger,
10    webapp::{EventHandle, TelegramWebApp}
11};
12
13thread_local! {
14    static SETTINGS_BUTTON_HANDLE: RefCell<Option<EventHandle<dyn FnMut()>>> =
15        const { RefCell::new(None) };
16}
17
18/// Leptos component for the native settings button.
19///
20/// Drives `WebApp.SettingsButton`: shows/hides it based on the `visible`
21/// signal, registers the optional click callback, and cleans both up on
22/// unmount.
23///
24/// # Examples
25/// ```no_run
26/// use leptos::prelude::*;
27/// use telegram_webapp_sdk::leptos::SettingsButton;
28///
29/// #[component]
30/// fn App() -> impl IntoView {
31///     let visible = RwSignal::new(true);
32///     view! {
33///         <SettingsButton
34///             visible=visible
35///             on_click=move || { web_sys::console::log_1(&"settings".into()); }
36///         />
37///     }
38/// }
39/// ```
40#[component]
41pub fn SettingsButton<F>(
42    /// Reactive flag controlling whether the settings button is shown.
43    #[prop(into)]
44    visible: Signal<bool>,
45    /// Optional callback invoked when the settings button is clicked.
46    #[prop(optional)]
47    on_click: Option<F>
48) -> impl IntoView
49where
50    F: Fn() + Clone + 'static
51{
52    Effect::new(move |_| {
53        if let Some(app) = TelegramWebApp::instance() {
54            let result = if visible.get() {
55                app.show_settings_button()
56            } else {
57                app.hide_settings_button()
58            };
59            if let Err(err) = result {
60                logger::error(&format!("SettingsButton visibility toggle failed: {err:?}"));
61            }
62        }
63    });
64
65    if let Some(cb) = on_click
66        && let Some(app) = TelegramWebApp::instance()
67    {
68        match app.set_settings_button_callback(cb) {
69            Ok(handle) => SETTINGS_BUTTON_HANDLE.with(|c| {
70                *c.borrow_mut() = Some(handle);
71            }),
72            Err(err) => logger::error(&format!("set_settings_button_callback failed: {err:?}"))
73        }
74    }
75
76    on_cleanup(move || {
77        if let Some(app) = TelegramWebApp::instance() {
78            SETTINGS_BUTTON_HANDLE.with(|c| {
79                if let Some(handle) = c.borrow_mut().take()
80                    && let Err(err) = app.remove_settings_button_callback(handle)
81                {
82                    logger::error(&format!("remove_settings_button_callback failed: {err:?}"));
83                }
84            });
85            if let Err(err) = app.hide_settings_button() {
86                logger::error(&format!("hide_settings_button failed: {err:?}"));
87            }
88        }
89    });
90
91    View::new(())
92}