Allow calling an user, render contacts in collab panel

Piotr Osiewicz created

Change summary

crates/call2/src/call2.rs             | 74 ++++++++++++++++------------
crates/collab_ui2/src/collab_panel.rs | 42 +++++++++++++---
crates/workspace2/src/workspace2.rs   |  6 ++
3 files changed, 82 insertions(+), 40 deletions(-)

Detailed changes

crates/call2/src/call2.rs 🔗

@@ -549,6 +549,40 @@ impl Call {
 
 #[async_trait(?Send)]
 impl CallHandler for Call {
+    fn peer_state(
+        &mut self,
+        leader_id: PeerId,
+        cx: &mut ViewContext<Workspace>,
+    ) -> Option<(bool, bool)> {
+        let (call, _) = self.active_call.as_ref()?;
+        let room = call.read(cx).room()?.read(cx);
+        let participant = room.remote_participant_for_peer_id(leader_id)?;
+
+        let leader_in_this_app;
+        let leader_in_this_project;
+        match participant.location {
+            ParticipantLocation::SharedProject { project_id } => {
+                leader_in_this_app = true;
+                leader_in_this_project = Some(project_id)
+                    == self
+                        .parent_workspace
+                        .update(cx, |this, cx| this.project().read(cx).remote_id())
+                        .log_err()
+                        .flatten();
+            }
+            ParticipantLocation::UnsharedProject => {
+                leader_in_this_app = true;
+                leader_in_this_project = false;
+            }
+            ParticipantLocation::External => {
+                leader_in_this_app = false;
+                leader_in_this_project = false;
+            }
+        };
+
+        Some((leader_in_this_project, leader_in_this_app))
+    }
+
     fn shared_screen_for_peer(
         &self,
         peer_id: PeerId,
@@ -571,7 +605,6 @@ impl CallHandler for Call {
         //     SharedScreen::new(&track, peer_id, user.clone(), cx)
         // })))
     }
-
     fn room_id(&self, cx: &AppContext) -> Option<u64> {
         Some(self.active_call.as_ref()?.0.read(cx).room()?.read(cx).id())
     }
@@ -585,38 +618,15 @@ impl CallHandler for Call {
     fn active_project(&self, cx: &AppContext) -> Option<WeakModel<Project>> {
         ActiveCall::global(cx).read(cx).location().cloned()
     }
-    fn peer_state(
+    fn invite(
         &mut self,
-        leader_id: PeerId,
-        cx: &mut ViewContext<Workspace>,
-    ) -> Option<(bool, bool)> {
-        let (call, _) = self.active_call.as_ref()?;
-        let room = call.read(cx).room()?.read(cx);
-        let participant = room.remote_participant_for_peer_id(leader_id)?;
-
-        let leader_in_this_app;
-        let leader_in_this_project;
-        match participant.location {
-            ParticipantLocation::SharedProject { project_id } => {
-                leader_in_this_app = true;
-                leader_in_this_project = Some(project_id)
-                    == self
-                        .parent_workspace
-                        .update(cx, |this, cx| this.project().read(cx).remote_id())
-                        .log_err()
-                        .flatten();
-            }
-            ParticipantLocation::UnsharedProject => {
-                leader_in_this_app = true;
-                leader_in_this_project = false;
-            }
-            ParticipantLocation::External => {
-                leader_in_this_app = false;
-                leader_in_this_project = false;
-            }
-        };
-
-        Some((leader_in_this_project, leader_in_this_app))
+        called_user_id: u64,
+        initial_project: Option<Model<Project>>,
+        cx: &mut AppContext,
+    ) -> Task<Result<()>> {
+        ActiveCall::global(cx).update(cx, |this, cx| {
+            this.invite(called_user_id, initial_project, cx)
+        })
     }
 }
 

crates/collab_ui2/src/collab_panel.rs 🔗

@@ -157,15 +157,17 @@ const COLLABORATION_PANEL_KEY: &'static str = "CollaborationPanel";
 
 use std::sync::Arc;
 
+use client::{Client, Contact, UserStore};
 use db::kvp::KEY_VALUE_STORE;
 use gpui::{
     actions, div, serde_json, AppContext, AsyncWindowContext, Div, EventEmitter, FocusHandle,
-    Focusable, FocusableView, InteractiveElement, ParentElement, Render, View, ViewContext,
-    VisualContext, WeakView,
+    Focusable, FocusableView, InteractiveElement, Model, ParentElement, Render, Styled, View,
+    ViewContext, VisualContext, WeakView,
 };
 use project::Fs;
 use serde_derive::{Deserialize, Serialize};
 use settings::Settings;
+use ui::{h_stack, Avatar, Label};
 use util::ResultExt;
 use workspace::{
     dock::{DockPosition, Panel, PanelEvent},
@@ -299,8 +301,8 @@ pub struct CollabPanel {
     // channel_editing_state: Option<ChannelEditingState>,
     // entries: Vec<ListEntry>,
     // selection: Option<usize>,
-    // user_store: ModelHandle<UserStore>,
-    // client: Arc<Client>,
+    user_store: Model<UserStore>,
+    client: Arc<Client>,
     // channel_store: ModelHandle<ChannelStore>,
     // project: ModelHandle<Project>,
     // match_candidates: Vec<StringMatchCandidate>,
@@ -595,7 +597,7 @@ impl CollabPanel {
                 //                 entries: Vec::default(),
                 //                 channel_editing_state: None,
                 //                 selection: None,
-                //                 user_store: workspace.user_store().clone(),
+                user_store: workspace.user_store().clone(),
                 //                 channel_store: ChannelStore::global(cx),
                 //                 project: workspace.project().clone(),
                 //                 subscriptions: Vec::default(),
@@ -603,7 +605,7 @@ impl CollabPanel {
                 //                 collapsed_sections: vec![Section::Offline],
                 //                 collapsed_channels: Vec::default(),
                 _workspace: workspace.weak_handle(),
-                //                 client: workspace.app_state().client.clone(),
+                client: workspace.app_state().client.clone(),
                 //                 context_menu_on_selected: true,
                 //                 drag_target_channel: ChannelDragTarget::None,
                 //                 list_state,
@@ -663,6 +665,9 @@ impl CollabPanel {
         })
     }
 
+    fn contacts(&self, cx: &AppContext) -> Option<Vec<Arc<Contact>>> {
+        Some(self.user_store.read(cx).contacts().to_owned())
+    }
     pub async fn load(
         workspace: WeakView<Workspace>,
         mut cx: AsyncWindowContext,
@@ -3297,11 +3302,32 @@ impl CollabPanel {
 impl Render for CollabPanel {
     type Element = Focusable<Div>;
 
-    fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
+        let contacts = self.contacts(cx).unwrap_or_default();
+        let workspace = self._workspace.clone();
         div()
             .key_context("CollabPanel")
             .track_focus(&self.focus_handle)
-            .child("COLLAB PANEL")
+            .children(contacts.into_iter().map(|contact| {
+                let id = contact.user.id;
+                h_stack()
+                    .p_2()
+                    .gap_2()
+                    .children(
+                        contact
+                            .user
+                            .avatar
+                            .as_ref()
+                            .map(|avatar| Avatar::new(avatar.clone())),
+                    )
+                    .child(Label::new(contact.user.github_login.clone()))
+                    .on_mouse_down(gpui::MouseButton::Left, {
+                        let workspace = workspace.clone();
+                        move |event, cx| {
+                            workspace.update(cx, |this, cx| this.call_state().invite(id, None, cx));
+                        }
+                    })
+            }))
     }
 }
 

crates/workspace2/src/workspace2.rs 🔗

@@ -454,6 +454,12 @@ pub trait CallHandler {
     }
     fn hang_up(&self, cx: AsyncWindowContext) -> Result<Task<Result<()>>>;
     fn active_project(&self, cx: &AppContext) -> Option<WeakModel<Project>>;
+    fn invite(
+        &mut self,
+        called_user_id: u64,
+        initial_project: Option<Model<Project>>,
+        cx: &mut AppContext,
+    ) -> Task<Result<()>>;
 }
 
 pub struct Workspace {