1mod collab_titlebar_item;
2mod collaborator_list_popover;
3mod contact_finder;
4mod contact_list;
5mod contact_notification;
6mod contacts_popover;
7mod incoming_call_notification;
8mod notifications;
9mod project_shared_notification;
10mod sharing_status_indicator;
11
12use anyhow::anyhow;
13use call::ActiveCall;
14pub use collab_titlebar_item::{CollabTitlebarItem, ToggleCollaborationMenu};
15use gpui::{actions, MutableAppContext, Task};
16use std::sync::Arc;
17use workspace::{AppState, JoinProject, ToggleFollow, Workspace};
18
19actions!(collab, [ToggleScreenSharing]);
20
21pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
22 collab_titlebar_item::init(cx);
23 contact_notification::init(cx);
24 contact_list::init(cx);
25 contact_finder::init(cx);
26 contacts_popover::init(cx);
27 incoming_call_notification::init(cx);
28 project_shared_notification::init(cx);
29 sharing_status_indicator::init(cx);
30
31 cx.add_global_action(toggle_screen_sharing);
32 cx.add_global_action(move |action: &JoinProject, cx| {
33 join_project(action, app_state.clone(), cx);
34 });
35}
36
37pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut MutableAppContext) {
38 if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() {
39 let toggle_screen_sharing = room.update(cx, |room, cx| {
40 if room.is_screen_sharing() {
41 Task::ready(room.unshare_screen(cx))
42 } else {
43 room.share_screen(cx)
44 }
45 });
46 toggle_screen_sharing.detach_and_log_err(cx);
47 }
48}
49
50fn join_project(action: &JoinProject, app_state: Arc<AppState>, cx: &mut MutableAppContext) {
51 let project_id = action.project_id;
52 let follow_user_id = action.follow_user_id;
53 cx.spawn(|mut cx| async move {
54 let existing_workspace = cx.update(|cx| {
55 cx.window_ids()
56 .filter_map(|window_id| cx.root_view::<Workspace>(window_id))
57 .find(|workspace| {
58 workspace.read(cx).project().read(cx).remote_id() == Some(project_id)
59 })
60 });
61
62 let workspace = if let Some(existing_workspace) = existing_workspace {
63 existing_workspace
64 } else {
65 let active_call = cx.read(ActiveCall::global);
66 let room = active_call
67 .read_with(&cx, |call, _| call.room().cloned())
68 .ok_or_else(|| anyhow!("not in a call"))?;
69 let project = room
70 .update(&mut cx, |room, cx| {
71 room.join_project(
72 project_id,
73 app_state.languages.clone(),
74 app_state.fs.clone(),
75 cx,
76 )
77 })
78 .await?;
79
80 let (_, workspace) = cx.add_window(
81 (app_state.build_window_options)(None, None, cx.platform().as_ref()),
82 |cx| {
83 let mut workspace = Workspace::new(
84 Default::default(),
85 0,
86 project,
87 app_state.dock_default_item_factory,
88 cx,
89 );
90 (app_state.initialize_workspace)(&mut workspace, &app_state, cx);
91 workspace
92 },
93 );
94 workspace
95 };
96
97 cx.activate_window(workspace.window_id());
98 cx.platform().activate(true);
99
100 workspace.update(&mut cx, |workspace, cx| {
101 if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() {
102 let follow_peer_id = room
103 .read(cx)
104 .remote_participants()
105 .iter()
106 .find(|(_, participant)| participant.user.id == follow_user_id)
107 .map(|(_, p)| p.peer_id)
108 .or_else(|| {
109 // If we couldn't follow the given user, follow the host instead.
110 let collaborator = workspace
111 .project()
112 .read(cx)
113 .collaborators()
114 .values()
115 .find(|collaborator| collaborator.replica_id == 0)?;
116 Some(collaborator.peer_id)
117 });
118
119 if let Some(follow_peer_id) = follow_peer_id {
120 if !workspace.is_following(follow_peer_id) {
121 workspace
122 .toggle_follow(&ToggleFollow(follow_peer_id), cx)
123 .map(|follow| follow.detach_and_log_err(cx));
124 }
125 }
126 }
127 });
128
129 anyhow::Ok(())
130 })
131 .detach_and_log_err(cx);
132}