109 lines
3.6 KiB
Rust
109 lines
3.6 KiB
Rust
use std::collections::BTreeMap;
|
|
|
|
use common::TimestampExt;
|
|
use community::ChatMessage;
|
|
use gpui::prelude::FluentBuilder;
|
|
use gpui::{
|
|
AnyElement, App, InteractiveElement, 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};
|
|
|
|
pub(crate) fn render(ix: usize, message: &ChatMessage, 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| {
|
|
this.child(
|
|
Avatar::new(author.avatar())
|
|
.seed(author.avatar_seed())
|
|
.flex_shrink_0(),
|
|
)
|
|
})
|
|
.child(
|
|
v_flex()
|
|
.flex_1()
|
|
.min_w_0()
|
|
.gap_0p5()
|
|
.child(
|
|
h_flex()
|
|
.gap_2()
|
|
.text_sm()
|
|
.child(div().font_semibold().child(author.name()))
|
|
.child(
|
|
div()
|
|
.text_color(cx.theme().text_placeholder)
|
|
.child(Timestamp::from_secs(message.at_ms / 1000).to_ago()),
|
|
)
|
|
.when(message.edited_at.is_some(), |this| {
|
|
this.child(
|
|
div()
|
|
.text_color(cx.theme().text_placeholder)
|
|
.child("(edited)"),
|
|
)
|
|
}),
|
|
)
|
|
.child(content(message, cx))
|
|
.when(!message.reactions.is_empty(), |this| {
|
|
this.child(reactions(message, cx))
|
|
}),
|
|
),
|
|
)
|
|
.into_any_element()
|
|
}
|
|
|
|
fn content(message: &ChatMessage, cx: &App) -> AnyElement {
|
|
if message.deleted {
|
|
return div()
|
|
.text_sm()
|
|
.text_color(cx.theme().text_placeholder)
|
|
.child("Message deleted")
|
|
.into_any_element();
|
|
}
|
|
|
|
div()
|
|
.text_sm()
|
|
.child(SharedString::from(message.content.clone()))
|
|
.into_any_element()
|
|
}
|
|
|
|
fn reactions(message: &ChatMessage, cx: &App) -> AnyElement {
|
|
let mut grouped: BTreeMap<&str, usize> = BTreeMap::new();
|
|
|
|
for emoji in message.reactions.values() {
|
|
*grouped.entry(emoji.as_str()).or_default() += 1;
|
|
}
|
|
|
|
h_flex()
|
|
.mt_1()
|
|
.gap_1()
|
|
.children(grouped.into_iter().map(|(emoji, count)| {
|
|
h_flex()
|
|
.gap_1()
|
|
.py_0p5()
|
|
.px_1()
|
|
.rounded(cx.theme().radius)
|
|
.border_1()
|
|
.border_color(cx.theme().border)
|
|
.text_xs()
|
|
.child(SharedString::from(emoji))
|
|
.child(SharedString::from(count.to_string()))
|
|
}))
|
|
.into_any_element()
|
|
}
|