This commit is contained in:
2026-09-24 21:13:09 +07:00
parent 2a50804583
commit ce9147c09c
6 changed files with 452 additions and 137 deletions
+36 -7
View File
@@ -19,6 +19,7 @@ use ui::avatar::Avatar;
use ui::button::{Button, ButtonVariants};
use ui::dock::{Panel, PanelEvent};
use ui::input::{InputEvent, Textarea, TextareaState};
use ui::message::WelcomeMessage;
use ui::notification::Notification;
use ui::scroll::Scrollbar;
use ui::{Disableable, IconName, Sizable, WindowExtension, h_flex, v_flex};
@@ -205,15 +206,15 @@ impl CommunityPanel {
self.rows.clear();
self.has_more = false;
self.loading = false;
self.list_state.reset(1);
self.list_state.reset(2);
}
channel
}
/// The list's item count: the load-older row, then every message row.
/// The list's item count: the welcome row, the load-older row, then every message row.
fn item_count(&self) -> usize {
self.rows.len() + 1
self.rows.len() + 2
}
/// A timeline read, `before_ms` exclusive, or `None` for the newest rows.
@@ -542,7 +543,8 @@ impl CommunityPanel {
shown.insert(message.id, at);
self.rows.insert(at, message);
self.list_state.splice(at + 1..at + 1, 1);
// The welcome and load-older rows sit above the messages.
self.list_state.splice(at + 2..at + 2, 1);
}
}
@@ -624,7 +626,29 @@ impl CommunityPanel {
.into_any_element()
}
/// The row at index 0: the affordance that pages older history in.
/// The row at index 0: the welcome message for the channel.
fn render_welcome(&self, cx: &Context<Self>) -> AnyElement {
let (name, avatar) = self
.community
.read_with(cx, |community, _cx| {
let seed = community.id().to_hex();
let avatar = match community.icon() {
Some(path) => Avatar::from_source(path).seed(seed).large(),
None => Avatar::new(None).seed(seed).large(),
};
(community.name(), avatar)
})
.unwrap_or_else(|_| (SharedString::from("this community"), Avatar::new(None)));
WelcomeMessage::new("welcome")
.icon(avatar)
.title(format!("Welcome to {}", name))
.message(format!("This is the start of the {} channel.", name))
.into_any_element()
}
/// The row at index 1: the affordance that pages older history in.
fn render_older(&self, cx: &mut Context<Self>) -> AnyElement {
if !self.has_more {
return div().into_any_element();
@@ -670,14 +694,19 @@ impl CommunityPanel {
cx: &mut Context<Self>,
) -> AnyElement {
if ix == 0 {
return self.render_welcome(cx);
}
if ix == 1 {
return self.render_older(cx);
}
let Some(message) = self.rows.get(ix - 1) else {
// The welcome and load-older rows sit above the messages.
let Some(message) = self.rows.get(ix - 2) else {
return div().into_any_element();
};
let show_author = self.opens_run(ix - 1);
let show_author = self.opens_run(ix - 2);
message::render(ix, message, show_author, cx)
}
+19 -50
View File
@@ -3,68 +3,37 @@ use std::collections::BTreeMap;
use common::TimestampExt;
use community::ChatMessage;
use gpui::prelude::FluentBuilder;
use gpui::{
AnyElement, App, InteractiveElement, IntoElement, ParentElement, SharedString, Styled, div, px,
};
use gpui::{AnyElement, App, IntoElement, ParentElement, SharedString, Styled, div};
use nostr_sdk::prelude::*;
use person::PersonRegistry;
use settings::AppSettings;
use theme::ActiveTheme;
use ui::avatar::Avatar;
use ui::{StyledExt, h_flex, v_flex};
use ui::h_flex;
use ui::message::MessageRow;
pub(crate) fn render(ix: usize, message: &ChatMessage, show_author: bool, 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);
div()
.id(ix)
.w_full()
.py_1()
.px_3()
.hover(|this| this.bg(cx.theme().surface_background))
.child(
h_flex()
.items_start()
.gap_3()
.when(!hide_avatar, |this| {
if show_author {
this.child(
Avatar::new(author.avatar())
.seed(author.avatar_seed())
.flex_shrink_0(),
)
} else {
this.child(div().flex_shrink_0().w(px(32.)))
}
})
.child(
v_flex()
.flex_1()
.min_w_0()
.gap_0p5()
.when(show_author, |this| {
this.child(
h_flex()
.gap_2()
.text_sm()
.text_color(cx.theme().text_placeholder)
.child(div().font_semibold().child(author.name()))
.child(
Timestamp::from_secs(message.at_ms / 1000).to_human_time(),
)
.when(message.edited_at.is_some(), |this| {
this.child(div().child("(edited)"))
}),
)
})
.child(content(message, cx))
.when(!message.reactions.is_empty(), |this| {
this.child(reactions(message, cx))
}),
),
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(Timestamp::from_secs(message.at_ms / 1000).to_human_time())
.when(message.edited_at.is_some(), |this| {
this.header_extra(div().child("(edited)"))
})
.child(content(message, cx))
.when(!message.reactions.is_empty(), |this| {
this.child(reactions(message, cx))
})
.into_any_element()
}