177 lines
5.9 KiB
Rust
177 lines
5.9 KiB
Rust
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<PublicKey>,
|
|
name: Option<SharedString>,
|
|
avatar: Option<SharedString>,
|
|
created_at: Option<SharedString>,
|
|
kind: Option<RoomKind>,
|
|
selected: bool,
|
|
#[allow(clippy::type_complexity)]
|
|
handler: Option<Rc<dyn Fn(&ClickEvent, &mut Window, &mut App)>>,
|
|
}
|
|
|
|
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<SharedString>) -> Self {
|
|
self.name = Some(name.into());
|
|
self
|
|
}
|
|
|
|
pub fn avatar(mut self, avatar: impl Into<SharedString>) -> Self {
|
|
self.avatar = Some(avatar.into());
|
|
self
|
|
}
|
|
|
|
pub fn created_at(mut self, created_at: impl Into<SharedString>) -> 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
|
|
})
|
|
});
|
|
}
|
|
})
|
|
})
|
|
}
|
|
}
|