Remove JoinProject internal action

This commit is contained in:
Antonio Scandurra 2023-04-28 11:12:09 +02:00
parent f881f9e3d8
commit d953729233
12 changed files with 302 additions and 287 deletions

View file

@ -23,7 +23,7 @@ use settings::Settings;
use std::{ops::Range, sync::Arc};
use theme::{AvatarStyle, Theme};
use util::ResultExt;
use workspace::{FollowNextCollaborator, JoinProject, Workspace};
use workspace::{FollowNextCollaborator, Workspace};
actions!(
collab,
@ -134,21 +134,18 @@ impl View for CollabTitlebarItem {
}
impl CollabTitlebarItem {
pub fn new(
workspace: &ViewHandle<Workspace>,
user_store: &ModelHandle<UserStore>,
cx: &mut ViewContext<Self>,
) -> Self {
pub fn new(workspace: &ViewHandle<Workspace>, cx: &mut ViewContext<Self>) -> Self {
let active_call = ActiveCall::global(cx);
let user_store = workspace.read(cx).user_store().clone();
let mut subscriptions = Vec::new();
subscriptions.push(cx.observe(workspace, |_, _, cx| cx.notify()));
subscriptions.push(cx.observe(&active_call, |this, _, cx| this.active_call_changed(cx)));
subscriptions.push(cx.observe_window_activation(|this, active, cx| {
this.window_activation_changed(active, cx)
}));
subscriptions.push(cx.observe(user_store, |_, _, cx| cx.notify()));
subscriptions.push(cx.observe(&user_store, |_, _, cx| cx.notify()));
subscriptions.push(
cx.subscribe(user_store, move |this, user_store, event, cx| {
cx.subscribe(&user_store, move |this, user_store, event, cx| {
if let Some(workspace) = this.workspace.upgrade(cx) {
workspace.update(cx, |workspace, cx| {
if let client::Event::Contact { user, kind } = event {
@ -257,9 +254,7 @@ impl CollabTitlebarItem {
pub fn toggle_contacts_popover(&mut self, _: &ToggleContactsMenu, cx: &mut ViewContext<Self>) {
if self.contacts_popover.take().is_none() {
if let Some(workspace) = self.workspace.upgrade(cx) {
let project = workspace.read(cx).project().clone();
let user_store = workspace.read(cx).user_store().clone();
let view = cx.add_view(|cx| ContactsPopover::new(project, user_store, cx));
let view = cx.add_view(|cx| ContactsPopover::new(&workspace, cx));
cx.subscribe(&view, |this, _, event, cx| {
match event {
contacts_popover::Event::Dismissed => {
@ -776,6 +771,8 @@ impl CollabTitlebarItem {
)
.into_any();
} else if let ParticipantLocation::SharedProject { project_id } = location {
enum JoinProject {}
let user_id = user.id;
content = MouseEventHandler::<JoinProject, Self>::new(
peer_id.as_u64() as usize,
@ -783,11 +780,12 @@ impl CollabTitlebarItem {
move |_, _| content,
)
.with_cursor_style(CursorStyle::PointingHand)
.on_click(MouseButton::Left, move |_, _, cx| {
cx.dispatch_action(JoinProject {
project_id,
follow_user_id: user_id,
})
.on_click(MouseButton::Left, move |_, this, cx| {
if let Some(workspace) = this.workspace.upgrade(cx) {
let app_state = workspace.read(cx).app_state().clone();
workspace::join_remote_project(project_id, user_id, app_state, cx)
.detach_and_log_err(cx);
}
})
.with_tooltip::<JoinProject>(
peer_id.as_u64() as usize,

View file

@ -10,29 +10,25 @@ mod notifications;
mod project_shared_notification;
mod sharing_status_indicator;
use anyhow::anyhow;
use call::ActiveCall;
pub use collab_titlebar_item::{CollabTitlebarItem, ToggleContactsMenu};
use gpui::{actions, AppContext, Task};
use std::sync::Arc;
use workspace::{AppState, JoinProject, Workspace};
use workspace::AppState;
actions!(collab, [ToggleScreenSharing]);
pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
pub fn init(app_state: &Arc<AppState>, cx: &mut AppContext) {
collab_titlebar_item::init(cx);
contact_notification::init(cx);
contact_list::init(cx);
contact_finder::init(cx);
contacts_popover::init(cx);
incoming_call_notification::init(cx);
project_shared_notification::init(cx);
incoming_call_notification::init(&app_state, cx);
project_shared_notification::init(&app_state, cx);
sharing_status_indicator::init(cx);
cx.add_global_action(toggle_screen_sharing);
cx.add_global_action(move |action: &JoinProject, cx| {
join_project(action, app_state.clone(), cx);
});
}
pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut AppContext) {
@ -47,88 +43,3 @@ pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut AppContext) {
toggle_screen_sharing.detach_and_log_err(cx);
}
}
fn join_project(action: &JoinProject, app_state: Arc<AppState>, cx: &mut AppContext) {
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)?.clone().downcast::<Workspace>())
.find(|workspace| {
workspace.read(cx).project().read(cx).remote_id() == Some(project_id)
})
});
let workspace = if let Some(existing_workspace) = existing_workspace {
existing_workspace.downgrade()
} 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?;
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,
app_state.background_actions,
cx,
);
(app_state.initialize_workspace)(&mut workspace, &app_state, cx);
workspace
},
);
workspace.downgrade()
};
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_being_followed(follow_peer_id) {
workspace
.toggle_follow(follow_peer_id, cx)
.map(|follow| follow.detach_and_log_err(cx));
}
}
}
})?;
anyhow::Ok(())
})
.detach_and_log_err(cx);
}

View file

@ -11,7 +11,7 @@ use gpui::{
impl_actions, impl_internal_actions,
keymap_matcher::KeymapContext,
platform::{CursorStyle, MouseButton, PromptLevel},
AppContext, Entity, ModelHandle, Subscription, View, ViewContext, ViewHandle,
AppContext, Entity, ModelHandle, Subscription, View, ViewContext, ViewHandle, WeakViewHandle,
};
use menu::{Confirm, SelectNext, SelectPrev};
use project::Project;
@ -19,7 +19,7 @@ use serde::Deserialize;
use settings::Settings;
use std::{mem, sync::Arc};
use theme::IconButton;
use workspace::{JoinProject, OpenSharedScreen};
use workspace::{OpenSharedScreen, Workspace};
impl_actions!(contact_list, [RemoveContact, RespondToContactRequest]);
impl_internal_actions!(contact_list, [ToggleExpanded, Call]);
@ -161,6 +161,7 @@ pub struct ContactList {
match_candidates: Vec<StringMatchCandidate>,
list_state: ListState<Self>,
project: ModelHandle<Project>,
workspace: WeakViewHandle<Workspace>,
user_store: ModelHandle<UserStore>,
filter_editor: ViewHandle<Editor>,
collapsed_sections: Vec<Section>,
@ -169,11 +170,7 @@ pub struct ContactList {
}
impl ContactList {
pub fn new(
project: ModelHandle<Project>,
user_store: ModelHandle<UserStore>,
cx: &mut ViewContext<Self>,
) -> Self {
pub fn new(workspace: &ViewHandle<Workspace>, cx: &mut ViewContext<Self>) -> Self {
let filter_editor = cx.add_view(|cx| {
let mut editor = Editor::single_line(
Some(Arc::new(|theme| {
@ -278,6 +275,7 @@ impl ContactList {
});
let active_call = ActiveCall::global(cx);
let user_store = workspace.read(cx).user_store().clone();
let mut subscriptions = Vec::new();
subscriptions.push(cx.observe(&user_store, |this, _, cx| this.update_entries(cx)));
subscriptions.push(cx.observe(&active_call, |this, _, cx| this.update_entries(cx)));
@ -290,7 +288,8 @@ impl ContactList {
match_candidates: Default::default(),
filter_editor,
_subscriptions: subscriptions,
project,
project: workspace.read(cx).project().clone(),
workspace: workspace.downgrade(),
user_store,
};
this.update_entries(cx);
@ -422,10 +421,16 @@ impl ContactList {
host_user_id,
..
} => {
cx.dispatch_global_action(JoinProject {
project_id: *project_id,
follow_user_id: *host_user_id,
});
if let Some(workspace) = self.workspace.upgrade(cx) {
let app_state = workspace.read(cx).app_state().clone();
workspace::join_remote_project(
*project_id,
*host_user_id,
app_state,
cx,
)
.detach_and_log_err(cx);
}
}
ContactEntry::ParticipantScreen { peer_id, .. } => {
cx.dispatch_action(OpenSharedScreen { peer_id: *peer_id });
@ -798,6 +803,8 @@ impl ContactList {
theme: &theme::ContactList,
cx: &mut ViewContext<Self>,
) -> AnyElement<Self> {
enum JoinProject {}
let font_cache = cx.font_cache();
let host_avatar_height = theme
.contact_avatar
@ -873,12 +880,13 @@ impl ContactList {
} else {
CursorStyle::Arrow
})
.on_click(MouseButton::Left, move |_, _, cx| {
.on_click(MouseButton::Left, move |_, this, cx| {
if !is_current {
cx.dispatch_global_action(JoinProject {
project_id,
follow_user_id: host_user_id,
});
if let Some(workspace) = this.workspace.upgrade(cx) {
let app_state = workspace.read(cx).app_state().clone();
workspace::join_remote_project(project_id, host_user_id, app_state, cx)
.detach_and_log_err(cx);
}
}
})
.into_any()

View file

@ -6,11 +6,11 @@ use crate::{
use client::UserStore;
use gpui::{
actions, elements::*, platform::MouseButton, AppContext, Entity, ModelHandle, View,
ViewContext, ViewHandle,
ViewContext, ViewHandle, WeakViewHandle,
};
use picker::PickerEvent;
use project::Project;
use settings::Settings;
use workspace::Workspace;
actions!(contacts_popover, [ToggleContactFinder]);
@ -29,23 +29,17 @@ enum Child {
pub struct ContactsPopover {
child: Child,
project: ModelHandle<Project>,
user_store: ModelHandle<UserStore>,
workspace: WeakViewHandle<Workspace>,
_subscription: Option<gpui::Subscription>,
}
impl ContactsPopover {
pub fn new(
project: ModelHandle<Project>,
user_store: ModelHandle<UserStore>,
cx: &mut ViewContext<Self>,
) -> Self {
pub fn new(workspace: &ViewHandle<Workspace>, cx: &mut ViewContext<Self>) -> Self {
let mut this = Self {
child: Child::ContactList(
cx.add_view(|cx| ContactList::new(project.clone(), user_store.clone(), cx)),
),
project,
user_store,
child: Child::ContactList(cx.add_view(|cx| ContactList::new(workspace, cx))),
user_store: workspace.read(cx).user_store().clone(),
workspace: workspace.downgrade(),
_subscription: None,
};
this.show_contact_list(String::new(), cx);
@ -74,16 +68,16 @@ impl ContactsPopover {
}
fn show_contact_list(&mut self, editor_text: String, cx: &mut ViewContext<ContactsPopover>) {
let child = cx.add_view(|cx| {
ContactList::new(self.project.clone(), self.user_store.clone(), cx)
.with_editor_text(editor_text, cx)
});
cx.focus(&child);
self._subscription = Some(cx.subscribe(&child, |_, _, event, cx| match event {
crate::contact_list::Event::Dismissed => cx.emit(Event::Dismissed),
}));
self.child = Child::ContactList(child);
cx.notify();
if let Some(workspace) = self.workspace.upgrade(cx) {
let child = cx
.add_view(|cx| ContactList::new(&workspace, cx).with_editor_text(editor_text, cx));
cx.focus(&child);
self._subscription = Some(cx.subscribe(&child, |_, _, event, cx| match event {
crate::contact_list::Event::Dismissed => cx.emit(Event::Dismissed),
}));
self.child = Child::ContactList(child);
cx.notify();
}
}
}

View file

@ -1,3 +1,5 @@
use std::sync::{Arc, Weak};
use call::{ActiveCall, IncomingCall};
use client::proto;
use futures::StreamExt;
@ -10,13 +12,14 @@ use gpui::{
};
use settings::Settings;
use util::ResultExt;
use workspace::JoinProject;
use workspace::AppState;
impl_internal_actions!(incoming_call_notification, [RespondToCall]);
pub fn init(cx: &mut AppContext) {
pub fn init(app_state: &Arc<AppState>, cx: &mut AppContext) {
cx.add_action(IncomingCallNotification::respond_to_call);
let app_state = Arc::downgrade(app_state);
let mut incoming_call = ActiveCall::global(cx).read(cx).incoming();
cx.spawn(|mut cx| async move {
let mut notification_windows = Vec::new();
@ -48,7 +51,7 @@ pub fn init(cx: &mut AppContext) {
is_movable: false,
screen: Some(screen),
},
|_| IncomingCallNotification::new(incoming_call.clone()),
|_| IncomingCallNotification::new(incoming_call.clone(), app_state.clone()),
);
notification_windows.push(window_id);
@ -66,11 +69,12 @@ struct RespondToCall {
pub struct IncomingCallNotification {
call: IncomingCall,
app_state: Weak<AppState>,
}
impl IncomingCallNotification {
pub fn new(call: IncomingCall) -> Self {
Self { call }
pub fn new(call: IncomingCall, app_state: Weak<AppState>) -> Self {
Self { call, app_state }
}
fn respond_to_call(&mut self, action: &RespondToCall, cx: &mut ViewContext<Self>) {
@ -79,15 +83,20 @@ impl IncomingCallNotification {
let join = active_call.update(cx, |active_call, cx| active_call.accept_incoming(cx));
let caller_user_id = self.call.calling_user.id;
let initial_project_id = self.call.initial_project.as_ref().map(|project| project.id);
cx.spawn(|_, mut cx| async move {
cx.spawn(|this, mut cx| async move {
join.await?;
if let Some(project_id) = initial_project_id {
cx.update(|cx| {
cx.dispatch_global_action(JoinProject {
project_id,
follow_user_id: caller_user_id,
})
});
this.update(&mut cx, |this, cx| {
if let Some(app_state) = this.app_state.upgrade() {
workspace::join_remote_project(
project_id,
caller_user_id,
app_state,
cx,
)
.detach_and_log_err(cx);
}
})?;
}
anyhow::Ok(())
})

View file

@ -2,22 +2,17 @@ use call::{room, ActiveCall};
use client::User;
use collections::HashMap;
use gpui::{
actions,
elements::*,
geometry::{rect::RectF, vector::vec2f},
platform::{CursorStyle, MouseButton, WindowBounds, WindowKind, WindowOptions},
AppContext, Entity, View, ViewContext,
};
use settings::Settings;
use std::sync::Arc;
use workspace::JoinProject;
actions!(project_shared_notification, [DismissProject]);
pub fn init(cx: &mut AppContext) {
cx.add_action(ProjectSharedNotification::join);
cx.add_action(ProjectSharedNotification::dismiss);
use std::sync::{Arc, Weak};
use workspace::AppState;
pub fn init(app_state: &Arc<AppState>, cx: &mut AppContext) {
let app_state = Arc::downgrade(app_state);
let active_call = ActiveCall::global(cx);
let mut notification_windows = HashMap::default();
cx.subscribe(&active_call, move |_, event, cx| match event {
@ -50,6 +45,7 @@ pub fn init(cx: &mut AppContext) {
owner.clone(),
*project_id,
worktree_root_names.clone(),
app_state.clone(),
)
},
);
@ -82,23 +78,33 @@ pub struct ProjectSharedNotification {
project_id: u64,
worktree_root_names: Vec<String>,
owner: Arc<User>,
app_state: Weak<AppState>,
}
impl ProjectSharedNotification {
fn new(owner: Arc<User>, project_id: u64, worktree_root_names: Vec<String>) -> Self {
fn new(
owner: Arc<User>,
project_id: u64,
worktree_root_names: Vec<String>,
app_state: Weak<AppState>,
) -> Self {
Self {
project_id,
worktree_root_names,
owner,
app_state,
}
}
fn join(&mut self, _: &JoinProject, cx: &mut ViewContext<Self>) {
fn join(&mut self, cx: &mut ViewContext<Self>) {
cx.remove_window();
cx.propagate_action();
if let Some(app_state) = self.app_state.upgrade() {
workspace::join_remote_project(self.project_id, self.owner.id, app_state, cx)
.detach_and_log_err(cx);
}
}
fn dismiss(&mut self, _: &DismissProject, cx: &mut ViewContext<Self>) {
fn dismiss(&mut self, cx: &mut ViewContext<Self>) {
cx.remove_window();
}
@ -161,9 +167,6 @@ impl ProjectSharedNotification {
enum Open {}
enum Dismiss {}
let project_id = self.project_id;
let owner_user_id = self.owner.id;
Flex::column()
.with_child(
MouseEventHandler::<Open, Self>::new(0, cx, |_, cx| {
@ -174,12 +177,7 @@ impl ProjectSharedNotification {
.with_style(theme.open_button.container)
})
.with_cursor_style(CursorStyle::PointingHand)
.on_click(MouseButton::Left, move |_, _, cx| {
cx.dispatch_action(JoinProject {
project_id,
follow_user_id: owner_user_id,
});
})
.on_click(MouseButton::Left, move |_, this, cx| this.join(cx))
.flex(1., true),
)
.with_child(
@ -191,8 +189,8 @@ impl ProjectSharedNotification {
.with_style(theme.dismiss_button.container)
})
.with_cursor_style(CursorStyle::PointingHand)
.on_click(MouseButton::Left, |_, _, cx| {
cx.dispatch_action(DismissProject);
.on_click(MouseButton::Left, |_, this, cx| {
this.dismiss(cx);
})
.flex(1., true),
)