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