Do more on channel join (#7268)

This change makes it so that if you are the first to join a channel,
your project is automatically shared.

It also makes it so that if you join a channel via a link and there are
no shared projects, you open the notes instead of an empty workspace
with nothing.

This is to try and address the discoverability of project sharing: we've
had
two reviews that have talked about channels, but not talked about
sharing
projects into them, which makes me suspect they didn't know about the
feature.

Release Notes:

- Added a setting `share_on_join` (defaulting to true). When set, and
you join an empty channel, your project is automatically shared.
This commit is contained in:
Conrad Irwin 2024-02-02 09:52:30 -07:00 committed by GitHub
parent 6f6cb53fad
commit 074acacdf7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 68 additions and 5 deletions

View file

@ -104,8 +104,10 @@
"show_whitespaces": "selection", "show_whitespaces": "selection",
// Settings related to calls in Zed // Settings related to calls in Zed
"calls": { "calls": {
// Join calls with the microphone muted by default // Join calls with the microphone live by default
"mute_on_join": false "mute_on_join": false,
// Share your project when you are the first to join a channel
"share_on_join": true
}, },
// Scrollbar related settings // Scrollbar related settings
"scrollbar": { "scrollbar": {

View file

@ -7,6 +7,7 @@ use settings::Settings;
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
pub struct CallSettings { pub struct CallSettings {
pub mute_on_join: bool, pub mute_on_join: bool,
pub share_on_join: bool,
} }
/// Configuration of voice calls in Zed. /// Configuration of voice calls in Zed.
@ -16,6 +17,11 @@ pub struct CallSettingsContent {
/// ///
/// Default: false /// Default: false
pub mute_on_join: Option<bool>, pub mute_on_join: Option<bool>,
/// Whether your current project should be shared when joining an empty channel.
///
/// Default: true
pub share_on_join: Option<bool>,
} }
impl Settings for CallSettings { impl Settings for CallSettings {

View file

@ -617,6 +617,10 @@ impl Room {
self.local_participant.role == proto::ChannelRole::Admin self.local_participant.role == proto::ChannelRole::Admin
} }
pub fn local_participant_is_guest(&self) -> bool {
self.local_participant.role == proto::ChannelRole::Guest
}
pub fn set_participant_role( pub fn set_participant_role(
&mut self, &mut self,
user_id: u64, user_id: u64,
@ -1202,7 +1206,7 @@ impl Room {
}) })
} }
pub(crate) fn share_project( pub fn share_project(
&mut self, &mut self,
project: Model<Project>, project: Model<Project>,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,

View file

@ -40,7 +40,7 @@ use util::{maybe, ResultExt, TryFutureExt};
use workspace::{ use workspace::{
dock::{DockPosition, Panel, PanelEvent}, dock::{DockPosition, Panel, PanelEvent},
notifications::{DetachAndPromptErr, NotifyResultExt, NotifyTaskExt}, notifications::{DetachAndPromptErr, NotifyResultExt, NotifyTaskExt},
Workspace, OpenChannelNotes, Workspace,
}; };
actions!( actions!(
@ -69,6 +69,19 @@ pub fn init(cx: &mut AppContext) {
workspace.register_action(|workspace, _: &ToggleFocus, cx| { workspace.register_action(|workspace, _: &ToggleFocus, cx| {
workspace.toggle_panel_focus::<CollabPanel>(cx); workspace.toggle_panel_focus::<CollabPanel>(cx);
}); });
workspace.register_action(|_, _: &OpenChannelNotes, cx| {
let channel_id = ActiveCall::global(cx)
.read(cx)
.room()
.and_then(|room| room.read(cx).channel_id());
if let Some(channel_id) = channel_id {
let workspace = cx.view().clone();
cx.window_context().defer(move |cx| {
ChannelView::open(channel_id, workspace, cx).detach_and_log_err(cx)
});
}
});
}) })
.detach(); .detach();
} }

View file

@ -12,7 +12,7 @@ mod toolbar;
mod workspace_settings; mod workspace_settings;
use anyhow::{anyhow, Context as _, Result}; use anyhow::{anyhow, Context as _, Result};
use call::ActiveCall; use call::{call_settings::CallSettings, ActiveCall};
use client::{ use client::{
proto::{self, ErrorCode, PeerId}, proto::{self, ErrorCode, PeerId},
Client, ErrorExt, Status, TypedEnvelope, UserStore, Client, ErrorExt, Status, TypedEnvelope, UserStore,
@ -3974,6 +3974,8 @@ pub async fn last_opened_workspace_paths() -> Option<WorkspaceLocation> {
DB.last_workspace().await.log_err().flatten() DB.last_workspace().await.log_err().flatten()
} }
actions!(collab, [OpenChannelNotes]);
async fn join_channel_internal( async fn join_channel_internal(
channel_id: u64, channel_id: u64,
app_state: &Arc<AppState>, app_state: &Arc<AppState>,
@ -4075,6 +4077,36 @@ async fn join_channel_internal(
return Some(join_remote_project(project, host, app_state.clone(), cx)); return Some(join_remote_project(project, host, app_state.clone(), cx));
} }
// if you are the first to join a channel, share your project
if room.remote_participants().len() == 0 && !room.local_participant_is_guest() {
if let Some(workspace) = requesting_window {
let project = workspace.update(cx, |workspace, cx| {
if !CallSettings::get_global(cx).share_on_join {
return None;
}
let project = workspace.project.read(cx);
if project.is_local()
&& project.visible_worktrees(cx).any(|tree| {
tree.read(cx)
.root_entry()
.map_or(false, |entry| entry.is_dir())
})
{
Some(workspace.project.clone())
} else {
None
}
});
if let Ok(Some(project)) = project {
return Some(cx.spawn(|room, mut cx| async move {
room.update(&mut cx, |room, cx| room.share_project(project, cx))?
.await?;
Ok(())
}));
}
}
}
None None
})?; })?;
if let Some(task) = task { if let Some(task) = task {
@ -4117,6 +4149,12 @@ pub fn join_channel(
})? })?
.await?; .await?;
if result.is_ok() {
cx.update(|cx| {
cx.dispatch_action(&OpenChannelNotes);
}).log_err();
}
active_window = Some(window_handle); active_window = Some(window_handle);
} }