From 8f8843711ff80bb3afed3f29ed22eff41df4a790 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 5 Oct 2022 15:02:57 +0200 Subject: [PATCH] Move logic for joining project into a global action in `collab_ui` --- crates/collab_ui/src/collab_ui.rs | 79 ++++++++++++++++++- .../src/incoming_call_notification.rs | 51 +++++------- .../src/project_shared_notification.rs | 52 ++++-------- crates/gpui/src/app.rs | 4 + crates/workspace/src/workspace.rs | 6 +- 5 files changed, 115 insertions(+), 77 deletions(-) diff --git a/crates/collab_ui/src/collab_ui.rs b/crates/collab_ui/src/collab_ui.rs index 607c1b50543b886f52efa9dafb02801e38f7d44e..786d344df19c57bd520a434beac5957a45a871ad 100644 --- a/crates/collab_ui/src/collab_ui.rs +++ b/crates/collab_ui/src/collab_ui.rs @@ -3,14 +3,87 @@ mod contacts_popover; mod incoming_call_notification; mod project_shared_notification; +use call::ActiveCall; pub use collab_titlebar_item::CollabTitlebarItem; use gpui::MutableAppContext; +use project::Project; use std::sync::Arc; -use workspace::AppState; +use workspace::{AppState, JoinProject, ToggleFollow, Workspace}; pub fn init(app_state: Arc, cx: &mut MutableAppContext) { contacts_popover::init(cx); collab_titlebar_item::init(cx); - incoming_call_notification::init(app_state.clone(), cx); - project_shared_notification::init(app_state, cx); + incoming_call_notification::init(app_state.user_store.clone(), cx); + project_shared_notification::init(cx); + + 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) + }) + }); + + let workspace = if let Some(existing_workspace) = existing_workspace { + existing_workspace + } else { + let project = Project::remote( + project_id, + app_state.client.clone(), + app_state.user_store.clone(), + app_state.project_store.clone(), + app_state.languages.clone(), + app_state.fs.clone(), + cx.clone(), + ) + .await?; + + let (_, workspace) = cx.add_window((app_state.build_window_options)(), |cx| { + let mut workspace = Workspace::new(project, app_state.default_item_factory, cx); + (app_state.initialize_workspace)(&mut workspace, &app_state, cx); + workspace + }); + workspace + }; + + cx.activate_window(workspace.window_id()); + + 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(|(peer_id, _)| *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); + }); } diff --git a/crates/collab_ui/src/incoming_call_notification.rs b/crates/collab_ui/src/incoming_call_notification.rs index 4630054c5e355bd41eb7dce4729376d5248ceeb7..e46e69522f2548e5683caf74a39ffb59f6c69207 100644 --- a/crates/collab_ui/src/incoming_call_notification.rs +++ b/crates/collab_ui/src/incoming_call_notification.rs @@ -1,25 +1,22 @@ -use std::sync::Arc; - use call::ActiveCall; -use client::incoming_call::IncomingCall; +use client::{incoming_call::IncomingCall, UserStore}; use futures::StreamExt; use gpui::{ elements::*, geometry::{rect::RectF, vector::vec2f}, - impl_internal_actions, Entity, MouseButton, MutableAppContext, RenderContext, View, - ViewContext, WindowBounds, WindowKind, WindowOptions, + impl_internal_actions, Entity, ModelHandle, MouseButton, MutableAppContext, RenderContext, + View, ViewContext, WindowBounds, WindowKind, WindowOptions, }; -use project::Project; use settings::Settings; use util::ResultExt; -use workspace::{AppState, Workspace}; +use workspace::JoinProject; impl_internal_actions!(incoming_call_notification, [RespondToCall]); -pub fn init(app_state: Arc, cx: &mut MutableAppContext) { +pub fn init(user_store: ModelHandle, cx: &mut MutableAppContext) { cx.add_action(IncomingCallNotification::respond_to_call); - let mut incoming_call = app_state.user_store.read(cx).incoming_call(); + let mut incoming_call = user_store.read(cx).incoming_call(); cx.spawn(|mut cx| async move { let mut notification_window = None; while let Some(incoming_call) = incoming_call.next().await { @@ -36,7 +33,7 @@ pub fn init(app_state: Arc, cx: &mut MutableAppContext) { kind: WindowKind::PopUp, is_movable: false, }, - |_| IncomingCallNotification::new(incoming_call, app_state.clone()), + |_| IncomingCallNotification::new(incoming_call, user_store.clone()), ); notification_window = Some(window_id); } @@ -52,47 +49,35 @@ struct RespondToCall { pub struct IncomingCallNotification { call: IncomingCall, - app_state: Arc, + user_store: ModelHandle, } impl IncomingCallNotification { - pub fn new(call: IncomingCall, app_state: Arc) -> Self { - Self { call, app_state } + pub fn new(call: IncomingCall, user_store: ModelHandle) -> Self { + Self { call, user_store } } fn respond_to_call(&mut self, action: &RespondToCall, cx: &mut ViewContext) { if action.accept { - let app_state = self.app_state.clone(); let join = ActiveCall::global(cx) .update(cx, |active_call, cx| active_call.join(&self.call, cx)); + let caller_user_id = self.call.caller.id; let initial_project_id = self.call.initial_project_id; cx.spawn_weak(|_, mut cx| async move { join.await?; - if let Some(initial_project_id) = initial_project_id { - let project = Project::remote( - initial_project_id, - app_state.client.clone(), - app_state.user_store.clone(), - app_state.project_store.clone(), - app_state.languages.clone(), - app_state.fs.clone(), - cx.clone(), - ) - .await?; - - cx.add_window((app_state.build_window_options)(), |cx| { - let mut workspace = - Workspace::new(project, app_state.default_item_factory, cx); - (app_state.initialize_workspace)(&mut workspace, &app_state, cx); - workspace + if let Some(project_id) = initial_project_id { + cx.update(|cx| { + cx.dispatch_global_action(JoinProject { + project_id, + follow_user_id: caller_user_id, + }) }); } anyhow::Ok(()) }) .detach_and_log_err(cx); } else { - self.app_state - .user_store + self.user_store .update(cx, |user_store, _| user_store.decline_call().log_err()); } diff --git a/crates/collab_ui/src/project_shared_notification.rs b/crates/collab_ui/src/project_shared_notification.rs index 53eb17684e9a0f53aecbf03efc201b9c5099768c..e0c196614450550d25ba9afc921f798b1be65031 100644 --- a/crates/collab_ui/src/project_shared_notification.rs +++ b/crates/collab_ui/src/project_shared_notification.rs @@ -7,14 +7,13 @@ use gpui::{ Entity, MouseButton, MutableAppContext, RenderContext, View, ViewContext, WindowBounds, WindowKind, WindowOptions, }; -use project::Project; use settings::Settings; use std::sync::Arc; -use workspace::{AppState, Workspace}; +use workspace::JoinProject; -actions!(project_shared_notification, [JoinProject, DismissProject]); +actions!(project_shared_notification, [DismissProject]); -pub fn init(app_state: Arc, cx: &mut MutableAppContext) { +pub fn init(cx: &mut MutableAppContext) { cx.add_action(ProjectSharedNotification::join); cx.add_action(ProjectSharedNotification::dismiss); @@ -29,7 +28,7 @@ pub fn init(app_state: Arc, cx: &mut MutableAppContext) { kind: WindowKind::PopUp, is_movable: false, }, - |_| ProjectSharedNotification::new(*project_id, owner.clone(), app_state.clone()), + |_| ProjectSharedNotification::new(*project_id, owner.clone()), ); } }) @@ -39,45 +38,17 @@ pub fn init(app_state: Arc, cx: &mut MutableAppContext) { pub struct ProjectSharedNotification { project_id: u64, owner: Arc, - app_state: Arc, } impl ProjectSharedNotification { - fn new(project_id: u64, owner: Arc, app_state: Arc) -> Self { - Self { - project_id, - owner, - app_state, - } + fn new(project_id: u64, owner: Arc) -> Self { + Self { project_id, owner } } fn join(&mut self, _: &JoinProject, cx: &mut ViewContext) { - let project_id = self.project_id; - let app_state = self.app_state.clone(); - cx.spawn_weak(|_, mut cx| async move { - let project = Project::remote( - project_id, - app_state.client.clone(), - app_state.user_store.clone(), - app_state.project_store.clone(), - app_state.languages.clone(), - app_state.fs.clone(), - cx.clone(), - ) - .await?; - - cx.add_window((app_state.build_window_options)(), |cx| { - let mut workspace = Workspace::new(project, app_state.default_item_factory, cx); - (app_state.initialize_workspace)(&mut workspace, &app_state, cx); - workspace - }); - - anyhow::Ok(()) - }) - .detach_and_log_err(cx); - let window_id = cx.window_id(); cx.remove_window(window_id); + cx.propagate_action(); } fn dismiss(&mut self, _: &DismissProject, cx: &mut ViewContext) { @@ -108,6 +79,8 @@ impl ProjectSharedNotification { enum Join {} enum Dismiss {} + let project_id = self.project_id; + let owner_user_id = self.owner.id; Flex::row() .with_child( MouseEventHandler::::new(0, cx, |_, cx| { @@ -117,8 +90,11 @@ impl ProjectSharedNotification { .with_style(theme.join_button.container) .boxed() }) - .on_click(MouseButton::Left, |_, cx| { - cx.dispatch_action(JoinProject); + .on_click(MouseButton::Left, move |_, cx| { + cx.dispatch_action(JoinProject { + project_id, + follow_user_id: owner_user_id, + }); }) .boxed(), ) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 04e27a8279836a2bc4c7b4ea89fae6bf18d9dc48..002bd01377dd173a07b47850d6c16df045e8955f 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -790,6 +790,10 @@ impl AsyncAppContext { self.update(|cx| cx.remove_window(window_id)) } + pub fn activate_window(&mut self, window_id: usize) { + self.update(|cx| cx.activate_window(window_id)) + } + pub fn platform(&self) -> Arc { self.0.borrow().platform() } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 5bec4b4c6dfd36f4f6088de7a5783522ab9c0e37..1509c52887959e38caa8fdf71489c5c3aaf0e97b 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -13,7 +13,7 @@ mod toolbar; use anyhow::{anyhow, Context, Result}; use call::ActiveCall; -use client::{proto, Client, Contact, PeerId, TypedEnvelope, UserStore}; +use client::{proto, Client, PeerId, TypedEnvelope, UserStore}; use collections::{hash_map, HashMap, HashSet}; use dock::{DefaultItemFactory, Dock, ToggleDockButton}; use drag_and_drop::DragAndDrop; @@ -116,8 +116,8 @@ pub struct ToggleFollow(pub PeerId); #[derive(Clone, PartialEq)] pub struct JoinProject { - pub contact: Arc, - pub project_index: usize, + pub project_id: u64, + pub follow_user_id: u64, } impl_internal_actions!(