collab_ui.rs

  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}