From 303216291be4fdebb4da4f5fbc047001647abeed Mon Sep 17 00:00:00 2001 From: Kay Simmons Date: Fri, 3 Feb 2023 11:17:50 -0800 Subject: [PATCH] Move sharing status indicator out of the call crate and into collab_ui in order so that the model doesn't depend on the view --- crates/call/src/call.rs | 41 +---- crates/collab_ui/src/collab_titlebar_item.rs | 23 ++- crates/collab_ui/src/collab_ui.rs | 171 ++++++++++-------- .../src/sharing_status_indicator.rs} | 24 ++- 4 files changed, 141 insertions(+), 118 deletions(-) rename crates/{call/src/indicator.rs => collab_ui/src/sharing_status_indicator.rs} (53%) diff --git a/crates/call/src/call.rs b/crates/call/src/call.rs index c34d124162812b709153e769c925432689f7e320..596a0ec8535e626cc379ec9fb3a62318ff7d54b6 100644 --- a/crates/call/src/call.rs +++ b/crates/call/src/call.rs @@ -1,4 +1,3 @@ -mod indicator; pub mod participant; pub mod room; @@ -10,22 +9,17 @@ use collections::HashSet; use postage::watch; use gpui::{ - actions, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext, - Subscription, Task, ViewHandle, WeakModelHandle, + AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext, + Subscription, Task, WeakModelHandle, }; use project::Project; -use settings::Settings; -use indicator::SharingStatusIndicator; pub use participant::ParticipantLocation; pub use room::Room; -actions!(collab, [ToggleScreenSharing]); - pub fn init(client: Arc, user_store: ModelHandle, cx: &mut MutableAppContext) { let active_call = cx.add_model(|cx| ActiveCall::new(client, user_store, cx)); cx.set_global(active_call); - cx.add_global_action(toggle_screen_sharing); } #[derive(Clone)] @@ -36,6 +30,7 @@ pub struct IncomingCall { pub initial_project: Option, } +/// Singleton global maintaining the user's participation in a room across workspaces. pub struct ActiveCall { room: Option<(ModelHandle, Vec)>, location: Option>, @@ -46,7 +41,6 @@ pub struct ActiveCall { ), client: Arc, user_store: ModelHandle, - sharing_status_indicator: Option<(usize, ViewHandle)>, _subscriptions: Vec, } @@ -71,7 +65,6 @@ impl ActiveCall { ], client, user_store, - sharing_status_indicator: None, } } @@ -290,8 +283,6 @@ impl ActiveCall { this.set_room(None, cx).detach_and_log_err(cx); } - this.set_sharing_status(room.read(cx).is_screen_sharing(), cx); - cx.notify(); }), cx.subscribe(&room, |_, _, event, cx| cx.emit(event.clone())), @@ -316,30 +307,4 @@ impl ActiveCall { pub fn pending_invites(&self) -> &HashSet { &self.pending_invites } - - pub fn set_sharing_status(&mut self, is_screen_sharing: bool, cx: &mut MutableAppContext) { - if is_screen_sharing { - if self.sharing_status_indicator.is_none() - && cx.global::().show_call_status_icon - { - self.sharing_status_indicator = - Some(cx.add_status_bar_item(|_| SharingStatusIndicator)); - } - } else if let Some((window_id, _)) = self.sharing_status_indicator.take() { - cx.remove_status_bar_item(window_id); - } - } -} - -pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut MutableAppContext) { - if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { - let toggle_screen_sharing = room.update(cx, |room, cx| { - if room.is_screen_sharing() { - Task::ready(room.unshare_screen(cx)) - } else { - room.share_screen(cx) - } - }); - toggle_screen_sharing.detach_and_log_err(cx); - } } diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 116a331578c54ac8096dd7783774783bac97cd46..778aa4a71ef5f56d14bc4cdd43d792e3fcf8eed7 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -1,5 +1,5 @@ use crate::{contact_notification::ContactNotification, contacts_popover}; -use call::{ActiveCall, ParticipantLocation, ToggleScreenSharing}; +use call::{ActiveCall, ParticipantLocation}; use client::{proto::PeerId, Authenticate, ContactEventKind, User, UserStore}; use clock::ReplicaId; use contacts_popover::ContactsPopover; @@ -10,17 +10,21 @@ use gpui::{ geometry::{rect::RectF, vector::vec2f, PathBuilder}, json::{self, ToJson}, Border, CursorStyle, Entity, ModelHandle, MouseButton, MutableAppContext, RenderContext, - Subscription, View, ViewContext, ViewHandle, WeakViewHandle, + Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle, }; use settings::Settings; use std::ops::Range; use theme::Theme; use workspace::{FollowNextCollaborator, JoinProject, ToggleFollow, Workspace}; -actions!(collab, [ToggleCollaborationMenu, ShareProject]); +actions!( + collab, + [ToggleCollaborationMenu, ToggleScreenSharing, ShareProject] +); pub fn init(cx: &mut MutableAppContext) { cx.add_action(CollabTitlebarItem::toggle_contacts_popover); + cx.add_global_action(CollabTitlebarItem::toggle_screen_sharing); cx.add_action(CollabTitlebarItem::share_project); } @@ -168,6 +172,19 @@ impl CollabTitlebarItem { cx.notify(); } + pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut MutableAppContext) { + if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { + let toggle_screen_sharing = room.update(cx, |room, cx| { + if room.is_screen_sharing() { + Task::ready(room.unshare_screen(cx)) + } else { + room.share_screen(cx) + } + }); + toggle_screen_sharing.detach_and_log_err(cx); + } + } + fn render_toggle_contacts_button( &self, theme: &Theme, diff --git a/crates/collab_ui/src/collab_ui.rs b/crates/collab_ui/src/collab_ui.rs index 38a47e87dcb6b5e2f420297e8d279a80f5f5688c..d26e2c99ccfb53d9b5e83160464df1a5c73aeafe 100644 --- a/crates/collab_ui/src/collab_ui.rs +++ b/crates/collab_ui/src/collab_ui.rs @@ -6,14 +6,17 @@ mod contacts_popover; mod incoming_call_notification; mod notifications; mod project_shared_notification; +mod sharing_status_indicator; use anyhow::anyhow; use call::ActiveCall; pub use collab_titlebar_item::{CollabTitlebarItem, ToggleCollaborationMenu}; -use gpui::MutableAppContext; +use gpui::{actions, MutableAppContext, Task}; use std::sync::Arc; use workspace::{AppState, JoinProject, ToggleFollow, Workspace}; +actions!(collab, [ToggleScreenSharing]); + pub fn init(app_state: Arc, cx: &mut MutableAppContext) { collab_titlebar_item::init(cx); contact_notification::init(cx); @@ -22,89 +25,107 @@ pub fn init(app_state: Arc, cx: &mut MutableAppContext) { contacts_popover::init(cx); incoming_call_notification::init(cx); project_shared_notification::init(cx); + sharing_status_indicator::init(cx); + cx.add_global_action(toggle_screen_sharing); cx.add_global_action(move |action: &JoinProject, cx| { - let project_id = action.project_id; - let follow_user_id = action.follow_user_id; - let app_state = app_state.clone(); - cx.spawn(|mut cx| async move { - let existing_workspace = cx.update(|cx| { - cx.window_ids() - .filter_map(|window_id| cx.root_view::(window_id)) - .find(|workspace| { - workspace.read(cx).project().read(cx).remote_id() == Some(project_id) - }) - }); + join_project(action, app_state.clone(), cx); + }); +} - let workspace = if let Some(existing_workspace) = existing_workspace { - existing_workspace +pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut MutableAppContext) { + if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { + let toggle_screen_sharing = room.update(cx, |room, cx| { + if room.is_screen_sharing() { + Task::ready(room.unshare_screen(cx)) } else { - let active_call = cx.read(ActiveCall::global); - let room = active_call - .read_with(&cx, |call, _| call.room().cloned()) - .ok_or_else(|| anyhow!("not in a call"))?; - let project = room - .update(&mut cx, |room, cx| { - room.join_project( - project_id, - app_state.languages.clone(), - app_state.fs.clone(), - cx, - ) - }) - .await?; + room.share_screen(cx) + } + }); + toggle_screen_sharing.detach_and_log_err(cx); + } +} - let (_, workspace) = cx.add_window( - (app_state.build_window_options)(None, None, cx.platform().as_ref()), - |cx| { - let mut workspace = Workspace::new( - Default::default(), - 0, - project, - app_state.dock_default_item_factory, - cx, - ); - (app_state.initialize_workspace)(&mut workspace, &app_state, cx); - workspace - }, - ); - workspace - }; +fn join_project(action: &JoinProject, app_state: Arc, cx: &mut MutableAppContext) { + let project_id = action.project_id; + let follow_user_id = action.follow_user_id; + cx.spawn(|mut cx| async move { + let existing_workspace = cx.update(|cx| { + cx.window_ids() + .filter_map(|window_id| cx.root_view::(window_id)) + .find(|workspace| { + workspace.read(cx).project().read(cx).remote_id() == Some(project_id) + }) + }); - cx.activate_window(workspace.window_id()); - cx.platform().activate(true); + let workspace = if let Some(existing_workspace) = existing_workspace { + existing_workspace + } else { + let active_call = cx.read(ActiveCall::global); + let room = active_call + .read_with(&cx, |call, _| call.room().cloned()) + .ok_or_else(|| anyhow!("not in a call"))?; + let project = room + .update(&mut cx, |room, cx| { + room.join_project( + project_id, + app_state.languages.clone(), + app_state.fs.clone(), + cx, + ) + }) + .await?; - workspace.update(&mut cx, |workspace, cx| { - if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { - let follow_peer_id = room - .read(cx) - .remote_participants() - .iter() - .find(|(_, participant)| participant.user.id == follow_user_id) - .map(|(_, p)| p.peer_id) - .or_else(|| { - // If we couldn't follow the given user, follow the host instead. - let collaborator = workspace - .project() - .read(cx) - .collaborators() - .values() - .find(|collaborator| collaborator.replica_id == 0)?; - Some(collaborator.peer_id) - }); + let (_, workspace) = cx.add_window( + (app_state.build_window_options)(None, None, cx.platform().as_ref()), + |cx| { + let mut workspace = Workspace::new( + Default::default(), + 0, + project, + app_state.dock_default_item_factory, + cx, + ); + (app_state.initialize_workspace)(&mut workspace, &app_state, cx); + workspace + }, + ); + workspace + }; - if let Some(follow_peer_id) = follow_peer_id { - if !workspace.is_following(follow_peer_id) { - workspace - .toggle_follow(&ToggleFollow(follow_peer_id), cx) - .map(|follow| follow.detach_and_log_err(cx)); - } + cx.activate_window(workspace.window_id()); + cx.platform().activate(true); + + workspace.update(&mut cx, |workspace, cx| { + if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { + let follow_peer_id = room + .read(cx) + .remote_participants() + .iter() + .find(|(_, participant)| participant.user.id == follow_user_id) + .map(|(_, p)| p.peer_id) + .or_else(|| { + // If we couldn't follow the given user, follow the host instead. + let collaborator = workspace + .project() + .read(cx) + .collaborators() + .values() + .find(|collaborator| collaborator.replica_id == 0)?; + Some(collaborator.peer_id) + }); + + if let Some(follow_peer_id) = follow_peer_id { + if !workspace.is_following(follow_peer_id) { + workspace + .toggle_follow(&ToggleFollow(follow_peer_id), cx) + .map(|follow| follow.detach_and_log_err(cx)); } } - }); + } + }); - anyhow::Ok(()) - }) - .detach_and_log_err(cx); - }); + anyhow::Ok(()) + }) + .detach_and_log_err(cx); } diff --git a/crates/call/src/indicator.rs b/crates/collab_ui/src/sharing_status_indicator.rs similarity index 53% rename from crates/call/src/indicator.rs rename to crates/collab_ui/src/sharing_status_indicator.rs index 102ea5c551cc465b8e385a6de529fca38335de88..42c2aa59f210ff7c7ef43591ef6733787cf84edc 100644 --- a/crates/call/src/indicator.rs +++ b/crates/collab_ui/src/sharing_status_indicator.rs @@ -1,10 +1,30 @@ +use call::ActiveCall; use gpui::{ color::Color, elements::{MouseEventHandler, Svg}, - Appearance, Element, ElementBox, Entity, MouseButton, RenderContext, View, + Appearance, Element, ElementBox, Entity, MouseButton, MutableAppContext, RenderContext, View, }; +use settings::Settings; -use crate::ToggleScreenSharing; +use crate::collab_titlebar_item::ToggleScreenSharing; + +pub fn init(cx: &mut MutableAppContext) { + let active_call = ActiveCall::global(cx); + + let mut status_indicator = None; + cx.observe(&active_call, move |call, cx| { + if let Some(room) = call.read(cx).room() { + if room.read(cx).is_screen_sharing() { + if status_indicator.is_none() && cx.global::().show_call_status_icon { + status_indicator = Some(cx.add_status_bar_item(|_| SharingStatusIndicator)); + } + } else if let Some((window_id, _)) = status_indicator.take() { + cx.remove_status_bar_item(window_id); + } + } + }) + .detach(); +} pub struct SharingStatusIndicator;