add send reaction

This commit is contained in:
2026-07-31 08:45:56 +07:00
parent 9dbac5308d
commit c3d677ca81
2 changed files with 80 additions and 24 deletions

View File

@@ -1,11 +1,11 @@
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use instant::Duration;
use anyhow::{Error, anyhow};
use common::EventExt;
use device::DeviceRegistry;
use gpui::{App, AppContext, Context, EventEmitter, SharedString, Task};
use instant::Duration;
use itertools::Itertools;
use nostr_sdk::prelude::*;
use person::{Person, PersonRegistry};
@@ -419,12 +419,23 @@ impl Room {
}
// Construct a rumor event for direct message
pub fn rumor<S, I>(&self, content: S, replies: I, cx: &App) -> Option<UnsignedEvent>
pub fn rumor<S, I>(
&self,
content: S,
replies: I,
reaction: bool,
cx: &App,
) -> Option<UnsignedEvent>
where
S: Into<String>,
I: IntoIterator<Item = EventId>,
{
let kind = Kind::PrivateDirectMessage;
let kind = if reaction {
Kind::Reaction
} else {
Kind::PrivateDirectMessage
};
let content: String = content.into();
let replies: Vec<EventId> = replies.into_iter().collect();

View File

@@ -35,6 +35,9 @@ use ui::{
use crate::text::RenderedText;
const REACTION_EMOJIS: &[&str] = &["👍", "👎", "😄", "🎉", "😕", "❤️", "🚀", "👀"];
const COMPACT_REACTION_EMOJIS: &[&str] = &["👍", "❤️", "👀"];
mod actions;
mod text;
@@ -331,24 +334,49 @@ impl ChatPanel {
// Get the message which includes all attachments
let content = self.get_input_value(cx);
// Get the replies to this message
let replies: Vec<EventId> = self.replies_to.read(cx).iter().copied().collect();
// Return if message is empty
if content.trim().is_empty() {
window.push_notification("Cannot send an empty message", cx);
return;
}
self.send_message(&content, window, cx);
self.send_message(&content, replies, false, window, cx);
}
fn send_reaction(
&mut self,
emoji: &str,
target: &EventId,
window: &mut Window,
cx: &mut Context<Self>,
) {
// Return if emoji is empty
if emoji.trim().is_empty() {
window.push_notification("Cannot send an empty reaction", cx);
return;
}
self.send_message(emoji, vec![*target], true, window, cx);
}
/// Send a message to all members of the chat
fn send_message(&mut self, value: &str, window: &mut Window, cx: &mut Context<Self>) {
fn send_message(
&mut self,
value: &str,
replies: Vec<EventId>,
reaction: bool,
window: &mut Window,
cx: &mut Context<Self>,
) {
if value.trim().is_empty() {
window.push_notification("Cannot send an empty message", cx);
return;
}
let room = self.room.clone();
let replies: Vec<EventId> = self.replies_to.read(cx).iter().copied().collect();
let content = value.to_string();
let sent_ids = self.sent_ids.clone();
@@ -357,7 +385,7 @@ impl ChatPanel {
return;
};
let (rumor, send_task) = match room_entity.read_with(cx, |room, cx| {
let rumor = room.rumor(content.clone(), replies, cx)?;
let rumor = room.rumor(content.clone(), replies, reaction, cx)?;
let send_task = room.send(rumor.clone(), cx)?;
Some((rumor, send_task))
}) {
@@ -575,7 +603,10 @@ impl ChatPanel {
fn on_command(&mut self, command: &Command, window: &mut Window, cx: &mut Context<Self>) {
match command {
Command::Insert(content) => {
self.send_message(content, window, cx);
self.input.update(cx, |this, cx| {
let new_value = format!("{} {}", this.value(), content);
this.set_value(new_value, window, cx);
});
}
Command::ChangeSubject(subject) => {
if self
@@ -990,13 +1021,9 @@ impl ChatPanel {
.w_full()
.px_2()
.border_l_2()
.border_color(cx.theme().element_selected)
.border_color(cx.theme().element_active)
.text_sm()
.child(
div()
.text_color(cx.theme().text_accent)
.child(author.name()),
)
.child(div().child(author.name()))
.child(
div()
.w_full()
@@ -1192,6 +1219,29 @@ impl ChatPanel {
.border_1()
.border_color(cx.theme().border)
.bg(cx.theme().background)
.children({
let mut items = vec![];
for emoji in COMPACT_REACTION_EMOJIS {
items.push(
Button::new(*emoji)
.label(*emoji)
.tooltip(*emoji)
.small()
.ghost()
.on_click({
let emoji = *emoji;
let id = *id;
cx.listener(move |this, _event, window, cx| {
this.send_reaction(emoji, &id, window, cx);
})
}),
);
}
items
})
.child(div().flex_shrink_0().h_4().w_px().bg(cx.theme().border))
.child(
Button::new("reply")
.icon(IconName::Reply)
@@ -1305,7 +1355,7 @@ impl ChatPanel {
.gap_1()
.text_xs()
.text_color(cx.theme().text_muted)
.child(SharedString::from("Replying to:"))
.child("Replying to:")
.child(
div()
.text_color(cx.theme().text_accent)
@@ -1402,15 +1452,10 @@ impl ChatPanel {
.ghost()
.large()
.dropdown_menu_with_anchor(gpui::Anchor::BottomLeft, move |this, _window, _cx| {
this.horizontal()
.menu("👍", Box::new(Command::Insert("👍")))
.menu("👎", Box::new(Command::Insert("👎")))
.menu("😄", Box::new(Command::Insert("😄")))
.menu("🎉", Box::new(Command::Insert("🎉")))
.menu("😕", Box::new(Command::Insert("😕")))
.menu("❤️", Box::new(Command::Insert("❤️")))
.menu("🚀", Box::new(Command::Insert("🚀")))
.menu("👀", Box::new(Command::Insert("👀")))
let menu = this.horizontal();
REACTION_EMOJIS.iter().fold(menu, |this, emoji| {
this.menu(*emoji, Box::new(Command::Insert(emoji)))
})
})
}
}