synpad 0.1.0

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

use crate::components::avatar::Avatar;
use crate::room::room_settings_dialog::RoomSettingsDialog;
use crate::state::app_state::{AppState, RightPanelView};

/// Right panel showing room information: avatar, name, topic, settings, and
/// a leave button.
#[component]
pub fn RoomInfoPanel() -> Element {
    let mut state = use_context::<Signal<AppState>>();
    let mut show_settings = use_signal(|| false);
    let state_read = state.read();

    let room = state_read.active_room();
    let active_room_id_str = state_read
        .active_room_id
        .as_ref()
        .map(|id| id.to_string())
        .unwrap_or_default();

    let (room_name, avatar_url, topic, member_count, is_encrypted, is_direct) = match room {
        Some(r) => (
            r.display_name.clone(),
            r.avatar_url.clone(),
            r.topic.clone(),
            r.member_count,
            r.is_encrypted,
            r.is_direct,
        ),
        None => {
            return rsx! {
                div {
                    class: "room-info-panel",
                    p { "No room selected." }
                }
            };
        }
    };

    let mut is_leaving = use_signal(|| false);

    let close_panel = move |_| {
        state.write().right_panel = RightPanelView::Closed;
    };

    let open_members = move |_| {
        state.write().right_panel = RightPanelView::MemberList;
    };

    let open_files = move |_| {
        state.write().right_panel = RightPanelView::FilePanel;
    };

    let open_pinned = move |_| {
        state.write().right_panel = RightPanelView::PinnedMessages;
    };

    let open_notifications = move |_| {
        state.write().right_panel = RightPanelView::NotificationPanel;
    };

    rsx! {
        div {
            class: "room-info-panel",

            // Header with close button
            header {
                class: "room-info-panel__header",
                h3 {
                    class: "room-info-panel__title",
                    "Room Info"
                }
                button {
                    class: "room-info-panel__close-btn",
                    title: "Close panel",
                    onclick: close_panel,
                    ""
                }
            }

            // Room avatar and name
            div {
                class: "room-info-panel__identity",
                Avatar {
                    name: room_name.clone(),
                    url: avatar_url,
                    size: 72,
                }
                h2 {
                    class: "room-info-panel__room-name",
                    "{room_name}"
                }
                if is_direct {
                    span {
                        class: "room-info-panel__badge room-info-panel__badge--dm",
                        "Direct Message"
                    }
                }
                if is_encrypted {
                    span {
                        class: "room-info-panel__badge room-info-panel__badge--encrypted",
                        "Encrypted"
                    }
                }
            }

            // Topic
            div {
                class: "room-info-panel__section",
                h4 { class: "room-info-panel__section-title", "Topic" }
                p {
                    class: "room-info-panel__topic",
                    if let Some(ref topic_text) = topic {
                        "{topic_text}"
                    } else {
                        em { "No topic set." }
                    }
                }
            }

            // Quick actions / settings links
            div {
                class: "room-info-panel__section",
                h4 { class: "room-info-panel__section-title", "Options" }

                nav {
                    class: "room-info-panel__nav",

                    button {
                        class: "room-info-panel__nav-item",
                        onclick: open_members,
                        span { class: "room-info-panel__nav-icon", "👥" }
                        span { class: "room-info-panel__nav-label", "Members" }
                        span { class: "room-info-panel__nav-detail", "{member_count}" }
                    }

                    button {
                        class: "room-info-panel__nav-item",
                        onclick: open_files,
                        span { class: "room-info-panel__nav-icon", "📁" }
                        span { class: "room-info-panel__nav-label", "Files" }
                    }

                    button {
                        class: "room-info-panel__nav-item",
                        onclick: open_pinned,
                        span { class: "room-info-panel__nav-icon", "📌" }
                        span { class: "room-info-panel__nav-label", "Pinned Messages" }
                    }

                    button {
                        class: "room-info-panel__nav-item",
                        onclick: open_notifications,
                        span { class: "room-info-panel__nav-icon", "🔔" }
                        span { class: "room-info-panel__nav-label", "Notifications" }
                    }

                    // Settings link
                    button {
                        class: "room-info-panel__nav-item",
                        onclick: move |_| show_settings.set(true),
                        span { class: "room-info-panel__nav-icon", "" }
                        span { class: "room-info-panel__nav-label", "Room Settings" }
                    }
                }
            }

            // Leave room button
            div {
                class: "room-info-panel__section room-info-panel__section--danger",
                button {
                    class: "room-info-panel__leave-btn",
                    disabled: *is_leaving.read(),
                    onclick: {
                        let rid = active_room_id_str.clone();
                        move |_| {
                            let rid = rid.clone();
                            is_leaving.set(true);
                            spawn(async move {
                                let client = { state.read().client.clone() };
                                if let Some(client) = client {
                                    if let Ok(room_id) = matrix_sdk::ruma::OwnedRoomId::try_from(rid.as_str()) {
                                        if let Some(room) = client.get_room(&room_id) {
                                            match room.leave().await {
                                                Ok(_) => {
                                                    tracing::info!("Left room {room_id}");
                                                    let mut w = state.write();
                                                    w.rooms.remove(&room_id);
                                                    if w.active_room_id.as_ref() == Some(&room_id) {
                                                        w.active_room_id = None;
                                                        w.current_view = crate::state::app_state::AppView::Home;
                                                    }
                                                    w.right_panel = RightPanelView::Closed;
                                                    w.update_sorted_rooms();
                                                }
                                                Err(e) => tracing::error!("Failed to leave room: {e}"),
                                            }
                                        }
                                    }
                                }
                                is_leaving.set(false);
                            });
                        }
                    },
                    if *is_leaving.read() { "Leaving..." } else { "Leave Room" }
                }
            }

            // Room settings dialog
            if *show_settings.read() {
                RoomSettingsDialog {
                    room_id: active_room_id_str.clone(),
                    on_close: move |_| show_settings.set(false),
                }
            }
        }
    }
}