Show a different message when participant is active on unshared project

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Antonio Scandurra 2022-10-11 15:24:31 +02:00
parent 29c3b81a0a
commit 4504b36c8f
8 changed files with 97 additions and 54 deletions

View file

@ -1,28 +1,37 @@
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use client::{proto, User}; use client::{proto, User};
use gpui::WeakModelHandle;
use project::Project;
use std::sync::Arc; use std::sync::Arc;
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ParticipantLocation { pub enum ParticipantLocation {
Project { project_id: u64 }, SharedProject { project_id: u64 },
UnsharedProject,
External, External,
} }
impl ParticipantLocation { impl ParticipantLocation {
pub fn from_proto(location: Option<proto::ParticipantLocation>) -> Result<Self> { pub fn from_proto(location: Option<proto::ParticipantLocation>) -> Result<Self> {
match location.and_then(|l| l.variant) { match location.and_then(|l| l.variant) {
Some(proto::participant_location::Variant::Project(project)) => Ok(Self::Project { Some(proto::participant_location::Variant::SharedProject(project)) => {
Ok(Self::SharedProject {
project_id: project.id, project_id: project.id,
}), })
}
Some(proto::participant_location::Variant::UnsharedProject(_)) => {
Ok(Self::UnsharedProject)
}
Some(proto::participant_location::Variant::External(_)) => Ok(Self::External), Some(proto::participant_location::Variant::External(_)) => Ok(Self::External),
None => Err(anyhow!("participant location was not provided")), None => Err(anyhow!("participant location was not provided")),
} }
} }
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Default)]
pub struct LocalParticipant { pub struct LocalParticipant {
pub projects: Vec<proto::ParticipantProject>, pub projects: Vec<proto::ParticipantProject>,
pub active_project: Option<WeakModelHandle<Project>>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]

View file

@ -395,13 +395,26 @@ impl Room {
}) })
.collect(), .collect(),
}); });
cx.spawn_weak(|_, mut cx| async move { cx.spawn(|this, mut cx| async move {
let response = request.await?; let response = request.await?;
project project
.update(&mut cx, |project, cx| { .update(&mut cx, |project, cx| {
project.shared(response.project_id, cx) project.shared(response.project_id, cx)
}) })
.await?; .await?;
// If the user's location is in this project, it changes from UnsharedProject to SharedProject.
this.update(&mut cx, |this, cx| {
let active_project = this.local_participant.active_project.as_ref();
if active_project.map_or(false, |location| *location == project) {
this.set_location(Some(&project), cx)
} else {
Task::ready(Ok(()))
}
})
.await?;
Ok(response.project_id) Ok(response.project_id)
}) })
} }
@ -418,17 +431,22 @@ impl Room {
let client = self.client.clone(); let client = self.client.clone();
let room_id = self.id; let room_id = self.id;
let location = if let Some(project) = project { let location = if let Some(project) = project {
self.local_participant.active_project = Some(project.downgrade());
if let Some(project_id) = project.read(cx).remote_id() { if let Some(project_id) = project.read(cx).remote_id() {
proto::participant_location::Variant::Project( proto::participant_location::Variant::SharedProject(
proto::participant_location::Project { id: project_id }, proto::participant_location::SharedProject { id: project_id },
) )
} else { } else {
return Task::ready(Err(anyhow!("project is not shared"))); proto::participant_location::Variant::UnsharedProject(
proto::participant_location::UnsharedProject {},
)
} }
} else { } else {
self.local_participant.active_project = None;
proto::participant_location::Variant::External(proto::participant_location::External {}) proto::participant_location::Variant::External(proto::participant_location::External {})
}; };
cx.notify();
cx.foreground().spawn(async move { cx.foreground().spawn(async move {
client client
.request(proto::UpdateParticipantLocation { .request(proto::UpdateParticipantLocation {

View file

@ -946,6 +946,22 @@ async fn test_room_location(
} }
}); });
room_a
.update(cx_a, |room, cx| room.set_location(Some(&project_a), cx))
.await
.unwrap();
deterministic.run_until_parked();
assert!(a_notified.take());
assert_eq!(
participant_locations(&room_a, cx_a),
vec![("user_b".to_string(), ParticipantLocation::External)]
);
assert!(b_notified.take());
assert_eq!(
participant_locations(&room_b, cx_b),
vec![("user_a".to_string(), ParticipantLocation::UnsharedProject)]
);
let project_a_id = active_call_a let project_a_id = active_call_a
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx)) .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await .await
@ -959,7 +975,12 @@ async fn test_room_location(
assert!(b_notified.take()); assert!(b_notified.take());
assert_eq!( assert_eq!(
participant_locations(&room_b, cx_b), participant_locations(&room_b, cx_b),
vec![("user_a".to_string(), ParticipantLocation::External)] vec![(
"user_a".to_string(),
ParticipantLocation::SharedProject {
project_id: project_a_id
}
)]
); );
let project_b_id = active_call_b let project_b_id = active_call_b
@ -973,27 +994,11 @@ async fn test_room_location(
vec![("user_b".to_string(), ParticipantLocation::External)] vec![("user_b".to_string(), ParticipantLocation::External)]
); );
assert!(b_notified.take()); assert!(b_notified.take());
assert_eq!(
participant_locations(&room_b, cx_b),
vec![("user_a".to_string(), ParticipantLocation::External)]
);
room_a
.update(cx_a, |room, cx| room.set_location(Some(&project_a), cx))
.await
.unwrap();
deterministic.run_until_parked();
assert!(a_notified.take());
assert_eq!(
participant_locations(&room_a, cx_a),
vec![("user_b".to_string(), ParticipantLocation::External)]
);
assert!(b_notified.take());
assert_eq!( assert_eq!(
participant_locations(&room_b, cx_b), participant_locations(&room_b, cx_b),
vec![( vec![(
"user_a".to_string(), "user_a".to_string(),
ParticipantLocation::Project { ParticipantLocation::SharedProject {
project_id: project_a_id project_id: project_a_id
} }
)] )]
@ -1009,7 +1014,7 @@ async fn test_room_location(
participant_locations(&room_a, cx_a), participant_locations(&room_a, cx_a),
vec![( vec![(
"user_b".to_string(), "user_b".to_string(),
ParticipantLocation::Project { ParticipantLocation::SharedProject {
project_id: project_b_id project_id: project_b_id
} }
)] )]
@ -1019,7 +1024,7 @@ async fn test_room_location(
participant_locations(&room_b, cx_b), participant_locations(&room_b, cx_b),
vec![( vec![(
"user_a".to_string(), "user_a".to_string(),
ParticipantLocation::Project { ParticipantLocation::SharedProject {
project_id: project_a_id project_id: project_a_id
} }
)] )]
@ -1040,7 +1045,7 @@ async fn test_room_location(
participant_locations(&room_b, cx_b), participant_locations(&room_b, cx_b),
vec![( vec![(
"user_a".to_string(), "user_a".to_string(),
ParticipantLocation::Project { ParticipantLocation::SharedProject {
project_id: project_a_id project_id: project_a_id
} }
)] )]

View file

@ -684,7 +684,7 @@ impl Store {
.rooms .rooms
.get_mut(&room_id) .get_mut(&room_id)
.ok_or_else(|| anyhow!("no such room"))?; .ok_or_else(|| anyhow!("no such room"))?;
if let Some(proto::participant_location::Variant::Project(project)) = if let Some(proto::participant_location::Variant::SharedProject(project)) =
location.variant.as_ref() location.variant.as_ref()
{ {
anyhow::ensure!( anyhow::ensure!(

View file

@ -121,14 +121,11 @@ impl CollabTitlebarItem {
let room = ActiveCall::global(cx).read(cx).room().cloned(); let room = ActiveCall::global(cx).read(cx).room().cloned();
if let Some((workspace, room)) = workspace.zip(room) { if let Some((workspace, room)) = workspace.zip(room) {
let workspace = workspace.read(cx); let workspace = workspace.read(cx);
let project = if !active { let project = if active {
None
} else if workspace.project().read(cx).remote_id().is_some() {
Some(workspace.project().clone()) Some(workspace.project().clone())
} else { } else {
None None
}; };
room.update(cx, |room, cx| { room.update(cx, |room, cx| {
room.set_location(project.as_ref(), cx) room.set_location(project.as_ref(), cx)
.detach_and_log_err(cx); .detach_and_log_err(cx);
@ -139,19 +136,9 @@ impl CollabTitlebarItem {
fn share_project(&mut self, _: &ShareProject, cx: &mut ViewContext<Self>) { fn share_project(&mut self, _: &ShareProject, cx: &mut ViewContext<Self>) {
if let Some(workspace) = self.workspace.upgrade(cx) { if let Some(workspace) = self.workspace.upgrade(cx) {
let active_call = ActiveCall::global(cx); let active_call = ActiveCall::global(cx);
let window_id = cx.window_id();
let project = workspace.read(cx).project().clone(); let project = workspace.read(cx).project().clone();
let share = active_call.update(cx, |call, cx| call.share_project(project.clone(), cx)); active_call
cx.spawn_weak(|_, mut cx| async move { .update(cx, |call, cx| call.share_project(project, cx))
share.await?;
if cx.update(|cx| cx.window_is_active(window_id)) {
active_call.update(&mut cx, |call, cx| {
call.set_location(Some(&project), cx).detach_and_log_err(cx);
});
}
anyhow::Ok(())
})
.detach_and_log_err(cx); .detach_and_log_err(cx);
} }
} }
@ -363,7 +350,7 @@ impl CollabTitlebarItem {
let mut avatar_style; let mut avatar_style;
if let Some((_, _, location)) = peer.as_ref() { if let Some((_, _, location)) = peer.as_ref() {
if let ParticipantLocation::Project { project_id } = *location { if let ParticipantLocation::SharedProject { project_id } = *location {
if Some(project_id) == workspace.read(cx).project().read(cx).remote_id() { if Some(project_id) == workspace.read(cx).project().read(cx).remote_id() {
avatar_style = theme.workspace.titlebar.avatar; avatar_style = theme.workspace.titlebar.avatar;
} else { } else {
@ -428,7 +415,7 @@ impl CollabTitlebarItem {
cx, cx,
) )
.boxed() .boxed()
} else if let ParticipantLocation::Project { project_id } = location { } else if let ParticipantLocation::SharedProject { project_id } = location {
let user_id = user.id; let user_id = user.id;
MouseEventHandler::<JoinProject>::new(peer_id.0 as usize, cx, move |_, _| content) MouseEventHandler::<JoinProject>::new(peer_id.0 as usize, cx, move |_, _| content)
.with_cursor_style(CursorStyle::PointingHand) .with_cursor_style(CursorStyle::PointingHand)

View file

@ -4687,6 +4687,12 @@ impl<T> PartialEq for WeakModelHandle<T> {
impl<T> Eq for WeakModelHandle<T> {} impl<T> Eq for WeakModelHandle<T> {}
impl<T: Entity> PartialEq<ModelHandle<T>> for WeakModelHandle<T> {
fn eq(&self, other: &ModelHandle<T>) -> bool {
self.model_id == other.model_id
}
}
impl<T> Clone for WeakModelHandle<T> { impl<T> Clone for WeakModelHandle<T> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {

View file

@ -174,14 +174,17 @@ message ParticipantProject {
message ParticipantLocation { message ParticipantLocation {
oneof variant { oneof variant {
Project project = 1; SharedProject shared_project = 1;
External external = 2; UnsharedProject unshared_project = 2;
External external = 3;
} }
message Project { message SharedProject {
uint64 id = 1; uint64 id = 1;
} }
message UnsharedProject {}
message External {} message External {}
} }

View file

@ -138,7 +138,7 @@ impl Member {
border.overlay = true; border.overlay = true;
match leader.location { match leader.location {
call::ParticipantLocation::Project { call::ParticipantLocation::SharedProject {
project_id: leader_project_id, project_id: leader_project_id,
} => { } => {
if Some(leader_project_id) == project.read(cx).remote_id() { if Some(leader_project_id) == project.read(cx).remote_id() {
@ -183,6 +183,21 @@ impl Member {
) )
} }
} }
call::ParticipantLocation::UnsharedProject => Some(
Label::new(
format!(
"{} is viewing an unshared Zed project",
leader.user.github_login
),
theme.workspace.external_location_message.text.clone(),
)
.contained()
.with_style(theme.workspace.external_location_message.container)
.aligned()
.bottom()
.right()
.boxed(),
),
call::ParticipantLocation::External => Some( call::ParticipantLocation::External => Some(
Label::new( Label::new(
format!( format!(