WIP

Nathan Sobo and Antonio Scandurra created

Co-Authored-By: Antonio Scandurra <me@as-cii.com>

Change summary

zed/src/channel.rs    | 48 ++++++++++++++++++++++-----------
zed/src/chat_panel.rs | 64 +++++++++++++++++++++++++-------------------
2 files changed, 68 insertions(+), 44 deletions(-)

Detailed changes

zed/src/channel.rs 🔗

@@ -5,8 +5,9 @@ use crate::{
 use anyhow::{anyhow, Context, Result};
 use gpui::{
     sum_tree::{self, Bias, SumTree},
-    Entity, ModelContext, ModelHandle, MutableAppContext, WeakModelHandle,
+    Entity, ModelContext, ModelHandle, MutableAppContext, Task, WeakModelHandle,
 };
+use postage::prelude::Stream;
 use std::{
     collections::{hash_map, HashMap},
     ops::Range,
@@ -21,6 +22,7 @@ pub struct ChannelList {
     available_channels: Option<Vec<ChannelDetails>>,
     channels: HashMap<u64, WeakModelHandle<Channel>>,
     rpc: Arc<Client>,
+    _task: Task<Option<()>>,
 }
 
 #[derive(Clone, Debug, PartialEq)]
@@ -74,27 +76,42 @@ impl Entity for ChannelList {
 
 impl ChannelList {
     pub fn new(rpc: Arc<rpc::Client>, cx: &mut ModelContext<Self>) -> Self {
-        cx.spawn(|this, mut cx| {
+        let _task = cx.spawn(|this, mut cx| {
             let rpc = rpc.clone();
             async move {
-                let response = rpc
-                    .request(proto::GetChannels {})
-                    .await
-                    .context("failed to fetch available channels")?;
-                this.update(&mut cx, |this, cx| {
-                    this.available_channels =
-                        Some(response.channels.into_iter().map(Into::into).collect());
-                    cx.notify();
-                });
-                Ok(())
+                let mut user_id = rpc.user_id();
+                loop {
+                    let available_channels = if user_id.recv().await.unwrap().is_some() {
+                        Some(
+                            rpc.request(proto::GetChannels {})
+                                .await
+                                .context("failed to fetch available channels")?
+                                .channels
+                                .into_iter()
+                                .map(Into::into)
+                                .collect(),
+                        )
+                    } else {
+                        None
+                    };
+
+                    this.update(&mut cx, |this, cx| {
+                        if available_channels.is_none() {
+                            this.channels.clear();
+                        }
+                        this.available_channels = available_channels;
+                        cx.notify();
+                    });
+                }
             }
             .log_err()
-        })
-        .detach();
+        });
+
         Self {
             available_channels: None,
             channels: Default::default(),
             rpc,
+            _task,
         }
     }
 
@@ -223,8 +240,7 @@ impl Channel {
     }
 
     fn current_user_id(&self) -> Result<u64> {
-        self
-            .rpc
+        self.rpc
             .user_id()
             .borrow()
             .ok_or_else(|| anyhow!("not logged in"))

zed/src/chat_panel.rs 🔗

@@ -5,8 +5,8 @@ use crate::{
     Settings,
 };
 use gpui::{
-    action, elements::*, Entity, ModelHandle, MutableAppContext, RenderContext, Subscription, View,
-    ViewContext, ViewHandle,
+    action, elements::*, keymap::Binding, Entity, ModelHandle, MutableAppContext, RenderContext,
+    Subscription, View, ViewContext, ViewHandle,
 };
 use postage::watch;
 
@@ -24,6 +24,8 @@ action!(Send);
 
 pub fn init(cx: &mut MutableAppContext) {
     cx.add_action(ChatPanel::send);
+
+    cx.add_bindings(vec![Binding::new("enter", Send, Some("ChatPanel"))]);
 }
 
 impl ChatPanel {
@@ -41,44 +43,50 @@ impl ChatPanel {
             settings,
         };
 
-        this.assign_active_channel(cx);
+        this.init_active_channel(cx);
         cx.observe(&this.channel_list, |this, _, cx| {
-            this.assign_active_channel(cx);
+            this.init_active_channel(cx);
         })
         .detach();
 
         this
     }
 
-    pub fn assign_active_channel(&mut self, cx: &mut ViewContext<Self>) {
-        let channel = self.channel_list.update(cx, |list, cx| {
-            if let Some(channel_id) = list
-                .available_channels()
-                .and_then(|channels| channels.first())
-                .map(|details| details.id)
-            {
-                return list.get_channel(channel_id, cx);
-            }
-            None
-        });
-        if let Some(channel) = channel {
-            if self.active_channel.as_ref().map(|e| &e.0) != Some(&channel) {
-                let subscription = cx.subscribe(&channel, Self::channel_did_change);
-                self.messages = ListState::new(
-                    channel
-                        .read(cx)
-                        .messages()
-                        .cursor::<(), ()>()
-                        .map(|m| self.render_message(m))
-                        .collect(),
-                );
-                self.active_channel = Some((channel, subscription));
+    fn init_active_channel(&mut self, cx: &mut ViewContext<Self>) {
+        if self.active_channel.is_none() {
+            let channel = self.channel_list.update(cx, |list, cx| {
+                if let Some(channel_id) = list
+                    .available_channels()
+                    .and_then(|channels| channels.first())
+                    .map(|details| details.id)
+                {
+                    return list.get_channel(channel_id, cx);
+                }
+                None
+            });
+            if let Some(channel) = channel {
+                self.set_active_channel(channel, cx);
             }
-        } else {
+        } else if self.channel_list.read(cx).available_channels().is_none() {
             self.active_channel = None;
         }
     }
 
+    fn set_active_channel(&mut self, channel: ModelHandle<Channel>, cx: &mut ViewContext<Self>) {
+        if self.active_channel.as_ref().map(|e| &e.0) != Some(&channel) {
+            let subscription = cx.subscribe(&channel, Self::channel_did_change);
+            self.messages = ListState::new(
+                channel
+                    .read(cx)
+                    .messages()
+                    .cursor::<(), ()>()
+                    .map(|m| self.render_message(m))
+                    .collect(),
+            );
+            self.active_channel = Some((channel, subscription));
+        }
+    }
+
     fn channel_did_change(
         &mut self,
         _: ModelHandle<Channel>,