Show a different message when participant is active on unshared project
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
29c3b81a0a
commit
4504b36c8f
8 changed files with 97 additions and 54 deletions
|
@ -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)) => {
|
||||||
project_id: project.id,
|
Ok(Self::SharedProject {
|
||||||
}),
|
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)]
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
)]
|
)]
|
||||||
|
|
|
@ -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!(
|
||||||
|
|
|
@ -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,20 +136,10 @@ 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?;
|
.detach_and_log_err(cx);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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!(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue