Skip to content

Commit f41af73

Browse files
feat: add reactions to the chat message model
1 parent 436930f commit f41af73

File tree

6 files changed

+119
-2
lines changed

6 files changed

+119
-2
lines changed

src/chat/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
pub mod async_list;
22
pub mod channel;
33
pub mod message;
4+
pub mod reaction;

src/chat/src/message.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use chrono::{DateTime, Utc};
22
use gpui::Element;
33

44
use crate::async_list::AsyncListItem;
5+
use crate::reaction::MessageReaction;
56

67
pub trait Message: Clone + AsyncListItem + Send {
78
fn get_author(&self) -> &impl MessageAuthor;
@@ -10,6 +11,7 @@ pub trait Message: Clone + AsyncListItem + Send {
1011
fn get_nonce(&self) -> Option<&String>;
1112
fn should_group(&self, previous: &Self) -> bool;
1213
fn get_timestamp(&self) -> Option<DateTime<Utc>>;
14+
fn get_reactions(&self) -> Vec<impl MessageReaction>;
1315
}
1416

1517
pub trait MessageAuthor: PartialEq + Eq {

src/chat/src/reaction.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use gpui::Rgba;
2+
3+
#[derive(Copy, Clone, Debug)]
4+
pub enum MessageReactionType {
5+
Normal,
6+
Burst,
7+
}
8+
9+
#[derive(Clone, Debug)]
10+
pub enum ReactionEmoji {
11+
Simple(String),
12+
Custom { url: String, animated: bool, name: Option<String> },
13+
}
14+
15+
pub trait MessageReaction {
16+
fn get_count(&self, kind: Option<MessageReactionType>) -> u32;
17+
fn get_self_reaction(&self) -> Option<MessageReactionType>;
18+
fn get_emoji(&self) -> ReactionEmoji;
19+
fn get_burst_colors(&self) -> Vec<Rgba>;
20+
}

src/discord/src/channel/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ impl Channel for DiscordChannel {
6161
id: Snowflake { content: 0 },
6262
nonce: Some(nonce),
6363
creation_time: Timestamp::now(),
64+
reactions: vec![],
6465
}
6566
}
6667
}

src/discord/src/message/mod.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ use content::DiscordMessageContent;
44
use gpui::{Element, IntoElement};
55
use scope_chat::{async_list::AsyncListItem, message::Message};
66
use serenity::all::Nonce;
7-
7+
use scope_chat::message::MessageAuthor;
8+
use scope_chat::reaction::MessageReaction;
89
use crate::snowflake::Snowflake;
910

1011
pub mod author;
1112
pub mod content;
13+
mod reaction;
1214

1315
#[derive(Clone, Debug)]
1416
pub struct DiscordMessage {
@@ -17,10 +19,15 @@ pub struct DiscordMessage {
1719
pub id: Snowflake,
1820
pub nonce: Option<String>,
1921
pub creation_time: serenity::model::Timestamp,
22+
pub reactions: Vec<reaction::DiscordMessageReaction>,
2023
}
2124

2225
impl DiscordMessage {
2326
pub fn from_serenity(msg: &serenity::all::Message) -> Self {
27+
let reactions = &msg.reactions.iter().map(|r| reaction::DiscordMessageReaction::from_serenity(r)).filter_map(Result::ok).collect::<Vec<_>>();
28+
if !reactions.is_empty() {
29+
println!("Reactions: {:?}", reactions);
30+
}
2431
DiscordMessage {
2532
id: Snowflake { content: msg.id.get() },
2633
author: DiscordMessageAuthor {
@@ -37,12 +44,13 @@ impl DiscordMessage {
3744
Nonce::String(s) => s,
3845
}),
3946
creation_time: msg.timestamp,
47+
reactions: reactions.clone(),
4048
}
4149
}
4250
}
4351

4452
impl Message for DiscordMessage {
45-
fn get_author(&self) -> &impl scope_chat::message::MessageAuthor {
53+
fn get_author(&self) -> &impl MessageAuthor {
4654
&self.author
4755
}
4856

@@ -69,6 +77,10 @@ impl Message for DiscordMessage {
6977

7078
DateTime::from_timestamp_millis(ts)
7179
}
80+
81+
fn get_reactions(&self) -> Vec<impl MessageReaction> {
82+
self.reactions.clone()
83+
}
7284
}
7385

7486
impl AsyncListItem for DiscordMessage {

src/discord/src/message/reaction.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
use gpui::Rgba;
2+
use serenity::all::ReactionType;
3+
use scope_chat::reaction::{MessageReaction, ReactionEmoji, MessageReactionType};
4+
5+
#[derive(Clone, Debug)]
6+
pub struct DiscordMessageReaction {
7+
pub count: u32,
8+
pub count_burst: u32,
9+
pub self_reaction: Option<MessageReactionType>,
10+
pub emoji: ReactionEmoji,
11+
pub burst_colors: Vec<Rgba>,
12+
}
13+
14+
impl DiscordMessageReaction {
15+
pub fn from_serenity(reaction: &serenity::all::MessageReaction) -> Result<Self, String> {
16+
let emoji = match &reaction.reaction_type {
17+
ReactionType::Custom { animated, id, name } => {
18+
ReactionEmoji::Custom {
19+
url: format!("https://cdn.discordapp.com/emojis/{}.png", id),
20+
animated: *animated,
21+
name: name.clone(),
22+
}
23+
}
24+
ReactionType::Unicode(character) => {
25+
ReactionEmoji::Simple(character.clone())
26+
}
27+
ty => {
28+
return Err(format!("Unsupported reaction type: {:?}", ty));
29+
}
30+
};
31+
32+
let count = reaction.count_details.normal as u32;
33+
let count_burst = reaction.count_details.burst as u32;
34+
let burst_colors = reaction.burst_colours.iter().map(|color| {
35+
Rgba {
36+
r: color.r() as f32,
37+
g: color.g() as f32,
38+
b: color.b() as f32,
39+
a: 1f32,
40+
}
41+
}).collect();
42+
43+
let self_reaction = if reaction.me {
44+
Some(MessageReactionType::Normal)
45+
} else if reaction.me_burst {
46+
Some(MessageReactionType::Burst)
47+
} else {
48+
None
49+
};
50+
51+
Ok(DiscordMessageReaction {
52+
count,
53+
count_burst,
54+
self_reaction,
55+
emoji,
56+
burst_colors,
57+
})
58+
}
59+
}
60+
61+
impl MessageReaction for DiscordMessageReaction {
62+
fn get_count(&self, kind: Option<MessageReactionType>) -> u32 {
63+
match kind {
64+
Some(MessageReactionType::Burst) => self.count_burst,
65+
Some(MessageReactionType::Normal) => self.count,
66+
None => self.count + self.count_burst,
67+
}
68+
}
69+
70+
fn get_self_reaction(&self) -> Option<MessageReactionType> {
71+
self.self_reaction
72+
}
73+
74+
fn get_emoji(&self) -> ReactionEmoji {
75+
self.emoji.clone()
76+
}
77+
78+
fn get_burst_colors(&self) -> Vec<Rgba> {
79+
self.burst_colors.clone()
80+
}
81+
}

0 commit comments

Comments
 (0)