add group activity rows to nip29 timeline
This commit is contained in:
+32
-32
@@ -1,7 +1,6 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use anyhow::Result;
|
||||
use chat::Message;
|
||||
use chat_ui::text::rendered_text;
|
||||
use gpui::prelude::FluentBuilder;
|
||||
use gpui::{
|
||||
@@ -9,7 +8,7 @@ use gpui::{
|
||||
Focusable, FollowMode, IntoElement, ListAlignment, ListScrollEvent, ListState, ParentElement,
|
||||
Render, SharedString, Styled, Subscription, Task, WeakEntity, Window, div, list, px,
|
||||
};
|
||||
use nip29::{Group, GroupEvent, GroupMetadata, GroupsRegistry, Membership, Pin};
|
||||
use nip29::{Group, GroupEvent, GroupMetadata, GroupsRegistry, Membership, Pin, Row};
|
||||
use nostr_sdk::prelude::*;
|
||||
use person::PersonRegistry;
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
@@ -88,20 +87,23 @@ fn display_name(group: &Group) -> SharedString {
|
||||
)
|
||||
}
|
||||
|
||||
fn opens_run(messages: &[Message], index: usize) -> bool {
|
||||
let Some(current) = messages.get(index) else {
|
||||
fn opens_run(rows: &[Row], index: usize) -> bool {
|
||||
let (Some(current), Some(previous)) = (
|
||||
rows.get(index),
|
||||
index.checked_sub(1).and_then(|index| rows.get(index)),
|
||||
) else {
|
||||
return true;
|
||||
};
|
||||
|
||||
let Some(previous) = index.checked_sub(1).and_then(|index| messages.get(index)) else {
|
||||
if !matches!((current, previous), (Row::Message(_), Row::Message(_))) {
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
current.author != previous.author
|
||||
current.author() != previous.author()
|
||||
|| current
|
||||
.created_at
|
||||
.created_at()
|
||||
.as_secs()
|
||||
.saturating_sub(previous.created_at.as_secs())
|
||||
.saturating_sub(previous.created_at().as_secs())
|
||||
> RUN_WINDOW_SECS
|
||||
}
|
||||
|
||||
@@ -123,9 +125,7 @@ pub(crate) fn pin_label(group: &Group, pin: &Pin) -> SharedString {
|
||||
Pin::Address(coordinate) => SharedString::from(format!("{coordinate}")),
|
||||
Pin::Event(id) => {
|
||||
let snippet = group
|
||||
.messages()
|
||||
.iter()
|
||||
.find(|message| message.id == *id)
|
||||
.message(*id)
|
||||
.and_then(|message| message.content.lines().next())
|
||||
.map(str::trim)
|
||||
.filter(|line| !line.is_empty());
|
||||
@@ -154,13 +154,13 @@ impl GroupPanel {
|
||||
pub fn new(group: Entity<Group>, window: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||
let (id, name, count, head) = {
|
||||
let group = group.read(cx);
|
||||
let messages = group.messages();
|
||||
let rows = group.rows();
|
||||
|
||||
(
|
||||
SharedString::from(format!("group-{}", group.key().cache_tag())),
|
||||
display_name(group),
|
||||
messages.len(),
|
||||
messages.first().map(|message| message.id),
|
||||
rows.len(),
|
||||
rows.first().map(Row::id),
|
||||
)
|
||||
};
|
||||
|
||||
@@ -220,7 +220,7 @@ impl GroupPanel {
|
||||
fn item_count(&self, cx: &App) -> usize {
|
||||
self.group
|
||||
.upgrade()
|
||||
.map_or(2, |group| group.read(cx).messages().len() + 2)
|
||||
.map_or(2, |group| group.read(cx).rows().len() + 2)
|
||||
}
|
||||
|
||||
fn sync(&mut self, cx: &App) {
|
||||
@@ -229,9 +229,9 @@ impl GroupPanel {
|
||||
};
|
||||
|
||||
let group = group.read(cx);
|
||||
let messages = group.messages();
|
||||
let head = messages.first().map(|message| message.id);
|
||||
let total = messages.len() + 2;
|
||||
let rows = group.rows();
|
||||
let head = rows.first().map(Row::id);
|
||||
let total = rows.len() + 2;
|
||||
let old_total = self.list_state.item_count();
|
||||
|
||||
if total == old_total {
|
||||
@@ -242,8 +242,8 @@ impl GroupPanel {
|
||||
let old_len = old_total.saturating_sub(2);
|
||||
let prepended = self
|
||||
.head
|
||||
.and_then(|old_head| messages.iter().position(|message| message.id == old_head))
|
||||
.filter(|prepended| prepended + old_len <= messages.len());
|
||||
.and_then(|old_head| rows.iter().position(|row| row.id() == old_head))
|
||||
.filter(|prepended| prepended + old_len <= rows.len());
|
||||
|
||||
match prepended {
|
||||
Some(prepended) => {
|
||||
@@ -251,7 +251,7 @@ impl GroupPanel {
|
||||
self.list_state.splice(2..2, prepended);
|
||||
}
|
||||
|
||||
let appended = messages.len() - old_len - prepended;
|
||||
let appended = rows.len() - old_len - prepended;
|
||||
|
||||
if appended > 0 {
|
||||
let at = old_total + prepended;
|
||||
@@ -837,12 +837,7 @@ impl GroupPanel {
|
||||
}
|
||||
}
|
||||
|
||||
fn render_message(
|
||||
&mut self,
|
||||
ix: usize,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> AnyElement {
|
||||
fn render_row(&mut self, ix: usize, window: &mut Window, cx: &mut Context<Self>) -> AnyElement {
|
||||
if ix == 0 {
|
||||
return self.render_welcome(cx);
|
||||
}
|
||||
@@ -856,12 +851,17 @@ impl GroupPanel {
|
||||
};
|
||||
|
||||
let group = group.read(cx);
|
||||
let messages = group.messages();
|
||||
let rows = group.rows();
|
||||
|
||||
let Some(message) = messages.get(ix - 2) else {
|
||||
let Some(row) = rows.get(ix - 2) else {
|
||||
return div().into_any_element();
|
||||
};
|
||||
|
||||
let message = match row {
|
||||
Row::Message(message) => message,
|
||||
Row::Activity(activity) => return message::render_activity(ix, activity, cx),
|
||||
};
|
||||
|
||||
let nostr = NostrRegistry::global(cx);
|
||||
let persons = PersonRegistry::global(cx);
|
||||
|
||||
@@ -878,7 +878,7 @@ impl GroupPanel {
|
||||
.current_user()
|
||||
.is_some_and(|me| group.admins().contains(&me));
|
||||
|
||||
let show_author = opens_run(messages, ix - 2);
|
||||
let show_author = opens_run(rows, ix - 2);
|
||||
let pinned = group.pins().pins().contains(&Pin::Event(message.id));
|
||||
|
||||
message::render(
|
||||
@@ -1005,7 +1005,7 @@ impl Render for GroupPanel {
|
||||
list(
|
||||
self.list_state.clone(),
|
||||
cx.processor(move |this, ix, window, cx| {
|
||||
this.render_message(ix, window, cx)
|
||||
this.render_row(ix, window, cx)
|
||||
}),
|
||||
)
|
||||
.size_full(),
|
||||
|
||||
@@ -2,11 +2,11 @@ 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,
|
||||
AnyElement, App, InteractiveElement, IntoElement, ObjectFit, ParentElement, SharedString,
|
||||
SharedUri, Styled, StyledImage, WeakEntity, div, img, px,
|
||||
};
|
||||
use nip29::Group;
|
||||
use nostr_sdk::prelude::EventId;
|
||||
use nip29::{Activity, Group};
|
||||
use nostr_sdk::prelude::{EventId, Kind};
|
||||
use person::PersonRegistry;
|
||||
use settings::AppSettings;
|
||||
use theme::ActiveTheme;
|
||||
@@ -129,6 +129,38 @@ fn react_menu(
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn render_activity(ix: usize, activity: &Activity, cx: &App) -> AnyElement {
|
||||
let persons = PersonRegistry::global(cx);
|
||||
let subject = persons.read(cx).get(&activity.subject(), cx);
|
||||
let hide_avatar = AppSettings::get_hide_avatar(cx);
|
||||
|
||||
MessageRow::new(ix)
|
||||
.show_author(true)
|
||||
.hide_avatar(hide_avatar)
|
||||
.avatar(
|
||||
Avatar::new(subject.avatar())
|
||||
.seed(subject.avatar_seed())
|
||||
.flex_shrink_0(),
|
||||
)
|
||||
.author(SharedString::from(format!(
|
||||
"{} {}",
|
||||
subject.name(),
|
||||
action(activity)
|
||||
)))
|
||||
.timestamp(activity.created_at.to_human_time())
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
fn action(activity: &Activity) -> String {
|
||||
match activity.kind {
|
||||
Kind::GroupJoinRequest => "joined the group".to_owned(),
|
||||
Kind::GroupLeaveRequest => "left the group".to_owned(),
|
||||
Kind::GroupRemoveUser => "was removed from the group".to_owned(),
|
||||
Kind::GroupPutUser => format!("is now {}", activity.roles.join(", ")),
|
||||
_ => String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn media(media: &[SharedUri], cx: &App) -> AnyElement {
|
||||
if let [only] = media {
|
||||
return div()
|
||||
|
||||
Reference in New Issue
Block a user