Basic channel joining!

Conrad Irwin created

Change summary

crates/call2/src/call2.rs             |  51 ++++++++++++-
crates/collab_ui2/src/collab_panel.rs | 106 +++++++++++++++-------------
2 files changed, 102 insertions(+), 55 deletions(-)

Detailed changes

crates/call2/src/call2.rs 🔗

@@ -14,8 +14,8 @@ use client::{
 use collections::HashSet;
 use futures::{channel::oneshot, future::Shared, Future, FutureExt};
 use gpui::{
-    AppContext, AsyncAppContext, Context, EventEmitter, Model, ModelContext, Subscription, Task,
-    View, ViewContext, VisualContext, WeakModel, WeakView,
+    AppContext, AsyncAppContext, Context, EventEmitter, Model, ModelContext, PromptLevel,
+    Subscription, Task, View, ViewContext, VisualContext, WeakModel, WeakView, WindowHandle,
 };
 pub use participant::ParticipantLocation;
 use postage::watch;
@@ -334,12 +334,55 @@ impl ActiveCall {
     pub fn join_channel(
         &mut self,
         channel_id: u64,
+        requesting_window: WindowHandle<Workspace>,
         cx: &mut ModelContext<Self>,
     ) -> Task<Result<Option<Model<Room>>>> {
         if let Some(room) = self.room().cloned() {
             if room.read(cx).channel_id() == Some(channel_id) {
-                return Task::ready(Ok(Some(room)));
-            } else {
+                return cx.spawn(|_, _| async move {
+                    todo!();
+                    // let future = room.update(&mut cx, |room, cx| {
+                    //     room.most_active_project(cx).map(|(host, project)| {
+                    //         room.join_project(project, host, app_state.clone(), cx)
+                    //     })
+                    // })
+
+                    // if let Some(future) = future {
+                    //     future.await?;
+                    // }
+
+                    // Ok(Some(room))
+                });
+            }
+
+            let should_prompt = room.update(cx, |room, _| {
+                room.channel_id().is_some()
+                    && room.is_sharing_project()
+                    && room.remote_participants().len() > 0
+            });
+            if should_prompt {
+                return cx.spawn(|this, mut cx| async move {
+                    let answer = requesting_window.update(&mut cx, |_, cx| {
+                        cx.prompt(
+                            PromptLevel::Warning,
+                            "Leaving this call will unshare your current project.\nDo you want to switch channels?",
+                            &["Yes, Join Channel", "Cancel"],
+                        )
+                    })?;
+                    if answer.await? == 1 {
+                        return Ok(None);
+                    }
+
+                    room.update(&mut cx, |room, cx| room.clear_state(cx))?;
+
+                    this.update(&mut cx, |this, cx| {
+                        this.join_channel(channel_id, requesting_window, cx)
+                    })?
+                    .await
+                });
+            }
+
+            if room.read(cx).channel_id().is_some() {
                 room.update(cx, |room, cx| room.clear_state(cx));
             }
         }

crates/collab_ui2/src/collab_panel.rs 🔗

@@ -90,10 +90,10 @@ use rpc::proto;
 //     channel_id: ChannelId,
 // }
 
-// #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
-// pub struct OpenChannelNotes {
-//     pub channel_id: ChannelId,
-// }
+#[derive(Action, PartialEq, Debug, Clone, Serialize, Deserialize)]
+pub struct OpenChannelNotes {
+    pub channel_id: ChannelId,
+}
 
 // #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
 // pub struct JoinChannelCall {
@@ -167,10 +167,10 @@ use editor::Editor;
 use feature_flags::{ChannelsAlpha, FeatureFlagAppExt};
 use fuzzy::{match_strings, StringMatchCandidate};
 use gpui::{
-    actions, div, img, prelude::*, serde_json, AppContext, AsyncWindowContext, Div, EventEmitter,
-    FocusHandle, Focusable, FocusableView, InteractiveElement, IntoElement, Model, ParentElement,
-    Render, RenderOnce, SharedString, Styled, Subscription, View, ViewContext, VisualContext,
-    WeakView,
+    actions, div, img, prelude::*, serde_json, Action, AppContext, AsyncWindowContext, Div,
+    EventEmitter, FocusHandle, Focusable, FocusableView, InteractiveElement, IntoElement, Model,
+    ParentElement, Render, RenderOnce, SharedString, Styled, Subscription, View, ViewContext,
+    VisualContext, WeakView,
 };
 use project::Fs;
 use serde_derive::{Deserialize, Serialize};
@@ -322,17 +322,17 @@ pub struct CollabPanel {
     subscriptions: Vec<Subscription>,
     collapsed_sections: Vec<Section>,
     collapsed_channels: Vec<ChannelId>,
-    // drag_target_channel: ChannelDragTarget,
+    drag_target_channel: ChannelDragTarget,
     workspace: WeakView<Workspace>,
     // context_menu_on_selected: bool,
 }
 
-// #[derive(PartialEq, Eq)]
-// enum ChannelDragTarget {
-//     None,
-//     Root,
-//     Channel(ChannelId),
-// }
+#[derive(PartialEq, Eq)]
+enum ChannelDragTarget {
+    None,
+    Root,
+    Channel(ChannelId),
+}
 
 #[derive(Serialize, Deserialize)]
 struct SerializedCollabPanel {
@@ -614,7 +614,7 @@ impl CollabPanel {
                 workspace: workspace.weak_handle(),
                 client: workspace.app_state().client.clone(),
                 //                 context_menu_on_selected: true,
-                //                 drag_target_channel: ChannelDragTarget::None,
+                drag_target_channel: ChannelDragTarget::None,
                 //                 list_state,
             };
 
@@ -2346,11 +2346,12 @@ impl CollabPanel {
     //         }
     //     }
 
-    //     fn open_channel_notes(&mut self, action: &OpenChannelNotes, cx: &mut ViewContext<Self>) {
-    //         if let Some(workspace) = self.workspace.upgrade(cx) {
-    //             ChannelView::open(action.channel_id, workspace, cx).detach();
-    //         }
-    //     }
+    fn open_channel_notes(&mut self, action: &OpenChannelNotes, cx: &mut ViewContext<Self>) {
+        if let Some(workspace) = self.workspace.upgrade() {
+            todo!();
+            // ChannelView::open(action.channel_id, workspace, cx).detach();
+        }
+    }
 
     //     fn show_inline_context_menu(&mut self, _: &menu::ShowContextMenu, cx: &mut ViewContext<Self>) {
     //         let Some(channel) = self.selected_channel() else {
@@ -2504,21 +2505,17 @@ impl CollabPanel {
     //             .detach_and_log_err(cx);
     //     }
 
-    //     fn join_channel(&self, channel_id: u64, cx: &mut ViewContext<Self>) {
-    //         let Some(workspace) = self.workspace.upgrade(cx) else {
-    //             return;
-    //         };
-    //         let Some(handle) = cx.window().downcast::<Workspace>() else {
-    //             return;
-    //         };
-    //         workspace::join_channel(
-    //             channel_id,
-    //             workspace.read(cx).app_state().clone(),
-    //             Some(handle),
-    //             cx,
-    //         )
-    //         .detach_and_log_err(cx)
-    //     }
+    fn join_channel(&self, channel_id: u64, cx: &mut ViewContext<Self>) {
+        let Some(handle) = cx.window_handle().downcast::<Workspace>() else {
+            return;
+        };
+        let active_call = ActiveCall::global(cx);
+        active_call
+            .update(cx, |active_call, cx| {
+                active_call.join_channel(channel_id, handle, cx)
+            })
+            .detach_and_log_err(cx)
+    }
 
     //     fn join_channel_chat(&mut self, action: &JoinChannelChat, cx: &mut ViewContext<Self>) {
     //         let channel_id = action.channel_id;
@@ -2982,9 +2979,7 @@ impl CollabPanel {
         is_selected: bool,
         cx: &mut ViewContext<Self>,
     ) -> impl IntoElement {
-        ListItem::new("contact-placeholder")
-            .child(Label::new("Add a Contact"))
-            .on_click(cx.listener(|this, _, cx| todo!()))
+        ListItem::new("contact-placeholder").child(Label::new("Add a Contact"))
         // enum AddContacts {}
         // MouseEventHandler::new::<AddContacts, _>(0, cx, |state, _| {
         //     let style = theme.list_empty_state.style_for(is_selected, state);
@@ -3023,6 +3018,15 @@ impl CollabPanel {
     ) -> impl IntoElement {
         let channel_id = channel.id;
 
+        let is_active = maybe!({
+            let call_channel = ActiveCall::global(cx)
+                .read(cx)
+                .room()?
+                .read(cx)
+                .channel_id()?;
+            Some(call_channel == channel_id)
+        })
+        .unwrap_or(false);
         let is_public = self
             .channel_store
             .read(cx)
@@ -3034,16 +3038,6 @@ impl CollabPanel {
             .then(|| !self.collapsed_channels.binary_search(&channel.id).is_ok())
             .unwrap_or(false);
 
-        let is_active = maybe!({
-            let call_channel = ActiveCall::global(cx)
-                .read(cx)
-                .room()?
-                .read(cx)
-                .channel_id()?;
-            Some(call_channel == channel_id)
-        })
-        .unwrap_or(false);
-
         let has_messages_notification = channel.unseen_message_id.is_some();
         let has_notes_notification = channel.unseen_note_version.is_some();
 
@@ -3052,6 +3046,7 @@ impl CollabPanel {
 
         let face_pile = if !participants.is_empty() {
             let extra_count = participants.len().saturating_sub(FACEPILE_LIMIT);
+            let user = &participants[0];
 
             let result = FacePile {
                 faces: participants
@@ -3059,6 +3054,7 @@ impl CollabPanel {
                     .filter_map(|user| Some(Avatar::data(user.avatar.clone()?).into_any_element()))
                     .take(FACEPILE_LIMIT)
                     .chain(if extra_count > 0 {
+                        // todo!() @nate - this label looks wrong.
                         Some(Label::new(format!("+{}", extra_count)).into_any_element())
                     } else {
                         None
@@ -3081,7 +3077,7 @@ impl CollabPanel {
                         .w_full()
                         .justify_between()
                         .child(
-                            div()
+                            h_stack()
                                 .id(channel_id as usize)
                                 .child(Label::new(channel.name.clone()))
                                 .children(face_pile.map(|face_pile| face_pile.render(cx)))
@@ -3128,7 +3124,15 @@ impl CollabPanel {
                 } else {
                     Toggle::NotToggleable
                 })
-                .on_click(cx.listener(|this, _, cx| todo!()))
+                .on_click(cx.listener(move |this, _, cx| {
+                    if this.drag_target_channel == ChannelDragTarget::None {
+                        if is_active {
+                            this.open_channel_notes(&OpenChannelNotes { channel_id }, cx)
+                        } else {
+                            this.join_channel(channel_id, cx)
+                        }
+                    }
+                }))
                 .on_secondary_mouse_down(cx.listener(|this, _, cx| {
                     todo!() // open context menu
                 })),