use std::rc::Rc; use chat::RoomKind; use gpui::prelude::FluentBuilder; use gpui::{ App, ClickEvent, InteractiveElement, IntoElement, ParentElement as _, RenderOnce, SharedString, StatefulInteractiveElement, Styled, Window, div, }; use nostr_sdk::prelude::*; use settings::AppSettings; use theme::ActiveTheme; use ui::avatar::Avatar; use ui::dock::ClosePanel; use ui::modal::ModalButtonProps; use ui::{Icon, IconName, Selectable, Sizable, StyledExt, WindowExtension, h_flex}; use crate::dialogs::screening; #[derive(IntoElement)] pub struct RoomEntry { ix: usize, public_key: Option, name: Option, avatar: Option, created_at: Option, kind: Option, selected: bool, #[allow(clippy::type_complexity)] handler: Option>, } impl RoomEntry { pub fn new(ix: usize) -> Self { Self { ix, public_key: None, name: None, avatar: None, created_at: None, kind: None, handler: None, selected: false, } } pub fn public_key(mut self, public_key: PublicKey) -> Self { self.public_key = Some(public_key); self } pub fn name(mut self, name: impl Into) -> Self { self.name = Some(name.into()); self } pub fn avatar(mut self, avatar: impl Into) -> Self { self.avatar = Some(avatar.into()); self } pub fn created_at(mut self, created_at: impl Into) -> Self { self.created_at = Some(created_at.into()); self } pub fn kind(mut self, kind: RoomKind) -> Self { self.kind = Some(kind); self } pub fn on_click( mut self, handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static, ) -> Self { self.handler = Some(Rc::new(handler)); self } } impl Selectable for RoomEntry { fn selected(mut self, selected: bool) -> Self { self.selected = selected; self } fn is_selected(&self) -> bool { self.selected } } impl RenderOnce for RoomEntry { fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement { let hide_avatar = AppSettings::get_hide_avatar(cx); let screening = AppSettings::get_screening(cx); let public_key = self.public_key; let is_selected = self.is_selected(); h_flex() .id(self.ix) .h_9() .w_full() .px_1p5() .gap_2() .text_sm() .rounded(cx.theme().radius) .when(!hide_avatar, |this| { this.when_some(self.avatar, |this, avatar| { this.child(Avatar::new(avatar).small().flex_shrink_0()) }) }) .child( div() .flex_1() .flex() .items_center() .justify_between() .when_some(self.name, |this, name| { this.child( h_flex() .flex_1() .justify_between() .line_clamp(1) .text_ellipsis() .truncate() .font_medium() .child(name) .when(is_selected, |this| { this.child( Icon::new(IconName::CheckCircle) .small() .text_color(cx.theme().icon_accent), ) }), ) }) .child( h_flex() .gap_1p5() .flex_shrink_0() .text_xs() .text_color(cx.theme().text_placeholder) .when_some(self.created_at, |this, created_at| this.child(created_at)), ), ) .hover(|this| this.bg(cx.theme().elevated_surface_background)) .when_some(self.handler, |this, handler| { this.on_click(move |event, window, cx| { handler(event, window, cx); if let Some(public_key) = public_key && self.kind != Some(RoomKind::Ongoing) && screening { let screening = screening::init(public_key, window, cx); window.open_modal(cx, move |this, _window, _cx| { this.confirm() .child(screening.clone()) .button_props( ModalButtonProps::default() .cancel_text("Ignore") .ok_text("Response"), ) .on_cancel(move |_event, window, cx| { window.dispatch_action(Box::new(ClosePanel), cx); // Prevent closing the modal on click // modal will be automatically closed after closing panel false }) }); } }) }) } }