Finish up decoupling workspace from call
This commit is contained in:
parent
ebccdb64bc
commit
abe5a9c85f
5 changed files with 126 additions and 153 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1175,6 +1175,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-broadcast",
|
"async-broadcast",
|
||||||
|
"async-trait",
|
||||||
"audio2",
|
"audio2",
|
||||||
"client2",
|
"client2",
|
||||||
"collections",
|
"collections",
|
||||||
|
|
|
@ -32,6 +32,7 @@ project = { package = "project2", path = "../project2" }
|
||||||
settings = { package = "settings2", path = "../settings2" }
|
settings = { package = "settings2", path = "../settings2" }
|
||||||
util = { path = "../util" }
|
util = { path = "../util" }
|
||||||
workspace = {package = "workspace2", path = "../workspace2"}
|
workspace = {package = "workspace2", path = "../workspace2"}
|
||||||
|
async-trait.workspace = true
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
async-broadcast = "0.4"
|
async-broadcast = "0.4"
|
||||||
futures.workspace = true
|
futures.workspace = true
|
||||||
|
|
|
@ -2,24 +2,29 @@ pub mod call_settings;
|
||||||
pub mod participant;
|
pub mod participant;
|
||||||
pub mod room;
|
pub mod room;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, bail, Result};
|
||||||
|
use async_trait::async_trait;
|
||||||
use audio::Audio;
|
use audio::Audio;
|
||||||
use call_settings::CallSettings;
|
use call_settings::CallSettings;
|
||||||
use client::{proto, Client, TelemetrySettings, TypedEnvelope, User, UserStore, ZED_ALWAYS_ACTIVE};
|
use client::{
|
||||||
|
proto::{self, PeerId},
|
||||||
|
Client, TelemetrySettings, TypedEnvelope, User, UserStore, ZED_ALWAYS_ACTIVE,
|
||||||
|
};
|
||||||
use collections::HashSet;
|
use collections::HashSet;
|
||||||
use futures::{channel::oneshot, future::Shared, Future, FutureExt};
|
use futures::{channel::oneshot, future::Shared, Future, FutureExt};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
AppContext, AsyncAppContext, Context, EventEmitter, Model, ModelContext, Subscription, Task,
|
AppContext, AsyncAppContext, AsyncWindowContext, Context, EventEmitter, Model, ModelContext,
|
||||||
WeakModel,
|
Subscription, Task, View, ViewContext, WeakModel, WeakView,
|
||||||
};
|
};
|
||||||
|
pub use participant::ParticipantLocation;
|
||||||
use postage::watch;
|
use postage::watch;
|
||||||
use project::Project;
|
use project::Project;
|
||||||
use room::Event;
|
use room::Event;
|
||||||
|
pub use room::Room;
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use util::ResultExt;
|
||||||
pub use participant::ParticipantLocation;
|
use workspace::{item::ItemHandle, CallHandler, Pane, Workspace};
|
||||||
pub use room::Room;
|
|
||||||
|
|
||||||
pub fn init(client: Arc<Client>, user_store: Model<UserStore>, cx: &mut AppContext) {
|
pub fn init(client: Arc<Client>, user_store: Model<UserStore>, cx: &mut AppContext) {
|
||||||
CallSettings::register(cx);
|
CallSettings::register(cx);
|
||||||
|
@ -505,35 +510,36 @@ pub fn report_call_event_for_channel(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Call {
|
pub struct Call {
|
||||||
follower_states: HashMap<View<Pane>, FollowerState>,
|
|
||||||
active_call: Option<(Model<ActiveCall>, Vec<Subscription>)>,
|
active_call: Option<(Model<ActiveCall>, Vec<Subscription>)>,
|
||||||
parent_workspace: WeakView<Workspace>,
|
parent_workspace: WeakView<Workspace>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Call {
|
impl Call {
|
||||||
fn new(parent_workspace: WeakView<Workspace>, cx: &mut ViewContext<'_, Workspace>) -> Self {
|
pub fn new(
|
||||||
|
parent_workspace: WeakView<Workspace>,
|
||||||
|
cx: &mut ViewContext<'_, Workspace>,
|
||||||
|
) -> Box<dyn CallHandler> {
|
||||||
let mut active_call = None;
|
let mut active_call = None;
|
||||||
if cx.has_global::<Model<ActiveCall>>() {
|
if cx.has_global::<Model<ActiveCall>>() {
|
||||||
let call = cx.global::<Model<ActiveCall>>().clone();
|
let call = cx.global::<Model<ActiveCall>>().clone();
|
||||||
let subscriptions = vec![cx.subscribe(&call, Self::on_active_call_event)];
|
let subscriptions = vec![cx.subscribe(&call, Self::on_active_call_event)];
|
||||||
active_call = Some((call, subscriptions));
|
active_call = Some((call, subscriptions));
|
||||||
}
|
}
|
||||||
Self {
|
Box::new(Self {
|
||||||
follower_states: Default::default(),
|
|
||||||
active_call,
|
active_call,
|
||||||
parent_workspace,
|
parent_workspace,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
fn on_active_call_event(
|
fn on_active_call_event(
|
||||||
workspace: &mut Workspace,
|
workspace: &mut Workspace,
|
||||||
_: Model<ActiveCall>,
|
_: Model<ActiveCall>,
|
||||||
event: &call2::room::Event,
|
event: &room::Event,
|
||||||
cx: &mut ViewContext<Workspace>,
|
cx: &mut ViewContext<Workspace>,
|
||||||
) {
|
) {
|
||||||
match event {
|
match event {
|
||||||
call2::room::Event::ParticipantLocationChanged { participant_id }
|
room::Event::ParticipantLocationChanged { participant_id }
|
||||||
| call2::room::Event::RemoteVideoTracksChanged { participant_id } => {
|
| room::Event::RemoteVideoTracksChanged { participant_id } => {
|
||||||
workspace.leader_updated(*participant_id, cx);
|
workspace.leader_updated(*participant_id, cx);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -543,78 +549,6 @@ impl Call {
|
||||||
|
|
||||||
#[async_trait(?Send)]
|
#[async_trait(?Send)]
|
||||||
impl CallHandler for Call {
|
impl CallHandler for Call {
|
||||||
fn leader_updated(&mut self, leader_id: PeerId, cx: &mut ViewContext<Workspace>) -> Option<()> {
|
|
||||||
cx.notify();
|
|
||||||
|
|
||||||
let (call, _) = self.active_call.as_ref()?;
|
|
||||||
let room = call.read(cx).room()?.read(cx);
|
|
||||||
let participant = room.remote_participant_for_peer_id(leader_id)?;
|
|
||||||
let mut items_to_activate = Vec::new();
|
|
||||||
|
|
||||||
let leader_in_this_app;
|
|
||||||
let leader_in_this_project;
|
|
||||||
match participant.location {
|
|
||||||
call2::ParticipantLocation::SharedProject { project_id } => {
|
|
||||||
leader_in_this_app = true;
|
|
||||||
leader_in_this_project = Some(project_id)
|
|
||||||
== self
|
|
||||||
.parent_workspace
|
|
||||||
.update(cx, |this, cx| this.project.read(cx).remote_id())
|
|
||||||
.log_err()
|
|
||||||
.flatten();
|
|
||||||
}
|
|
||||||
call2::ParticipantLocation::UnsharedProject => {
|
|
||||||
leader_in_this_app = true;
|
|
||||||
leader_in_this_project = false;
|
|
||||||
}
|
|
||||||
call2::ParticipantLocation::External => {
|
|
||||||
leader_in_this_app = false;
|
|
||||||
leader_in_this_project = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for (pane, state) in &self.follower_states {
|
|
||||||
if state.leader_id != leader_id {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if let (Some(active_view_id), true) = (state.active_view_id, leader_in_this_app) {
|
|
||||||
if let Some(item) = state.items_by_leader_view_id.get(&active_view_id) {
|
|
||||||
if leader_in_this_project || !item.is_project_item(cx) {
|
|
||||||
items_to_activate.push((pane.clone(), item.boxed_clone()));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log::warn!(
|
|
||||||
"unknown view id {:?} for leader {:?}",
|
|
||||||
active_view_id,
|
|
||||||
leader_id
|
|
||||||
);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// todo!()
|
|
||||||
// if let Some(shared_screen) = self.shared_screen_for_peer(leader_id, pane, cx) {
|
|
||||||
// items_to_activate.push((pane.clone(), Box::new(shared_screen)));
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
for (pane, item) in items_to_activate {
|
|
||||||
let pane_was_focused = pane.read(cx).has_focus(cx);
|
|
||||||
if let Some(index) = pane.update(cx, |pane, _| pane.index_for_item(item.as_ref())) {
|
|
||||||
pane.update(cx, |pane, cx| pane.activate_item(index, false, false, cx));
|
|
||||||
} else {
|
|
||||||
pane.update(cx, |pane, mut cx| {
|
|
||||||
pane.add_item(item.boxed_clone(), false, false, None, &mut cx)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if pane_was_focused {
|
|
||||||
pane.update(cx, |pane, cx| pane.focus_active_item(cx));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn shared_screen_for_peer(
|
fn shared_screen_for_peer(
|
||||||
&self,
|
&self,
|
||||||
peer_id: PeerId,
|
peer_id: PeerId,
|
||||||
|
@ -638,12 +572,6 @@ impl CallHandler for Call {
|
||||||
// })))
|
// })))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn follower_states_mut(&mut self) -> &mut HashMap<View<Pane>, FollowerState> {
|
|
||||||
&mut self.follower_states
|
|
||||||
}
|
|
||||||
fn follower_states(&self) -> &HashMap<View<Pane>, FollowerState> {
|
|
||||||
&self.follower_states
|
|
||||||
}
|
|
||||||
fn room_id(&self, cx: &AppContext) -> Option<u64> {
|
fn room_id(&self, cx: &AppContext) -> Option<u64> {
|
||||||
Some(self.active_call.as_ref()?.0.read(cx).room()?.read(cx).id())
|
Some(self.active_call.as_ref()?.0.read(cx).room()?.read(cx).id())
|
||||||
}
|
}
|
||||||
|
@ -657,6 +585,39 @@ impl CallHandler for Call {
|
||||||
fn active_project(&self, cx: &AppContext) -> Option<WeakModel<Project>> {
|
fn active_project(&self, cx: &AppContext) -> Option<WeakModel<Project>> {
|
||||||
ActiveCall::global(cx).read(cx).location().cloned()
|
ActiveCall::global(cx).read(cx).location().cloned()
|
||||||
}
|
}
|
||||||
|
fn peer_state(
|
||||||
|
&mut self,
|
||||||
|
leader_id: PeerId,
|
||||||
|
cx: &mut ViewContext<Workspace>,
|
||||||
|
) -> Option<(bool, bool)> {
|
||||||
|
let (call, _) = self.active_call.as_ref()?;
|
||||||
|
let room = call.read(cx).room()?.read(cx);
|
||||||
|
let participant = room.remote_participant_for_peer_id(leader_id)?;
|
||||||
|
|
||||||
|
let leader_in_this_app;
|
||||||
|
let leader_in_this_project;
|
||||||
|
match participant.location {
|
||||||
|
ParticipantLocation::SharedProject { project_id } => {
|
||||||
|
leader_in_this_app = true;
|
||||||
|
leader_in_this_project = Some(project_id)
|
||||||
|
== self
|
||||||
|
.parent_workspace
|
||||||
|
.update(cx, |this, cx| this.project().read(cx).remote_id())
|
||||||
|
.log_err()
|
||||||
|
.flatten();
|
||||||
|
}
|
||||||
|
ParticipantLocation::UnsharedProject => {
|
||||||
|
leader_in_this_app = true;
|
||||||
|
leader_in_this_project = false;
|
||||||
|
}
|
||||||
|
ParticipantLocation::External => {
|
||||||
|
leader_in_this_app = false;
|
||||||
|
leader_in_this_project = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Some((leader_in_this_project, leader_in_this_app))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -15,7 +15,7 @@ mod status_bar;
|
||||||
mod toolbar;
|
mod toolbar;
|
||||||
mod workspace_settings;
|
mod workspace_settings;
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, Context as _, Result};
|
use anyhow::{anyhow, Context as _, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use client2::{
|
use client2::{
|
||||||
proto::{self, PeerId},
|
proto::{self, PeerId},
|
||||||
|
@ -207,10 +207,10 @@ pub fn init_settings(cx: &mut AppContext) {
|
||||||
ItemSettings::register(cx);
|
ItemSettings::register(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
|
pub fn init(app_state: Arc<AppState>, cx: &mut AppContext, call_factory: CallFactory) {
|
||||||
init_settings(cx);
|
init_settings(cx);
|
||||||
notifications::init(cx);
|
notifications::init(cx);
|
||||||
|
cx.set_global(call_factory);
|
||||||
// cx.add_global_action({
|
// cx.add_global_action({
|
||||||
// let app_state = Arc::downgrade(&app_state);
|
// let app_state = Arc::downgrade(&app_state);
|
||||||
// move |_: &Open, cx: &mut AppContext| {
|
// move |_: &Open, cx: &mut AppContext| {
|
||||||
|
@ -410,15 +410,13 @@ pub enum Event {
|
||||||
|
|
||||||
#[async_trait(?Send)]
|
#[async_trait(?Send)]
|
||||||
pub trait CallHandler {
|
pub trait CallHandler {
|
||||||
fn leader_updated(&mut self, leader_id: PeerId, cx: &mut ViewContext<Workspace>) -> Option<()>;
|
fn peer_state(&mut self, id: PeerId, cx: &mut ViewContext<Workspace>) -> Option<(bool, bool)>;
|
||||||
fn shared_screen_for_peer(
|
fn shared_screen_for_peer(
|
||||||
&self,
|
&self,
|
||||||
peer_id: PeerId,
|
peer_id: PeerId,
|
||||||
pane: &View<Pane>,
|
pane: &View<Pane>,
|
||||||
cx: &mut ViewContext<Workspace>,
|
cx: &mut ViewContext<Workspace>,
|
||||||
) -> Option<Box<dyn ItemHandle>>;
|
) -> Option<Box<dyn ItemHandle>>;
|
||||||
fn follower_states_mut(&mut self) -> &mut HashMap<View<Pane>, FollowerState>;
|
|
||||||
fn follower_states(&self) -> &HashMap<View<Pane>, FollowerState>;
|
|
||||||
fn room_id(&self, cx: &AppContext) -> Option<u64>;
|
fn room_id(&self, cx: &AppContext) -> Option<u64>;
|
||||||
fn is_in_room(&self, cx: &mut ViewContext<Workspace>) -> bool {
|
fn is_in_room(&self, cx: &mut ViewContext<Workspace>) -> bool {
|
||||||
self.room_id(cx).is_some()
|
self.room_id(cx).is_some()
|
||||||
|
@ -448,6 +446,7 @@ pub struct Workspace {
|
||||||
notifications: Vec<(TypeId, usize, Box<dyn NotificationHandle>)>,
|
notifications: Vec<(TypeId, usize, Box<dyn NotificationHandle>)>,
|
||||||
project: Model<Project>,
|
project: Model<Project>,
|
||||||
call_handler: Box<dyn CallHandler>,
|
call_handler: Box<dyn CallHandler>,
|
||||||
|
follower_states: HashMap<View<Pane>, FollowerState>,
|
||||||
last_leaders_by_pane: HashMap<WeakView<Pane>, PeerId>,
|
last_leaders_by_pane: HashMap<WeakView<Pane>, PeerId>,
|
||||||
window_edited: bool,
|
window_edited: bool,
|
||||||
leader_updates_tx: mpsc::UnboundedSender<(PeerId, proto::UpdateFollowers)>,
|
leader_updates_tx: mpsc::UnboundedSender<(PeerId, proto::UpdateFollowers)>,
|
||||||
|
@ -458,7 +457,6 @@ pub struct Workspace {
|
||||||
_observe_current_user: Task<Result<()>>,
|
_observe_current_user: Task<Result<()>>,
|
||||||
_schedule_serialize: Option<Task<()>>,
|
_schedule_serialize: Option<Task<()>>,
|
||||||
pane_history_timestamp: Arc<AtomicUsize>,
|
pane_history_timestamp: Arc<AtomicUsize>,
|
||||||
call_factory: CallFactory,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventEmitter<Event> for Workspace {}
|
impl EventEmitter<Event> for Workspace {}
|
||||||
|
@ -484,7 +482,6 @@ impl Workspace {
|
||||||
workspace_id: WorkspaceId,
|
workspace_id: WorkspaceId,
|
||||||
project: Model<Project>,
|
project: Model<Project>,
|
||||||
app_state: Arc<AppState>,
|
app_state: Arc<AppState>,
|
||||||
call_factory: CallFactory,
|
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
cx.observe(&project, |_, _, cx| cx.notify()).detach();
|
cx.observe(&project, |_, _, cx| cx.notify()).detach();
|
||||||
|
@ -656,6 +653,7 @@ impl Workspace {
|
||||||
];
|
];
|
||||||
|
|
||||||
cx.defer(|this, cx| this.update_window_title(cx));
|
cx.defer(|this, cx| this.update_window_title(cx));
|
||||||
|
let call_factory = cx.global::<CallFactory>();
|
||||||
Workspace {
|
Workspace {
|
||||||
window_self: window_handle,
|
window_self: window_handle,
|
||||||
weak_self: weak_handle.clone(),
|
weak_self: weak_handle.clone(),
|
||||||
|
@ -675,7 +673,7 @@ impl Workspace {
|
||||||
bottom_dock,
|
bottom_dock,
|
||||||
right_dock,
|
right_dock,
|
||||||
project: project.clone(),
|
project: project.clone(),
|
||||||
|
follower_states: Default::default(),
|
||||||
last_leaders_by_pane: Default::default(),
|
last_leaders_by_pane: Default::default(),
|
||||||
window_edited: false,
|
window_edited: false,
|
||||||
|
|
||||||
|
@ -689,7 +687,6 @@ impl Workspace {
|
||||||
subscriptions,
|
subscriptions,
|
||||||
pane_history_timestamp,
|
pane_history_timestamp,
|
||||||
workspace_actions: Default::default(),
|
workspace_actions: Default::default(),
|
||||||
call_factory,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -697,7 +694,6 @@ impl Workspace {
|
||||||
abs_paths: Vec<PathBuf>,
|
abs_paths: Vec<PathBuf>,
|
||||||
app_state: Arc<AppState>,
|
app_state: Arc<AppState>,
|
||||||
requesting_window: Option<WindowHandle<Workspace>>,
|
requesting_window: Option<WindowHandle<Workspace>>,
|
||||||
call_factory: CallFactory,
|
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Task<
|
) -> Task<
|
||||||
anyhow::Result<(
|
anyhow::Result<(
|
||||||
|
@ -748,13 +744,7 @@ impl Workspace {
|
||||||
let window = if let Some(window) = requesting_window {
|
let window = if let Some(window) = requesting_window {
|
||||||
cx.update_window(window.into(), |old_workspace, cx| {
|
cx.update_window(window.into(), |old_workspace, cx| {
|
||||||
cx.replace_root_view(|cx| {
|
cx.replace_root_view(|cx| {
|
||||||
Workspace::new(
|
Workspace::new(workspace_id, project_handle.clone(), app_state.clone(), cx)
|
||||||
workspace_id,
|
|
||||||
project_handle.clone(),
|
|
||||||
app_state.clone(),
|
|
||||||
call_factory,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
})?;
|
})?;
|
||||||
window
|
window
|
||||||
|
@ -800,13 +790,7 @@ impl Workspace {
|
||||||
let project_handle = project_handle.clone();
|
let project_handle = project_handle.clone();
|
||||||
move |cx| {
|
move |cx| {
|
||||||
cx.build_view(|cx| {
|
cx.build_view(|cx| {
|
||||||
Workspace::new(
|
Workspace::new(workspace_id, project_handle, app_state, cx)
|
||||||
workspace_id,
|
|
||||||
project_handle,
|
|
||||||
app_state,
|
|
||||||
call_factory,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})?
|
})?
|
||||||
|
@ -1067,13 +1051,7 @@ impl Workspace {
|
||||||
if self.project.read(cx).is_local() {
|
if self.project.read(cx).is_local() {
|
||||||
Task::Ready(Some(Ok(callback(self, cx))))
|
Task::Ready(Some(Ok(callback(self, cx))))
|
||||||
} else {
|
} else {
|
||||||
let task = Self::new_local(
|
let task = Self::new_local(Vec::new(), self.app_state.clone(), None, cx);
|
||||||
Vec::new(),
|
|
||||||
self.app_state.clone(),
|
|
||||||
None,
|
|
||||||
self.call_factory,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
cx.spawn(|_vh, mut cx| async move {
|
cx.spawn(|_vh, mut cx| async move {
|
||||||
let (workspace, _) = task.await?;
|
let (workspace, _) = task.await?;
|
||||||
workspace.update(&mut cx, callback)
|
workspace.update(&mut cx, callback)
|
||||||
|
@ -1302,7 +1280,7 @@ impl Workspace {
|
||||||
Some(self.prepare_to_close(false, cx))
|
Some(self.prepare_to_close(false, cx))
|
||||||
};
|
};
|
||||||
let app_state = self.app_state.clone();
|
let app_state = self.app_state.clone();
|
||||||
let call_factory = self.call_factory;
|
|
||||||
cx.spawn(|_, mut cx| async move {
|
cx.spawn(|_, mut cx| async move {
|
||||||
let window_to_replace = if let Some(close_task) = close_task {
|
let window_to_replace = if let Some(close_task) = close_task {
|
||||||
if !close_task.await? {
|
if !close_task.await? {
|
||||||
|
@ -1312,7 +1290,7 @@ impl Workspace {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
cx.update(|_, cx| open_paths(&paths, &app_state, window_to_replace, call_factory, cx))?
|
cx.update(|_, cx| open_paths(&paths, &app_state, window_to_replace, cx))?
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
|
@ -2282,7 +2260,7 @@ impl Workspace {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collaborator_left(&mut self, peer_id: PeerId, cx: &mut ViewContext<Self>) {
|
fn collaborator_left(&mut self, peer_id: PeerId, cx: &mut ViewContext<Self>) {
|
||||||
self.call_handler.follower_states_mut().retain(|_, state| {
|
self.follower_states.retain(|_, state| {
|
||||||
if state.leader_id == peer_id {
|
if state.leader_id == peer_id {
|
||||||
for item in state.items_by_leader_view_id.values() {
|
for item in state.items_by_leader_view_id.values() {
|
||||||
item.set_leader_peer_id(None, cx);
|
item.set_leader_peer_id(None, cx);
|
||||||
|
@ -2435,7 +2413,7 @@ impl Workspace {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
pub fn unfollow(&mut self, pane: &View<Pane>, cx: &mut ViewContext<Self>) -> Option<PeerId> {
|
pub fn unfollow(&mut self, pane: &View<Pane>, cx: &mut ViewContext<Self>) -> Option<PeerId> {
|
||||||
let follower_states = self.call_handler.follower_states_mut();
|
let follower_states = &mut self.follower_states;
|
||||||
let state = follower_states.remove(pane)?;
|
let state = follower_states.remove(pane)?;
|
||||||
let leader_id = state.leader_id;
|
let leader_id = state.leader_id;
|
||||||
for (_, item) in state.items_by_leader_view_id {
|
for (_, item) in state.items_by_leader_view_id {
|
||||||
|
@ -2658,7 +2636,7 @@ impl Workspace {
|
||||||
match update.variant.ok_or_else(|| anyhow!("invalid update"))? {
|
match update.variant.ok_or_else(|| anyhow!("invalid update"))? {
|
||||||
proto::update_followers::Variant::UpdateActiveView(update_active_view) => {
|
proto::update_followers::Variant::UpdateActiveView(update_active_view) => {
|
||||||
this.update(cx, |this, _| {
|
this.update(cx, |this, _| {
|
||||||
for (_, state) in this.call_handler.follower_states_mut() {
|
for (_, state) in &mut this.follower_states {
|
||||||
if state.leader_id == leader_id {
|
if state.leader_id == leader_id {
|
||||||
state.active_view_id =
|
state.active_view_id =
|
||||||
if let Some(active_view_id) = update_active_view.id.clone() {
|
if let Some(active_view_id) = update_active_view.id.clone() {
|
||||||
|
@ -2681,7 +2659,7 @@ impl Workspace {
|
||||||
let mut tasks = Vec::new();
|
let mut tasks = Vec::new();
|
||||||
this.update(cx, |this, cx| {
|
this.update(cx, |this, cx| {
|
||||||
let project = this.project.clone();
|
let project = this.project.clone();
|
||||||
for (_, state) in this.call_handler.follower_states_mut() {
|
for (_, state) in &mut this.follower_states {
|
||||||
if state.leader_id == leader_id {
|
if state.leader_id == leader_id {
|
||||||
let view_id = ViewId::from_proto(id.clone())?;
|
let view_id = ViewId::from_proto(id.clone())?;
|
||||||
if let Some(item) = state.items_by_leader_view_id.get(&view_id) {
|
if let Some(item) = state.items_by_leader_view_id.get(&view_id) {
|
||||||
|
@ -2695,8 +2673,7 @@ impl Workspace {
|
||||||
}
|
}
|
||||||
proto::update_followers::Variant::CreateView(view) => {
|
proto::update_followers::Variant::CreateView(view) => {
|
||||||
let panes = this.update(cx, |this, _| {
|
let panes = this.update(cx, |this, _| {
|
||||||
this.call_handler
|
this.follower_states
|
||||||
.follower_states()
|
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(pane, state)| (state.leader_id == leader_id).then_some(pane))
|
.filter_map(|(pane, state)| (state.leader_id == leader_id).then_some(pane))
|
||||||
.cloned()
|
.cloned()
|
||||||
|
@ -2756,7 +2733,7 @@ impl Workspace {
|
||||||
for (pane, (item_tasks, leader_view_ids)) in item_tasks_by_pane {
|
for (pane, (item_tasks, leader_view_ids)) in item_tasks_by_pane {
|
||||||
let items = futures::future::try_join_all(item_tasks).await?;
|
let items = futures::future::try_join_all(item_tasks).await?;
|
||||||
this.update(cx, |this, cx| {
|
this.update(cx, |this, cx| {
|
||||||
let state = this.call_handler.follower_states_mut().get_mut(&pane)?;
|
let state = this.follower_states.get_mut(&pane)?;
|
||||||
for (id, item) in leader_view_ids.into_iter().zip(items) {
|
for (id, item) in leader_view_ids.into_iter().zip(items) {
|
||||||
item.set_leader_peer_id(Some(leader_id), cx);
|
item.set_leader_peer_id(Some(leader_id), cx);
|
||||||
state.items_by_leader_view_id.insert(id, item);
|
state.items_by_leader_view_id.insert(id, item);
|
||||||
|
@ -2813,14 +2790,55 @@ impl Workspace {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn leader_for_pane(&self, pane: &View<Pane>) -> Option<PeerId> {
|
pub fn leader_for_pane(&self, pane: &View<Pane>) -> Option<PeerId> {
|
||||||
self.call_handler
|
self.follower_states.get(pane).map(|state| state.leader_id)
|
||||||
.follower_states()
|
|
||||||
.get(pane)
|
|
||||||
.map(|state| state.leader_id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn leader_updated(&mut self, leader_id: PeerId, cx: &mut ViewContext<Self>) -> Option<()> {
|
pub fn leader_updated(&mut self, leader_id: PeerId, cx: &mut ViewContext<Self>) -> Option<()> {
|
||||||
self.call_handler.leader_updated(leader_id, cx)
|
cx.notify();
|
||||||
|
|
||||||
|
let (leader_in_this_project, leader_in_this_app) =
|
||||||
|
self.call_handler.peer_state(leader_id, cx)?;
|
||||||
|
let mut items_to_activate = Vec::new();
|
||||||
|
for (pane, state) in &self.follower_states {
|
||||||
|
if state.leader_id != leader_id {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let (Some(active_view_id), true) = (state.active_view_id, leader_in_this_app) {
|
||||||
|
if let Some(item) = state.items_by_leader_view_id.get(&active_view_id) {
|
||||||
|
if leader_in_this_project || !item.is_project_item(cx) {
|
||||||
|
items_to_activate.push((pane.clone(), item.boxed_clone()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log::warn!(
|
||||||
|
"unknown view id {:?} for leader {:?}",
|
||||||
|
active_view_id,
|
||||||
|
leader_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// todo!()
|
||||||
|
// if let Some(shared_screen) = self.shared_screen_for_peer(leader_id, pane, cx) {
|
||||||
|
// items_to_activate.push((pane.clone(), Box::new(shared_screen)));
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
for (pane, item) in items_to_activate {
|
||||||
|
let pane_was_focused = pane.read(cx).has_focus(cx);
|
||||||
|
if let Some(index) = pane.update(cx, |pane, _| pane.index_for_item(item.as_ref())) {
|
||||||
|
pane.update(cx, |pane, cx| pane.activate_item(index, false, false, cx));
|
||||||
|
} else {
|
||||||
|
pane.update(cx, |pane, mut cx| {
|
||||||
|
pane.add_item(item.boxed_clone(), false, false, None, &mut cx)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if pane_was_focused {
|
||||||
|
pane.update(cx, |pane, cx| pane.focus_active_item(cx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo!()
|
// todo!()
|
||||||
|
@ -3637,7 +3655,7 @@ impl Render for Workspace {
|
||||||
.flex_1()
|
.flex_1()
|
||||||
.child(self.center.render(
|
.child(self.center.render(
|
||||||
&self.project,
|
&self.project,
|
||||||
&self.call_handler.follower_states(),
|
&self.follower_states,
|
||||||
&self.active_pane,
|
&self.active_pane,
|
||||||
self.zoomed.as_ref(),
|
self.zoomed.as_ref(),
|
||||||
&self.app_state,
|
&self.app_state,
|
||||||
|
@ -4201,7 +4219,6 @@ pub fn open_paths(
|
||||||
abs_paths: &[PathBuf],
|
abs_paths: &[PathBuf],
|
||||||
app_state: &Arc<AppState>,
|
app_state: &Arc<AppState>,
|
||||||
requesting_window: Option<WindowHandle<Workspace>>,
|
requesting_window: Option<WindowHandle<Workspace>>,
|
||||||
call_factory: CallFactory,
|
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Task<
|
) -> Task<
|
||||||
anyhow::Result<(
|
anyhow::Result<(
|
||||||
|
@ -4228,13 +4245,7 @@ pub fn open_paths(
|
||||||
todo!()
|
todo!()
|
||||||
} else {
|
} else {
|
||||||
cx.update(move |cx| {
|
cx.update(move |cx| {
|
||||||
Workspace::new_local(
|
Workspace::new_local(abs_paths, app_state.clone(), requesting_window, cx)
|
||||||
abs_paths,
|
|
||||||
app_state.clone(),
|
|
||||||
requesting_window,
|
|
||||||
call_factory,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
})?
|
})?
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
@ -4245,9 +4256,8 @@ pub fn open_new(
|
||||||
app_state: &Arc<AppState>,
|
app_state: &Arc<AppState>,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
init: impl FnOnce(&mut Workspace, &mut ViewContext<Workspace>) + 'static + Send,
|
init: impl FnOnce(&mut Workspace, &mut ViewContext<Workspace>) + 'static + Send,
|
||||||
call_factory: CallFactory,
|
|
||||||
) -> Task<()> {
|
) -> Task<()> {
|
||||||
let task = Workspace::new_local(Vec::new(), app_state.clone(), None, call_factory, cx);
|
let task = Workspace::new_local(Vec::new(), app_state.clone(), None, cx);
|
||||||
cx.spawn(|mut cx| async move {
|
cx.spawn(|mut cx| async move {
|
||||||
if let Some((workspace, opened_paths)) = task.await.log_err() {
|
if let Some((workspace, opened_paths)) = task.await.log_err() {
|
||||||
workspace
|
workspace
|
||||||
|
|
|
@ -189,7 +189,7 @@ fn main() {
|
||||||
// audio::init(Assets, cx);
|
// audio::init(Assets, cx);
|
||||||
auto_update::init(http.clone(), client::ZED_SERVER_URL.clone(), cx);
|
auto_update::init(http.clone(), client::ZED_SERVER_URL.clone(), cx);
|
||||||
|
|
||||||
workspace::init(app_state.clone(), cx);
|
workspace::init(app_state.clone(), cx, call::Call::new);
|
||||||
// recent_projects::init(cx);
|
// recent_projects::init(cx);
|
||||||
|
|
||||||
go_to_line::init(cx);
|
go_to_line::init(cx);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue