Add actions for calls (#28048)

Julia Ryan , Ben Kunkle , and Ben Kunkle created

Add the following actions for use while calling: `Mute`, `Deafen`,
`ShareProject`, `ScreenShare`, `LeaveCall`

We were also interested in adding push-to-talk functionality for mute,
but that will go in a followup PR

Release Notes:

- Call actions (mute/screenshare/etc.) can now be bound to keys and run from the command palette.

---------

Co-authored-by: Ben Kunkle <ben.kunkle@gmail.com>
Co-authored-by: Ben Kunkle <ben@zed.dev>

Change summary

crates/collab_ui/src/collab_panel.rs | 53 +++++++++++++++++++++++++++++
crates/title_bar/src/collab.rs       |  4 +-
crates/title_bar/src/title_bar.rs    | 15 +------
crates/workspace/src/workspace.rs    | 12 ++++++
4 files changed, 68 insertions(+), 16 deletions(-)

Detailed changes

crates/collab_ui/src/collab_panel.rs 🔗

@@ -35,7 +35,7 @@ use ui::{
 };
 use util::{ResultExt, TryFutureExt, maybe};
 use workspace::{
-    OpenChannelNotes, Workspace,
+    Deafen, LeaveCall, Mute, OpenChannelNotes, ScreenShare, ShareProject, Workspace,
     dock::{DockPosition, Panel, PanelEvent},
     notifications::{DetachAndPromptErr, NotifyResultExt, NotifyTaskExt},
 };
@@ -80,6 +80,57 @@ pub fn init(cx: &mut App) {
                 });
             }
         });
+        // TODO: make it possible to bind this one to a held key for push to talk?
+        // how to make "toggle_on_modifiers_press" contextual?
+        workspace.register_action(|_, _: &Mute, window, cx| {
+            let room = ActiveCall::global(cx).read(cx).room().cloned();
+            if let Some(room) = room {
+                window.defer(cx, move |_window, cx| {
+                    room.update(cx, |room, cx| room.toggle_mute(cx))
+                });
+            }
+        });
+        workspace.register_action(|_, _: &Deafen, window, cx| {
+            let room = ActiveCall::global(cx).read(cx).room().cloned();
+            if let Some(room) = room {
+                window.defer(cx, move |_window, cx| {
+                    room.update(cx, |room, cx| room.toggle_deafen(cx))
+                });
+            }
+        });
+        workspace.register_action(|_, _: &LeaveCall, window, cx| {
+            CollabPanel::leave_call(window, cx);
+        });
+        workspace.register_action(|workspace, _: &ShareProject, window, cx| {
+            let project = workspace.project().clone();
+            println!("{project:?}");
+            window.defer(cx, move |_window, cx| {
+                ActiveCall::global(cx).update(cx, move |call, cx| {
+                    if let Some(room) = call.room() {
+                        println!("{room:?}");
+                        if room.read(cx).is_sharing_project() {
+                            call.unshare_project(project, cx).ok();
+                        } else {
+                            call.share_project(project, cx).detach_and_log_err(cx);
+                        }
+                    }
+                });
+            });
+        });
+        workspace.register_action(|_, _: &ScreenShare, window, cx| {
+            let room = ActiveCall::global(cx).read(cx).room().cloned();
+            if let Some(room) = room {
+                window.defer(cx, move |_window, cx| {
+                    room.update(cx, |room, cx| {
+                        if room.is_screen_sharing() {
+                            room.unshare_screen(cx).ok();
+                        } else {
+                            room.share_screen(cx).detach_and_log_err(cx);
+                        };
+                    });
+                });
+            }
+        });
     })
     .detach();
 }

crates/title_bar/src/collab.rs 🔗

@@ -320,9 +320,9 @@ impl TitleBar {
                 .label_size(LabelSize::Small)
                 .on_click(cx.listener(move |this, _, window, cx| {
                     if is_shared {
-                        this.unshare_project(&Default::default(), window, cx);
+                        this.unshare_project(window, cx);
                     } else {
-                        this.share_project(&Default::default(), cx);
+                        this.share_project(cx);
                     }
                 }))
                 .into_any_element(),

crates/title_bar/src/title_bar.rs 🔗

@@ -49,16 +49,7 @@ const MAX_BRANCH_NAME_LENGTH: usize = 40;
 
 const BOOK_ONBOARDING: &str = "https://dub.sh/zed-c-onboarding";
 
-actions!(
-    collab,
-    [
-        ShareProject,
-        UnshareProject,
-        ToggleUserMenu,
-        ToggleProjectMenu,
-        SwitchBranch
-    ]
-);
+actions!(collab, [ToggleUserMenu, ToggleProjectMenu, SwitchBranch]);
 
 pub fn init(cx: &mut App) {
     cx.observe_new(|workspace: &mut Workspace, window, cx| {
@@ -567,7 +558,7 @@ impl TitleBar {
         cx.notify();
     }
 
-    fn share_project(&mut self, _: &ShareProject, cx: &mut Context<Self>) {
+    fn share_project(&mut self, cx: &mut Context<Self>) {
         let active_call = ActiveCall::global(cx);
         let project = self.project.clone();
         active_call
@@ -575,7 +566,7 @@ impl TitleBar {
             .detach_and_log_err(cx);
     }
 
-    fn unshare_project(&mut self, _: &UnshareProject, _: &mut Window, cx: &mut Context<Self>) {
+    fn unshare_project(&mut self, _: &mut Window, cx: &mut Context<Self>) {
         let active_call = ActiveCall::global(cx);
         let project = self.project.clone();
         active_call

crates/workspace/src/workspace.rs 🔗

@@ -5808,7 +5808,17 @@ pub fn last_session_workspace_locations(
         .log_err()
 }
 
-actions!(collab, [OpenChannelNotes]);
+actions!(
+    collab,
+    [
+        OpenChannelNotes,
+        Mute,
+        Deafen,
+        LeaveCall,
+        ShareProject,
+        ScreenShare
+    ]
+);
 actions!(zed, [OpenLog]);
 
 async fn join_channel_internal(