synpad 0.1.0

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

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

/// Room context menu (right-click on room list entry).
#[component]
pub fn RoomContextMenu(
    room_id: String,
    room_name: String,
    is_favorite: bool,
    is_muted: bool,
    on_close: EventHandler<()>,
) -> Element {
    let mut state = use_context::<Signal<AppState>>();
    let room_id_for_leave = room_id.clone();

    let on_toggle_favorite = {
        let room_id = room_id.clone();
        let is_fav = is_favorite;
        move |_| {
            if let Ok(rid) = OwnedRoomId::try_from(room_id.as_str()) {
                let has_room = state.read().rooms.contains_key(&rid);
                if has_room {
                    let mut w = state.write();
                    if let Some(r) = w.rooms.get_mut(&rid) {
                        r.is_favorite = !is_fav;
                    }
                    w.update_sorted_rooms();
                }
            }
            on_close.call(());
        }
    };

    let on_leave = move |_| {
        let rid_str = room_id_for_leave.clone();
        spawn(async move {
            let client = { state.read().client.clone() };
            if let Some(client) = client {
                if let Ok(room_id) = OwnedRoomId::try_from(rid_str.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.update_sorted_rooms();
                            }
                            Err(e) => tracing::error!("Failed to leave room: {e}"),
                        }
                    }
                }
            }
        });
        on_close.call(());
    };

    rsx! {
        div {
            class: "room-context-menu",
            onclick: move |_| on_close.call(()),

            div {
                class: "room-context-menu__content",
                onclick: move |evt| evt.stop_propagation(),

                button {
                    class: "room-context-menu__item",
                    onclick: on_toggle_favorite,
                    if is_favorite { "Remove from favorites" } else { "Add to favorites" }
                }
                button {
                    class: "room-context-menu__item",
                    "Mark as read"
                }
                hr { class: "room-context-menu__divider" }
                button {
                    class: "room-context-menu__item",
                    "Copy room link"
                }
                hr { class: "room-context-menu__divider" }
                button {
                    class: "room-context-menu__item room-context-menu__item--danger",
                    onclick: on_leave,
                    "Leave room"
                }
            }
        }
    }
}