Avoid duplicate acks for messages with mentions

Max Brunsfeld created

Change summary

crates/channel/src/channel_chat.rs | 21 ++++++-----
crates/collab_ui/src/chat_panel.rs | 56 +++++++++++++++++--------------
2 files changed, 42 insertions(+), 35 deletions(-)

Detailed changes

crates/channel/src/channel_chat.rs 🔗

@@ -21,6 +21,7 @@ use util::{post_inc, ResultExt as _, TryFutureExt};
 pub struct ChannelChat {
     channel: Arc<Channel>,
     messages: SumTree<ChannelMessage>,
+    acknowledged_message_ids: HashSet<u64>,
     channel_store: ModelHandle<ChannelStore>,
     loaded_all_messages: bool,
     last_acknowledged_id: Option<u64>,
@@ -117,6 +118,7 @@ impl ChannelChat {
                 rpc: client,
                 outgoing_messages_lock: Default::default(),
                 messages: Default::default(),
+                acknowledged_message_ids: Default::default(),
                 loaded_all_messages,
                 next_pending_message_id: 0,
                 last_acknowledged_id: None,
@@ -370,16 +372,15 @@ impl ChannelChat {
         cursor.item().unwrap()
     }
 
-    pub fn rendered_message(&self, id: ChannelMessageId) {
-        let ChannelMessageId::Saved(id) = id else {
-            return;
-        };
-        self.rpc
-            .send(proto::AckChannelMessage {
-                channel_id: self.channel.id,
-                message_id: id,
-            })
-            .ok();
+    pub fn acknowledge_message(&mut self, id: u64) {
+        if self.acknowledged_message_ids.insert(id) {
+            self.rpc
+                .send(proto::AckChannelMessage {
+                    channel_id: self.channel.id,
+                    message_id: id,
+                })
+                .ok();
+        }
     }
 
     pub fn messages_in_range(&self, range: Range<usize>) -> impl Iterator<Item = &ChannelMessage> {

crates/collab_ui/src/chat_panel.rs 🔗

@@ -346,32 +346,38 @@ impl ChatPanel {
     }
 
     fn render_message(&mut self, ix: usize, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
-        let (message, is_continuation, is_last, is_admin) = {
-            let active_chat = self.active_chat.as_ref().unwrap().0.read(cx);
-            let is_admin = self
-                .channel_store
-                .read(cx)
-                .is_user_admin(active_chat.channel().id);
-            let last_message = active_chat.message(ix.saturating_sub(1));
-            let this_message = active_chat.message(ix);
-            let is_continuation = last_message.id != this_message.id
-                && this_message.sender.id == last_message.sender.id;
-
-            if this_message
-                .mentions
-                .iter()
-                .any(|(_, user_id)| Some(*user_id) == self.client.user_id())
-            {
-                active_chat.rendered_message(this_message.id);
-            }
+        let (message, is_continuation, is_last, is_admin) = self
+            .active_chat
+            .as_ref()
+            .unwrap()
+            .0
+            .update(cx, |active_chat, cx| {
+                let is_admin = self
+                    .channel_store
+                    .read(cx)
+                    .is_user_admin(active_chat.channel().id);
+                let last_message = active_chat.message(ix.saturating_sub(1));
+                let this_message = active_chat.message(ix).clone();
+                let is_continuation = last_message.id != this_message.id
+                    && this_message.sender.id == last_message.sender.id;
+
+                if let ChannelMessageId::Saved(id) = this_message.id {
+                    if this_message
+                        .mentions
+                        .iter()
+                        .any(|(_, user_id)| Some(*user_id) == self.client.user_id())
+                    {
+                        active_chat.acknowledge_message(id);
+                    }
+                }
 
-            (
-                this_message.clone(),
-                is_continuation,
-                active_chat.message_count() == ix + 1,
-                is_admin,
-            )
-        };
+                (
+                    this_message,
+                    is_continuation,
+                    active_chat.message_count() == ix + 1,
+                    is_admin,
+                )
+            });
 
         let is_pending = message.is_pending();
         let theme = theme::current(cx);