132 lines
3.8 KiB
Rust
132 lines
3.8 KiB
Rust
use chat::Message;
|
|
use common::TimestampExt;
|
|
use gpui::prelude::FluentBuilder;
|
|
use gpui::{
|
|
AnyElement, App, InteractiveElement, IntoElement, ObjectFit, ParentElement, SharedUri, Styled,
|
|
StyledImage, WeakEntity, div, img, px,
|
|
};
|
|
use nip29::Group;
|
|
use person::PersonRegistry;
|
|
use settings::AppSettings;
|
|
use theme::ActiveTheme;
|
|
use ui::avatar::Avatar;
|
|
use ui::menu::{ContextMenu, PopupMenuItem};
|
|
use ui::message::MessageRow;
|
|
|
|
use crate::GroupPanel;
|
|
|
|
pub(crate) struct Actions {
|
|
pub group: WeakEntity<Group>,
|
|
pub panel: WeakEntity<GroupPanel>,
|
|
pub admin: bool,
|
|
pub pinned: bool,
|
|
}
|
|
|
|
pub(crate) fn render(
|
|
ix: usize,
|
|
message: &Message,
|
|
content: AnyElement,
|
|
show_author: bool,
|
|
actions: Actions,
|
|
cx: &App,
|
|
) -> AnyElement {
|
|
let persons = PersonRegistry::global(cx);
|
|
let author = persons.read(cx).get(&message.author, cx);
|
|
let hide_avatar = AppSettings::get_hide_avatar(cx);
|
|
|
|
let row = MessageRow::new(ix)
|
|
.show_author(show_author)
|
|
.hide_avatar(hide_avatar)
|
|
.avatar(
|
|
Avatar::new(author.avatar())
|
|
.seed(author.avatar_seed())
|
|
.flex_shrink_0(),
|
|
)
|
|
.author(author.name())
|
|
.timestamp(message.created_at.to_human_time())
|
|
.child(content)
|
|
.when(!message.media.is_empty(), |this| {
|
|
this.child(media(&message.media, cx))
|
|
})
|
|
.into_any_element();
|
|
|
|
if !actions.admin {
|
|
return row;
|
|
}
|
|
|
|
let id = message.id;
|
|
let pinned = actions.pinned;
|
|
let group = actions.group;
|
|
let panel = actions.panel;
|
|
|
|
ContextMenu::new(
|
|
format!("message-menu-{}", id.to_hex()),
|
|
row,
|
|
move |menu, _window, _cx| {
|
|
let pin = {
|
|
let group = group.clone();
|
|
let panel = panel.clone();
|
|
|
|
PopupMenuItem::new(if pinned { "Unpin" } else { "Pin" }).on_click(
|
|
move |_event, _window, cx| {
|
|
if let Err(error) = panel.update_in(cx, |panel, window, cx| {
|
|
panel.toggle_pin(group.clone(), id, window, cx);
|
|
}) {
|
|
log::warn!("nip29: pinning a message failed: {error}");
|
|
}
|
|
},
|
|
)
|
|
};
|
|
|
|
let delete = {
|
|
let group = group.clone();
|
|
let panel = panel.clone();
|
|
|
|
PopupMenuItem::new("Delete message").on_click(move |_event, _window, cx| {
|
|
if let Err(error) = panel.update_in(cx, |panel, window, cx| {
|
|
panel.delete_message(group.clone(), id, window, cx);
|
|
}) {
|
|
log::warn!("nip29: deleting a message failed: {error}");
|
|
}
|
|
})
|
|
};
|
|
|
|
menu.item(pin).item(delete)
|
|
},
|
|
)
|
|
.into_any_element()
|
|
}
|
|
|
|
fn media(media: &[SharedUri], cx: &App) -> AnyElement {
|
|
if let [only] = media {
|
|
return div()
|
|
.child(
|
|
img(only.clone())
|
|
.border_1()
|
|
.border_color(cx.theme().border_variant)
|
|
.h(px(250.))
|
|
.object_fit(ObjectFit::Cover)
|
|
.rounded(cx.theme().radius),
|
|
)
|
|
.into_any_element();
|
|
}
|
|
|
|
div()
|
|
.w_full()
|
|
.flex_1()
|
|
.flex()
|
|
.flex_row()
|
|
.flex_wrap()
|
|
.gap_2()
|
|
.children(media.iter().enumerate().map(|(ix, item)| {
|
|
div().id(format!("media-{ix}")).child(
|
|
img(item.clone())
|
|
.h_32()
|
|
.border_1()
|
|
.border_color(cx.theme().border_variant)
|
|
.rounded(cx.theme().radius),
|
|
)
|
|
}))
|
|
.into_any_element()
|
|
}
|