Decouple workspace from call (#3380)
This PR decouples `call2` from `workspace2` in order to improve our compile times. Why pick such a small, innocent crate as `call`? It depends on `live_kit_client`, which is not-so-innocent and is in fact stalling our clean builds. In this PR, `call2` depends on `workspace2`; workspace crate defines a `CallHandler` trait for which the implementation resides in `call`; it it then all tied together in `zed`, which passes a factory of `Box<dyn CallHandler>` into workspace's `AppState`. Clean debug build before this change: ~1m45s Clean debug build after this change: ~1m25s Clean release build before this change: ~6m30s Clean release build after this change: ~4m30s ~Gonna follow up with release timings where I expect the change to be more impactful (as this allows 2/3 of the infamous trio of "project-workspace-editor" long pole to proceed quicker, without being blocked on live-kit-client build script)~. This should have little effect (if any) in incremental scenarios, where live_kit_client is already built. [release timings.zip](https://github.com/zed-industries/zed/files/13431121/release.timings.zip) Release Notes: - N/A
This commit is contained in:
commit
6da57cbc6e
8 changed files with 242 additions and 108 deletions
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -1186,6 +1186,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"async-broadcast",
|
||||
"async-trait",
|
||||
"audio2",
|
||||
"client2",
|
||||
"collections",
|
||||
|
@ -1204,6 +1205,7 @@ dependencies = [
|
|||
"serde_json",
|
||||
"settings2",
|
||||
"util",
|
||||
"workspace2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -11381,6 +11383,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion 1.0.5",
|
||||
"async-trait",
|
||||
"bincode",
|
||||
"call2",
|
||||
"client2",
|
||||
|
|
|
@ -31,7 +31,8 @@ media = { path = "../media" }
|
|||
project = { package = "project2", path = "../project2" }
|
||||
settings = { package = "settings2", path = "../settings2" }
|
||||
util = { path = "../util" }
|
||||
|
||||
workspace = {package = "workspace2", path = "../workspace2"}
|
||||
async-trait.workspace = true
|
||||
anyhow.workspace = true
|
||||
async-broadcast = "0.4"
|
||||
futures.workspace = true
|
||||
|
|
|
@ -2,24 +2,29 @@ pub mod call_settings;
|
|||
pub mod participant;
|
||||
pub mod room;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use async_trait::async_trait;
|
||||
use audio::Audio;
|
||||
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 futures::{channel::oneshot, future::Shared, Future, FutureExt};
|
||||
use gpui::{
|
||||
AppContext, AsyncAppContext, Context, EventEmitter, Model, ModelContext, Subscription, Task,
|
||||
WeakModel,
|
||||
AppContext, AsyncAppContext, AsyncWindowContext, Context, EventEmitter, Model, ModelContext,
|
||||
Subscription, Task, View, ViewContext, WeakModel, WeakView,
|
||||
};
|
||||
pub use participant::ParticipantLocation;
|
||||
use postage::watch;
|
||||
use project::Project;
|
||||
use room::Event;
|
||||
pub use room::Room;
|
||||
use settings::Settings;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub use participant::ParticipantLocation;
|
||||
pub use room::Room;
|
||||
use util::ResultExt;
|
||||
use workspace::{item::ItemHandle, CallHandler, Pane, Workspace};
|
||||
|
||||
pub fn init(client: Arc<Client>, user_store: Model<UserStore>, cx: &mut AppContext) {
|
||||
CallSettings::register(cx);
|
||||
|
@ -505,6 +510,116 @@ pub fn report_call_event_for_channel(
|
|||
)
|
||||
}
|
||||
|
||||
pub struct Call {
|
||||
active_call: Option<(Model<ActiveCall>, Vec<Subscription>)>,
|
||||
parent_workspace: WeakView<Workspace>,
|
||||
}
|
||||
|
||||
impl Call {
|
||||
pub fn new(
|
||||
parent_workspace: WeakView<Workspace>,
|
||||
cx: &mut ViewContext<'_, Workspace>,
|
||||
) -> Box<dyn CallHandler> {
|
||||
let mut active_call = None;
|
||||
if cx.has_global::<Model<ActiveCall>>() {
|
||||
let call = cx.global::<Model<ActiveCall>>().clone();
|
||||
let subscriptions = vec![cx.subscribe(&call, Self::on_active_call_event)];
|
||||
active_call = Some((call, subscriptions));
|
||||
}
|
||||
Box::new(Self {
|
||||
active_call,
|
||||
parent_workspace,
|
||||
})
|
||||
}
|
||||
fn on_active_call_event(
|
||||
workspace: &mut Workspace,
|
||||
_: Model<ActiveCall>,
|
||||
event: &room::Event,
|
||||
cx: &mut ViewContext<Workspace>,
|
||||
) {
|
||||
match event {
|
||||
room::Event::ParticipantLocationChanged { participant_id }
|
||||
| room::Event::RemoteVideoTracksChanged { participant_id } => {
|
||||
workspace.leader_updated(*participant_id, cx);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl CallHandler for Call {
|
||||
fn shared_screen_for_peer(
|
||||
&self,
|
||||
peer_id: PeerId,
|
||||
_pane: &View<Pane>,
|
||||
cx: &mut ViewContext<Workspace>,
|
||||
) -> Option<Box<dyn ItemHandle>> {
|
||||
let (call, _) = self.active_call.as_ref()?;
|
||||
let room = call.read(cx).room()?.read(cx);
|
||||
let participant = room.remote_participant_for_peer_id(peer_id)?;
|
||||
let _track = participant.video_tracks.values().next()?.clone();
|
||||
let _user = participant.user.clone();
|
||||
todo!();
|
||||
// for item in pane.read(cx).items_of_type::<SharedScreen>() {
|
||||
// if item.read(cx).peer_id == peer_id {
|
||||
// return Box::new(Some(item));
|
||||
// }
|
||||
// }
|
||||
|
||||
// Some(Box::new(cx.build_view(|cx| {
|
||||
// SharedScreen::new(&track, peer_id, user.clone(), cx)
|
||||
// })))
|
||||
}
|
||||
|
||||
fn room_id(&self, cx: &AppContext) -> Option<u64> {
|
||||
Some(self.active_call.as_ref()?.0.read(cx).room()?.read(cx).id())
|
||||
}
|
||||
fn hang_up(&self, mut cx: AsyncWindowContext) -> Result<Task<Result<()>>> {
|
||||
let Some((call, _)) = self.active_call.as_ref() else {
|
||||
bail!("Cannot exit a call; not in a call");
|
||||
};
|
||||
|
||||
call.update(&mut cx, |this, cx| this.hang_up(cx))
|
||||
}
|
||||
fn active_project(&self, cx: &AppContext) -> Option<WeakModel<Project>> {
|
||||
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)]
|
||||
mod test {
|
||||
use gpui::TestAppContext;
|
||||
|
|
|
@ -221,6 +221,7 @@ impl TestServer {
|
|||
fs: fs.clone(),
|
||||
build_window_options: |_, _, _| Default::default(),
|
||||
node_runtime: FakeNodeRuntime::new(),
|
||||
call_factory: |_, _| Box::new(workspace::TestCallHandler),
|
||||
});
|
||||
|
||||
cx.update(|cx| {
|
||||
|
|
|
@ -20,7 +20,6 @@ test-support = [
|
|||
|
||||
[dependencies]
|
||||
db2 = { path = "../db2" }
|
||||
call2 = { path = "../call2" }
|
||||
client2 = { path = "../client2" }
|
||||
collections = { path = "../collections" }
|
||||
# context_menu = { path = "../context_menu" }
|
||||
|
@ -37,6 +36,7 @@ theme2 = { path = "../theme2" }
|
|||
util = { path = "../util" }
|
||||
ui = { package = "ui2", path = "../ui2" }
|
||||
|
||||
async-trait.workspace = true
|
||||
async-recursion = "1.0.0"
|
||||
itertools = "0.10"
|
||||
bincode = "1.2.1"
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::{AppState, FollowerState, Pane, Workspace};
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use call2::ActiveCall;
|
||||
use collections::HashMap;
|
||||
use db2::sqlez::{
|
||||
bindable::{Bind, Column, StaticColumnCount},
|
||||
|
@ -127,7 +126,6 @@ impl PaneGroup {
|
|||
&self,
|
||||
project: &Model<Project>,
|
||||
follower_states: &HashMap<View<Pane>, FollowerState>,
|
||||
active_call: Option<&Model<ActiveCall>>,
|
||||
active_pane: &View<Pane>,
|
||||
zoomed: Option<&AnyWeakView>,
|
||||
app_state: &Arc<AppState>,
|
||||
|
@ -137,7 +135,6 @@ impl PaneGroup {
|
|||
project,
|
||||
0,
|
||||
follower_states,
|
||||
active_call,
|
||||
active_pane,
|
||||
zoomed,
|
||||
app_state,
|
||||
|
@ -199,7 +196,6 @@ impl Member {
|
|||
project: &Model<Project>,
|
||||
basis: usize,
|
||||
follower_states: &HashMap<View<Pane>, FollowerState>,
|
||||
active_call: Option<&Model<ActiveCall>>,
|
||||
active_pane: &View<Pane>,
|
||||
zoomed: Option<&AnyWeakView>,
|
||||
app_state: &Arc<AppState>,
|
||||
|
@ -234,7 +230,6 @@ impl Member {
|
|||
project,
|
||||
basis + 1,
|
||||
follower_states,
|
||||
active_call,
|
||||
active_pane,
|
||||
zoomed,
|
||||
app_state,
|
||||
|
@ -556,7 +551,7 @@ impl PaneAxis {
|
|||
project: &Model<Project>,
|
||||
basis: usize,
|
||||
follower_states: &HashMap<View<Pane>, FollowerState>,
|
||||
active_call: Option<&Model<ActiveCall>>,
|
||||
|
||||
active_pane: &View<Pane>,
|
||||
zoomed: Option<&AnyWeakView>,
|
||||
app_state: &Arc<AppState>,
|
||||
|
@ -578,7 +573,6 @@ impl PaneAxis {
|
|||
project,
|
||||
basis,
|
||||
follower_states,
|
||||
active_call,
|
||||
active_pane,
|
||||
zoomed,
|
||||
app_state,
|
||||
|
|
|
@ -16,7 +16,7 @@ mod toolbar;
|
|||
mod workspace_settings;
|
||||
|
||||
use anyhow::{anyhow, Context as _, Result};
|
||||
use call2::ActiveCall;
|
||||
use async_trait::async_trait;
|
||||
use client2::{
|
||||
proto::{self, PeerId},
|
||||
Client, TypedEnvelope, UserStore,
|
||||
|
@ -33,8 +33,8 @@ use gpui::{
|
|||
AsyncWindowContext, Bounds, Context, Div, Entity, EntityId, EventEmitter, FocusHandle,
|
||||
FocusableView, GlobalPixels, InteractiveElement, KeyContext, ManagedView, Model, ModelContext,
|
||||
ParentElement, PathPromptOptions, Point, PromptLevel, Render, Size, Styled, Subscription, Task,
|
||||
View, ViewContext, VisualContext, WeakView, WindowBounds, WindowContext, WindowHandle,
|
||||
WindowOptions,
|
||||
View, ViewContext, VisualContext, WeakModel, WeakView, WindowBounds, WindowContext,
|
||||
WindowHandle, WindowOptions,
|
||||
};
|
||||
use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, ProjectItem};
|
||||
use itertools::Itertools;
|
||||
|
@ -210,7 +210,6 @@ pub fn init_settings(cx: &mut AppContext) {
|
|||
pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
|
||||
init_settings(cx);
|
||||
notifications::init(cx);
|
||||
|
||||
// cx.add_global_action({
|
||||
// let app_state = Arc::downgrade(&app_state);
|
||||
// move |_: &Open, cx: &mut AppContext| {
|
||||
|
@ -304,6 +303,7 @@ pub struct AppState {
|
|||
pub user_store: Model<UserStore>,
|
||||
pub workspace_store: Model<WorkspaceStore>,
|
||||
pub fs: Arc<dyn fs2::Fs>,
|
||||
pub call_factory: CallFactory,
|
||||
pub build_window_options:
|
||||
fn(Option<WindowBounds>, Option<Uuid>, &mut AppContext) -> WindowOptions,
|
||||
pub node_runtime: Arc<dyn NodeRuntime>,
|
||||
|
@ -322,6 +322,36 @@ struct Follower {
|
|||
peer_id: PeerId,
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub struct TestCallHandler;
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
impl CallHandler for TestCallHandler {
|
||||
fn peer_state(&mut self, id: PeerId, cx: &mut ViewContext<Workspace>) -> Option<(bool, bool)> {
|
||||
None
|
||||
}
|
||||
|
||||
fn shared_screen_for_peer(
|
||||
&self,
|
||||
peer_id: PeerId,
|
||||
pane: &View<Pane>,
|
||||
cx: &mut ViewContext<Workspace>,
|
||||
) -> Option<Box<dyn ItemHandle>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn room_id(&self, cx: &AppContext) -> Option<u64> {
|
||||
None
|
||||
}
|
||||
|
||||
fn hang_up(&self, cx: AsyncWindowContext) -> Result<Task<Result<()>>> {
|
||||
anyhow::bail!("TestCallHandler should not be hanging up")
|
||||
}
|
||||
|
||||
fn active_project(&self, cx: &AppContext) -> Option<WeakModel<Project>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl AppState {
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub fn test(cx: &mut AppContext) -> Arc<Self> {
|
||||
|
@ -352,6 +382,7 @@ impl AppState {
|
|||
workspace_store,
|
||||
node_runtime: FakeNodeRuntime::new(),
|
||||
build_window_options: |_, _, _| Default::default(),
|
||||
call_factory: |_, _| Box::new(TestCallHandler),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -408,6 +439,23 @@ pub enum Event {
|
|||
WorkspaceCreated(WeakView<Workspace>),
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
pub trait CallHandler {
|
||||
fn peer_state(&mut self, id: PeerId, cx: &mut ViewContext<Workspace>) -> Option<(bool, bool)>;
|
||||
fn shared_screen_for_peer(
|
||||
&self,
|
||||
peer_id: PeerId,
|
||||
pane: &View<Pane>,
|
||||
cx: &mut ViewContext<Workspace>,
|
||||
) -> Option<Box<dyn ItemHandle>>;
|
||||
fn room_id(&self, cx: &AppContext) -> Option<u64>;
|
||||
fn is_in_room(&self, cx: &mut ViewContext<Workspace>) -> bool {
|
||||
self.room_id(cx).is_some()
|
||||
}
|
||||
fn hang_up(&self, cx: AsyncWindowContext) -> Result<Task<Result<()>>>;
|
||||
fn active_project(&self, cx: &AppContext) -> Option<WeakModel<Project>>;
|
||||
}
|
||||
|
||||
pub struct Workspace {
|
||||
window_self: WindowHandle<Self>,
|
||||
weak_self: WeakView<Self>,
|
||||
|
@ -428,10 +476,10 @@ pub struct Workspace {
|
|||
titlebar_item: Option<AnyView>,
|
||||
notifications: Vec<(TypeId, usize, Box<dyn NotificationHandle>)>,
|
||||
project: Model<Project>,
|
||||
call_handler: Box<dyn CallHandler>,
|
||||
follower_states: HashMap<View<Pane>, FollowerState>,
|
||||
last_leaders_by_pane: HashMap<WeakView<Pane>, PeerId>,
|
||||
window_edited: bool,
|
||||
active_call: Option<(Model<ActiveCall>, Vec<Subscription>)>,
|
||||
leader_updates_tx: mpsc::UnboundedSender<(PeerId, proto::UpdateFollowers)>,
|
||||
database_id: WorkspaceId,
|
||||
app_state: Arc<AppState>,
|
||||
|
@ -459,6 +507,7 @@ struct FollowerState {
|
|||
|
||||
enum WorkspaceBounds {}
|
||||
|
||||
type CallFactory = fn(WeakView<Workspace>, &mut ViewContext<Workspace>) -> Box<dyn CallHandler>;
|
||||
impl Workspace {
|
||||
pub fn new(
|
||||
workspace_id: WorkspaceId,
|
||||
|
@ -550,9 +599,19 @@ impl Workspace {
|
|||
mpsc::unbounded::<(PeerId, proto::UpdateFollowers)>();
|
||||
let _apply_leader_updates = cx.spawn(|this, mut cx| async move {
|
||||
while let Some((leader_id, update)) = leader_updates_rx.next().await {
|
||||
Self::process_leader_update(&this, leader_id, update, &mut cx)
|
||||
let mut cx2 = cx.clone();
|
||||
let t = this.clone();
|
||||
|
||||
Workspace::process_leader_update(&this, leader_id, update, &mut cx)
|
||||
.await
|
||||
.log_err();
|
||||
|
||||
// this.update(&mut cx, |this, cxx| {
|
||||
// this.call_handler
|
||||
// .process_leader_update(leader_id, update, cx2)
|
||||
// })?
|
||||
// .await
|
||||
// .log_err();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -585,14 +644,6 @@ impl Workspace {
|
|||
// drag_and_drop.register_container(weak_handle.clone());
|
||||
// });
|
||||
|
||||
let mut active_call = None;
|
||||
if cx.has_global::<Model<ActiveCall>>() {
|
||||
let call = cx.global::<Model<ActiveCall>>().clone();
|
||||
let mut subscriptions = Vec::new();
|
||||
subscriptions.push(cx.subscribe(&call, Self::on_active_call_event));
|
||||
active_call = Some((call, subscriptions));
|
||||
}
|
||||
|
||||
let subscriptions = vec![
|
||||
cx.observe_window_activation(Self::on_window_activation_changed),
|
||||
cx.observe_window_bounds(move |_, cx| {
|
||||
|
@ -655,7 +706,8 @@ impl Workspace {
|
|||
follower_states: Default::default(),
|
||||
last_leaders_by_pane: Default::default(),
|
||||
window_edited: false,
|
||||
active_call,
|
||||
|
||||
call_handler: (app_state.call_factory)(weak_handle.clone(), cx),
|
||||
database_id: workspace_id,
|
||||
app_state,
|
||||
_observe_current_user,
|
||||
|
@ -1102,7 +1154,7 @@ impl Workspace {
|
|||
cx: &mut ViewContext<Self>,
|
||||
) -> Task<Result<bool>> {
|
||||
//todo!(saveing)
|
||||
let active_call = self.active_call().cloned();
|
||||
|
||||
let window = cx.window_handle();
|
||||
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
|
@ -1113,10 +1165,12 @@ impl Workspace {
|
|||
.count()
|
||||
})?;
|
||||
|
||||
if let Some(active_call) = active_call {
|
||||
if !quitting
|
||||
&& workspace_count == 1
|
||||
&& active_call.read_with(&cx, |call, _| call.room().is_some())?
|
||||
&& this
|
||||
.update(&mut cx, |this, cx| this.call_handler.is_in_room(cx))
|
||||
.log_err()
|
||||
.unwrap_or_default()
|
||||
{
|
||||
let answer = window.update(&mut cx, |_, cx| {
|
||||
cx.prompt(
|
||||
|
@ -1129,13 +1183,11 @@ impl Workspace {
|
|||
if answer.await.log_err() == Some(1) {
|
||||
return anyhow::Ok(false);
|
||||
} else {
|
||||
active_call
|
||||
.update(&mut cx, |call, cx| call.hang_up(cx))?
|
||||
this.update(&mut cx, |this, cx| this.call_handler.hang_up(cx.to_async()))??
|
||||
.await
|
||||
.log_err();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(this
|
||||
.update(&mut cx, |this, cx| {
|
||||
|
@ -2391,19 +2443,19 @@ impl Workspace {
|
|||
// }
|
||||
|
||||
pub fn unfollow(&mut self, pane: &View<Pane>, cx: &mut ViewContext<Self>) -> Option<PeerId> {
|
||||
let state = self.follower_states.remove(pane)?;
|
||||
let follower_states = &mut self.follower_states;
|
||||
let state = follower_states.remove(pane)?;
|
||||
let leader_id = state.leader_id;
|
||||
for (_, item) in state.items_by_leader_view_id {
|
||||
item.set_leader_peer_id(None, cx);
|
||||
}
|
||||
|
||||
if self
|
||||
.follower_states
|
||||
if follower_states
|
||||
.values()
|
||||
.all(|state| state.leader_id != state.leader_id)
|
||||
{
|
||||
let project_id = self.project.read(cx).remote_id();
|
||||
let room_id = self.active_call()?.read(cx).room()?.read(cx).id();
|
||||
let room_id = self.call_handler.room_id(cx)?;
|
||||
self.app_state
|
||||
.client
|
||||
.send(proto::Unfollow {
|
||||
|
@ -2762,8 +2814,9 @@ impl Workspace {
|
|||
} else {
|
||||
None
|
||||
};
|
||||
let room_id = self.call_handler.room_id(cx)?;
|
||||
self.app_state().workspace_store.update(cx, |store, cx| {
|
||||
store.update_followers(project_id, update, cx)
|
||||
store.update_followers(project_id, room_id, update, cx)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -2771,31 +2824,12 @@ impl Workspace {
|
|||
self.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<()> {
|
||||
cx.notify();
|
||||
|
||||
let call = self.active_call()?;
|
||||
let room = call.read(cx).room()?.read(cx);
|
||||
let participant = room.remote_participant_for_peer_id(leader_id)?;
|
||||
let (leader_in_this_project, leader_in_this_app) =
|
||||
self.call_handler.peer_state(leader_id, cx)?;
|
||||
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.project.read(cx).remote_id();
|
||||
}
|
||||
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;
|
||||
|
@ -2825,8 +2859,8 @@ impl Workspace {
|
|||
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, cx| {
|
||||
pane.add_item(item.boxed_clone(), false, false, None, cx)
|
||||
pane.update(cx, |pane, mut cx| {
|
||||
pane.add_item(item.boxed_clone(), false, false, None, &mut cx)
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -2886,25 +2920,6 @@ impl Workspace {
|
|||
}
|
||||
}
|
||||
|
||||
fn active_call(&self) -> Option<&Model<ActiveCall>> {
|
||||
self.active_call.as_ref().map(|(call, _)| call)
|
||||
}
|
||||
|
||||
fn on_active_call_event(
|
||||
&mut self,
|
||||
_: Model<ActiveCall>,
|
||||
event: &call2::room::Event,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
match event {
|
||||
call2::room::Event::ParticipantLocationChanged { participant_id }
|
||||
| call2::room::Event::RemoteVideoTracksChanged { participant_id } => {
|
||||
self.leader_updated(*participant_id, cx);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn database_id(&self) -> WorkspaceId {
|
||||
self.database_id
|
||||
}
|
||||
|
@ -3314,6 +3329,7 @@ impl Workspace {
|
|||
fs: project.read(cx).fs().clone(),
|
||||
build_window_options: |_, _, _| Default::default(),
|
||||
node_runtime: FakeNodeRuntime::new(),
|
||||
call_factory: |_, _| Box::new(TestCallHandler),
|
||||
});
|
||||
let workspace = Self::new(0, project, app_state, cx);
|
||||
workspace.active_pane.update(cx, |pane, cx| pane.focus(cx));
|
||||
|
@ -3672,7 +3688,6 @@ impl Render for Workspace {
|
|||
.child(self.center.render(
|
||||
&self.project,
|
||||
&self.follower_states,
|
||||
self.active_call(),
|
||||
&self.active_pane,
|
||||
self.zoomed.as_ref(),
|
||||
&self.app_state,
|
||||
|
@ -3842,14 +3857,10 @@ impl WorkspaceStore {
|
|||
pub fn update_followers(
|
||||
&self,
|
||||
project_id: Option<u64>,
|
||||
room_id: u64,
|
||||
update: proto::update_followers::Variant,
|
||||
cx: &AppContext,
|
||||
) -> Option<()> {
|
||||
if !cx.has_global::<Model<ActiveCall>>() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let room_id = ActiveCall::global(cx).read(cx).room()?.read(cx).id();
|
||||
let follower_ids: Vec<_> = self
|
||||
.followers
|
||||
.iter()
|
||||
|
@ -3885,9 +3896,17 @@ impl WorkspaceStore {
|
|||
project_id: envelope.payload.project_id,
|
||||
peer_id: envelope.original_sender_id()?,
|
||||
};
|
||||
let active_project = ActiveCall::global(cx).read(cx).location().cloned();
|
||||
|
||||
let mut response = proto::FollowResponse::default();
|
||||
let active_project = this
|
||||
.workspaces
|
||||
.iter()
|
||||
.next()
|
||||
.and_then(|workspace| {
|
||||
workspace
|
||||
.read_with(cx, |this, cx| this.call_handler.active_project(cx))
|
||||
.log_err()
|
||||
})
|
||||
.flatten();
|
||||
for workspace in &this.workspaces {
|
||||
workspace
|
||||
.update(cx, |workspace, cx| {
|
||||
|
|
|
@ -180,6 +180,7 @@ fn main() {
|
|||
user_store,
|
||||
fs,
|
||||
build_window_options,
|
||||
call_factory: call::Call::new,
|
||||
// background_actions: todo!("ask Mikayla"),
|
||||
workspace_store,
|
||||
node_runtime,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue