Skip to content

Commit f05123e

Browse files
feat: show reactions in the UI
1 parent e66d5c8 commit f05123e

File tree

10 files changed

+68
-22
lines changed

10 files changed

+68
-22
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/chat/src/channel.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use tokio::sync::broadcast;
22

3+
use crate::reaction::ReactionEvent;
34
use crate::{async_list::AsyncList, message::Message};
4-
use crate::reaction::ReactionOperation;
55

66
pub trait Channel: AsyncList<Content = Self::Message> + Send + Sync + Clone {
77
type Message: Message;
88

99
fn get_message_receiver(&self) -> broadcast::Receiver<Self::Message>;
10-
fn get_reaction_receiver(&self) -> broadcast::Receiver<(String, ReactionOperation)>;
10+
fn get_reaction_receiver(&self) -> broadcast::Receiver<ReactionEvent>;
1111

1212
fn send_message(&self, content: String, nonce: String) -> Self::Message;
1313
}

src/chat/src/reaction.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use std::fmt::Debug;
2-
use gpui::Rgba;
2+
use gpui::{IntoElement, Rgba};
3+
4+
pub type ReactionEvent = (String, ReactionOperation);
35

46
#[derive(Copy, Clone, Debug)]
57
pub enum MessageReactionType {
@@ -13,7 +15,7 @@ pub enum ReactionEmoji {
1315
Custom { url: String, animated: bool, name: Option<String> },
1416
}
1517

16-
pub trait MessageReaction: Debug {
18+
pub trait MessageReaction: IntoElement {
1719
fn get_count(&self, kind: Option<MessageReactionType>) -> u64;
1820
fn get_self_reaction(&self) -> Option<MessageReactionType>;
1921
fn get_emoji(&self) -> ReactionEmoji;
@@ -31,7 +33,7 @@ pub enum ReactionOperation {
3133
RemoveEmoji(ReactionEmoji),
3234
}
3335

34-
pub trait ReactionList {
36+
pub trait ReactionList: IntoElement {
3537
fn get_reactions(&self) -> &Vec<impl MessageReaction>;
3638
fn get_reaction(&self, emoji: &ReactionEmoji) -> Option<&impl MessageReaction>;
3739
fn increment(&mut self, emoji: &ReactionEmoji, kind: MessageReactionType, user_is_self: bool, by: isize);

src/discord/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ edition = "2021"
55

66
[dependencies]
77
gpui.workspace = true
8+
components.workspace = true
89
scope-chat = { version = "0.1.0", path = "../chat" }
910
serenity = { git = "https://github.com/scopeclient/serenity", version = "0.12" }
1011
tokio = "1.41.1"

src/discord/src/channel/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
snowflake::Snowflake,
77
};
88
use scope_backend_cache::async_list::{refcacheslice::Exists, AsyncListCache};
9-
use scope_chat::reaction::ReactionOperation;
9+
use scope_chat::reaction::ReactionEvent;
1010
use scope_chat::{
1111
async_list::{AsyncList, AsyncListIndex, AsyncListItem, AsyncListResult},
1212
channel::Channel,
@@ -17,7 +17,7 @@ use tokio::sync::{broadcast, Mutex, Semaphore};
1717
pub struct DiscordChannel {
1818
channel_id: Snowflake,
1919
message_receiver: broadcast::Receiver<DiscordMessage>,
20-
reaction_receiver: broadcast::Receiver<(String, ReactionOperation)>,
20+
reaction_receiver: broadcast::Receiver<ReactionEvent>,
2121
client: Arc<DiscordClient>,
2222
cache: Arc<Mutex<AsyncListCache<DiscordMessage>>>,
2323
blocker: Semaphore,
@@ -49,7 +49,7 @@ impl Channel for DiscordChannel {
4949
self.message_receiver.resubscribe()
5050
}
5151

52-
fn get_reaction_receiver(&self) -> broadcast::Receiver<(String, ReactionOperation)> {
52+
fn get_reaction_receiver(&self) -> broadcast::Receiver<ReactionEvent> {
5353
self.reaction_receiver.resubscribe()
5454
}
5555

src/discord/src/client.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::{
1111
},
1212
snowflake::Snowflake,
1313
};
14-
use scope_chat::reaction::{MessageReactionType, ReactionOperation};
14+
use scope_chat::reaction::{MessageReactionType, ReactionEvent, ReactionOperation};
1515
use serenity::all::Reaction;
1616
use serenity::{
1717
all::{Cache, ChannelId, Context, CreateMessage, EventHandler, GatewayIntents, GetMessages, Http, Message, MessageId, Ready},
@@ -31,7 +31,7 @@ struct SerenityClient {
3131
#[derive(Default)]
3232
pub struct DiscordClient {
3333
channel_message_event_handlers: RwLock<HashMap<Snowflake, Vec<broadcast::Sender<DiscordMessage>>>>,
34-
channel_reaction_event_handlers: RwLock<HashMap<Snowflake, Vec<broadcast::Sender<(String, ReactionOperation)>>>>,
34+
channel_reaction_event_handlers: RwLock<HashMap<Snowflake, Vec<broadcast::Sender<ReactionEvent>>>>,
3535
client: OnceLock<SerenityClient>,
3636
user: OnceLock<DiscordMessageAuthor>,
3737
channels: RwLock<HashMap<Snowflake, Arc<DiscordChannel>>>,
@@ -70,7 +70,7 @@ impl DiscordClient {
7070
self.channel_message_event_handlers.write().await.entry(channel).or_default().push(sender);
7171
}
7272

73-
pub async fn add_channel_reaction_sender(&self, channel: Snowflake, sender: broadcast::Sender<(String, ReactionOperation)>) {
73+
pub async fn add_channel_reaction_sender(&self, channel: Snowflake, sender: broadcast::Sender<ReactionEvent>) {
7474
self.channel_reaction_event_handlers.write().await.entry(channel).or_default().push(sender);
7575
}
7676

src/discord/src/message/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::snowflake::Snowflake;
33
use author::{DiscordMessageAuthor, DisplayName};
44
use chrono::{DateTime, Utc};
55
use content::DiscordMessageContent;
6-
use gpui::{Element, IntoElement};
6+
use gpui::{div, Element, IntoElement, ParentElement};
77
use scope_chat::message::MessageAuthor;
88
use scope_chat::reaction::ReactionList;
99
use scope_chat::{async_list::AsyncListItem, message::Message};
@@ -26,7 +26,7 @@ pub struct DiscordMessage {
2626

2727
impl DiscordMessage {
2828
pub fn from_serenity(msg: &serenity::all::Message) -> Self {
29-
let reactions = msg.reactions.iter().map(|r| reaction::DiscordMessageReaction::from_message(r)).collect::<Vec<_>>();
29+
let reactions = msg.reactions.iter().map(reaction::DiscordMessageReaction::from_message).collect::<Vec<_>>();
3030
if !reactions.is_empty() {
3131
println!("Reactions: {:?}", reactions);
3232
}
@@ -57,7 +57,9 @@ impl Message for DiscordMessage {
5757
}
5858

5959
fn get_content(&self) -> impl Element {
60-
self.content.clone().into_element()
60+
div()
61+
.child(self.content.clone().into_element())
62+
.child(self.reactions.clone())
6163
}
6264

6365
fn get_identifier(&self) -> String {

src/discord/src/message/reaction.rs

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
use gpui::Rgba;
1+
use components::theme::ActiveTheme;
2+
use gpui::{div, img, px, AnyElement, IntoElement, ParentElement, RenderOnce, Rgba, Styled, WindowContext};
3+
use gpui::prelude::FluentBuilder;
4+
use scope_chat::reaction::MessageReactionType::Normal;
25
use scope_chat::reaction::{MessageReaction, MessageReactionType, ReactionEmoji};
36
use serenity::all::ReactionType;
47
use MessageReactionType::Burst;
5-
use scope_chat::reaction::MessageReactionType::Normal;
68

79
#[derive(Clone, Debug)]
810
pub enum ReactionData {
@@ -32,7 +34,7 @@ impl ReactionData {
3234
}
3335
}
3436

35-
#[derive(Clone, Debug)]
37+
#[derive(Clone, Debug, IntoElement)]
3638
pub struct DiscordMessageReaction {
3739
pub data: ReactionData,
3840
}
@@ -84,7 +86,7 @@ impl MessageReaction for DiscordMessageReaction {
8486
None
8587
}
8688
}
87-
ReactionData::Local { me, .. } => me.clone(),
89+
ReactionData::Local { me, .. } => *me,
8890
}
8991
}
9092

@@ -138,6 +140,30 @@ impl MessageReaction for DiscordMessageReaction {
138140
}
139141
}
140142

143+
impl DiscordMessageReaction {
144+
fn render_emoji(emoji: &ReactionEmoji) -> AnyElement {
145+
match emoji {
146+
ReactionEmoji::Simple(character) => div().text_size(px(12f32)).child(character.clone()).into_any_element(),
147+
ReactionEmoji::Custom { url, .. } => img(url.clone()).w(px(16f32)).h(px(16f32)).into_any_element(),
148+
}
149+
}
150+
}
151+
152+
impl RenderOnce for DiscordMessageReaction {
153+
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
154+
let emoji = self.get_emoji();
155+
let theme = cx.theme();
156+
div()
157+
.p_1()
158+
.border_1()
159+
.border_color(theme.border)
160+
.when(self.get_self_reaction().is_some(), |s| s.border_color(theme.accent))
161+
.bg(theme.panel)
162+
.rounded_md()
163+
.child(Self::render_emoji(&emoji))
164+
}
165+
}
166+
141167
pub fn discord_reaction_to_emoji(reaction: &serenity::all::ReactionType) -> ReactionEmoji {
142168
match reaction {
143169
ReactionType::Custom { animated, id, name } => ReactionEmoji::Custom {
@@ -151,4 +177,4 @@ pub fn discord_reaction_to_emoji(reaction: &serenity::all::ReactionType) -> Reac
151177
ReactionEmoji::Simple("❓".to_string())
152178
}
153179
}
154-
}
180+
}

src/discord/src/message/reaction_list.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use crate::message::reaction::{DiscordMessageReaction, ReactionData};
2+
use gpui::{div, IntoElement, ParentElement, RenderOnce, Styled, WindowContext};
23
use scope_chat::reaction::MessageReactionType::Normal;
34
use scope_chat::reaction::{MessageReaction, MessageReactionType, ReactionEmoji, ReactionList, ReactionOperation};
45

5-
#[derive(Clone, Debug, Default)]
6+
#[derive(Clone, Debug, Default, IntoElement)]
67
pub struct DiscordReactionList {
78
reactions: Vec<DiscordMessageReaction>,
89
}
@@ -67,3 +68,16 @@ impl ReactionList for DiscordReactionList {
6768
}
6869
}
6970
}
71+
72+
impl RenderOnce for DiscordReactionList {
73+
fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
74+
if self.reactions.is_empty() {
75+
return div();
76+
}
77+
78+
div()
79+
.flex()
80+
.gap_2()
81+
.children(self.reactions)
82+
}
83+
}

src/ui/src/channel/message_list.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use scope_chat::{
77
message::Message,
88
};
99
use tokio::sync::RwLock;
10-
use scope_chat::reaction::{ReactionList, ReactionOperation};
10+
use scope_chat::reaction::{ReactionEvent, ReactionList};
1111
use super::message::{message, MessageGroup};
1212

1313
#[derive(Clone, Copy)]
@@ -115,7 +115,7 @@ where
115115
});
116116
}
117117

118-
pub fn update_reaction(&mut self, cx: &mut ViewContext<Self>, reaction: (String, ReactionOperation)) {
118+
pub fn update_reaction(&mut self, cx: &mut ViewContext<Self>, reaction: ReactionEvent) {
119119
self.cache.update(cx, |borrow: &mut Vec<Element<Option<T::Content>>>, cx| {
120120
for item in borrow.iter_mut() {
121121
if let Element::Resolved(Some(haystack)) = item {

0 commit comments

Comments
 (0)