add group header, moderation menu, and pins strip

This commit is contained in:
2026-09-30 16:07:21 +07:00
parent 5b87b2fe27
commit ce1cff83ff
7 changed files with 619 additions and 14 deletions
+61 -3
View File
@@ -3,26 +3,38 @@ use common::TimestampExt;
use gpui::prelude::FluentBuilder;
use gpui::{
AnyElement, App, InteractiveElement, IntoElement, ObjectFit, ParentElement, SharedUri, Styled,
StyledImage, div, img, px,
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);
MessageRow::new(ix)
let row = MessageRow::new(ix)
.show_author(show_author)
.hide_avatar(hide_avatar)
.avatar(
@@ -36,7 +48,53 @@ pub(crate) fn render(
.when(!message.media.is_empty(), |this| {
this.child(media(&message.media, cx))
})
.into_any_element()
.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 {