mirror of
https://github.com/chatmail/core.git
synced 2026-05-14 04:16:30 +03:00
api!:jsonrpc: sort reactions in descending order (#4388)
convert `JSONRPCReactions.reactions` to a `Vec<JSONRPCReaction>` with unique reactions and their count, sorted in descending order. --------- Co-authored-by: link2xt <link2xt@testrun.org>
This commit is contained in:
committed by
GitHub
parent
2328ba54be
commit
4a593a8d7e
@@ -10,6 +10,7 @@
|
|||||||
- BREAKING: jsonrpc:
|
- BREAKING: jsonrpc:
|
||||||
- `get_chatlist_items_by_entries` now takes only chatids instead of `ChatListEntries`
|
- `get_chatlist_items_by_entries` now takes only chatids instead of `ChatListEntries`
|
||||||
- `get_chatlist_entries` now returns `Vec<u32>` of chatids instead of `ChatListEntries`
|
- `get_chatlist_entries` now returns `Vec<u32>` of chatids instead of `ChatListEntries`
|
||||||
|
- `JSONRPCReactions.reactions` is now a `Vec<JSONRPCReaction>` with unique reactions and their count, sorted in descending order.
|
||||||
- `Event`: `context_id` property is now called `contextId`
|
- `Event`: `context_id` property is now called `contextId`
|
||||||
- jsonrpc: expand `MessageSearchResult`:
|
- jsonrpc: expand `MessageSearchResult`:
|
||||||
- always include `chat_name`(not an option anymore)
|
- always include `chat_name`(not an option anymore)
|
||||||
|
|||||||
@@ -1,23 +1,37 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
use deltachat::contact::ContactId;
|
||||||
use deltachat::reaction::Reactions;
|
use deltachat::reaction::Reactions;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use typescript_type_def::TypeDef;
|
use typescript_type_def::TypeDef;
|
||||||
|
|
||||||
|
/// A single reaction emoji.
|
||||||
|
#[derive(Serialize, TypeDef)]
|
||||||
|
#[serde(rename = "Reaction", rename_all = "camelCase")]
|
||||||
|
pub struct JSONRPCReaction {
|
||||||
|
/// Emoji.
|
||||||
|
emoji: String,
|
||||||
|
|
||||||
|
/// Emoji frequency.
|
||||||
|
count: usize,
|
||||||
|
|
||||||
|
/// True if we reacted with this emoji.
|
||||||
|
is_from_self: bool,
|
||||||
|
}
|
||||||
|
|
||||||
/// Structure representing all reactions to a particular message.
|
/// Structure representing all reactions to a particular message.
|
||||||
#[derive(Serialize, TypeDef)]
|
#[derive(Serialize, TypeDef)]
|
||||||
#[serde(rename = "Reactions", rename_all = "camelCase")]
|
#[serde(rename = "Reactions", rename_all = "camelCase")]
|
||||||
pub struct JSONRPCReactions {
|
pub struct JSONRPCReactions {
|
||||||
/// Map from a contact to it's reaction to message.
|
/// Map from a contact to it's reaction to message.
|
||||||
reactions_by_contact: BTreeMap<u32, Vec<String>>,
|
reactions_by_contact: BTreeMap<u32, Vec<String>>,
|
||||||
/// Unique reactions and their count
|
/// Unique reactions and their count, sorted in descending order.
|
||||||
reactions: BTreeMap<String, u32>,
|
reactions: Vec<JSONRPCReaction>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Reactions> for JSONRPCReactions {
|
impl From<Reactions> for JSONRPCReactions {
|
||||||
fn from(reactions: Reactions) -> Self {
|
fn from(reactions: Reactions) -> Self {
|
||||||
let mut reactions_by_contact: BTreeMap<u32, Vec<String>> = BTreeMap::new();
|
let mut reactions_by_contact: BTreeMap<u32, Vec<String>> = BTreeMap::new();
|
||||||
let mut unique_reactions: BTreeMap<String, u32> = BTreeMap::new();
|
|
||||||
|
|
||||||
for contact_id in reactions.contacts() {
|
for contact_id in reactions.contacts() {
|
||||||
let reaction = reactions.get(contact_id);
|
let reaction = reactions.get(contact_id);
|
||||||
@@ -30,18 +44,29 @@ impl From<Reactions> for JSONRPCReactions {
|
|||||||
.map(|emoji| emoji.to_owned())
|
.map(|emoji| emoji.to_owned())
|
||||||
.collect();
|
.collect();
|
||||||
reactions_by_contact.insert(contact_id.to_u32(), emojis.clone());
|
reactions_by_contact.insert(contact_id.to_u32(), emojis.clone());
|
||||||
for emoji in emojis {
|
}
|
||||||
if let Some(x) = unique_reactions.get_mut(&emoji) {
|
|
||||||
*x += 1;
|
let self_reactions = reactions_by_contact.get(&ContactId::SELF.to_u32());
|
||||||
} else {
|
|
||||||
unique_reactions.insert(emoji, 1);
|
let mut reactions_v = Vec::new();
|
||||||
}
|
for (emoji, count) in reactions.emoji_sorted_by_frequency() {
|
||||||
}
|
let is_from_self = if let Some(self_reactions) = self_reactions {
|
||||||
|
self_reactions.contains(&emoji)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
let reaction = JSONRPCReaction {
|
||||||
|
emoji,
|
||||||
|
count,
|
||||||
|
is_from_self,
|
||||||
|
};
|
||||||
|
reactions_v.push(reaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONRPCReactions {
|
JSONRPCReactions {
|
||||||
reactions_by_contact,
|
reactions_by_contact,
|
||||||
reactions: unique_reactions,
|
reactions: reactions_v,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
//! possible to remove all reactions by sending an empty string as a reaction,
|
//! possible to remove all reactions by sending an empty string as a reaction,
|
||||||
//! even though RFC 9078 requires at least one emoji to be sent.
|
//! even though RFC 9078 requires at least one emoji to be sent.
|
||||||
|
|
||||||
|
use std::cmp::Ordering;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
@@ -116,10 +117,9 @@ impl Reactions {
|
|||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.reactions.is_empty()
|
self.reactions.is_empty()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Reactions {
|
/// Returns a map from emojis to their frequencies.
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
pub fn emoji_frequencies(&self) -> BTreeMap<String, usize> {
|
||||||
let mut emoji_frequencies: BTreeMap<String, usize> = BTreeMap::new();
|
let mut emoji_frequencies: BTreeMap<String, usize> = BTreeMap::new();
|
||||||
for reaction in self.reactions.values() {
|
for reaction in self.reactions.values() {
|
||||||
for emoji in reaction.emojis() {
|
for emoji in reaction.emojis() {
|
||||||
@@ -129,6 +129,30 @@ impl fmt::Display for Reactions {
|
|||||||
.or_insert(1);
|
.or_insert(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
emoji_frequencies
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a vector of emojis
|
||||||
|
/// sorted in descending order of frequencies.
|
||||||
|
///
|
||||||
|
/// This function can be used to display the reactions in
|
||||||
|
/// the message bubble in the UIs.
|
||||||
|
pub fn emoji_sorted_by_frequency(&self) -> Vec<(String, usize)> {
|
||||||
|
let mut emoji_frequencies: Vec<(String, usize)> =
|
||||||
|
self.emoji_frequencies().into_iter().collect();
|
||||||
|
emoji_frequencies.sort_by(|(a, a_count), (b, b_count)| {
|
||||||
|
match a_count.cmp(b_count).reverse() {
|
||||||
|
Ordering::Equal => a.cmp(b),
|
||||||
|
other => other,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
emoji_frequencies
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Reactions {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let emoji_frequencies = self.emoji_sorted_by_frequency();
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
for (emoji, frequency) in emoji_frequencies {
|
for (emoji, frequency) in emoji_frequencies {
|
||||||
if !first {
|
if !first {
|
||||||
@@ -481,6 +505,11 @@ Content-Disposition: reaction\n\
|
|||||||
let reactions = get_msg_reactions(&alice, alice_msg.sender_msg_id).await?;
|
let reactions = get_msg_reactions(&alice, alice_msg.sender_msg_id).await?;
|
||||||
assert_eq!(reactions.to_string(), "👍2 😀1");
|
assert_eq!(reactions.to_string(), "👍2 😀1");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
reactions.emoji_sorted_by_frequency(),
|
||||||
|
vec![("👍".to_string(), 2), ("😀".to_string(), 1)]
|
||||||
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user