synpad 0.1.0

A full-featured Matrix chat client built with Dioxus
use dioxus::prelude::*;

use crate::persistence::app_state as prefs;

/// Notification settings panel.
#[component]
pub fn NotificationSettings() -> Element {
    let mut desktop_notifications = use_signal(|| true);
    let mut notification_sounds = use_signal(|| true);
    let mut show_message_preview = use_signal(|| true);
    let mut keywords = use_signal(Vec::<String>::new);
    let mut new_keyword = use_signal(|| String::new());
    let mut loaded = use_signal(|| false);

    // Load persisted settings on first render
    if !*loaded.read() {
        loaded.set(true);
        spawn(async move {
            if let Ok(p) = prefs::load_preferences().await {
                desktop_notifications.set(p.desktop_notifications);
                notification_sounds.set(p.notification_sounds);
                show_message_preview.set(p.show_message_preview);
                keywords.set(p.notification_keywords);
            }
        });
    }

    // Persist settings when toggled
    let save_settings = move || {
        let desktop = *desktop_notifications.read();
        let sounds = *notification_sounds.read();
        let preview = *show_message_preview.read();
        let kws = keywords.read().clone();
        spawn(async move {
            let mut p = prefs::load_preferences().await.unwrap_or_default();
            p.desktop_notifications = desktop;
            p.notification_sounds = sounds;
            p.show_message_preview = preview;
            p.notification_keywords = kws;
            if let Err(e) = prefs::save_preferences(&p).await {
                tracing::error!("Failed to save notification prefs: {e}");
            }
        });
    };

    let save_settings_kw = save_settings.clone();
    let on_add_keyword = move |_| {
        let kw = new_keyword.read().trim().to_string();
        if !kw.is_empty() {
            keywords.write().push(kw);
            new_keyword.set(String::new());
            save_settings_kw();
        }
    };

    rsx! {
        div {
            class: "notification-settings",

            h3 { "Notifications" }

            div {
                class: "settings-section",

                // Desktop notifications
                label {
                    class: "settings-toggle",
                    input {
                        r#type: "checkbox",
                        checked: *desktop_notifications.read(),
                        oninput: move |evt| {
                            desktop_notifications.set(evt.checked());
                            save_settings();
                        },
                    }
                    div {
                        class: "settings-toggle__info",
                        span { class: "settings-toggle__label", "Desktop notifications" }
                        span { class: "settings-toggle__description", "Show notifications for new messages" }
                    }
                }

                // Notification sounds
                label {
                    class: "settings-toggle",
                    input {
                        r#type: "checkbox",
                        checked: *notification_sounds.read(),
                        oninput: move |evt| {
                            notification_sounds.set(evt.checked());
                            save_settings();
                        },
                    }
                    div {
                        class: "settings-toggle__info",
                        span { class: "settings-toggle__label", "Notification sounds" }
                        span { class: "settings-toggle__description", "Play a sound for new messages" }
                    }
                }

                // Message preview in notifications
                label {
                    class: "settings-toggle",
                    input {
                        r#type: "checkbox",
                        checked: *show_message_preview.read(),
                        oninput: move |evt| {
                            show_message_preview.set(evt.checked());
                            save_settings();
                        },
                    }
                    div {
                        class: "settings-toggle__info",
                        span { class: "settings-toggle__label", "Show message preview" }
                        span { class: "settings-toggle__description", "Show message content in notifications" }
                    }
                }
            }

            div {
                class: "settings-section",
                h4 { "Keyword Alerts" }
                p { class: "settings-description", "Get notified when specific words are mentioned." }

                div {
                    class: "keyword-input-row",
                    input {
                        r#type: "text",
                        placeholder: "Add a keyword...",
                        class: "settings-input",
                        value: "{new_keyword}",
                        oninput: move |evt| new_keyword.set(evt.value()),
                        onkeydown: move |evt: Event<KeyboardData>| {
                            if evt.key() == Key::Enter {
                                evt.prevent_default();
                                let kw = new_keyword.read().trim().to_string();
                                if !kw.is_empty() {
                                    keywords.write().push(kw);
                                    new_keyword.set(String::new());
                                }
                            }
                        },
                    }
                    button {
                        class: "btn btn--primary btn--sm",
                        onclick: on_add_keyword,
                        "Add"
                    }
                }

                div {
                    class: "keyword-list",
                    for (idx, keyword) in keywords.read().iter().enumerate() {
                        {
                            let kw = keyword.clone();
                            rsx! {
                                span {
                                    class: "keyword-tag",
                                    "{kw}"
                                    button {
                                        class: "keyword-tag__remove",
                                        onclick: move |_| {
                                            keywords.write().remove(idx);
                                            save_settings();
                                        },
                                        ""
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}