synpad 0.1.0

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

use crate::state::app_state::AppState;

/// Session verification prompt shown after login when device is unverified.
#[component]
pub fn SessionVerificationPrompt(on_dismiss: EventHandler<()>) -> Element {
    let mut mode = use_signal(|| VerifyMode::Choose);

    rsx! {
        div {
            class: "session-prompt",
            div {
                class: "session-prompt__card",
                div {
                    class: "session-prompt__icon",
                    "🔐"
                }
                h3 { "Verify this device" }
                p { class: "session-prompt__desc",
                    "Verify this device to access your encrypted messages and prove your identity to others."
                }

                if *mode.read() == VerifyMode::Choose {
                    div {
                        class: "session-prompt__options",
                        button {
                            class: "session-prompt__option",
                            onclick: move |_| mode.set(VerifyMode::SecurityKey),
                            div {
                                strong { "Use Security Key" }
                                p { "Enter your recovery key or passphrase" }
                            }
                        }
                        button {
                            class: "session-prompt__option",
                            onclick: move |_| mode.set(VerifyMode::AnotherDevice),
                            div {
                                strong { "Verify from another device" }
                                p { "Compare emoji on another logged-in device" }
                            }
                        }
                        button {
                            class: "session-prompt__skip",
                            onclick: move |_| on_dismiss.call(()),
                            "Skip for now"
                        }
                    }
                }

                if *mode.read() == VerifyMode::SecurityKey {
                    div {
                        class: "session-prompt__key-input",
                        h4 { "Enter Security Key" }
                        textarea {
                            class: "settings-textarea",
                            rows: "3",
                            placeholder: "Enter your recovery key...",
                        }
                        div {
                            class: "session-prompt__actions",
                            button { class: "btn btn--secondary", onclick: move |_| mode.set(VerifyMode::Choose), "Back" }
                            button { class: "btn btn--primary", "Verify" }
                        }
                    }
                }

                if *mode.read() == VerifyMode::AnotherDevice {
                    div {
                        class: "session-prompt__another",
                        h4 { "Waiting for verification" }
                        p { "Open Netrix on another device and accept the verification request." }
                        div { class: "spinner" }
                        div {
                            class: "session-prompt__actions",
                            button { class: "btn btn--secondary", onclick: move |_| mode.set(VerifyMode::Choose), "Back" }
                        }
                    }
                }
            }
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
enum VerifyMode {
    Choose,
    SecurityKey,
    AnotherDevice,
}

/// Secure backup setup toast shown after first encrypted message.
#[component]
pub fn SecureBackupToast(on_setup: EventHandler<()>, on_dismiss: EventHandler<()>) -> Element {
    rsx! {
        div {
            class: "backup-toast",
            div {
                class: "backup-toast__icon",
                "🔑"
            }
            div {
                class: "backup-toast__content",
                strong { "Set up Secure Backup" }
                p { "Back up your encryption keys to avoid losing access to encrypted messages." }
            }
            div {
                class: "backup-toast__actions",
                button {
                    class: "btn btn--primary btn--sm",
                    onclick: move |_| on_setup.call(()),
                    "Set up"
                }
                button {
                    class: "btn btn--secondary btn--sm",
                    onclick: move |_| on_dismiss.call(()),
                    "Later"
                }
            }
        }
    }
}

/// Privacy toggles component for settings.
#[component]
pub fn PrivacyToggles() -> Element {
    let mut state = use_context::<Signal<AppState>>();
    let send_read_receipts = state.read().send_read_receipts;
    let send_typing = state.read().send_typing_notifications;
    let show_read_receipts = state.read().show_read_receipts;
    let show_join_leave = state.read().show_join_leave;
    let show_display_name_changes = state.read().show_display_name_changes;
    let show_avatar_changes = state.read().show_avatar_changes;

    rsx! {
        div {
            class: "privacy-toggles",
            h4 { "Privacy & Appearance" }

            label {
                class: "settings-toggle",
                input {
                    r#type: "checkbox",
                    checked: send_read_receipts,
                    oninput: move |evt| {
                        state.write().send_read_receipts = evt.checked();
                    },
                }
                div {
                    strong { "Send read receipts" }
                    p { "Let others see when you've read messages" }
                }
            }

            label {
                class: "settings-toggle",
                input {
                    r#type: "checkbox",
                    checked: send_typing,
                    oninput: move |evt| {
                        state.write().send_typing_notifications = evt.checked();
                    },
                }
                div {
                    strong { "Send typing notifications" }
                    p { "Let others see when you're typing" }
                }
            }

            label {
                class: "settings-toggle",
                input {
                    r#type: "checkbox",
                    checked: show_read_receipts,
                    oninput: move |evt| {
                        state.write().show_read_receipts = evt.checked();
                    },
                }
                div {
                    strong { "Show read receipts" }
                    p { "See when others have read messages" }
                }
            }

            label {
                class: "settings-toggle",
                input {
                    r#type: "checkbox",
                    checked: show_join_leave,
                    oninput: move |evt| {
                        state.write().show_join_leave = evt.checked();
                    },
                }
                div {
                    strong { "Show join/leave messages" }
                    p { "Show when users join or leave the room" }
                }
            }

            label {
                class: "settings-toggle",
                input {
                    r#type: "checkbox",
                    checked: show_display_name_changes,
                    oninput: move |evt| {
                        state.write().show_display_name_changes = evt.checked();
                    },
                }
                div {
                    strong { "Show display name changes" }
                    p { "Show when users change their display name" }
                }
            }

            label {
                class: "settings-toggle",
                input {
                    r#type: "checkbox",
                    checked: show_avatar_changes,
                    oninput: move |evt| {
                        state.write().show_avatar_changes = evt.checked();
                    },
                }
                div {
                    strong { "Show avatar changes" }
                    p { "Show when users change their profile picture" }
                }
            }
        }
    }
}