Set room location when active workspace changes
This commit is contained in:
parent
78e3370c1e
commit
383c21046f
7 changed files with 119 additions and 20 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -7084,6 +7084,7 @@ name = "workspace"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"call",
|
||||||
"client",
|
"client",
|
||||||
"collections",
|
"collections",
|
||||||
"context_menu",
|
"context_menu",
|
||||||
|
|
|
@ -76,6 +76,10 @@ impl CollabTitlebarItem {
|
||||||
let mut subscriptions = Vec::new();
|
let mut subscriptions = Vec::new();
|
||||||
subscriptions.push(cx.observe(workspace, |_, _, cx| cx.notify()));
|
subscriptions.push(cx.observe(workspace, |_, _, cx| cx.notify()));
|
||||||
subscriptions.push(cx.observe(&active_call, |_, _, cx| cx.notify()));
|
subscriptions.push(cx.observe(&active_call, |_, _, cx| cx.notify()));
|
||||||
|
subscriptions.push(cx.observe_window_activation(|this, active, cx| {
|
||||||
|
this.window_activation_changed(active, cx)
|
||||||
|
}));
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
workspace: workspace.downgrade(),
|
workspace: workspace.downgrade(),
|
||||||
contacts_popover: None,
|
contacts_popover: None,
|
||||||
|
@ -83,14 +87,43 @@ impl CollabTitlebarItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn window_activation_changed(&mut self, active: bool, cx: &mut ViewContext<Self>) {
|
||||||
|
let workspace = self.workspace.upgrade(cx);
|
||||||
|
let room = ActiveCall::global(cx).read(cx).room().cloned();
|
||||||
|
if let Some((workspace, room)) = workspace.zip(room) {
|
||||||
|
let workspace = workspace.read(cx);
|
||||||
|
let project = if !active {
|
||||||
|
None
|
||||||
|
} else if workspace.project().read(cx).remote_id().is_some() {
|
||||||
|
Some(workspace.project().clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
room.update(cx, |room, cx| {
|
||||||
|
room.set_location(project.as_ref(), cx)
|
||||||
|
.detach_and_log_err(cx);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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) {
|
||||||
if let Some(room) = ActiveCall::global(cx).read(cx).room() {
|
if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() {
|
||||||
|
let window_id = cx.window_id();
|
||||||
let room_id = room.read(cx).id();
|
let room_id = room.read(cx).id();
|
||||||
let project = workspace.read(cx).project().clone();
|
let project = workspace.read(cx).project().clone();
|
||||||
project
|
let share = project.update(cx, |project, cx| project.share(room_id, cx));
|
||||||
.update(cx, |project, cx| project.share(room_id, cx))
|
cx.spawn_weak(|_, mut cx| async move {
|
||||||
.detach_and_log_err(cx);
|
share.await?;
|
||||||
|
if cx.update(|cx| cx.window_is_active(window_id)) {
|
||||||
|
room.update(&mut cx, |room, cx| {
|
||||||
|
room.set_location(Some(&project), cx).detach_and_log_err(cx);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
anyhow::Ok(())
|
||||||
|
})
|
||||||
|
.detach_and_log_err(cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,7 @@ pub struct Workspace {
|
||||||
pub notifications: Notifications,
|
pub notifications: Notifications,
|
||||||
pub joining_project_avatar: ImageStyle,
|
pub joining_project_avatar: ImageStyle,
|
||||||
pub joining_project_message: ContainedText,
|
pub joining_project_message: ContainedText,
|
||||||
|
pub external_location_message: ContainedText,
|
||||||
pub dock: Dock,
|
pub dock: Dock,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,15 @@ path = "src/workspace.rs"
|
||||||
doctest = false
|
doctest = false
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
test-support = ["client/test-support", "project/test-support", "settings/test-support"]
|
test-support = [
|
||||||
|
"call/test-support",
|
||||||
|
"client/test-support",
|
||||||
|
"project/test-support",
|
||||||
|
"settings/test-support"
|
||||||
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
call = { path = "../call" }
|
||||||
client = { path = "../client" }
|
client = { path = "../client" }
|
||||||
collections = { path = "../collections" }
|
collections = { path = "../collections" }
|
||||||
context_menu = { path = "../context_menu" }
|
context_menu = { path = "../context_menu" }
|
||||||
|
@ -32,6 +38,7 @@ serde_json = { version = "1.0", features = ["preserve_order"] }
|
||||||
smallvec = { version = "1.6", features = ["union"] }
|
smallvec = { version = "1.6", features = ["union"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
call = { path = "../call", features = ["test-support"] }
|
||||||
client = { path = "../client", features = ["test-support"] }
|
client = { path = "../client", features = ["test-support"] }
|
||||||
gpui = { path = "../gpui", features = ["test-support"] }
|
gpui = { path = "../gpui", features = ["test-support"] }
|
||||||
project = { path = "../project", features = ["test-support"] }
|
project = { path = "../project", features = ["test-support"] }
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
use crate::{FollowerStatesByLeader, Pane};
|
use crate::{FollowerStatesByLeader, Pane};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
|
use call::ActiveCall;
|
||||||
use client::PeerId;
|
use client::PeerId;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use gpui::{elements::*, Axis, Border, ViewHandle};
|
use gpui::{elements::*, AppContext, Axis, Border, ViewHandle};
|
||||||
use project::Collaborator;
|
use project::Collaborator;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use theme::Theme;
|
use theme::Theme;
|
||||||
|
@ -56,11 +57,14 @@ impl PaneGroup {
|
||||||
|
|
||||||
pub(crate) fn render(
|
pub(crate) fn render(
|
||||||
&self,
|
&self,
|
||||||
|
project_id: Option<u64>,
|
||||||
theme: &Theme,
|
theme: &Theme,
|
||||||
follower_states: &FollowerStatesByLeader,
|
follower_states: &FollowerStatesByLeader,
|
||||||
collaborators: &HashMap<PeerId, Collaborator>,
|
collaborators: &HashMap<PeerId, Collaborator>,
|
||||||
|
cx: &AppContext,
|
||||||
) -> ElementBox {
|
) -> ElementBox {
|
||||||
self.root.render(theme, follower_states, collaborators)
|
self.root
|
||||||
|
.render(project_id, theme, follower_states, collaborators, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn panes(&self) -> Vec<&ViewHandle<Pane>> {
|
pub(crate) fn panes(&self) -> Vec<&ViewHandle<Pane>> {
|
||||||
|
@ -100,13 +104,14 @@ impl Member {
|
||||||
|
|
||||||
pub fn render(
|
pub fn render(
|
||||||
&self,
|
&self,
|
||||||
|
project_id: Option<u64>,
|
||||||
theme: &Theme,
|
theme: &Theme,
|
||||||
follower_states: &FollowerStatesByLeader,
|
follower_states: &FollowerStatesByLeader,
|
||||||
collaborators: &HashMap<PeerId, Collaborator>,
|
collaborators: &HashMap<PeerId, Collaborator>,
|
||||||
|
cx: &AppContext,
|
||||||
) -> ElementBox {
|
) -> ElementBox {
|
||||||
match self {
|
match self {
|
||||||
Member::Pane(pane) => {
|
Member::Pane(pane) => {
|
||||||
let mut border = Border::default();
|
|
||||||
let leader = follower_states
|
let leader = follower_states
|
||||||
.iter()
|
.iter()
|
||||||
.find_map(|(leader_id, follower_states)| {
|
.find_map(|(leader_id, follower_states)| {
|
||||||
|
@ -116,21 +121,61 @@ impl Member {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.and_then(|leader_id| collaborators.get(leader_id));
|
.and_then(|leader_id| {
|
||||||
if let Some(leader) = leader {
|
let room = ActiveCall::global(cx).read(cx).room()?.read(cx);
|
||||||
let leader_color = theme
|
let collaborator = collaborators.get(leader_id)?;
|
||||||
.editor
|
let participant = room.remote_participants().get(&leader_id)?;
|
||||||
.replica_selection_style(leader.replica_id)
|
Some((collaborator.replica_id, participant))
|
||||||
.cursor;
|
});
|
||||||
border = Border::all(theme.workspace.leader_border_width, leader_color);
|
|
||||||
|
if let Some((replica_id, leader)) = leader {
|
||||||
|
let view = match leader.location {
|
||||||
|
call::ParticipantLocation::Project {
|
||||||
|
project_id: leader_project_id,
|
||||||
|
} => {
|
||||||
|
if Some(leader_project_id) == project_id {
|
||||||
|
ChildView::new(pane).boxed()
|
||||||
|
} else {
|
||||||
|
Label::new(
|
||||||
|
format!(
|
||||||
|
"Follow {} on their currently active project",
|
||||||
|
leader.user.github_login,
|
||||||
|
),
|
||||||
|
theme.workspace.external_location_message.text.clone(),
|
||||||
|
)
|
||||||
|
.contained()
|
||||||
|
.with_style(theme.workspace.external_location_message.container)
|
||||||
|
.aligned()
|
||||||
|
.boxed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
call::ParticipantLocation::External => Label::new(
|
||||||
|
format!(
|
||||||
|
"{} is viewing a window outside of Zed",
|
||||||
|
leader.user.github_login
|
||||||
|
),
|
||||||
|
theme.workspace.external_location_message.text.clone(),
|
||||||
|
)
|
||||||
|
.contained()
|
||||||
|
.with_style(theme.workspace.external_location_message.container)
|
||||||
|
.aligned()
|
||||||
|
.boxed(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let leader_color = theme.editor.replica_selection_style(replica_id).cursor;
|
||||||
|
let mut border = Border::all(theme.workspace.leader_border_width, leader_color);
|
||||||
border
|
border
|
||||||
.color
|
.color
|
||||||
.fade_out(1. - theme.workspace.leader_border_opacity);
|
.fade_out(1. - theme.workspace.leader_border_opacity);
|
||||||
border.overlay = true;
|
border.overlay = true;
|
||||||
|
Container::new(view).with_border(border).boxed()
|
||||||
|
} else {
|
||||||
|
ChildView::new(pane).boxed()
|
||||||
}
|
}
|
||||||
ChildView::new(pane).contained().with_border(border).boxed()
|
|
||||||
}
|
}
|
||||||
Member::Axis(axis) => axis.render(theme, follower_states, collaborators),
|
Member::Axis(axis) => {
|
||||||
|
axis.render(project_id, theme, follower_states, collaborators, cx)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,14 +277,17 @@ impl PaneAxis {
|
||||||
|
|
||||||
fn render(
|
fn render(
|
||||||
&self,
|
&self,
|
||||||
|
project_id: Option<u64>,
|
||||||
theme: &Theme,
|
theme: &Theme,
|
||||||
follower_state: &FollowerStatesByLeader,
|
follower_state: &FollowerStatesByLeader,
|
||||||
collaborators: &HashMap<PeerId, Collaborator>,
|
collaborators: &HashMap<PeerId, Collaborator>,
|
||||||
|
cx: &AppContext,
|
||||||
) -> ElementBox {
|
) -> ElementBox {
|
||||||
let last_member_ix = self.members.len() - 1;
|
let last_member_ix = self.members.len() - 1;
|
||||||
Flex::new(self.axis)
|
Flex::new(self.axis)
|
||||||
.with_children(self.members.iter().enumerate().map(|(ix, member)| {
|
.with_children(self.members.iter().enumerate().map(|(ix, member)| {
|
||||||
let mut member = member.render(theme, follower_state, collaborators);
|
let mut member =
|
||||||
|
member.render(project_id, theme, follower_state, collaborators, cx);
|
||||||
if ix < last_member_ix {
|
if ix < last_member_ix {
|
||||||
let mut border = theme.workspace.pane_divider;
|
let mut border = theme.workspace.pane_divider;
|
||||||
border.left = false;
|
border.left = false;
|
||||||
|
|
|
@ -12,7 +12,8 @@ mod status_bar;
|
||||||
mod toolbar;
|
mod toolbar;
|
||||||
|
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use client::{proto, Client, Contact, PeerId, Subscription, TypedEnvelope, UserStore};
|
use call::ActiveCall;
|
||||||
|
use client::{proto, Client, Contact, PeerId, TypedEnvelope, UserStore};
|
||||||
use collections::{hash_map, HashMap, HashSet};
|
use collections::{hash_map, HashMap, HashSet};
|
||||||
use dock::{DefaultItemFactory, Dock, ToggleDockButton};
|
use dock::{DefaultItemFactory, Dock, ToggleDockButton};
|
||||||
use drag_and_drop::DragAndDrop;
|
use drag_and_drop::DragAndDrop;
|
||||||
|
@ -860,7 +861,7 @@ pub struct Workspace {
|
||||||
weak_self: WeakViewHandle<Self>,
|
weak_self: WeakViewHandle<Self>,
|
||||||
client: Arc<Client>,
|
client: Arc<Client>,
|
||||||
user_store: ModelHandle<client::UserStore>,
|
user_store: ModelHandle<client::UserStore>,
|
||||||
remote_entity_subscription: Option<Subscription>,
|
remote_entity_subscription: Option<client::Subscription>,
|
||||||
fs: Arc<dyn Fs>,
|
fs: Arc<dyn Fs>,
|
||||||
modal: Option<AnyViewHandle>,
|
modal: Option<AnyViewHandle>,
|
||||||
center: PaneGroup,
|
center: PaneGroup,
|
||||||
|
@ -880,6 +881,7 @@ pub struct Workspace {
|
||||||
last_leaders_by_pane: HashMap<WeakViewHandle<Pane>, PeerId>,
|
last_leaders_by_pane: HashMap<WeakViewHandle<Pane>, PeerId>,
|
||||||
window_edited: bool,
|
window_edited: bool,
|
||||||
_observe_current_user: Task<()>,
|
_observe_current_user: Task<()>,
|
||||||
|
_active_call_observation: gpui::Subscription,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -1015,6 +1017,7 @@ impl Workspace {
|
||||||
last_leaders_by_pane: Default::default(),
|
last_leaders_by_pane: Default::default(),
|
||||||
window_edited: false,
|
window_edited: false,
|
||||||
_observe_current_user,
|
_observe_current_user,
|
||||||
|
_active_call_observation: cx.observe(&ActiveCall::global(cx), |_, _, cx| cx.notify()),
|
||||||
};
|
};
|
||||||
this.project_remote_id_changed(this.project.read(cx).remote_id(), cx);
|
this.project_remote_id_changed(this.project.read(cx).remote_id(), cx);
|
||||||
cx.defer(|this, cx| this.update_window_title(cx));
|
cx.defer(|this, cx| this.update_window_title(cx));
|
||||||
|
@ -2430,9 +2433,11 @@ impl View for Workspace {
|
||||||
Flex::column()
|
Flex::column()
|
||||||
.with_child(
|
.with_child(
|
||||||
FlexItem::new(self.center.render(
|
FlexItem::new(self.center.render(
|
||||||
|
self.project.read(cx).remote_id(),
|
||||||
&theme,
|
&theme,
|
||||||
&self.follower_states_by_leader,
|
&self.follower_states_by_leader,
|
||||||
self.project.read(cx).collaborators(),
|
self.project.read(cx).collaborators(),
|
||||||
|
cx,
|
||||||
))
|
))
|
||||||
.flex(1., true)
|
.flex(1., true)
|
||||||
.boxed(),
|
.boxed(),
|
||||||
|
|
|
@ -48,6 +48,10 @@ export default function workspace(theme: Theme) {
|
||||||
padding: 12,
|
padding: 12,
|
||||||
...text(theme, "sans", "primary", { size: "lg" }),
|
...text(theme, "sans", "primary", { size: "lg" }),
|
||||||
},
|
},
|
||||||
|
externalLocationMessage: {
|
||||||
|
padding: 12,
|
||||||
|
...text(theme, "sans", "primary", { size: "lg" }),
|
||||||
|
},
|
||||||
leaderBorderOpacity: 0.7,
|
leaderBorderOpacity: 0.7,
|
||||||
leaderBorderWidth: 2.0,
|
leaderBorderWidth: 2.0,
|
||||||
tabBar: tabBar(theme),
|
tabBar: tabBar(theme),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue