Encapsulate Room
interaction within ActiveCall
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
e0db62173a
commit
1898e813f5
9 changed files with 63 additions and 92 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -7154,6 +7154,7 @@ dependencies = [
|
||||||
"auto_update",
|
"auto_update",
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"breadcrumbs",
|
"breadcrumbs",
|
||||||
|
"call",
|
||||||
"chat_panel",
|
"chat_panel",
|
||||||
"chrono",
|
"chrono",
|
||||||
"cli",
|
"cli",
|
||||||
|
|
|
@ -6,11 +6,16 @@ use client::{incoming_call::IncomingCall, Client, UserStore};
|
||||||
use gpui::{Entity, ModelContext, ModelHandle, MutableAppContext, Task};
|
use gpui::{Entity, ModelContext, ModelHandle, MutableAppContext, Task};
|
||||||
pub use room::Room;
|
pub use room::Room;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use util::ResultExt;
|
|
||||||
|
|
||||||
#[derive(Default)]
|
pub fn init(client: Arc<Client>, user_store: ModelHandle<UserStore>, cx: &mut MutableAppContext) {
|
||||||
|
let active_call = cx.add_model(|_| ActiveCall::new(client, user_store));
|
||||||
|
cx.set_global(active_call);
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ActiveCall {
|
pub struct ActiveCall {
|
||||||
room: Option<ModelHandle<Room>>,
|
room: Option<ModelHandle<Room>>,
|
||||||
|
client: Arc<Client>,
|
||||||
|
user_store: ModelHandle<UserStore>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Entity for ActiveCall {
|
impl Entity for ActiveCall {
|
||||||
|
@ -18,68 +23,62 @@ impl Entity for ActiveCall {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ActiveCall {
|
impl ActiveCall {
|
||||||
pub fn global(cx: &mut MutableAppContext) -> ModelHandle<Self> {
|
fn new(client: Arc<Client>, user_store: ModelHandle<UserStore>) -> Self {
|
||||||
if cx.has_global::<ModelHandle<Self>>() {
|
Self {
|
||||||
cx.global::<ModelHandle<Self>>().clone()
|
room: None,
|
||||||
} else {
|
client,
|
||||||
let active_call = cx.add_model(|_| ActiveCall::default());
|
user_store,
|
||||||
cx.set_global(active_call.clone());
|
|
||||||
active_call
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_or_create(
|
pub fn global(cx: &mut MutableAppContext) -> ModelHandle<Self> {
|
||||||
|
cx.global::<ModelHandle<Self>>().clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn invite(
|
||||||
&mut self,
|
&mut self,
|
||||||
client: &Arc<Client>,
|
recipient_user_id: u64,
|
||||||
user_store: &ModelHandle<UserStore>,
|
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) -> Task<Result<ModelHandle<Room>>> {
|
) -> Task<Result<()>> {
|
||||||
if let Some(room) = self.room.clone() {
|
let room = self.room.clone();
|
||||||
Task::ready(Ok(room))
|
|
||||||
} else {
|
let client = self.client.clone();
|
||||||
let client = client.clone();
|
let user_store = self.user_store.clone();
|
||||||
let user_store = user_store.clone();
|
|
||||||
cx.spawn(|this, mut cx| async move {
|
cx.spawn(|this, mut cx| async move {
|
||||||
|
let room = if let Some(room) = room {
|
||||||
|
room
|
||||||
|
} else {
|
||||||
let room = cx.update(|cx| Room::create(client, user_store, cx)).await?;
|
let room = cx.update(|cx| Room::create(client, user_store, cx)).await?;
|
||||||
this.update(&mut cx, |this, cx| {
|
this.update(&mut cx, |this, cx| {
|
||||||
this.room = Some(room.clone());
|
this.room = Some(room.clone());
|
||||||
cx.notify();
|
cx.notify();
|
||||||
});
|
});
|
||||||
Ok(room)
|
room
|
||||||
|
};
|
||||||
|
room.update(&mut cx, |room, cx| room.call(recipient_user_id, cx))
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn join(
|
pub fn join(&mut self, call: &IncomingCall, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
|
||||||
&mut self,
|
|
||||||
call: &IncomingCall,
|
|
||||||
client: &Arc<Client>,
|
|
||||||
user_store: &ModelHandle<UserStore>,
|
|
||||||
cx: &mut ModelContext<Self>,
|
|
||||||
) -> Task<Result<ModelHandle<Room>>> {
|
|
||||||
if self.room.is_some() {
|
if self.room.is_some() {
|
||||||
return Task::ready(Err(anyhow!("cannot join while on another call")));
|
return Task::ready(Err(anyhow!("cannot join while on another call")));
|
||||||
}
|
}
|
||||||
|
|
||||||
let join = Room::join(call, client.clone(), user_store.clone(), cx);
|
let join = Room::join(call, self.client.clone(), self.user_store.clone(), cx);
|
||||||
cx.spawn(|this, mut cx| async move {
|
cx.spawn(|this, mut cx| async move {
|
||||||
let room = join.await?;
|
let room = join.await?;
|
||||||
this.update(&mut cx, |this, cx| {
|
this.update(&mut cx, |this, cx| {
|
||||||
this.room = Some(room.clone());
|
this.room = Some(room);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
});
|
});
|
||||||
Ok(room)
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn room(&self) -> Option<&ModelHandle<Room>> {
|
pub fn room(&self) -> Option<&ModelHandle<Room>> {
|
||||||
self.room.as_ref()
|
self.room.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self, cx: &mut ModelContext<Self>) {
|
|
||||||
if let Some(room) = self.room.take() {
|
|
||||||
room.update(cx, |room, cx| room.leave(cx)).log_err();
|
|
||||||
cx.notify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,9 +69,8 @@ impl CollabTitlebarItem {
|
||||||
Some(_) => {}
|
Some(_) => {}
|
||||||
None => {
|
None => {
|
||||||
if let Some(workspace) = self.workspace.upgrade(cx) {
|
if let Some(workspace) = self.workspace.upgrade(cx) {
|
||||||
let client = workspace.read(cx).client().clone();
|
|
||||||
let user_store = workspace.read(cx).user_store().clone();
|
let user_store = workspace.read(cx).user_store().clone();
|
||||||
let view = cx.add_view(|cx| ContactsPopover::new(client, user_store, cx));
|
let view = cx.add_view(|cx| ContactsPopover::new(user_store, cx));
|
||||||
cx.focus(&view);
|
cx.focus(&view);
|
||||||
cx.subscribe(&view, |this, _, event, cx| {
|
cx.subscribe(&view, |this, _, event, cx| {
|
||||||
match event {
|
match event {
|
||||||
|
|
|
@ -2,13 +2,12 @@ mod collab_titlebar_item;
|
||||||
mod contacts_popover;
|
mod contacts_popover;
|
||||||
mod incoming_call_notification;
|
mod incoming_call_notification;
|
||||||
|
|
||||||
use client::{Client, UserStore};
|
use client::UserStore;
|
||||||
pub use collab_titlebar_item::CollabTitlebarItem;
|
pub use collab_titlebar_item::CollabTitlebarItem;
|
||||||
use gpui::{ModelHandle, MutableAppContext};
|
use gpui::{ModelHandle, MutableAppContext};
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
pub fn init(client: Arc<Client>, user_store: ModelHandle<UserStore>, cx: &mut MutableAppContext) {
|
pub fn init(user_store: ModelHandle<UserStore>, cx: &mut MutableAppContext) {
|
||||||
contacts_popover::init(cx);
|
contacts_popover::init(cx);
|
||||||
collab_titlebar_item::init(cx);
|
collab_titlebar_item::init(cx);
|
||||||
incoming_call_notification::init(client, user_store, cx);
|
incoming_call_notification::init(user_store, cx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use call::ActiveCall;
|
use call::ActiveCall;
|
||||||
use client::{Client, Contact, User, UserStore};
|
use client::{Contact, User, UserStore};
|
||||||
use editor::{Cancel, Editor};
|
use editor::{Cancel, Editor};
|
||||||
use fuzzy::{match_strings, StringMatchCandidate};
|
use fuzzy::{match_strings, StringMatchCandidate};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
|
@ -84,7 +84,6 @@ pub struct ContactsPopover {
|
||||||
entries: Vec<ContactEntry>,
|
entries: Vec<ContactEntry>,
|
||||||
match_candidates: Vec<StringMatchCandidate>,
|
match_candidates: Vec<StringMatchCandidate>,
|
||||||
list_state: ListState,
|
list_state: ListState,
|
||||||
client: Arc<Client>,
|
|
||||||
user_store: ModelHandle<UserStore>,
|
user_store: ModelHandle<UserStore>,
|
||||||
filter_editor: ViewHandle<Editor>,
|
filter_editor: ViewHandle<Editor>,
|
||||||
collapsed_sections: Vec<Section>,
|
collapsed_sections: Vec<Section>,
|
||||||
|
@ -93,11 +92,7 @@ pub struct ContactsPopover {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContactsPopover {
|
impl ContactsPopover {
|
||||||
pub fn new(
|
pub fn new(user_store: ModelHandle<UserStore>, cx: &mut ViewContext<Self>) -> Self {
|
||||||
client: Arc<Client>,
|
|
||||||
user_store: ModelHandle<UserStore>,
|
|
||||||
cx: &mut ViewContext<Self>,
|
|
||||||
) -> Self {
|
|
||||||
let filter_editor = cx.add_view(|cx| {
|
let filter_editor = cx.add_view(|cx| {
|
||||||
let mut editor = Editor::single_line(
|
let mut editor = Editor::single_line(
|
||||||
Some(|theme| theme.contacts_panel.user_query_editor.clone()),
|
Some(|theme| theme.contacts_panel.user_query_editor.clone()),
|
||||||
|
@ -182,7 +177,6 @@ impl ContactsPopover {
|
||||||
match_candidates: Default::default(),
|
match_candidates: Default::default(),
|
||||||
filter_editor,
|
filter_editor,
|
||||||
_subscriptions: subscriptions,
|
_subscriptions: subscriptions,
|
||||||
client,
|
|
||||||
user_store,
|
user_store,
|
||||||
};
|
};
|
||||||
this.update_entries(cx);
|
this.update_entries(cx);
|
||||||
|
@ -633,17 +627,11 @@ impl ContactsPopover {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, action: &Call, cx: &mut ViewContext<Self>) {
|
fn call(&mut self, action: &Call, cx: &mut ViewContext<Self>) {
|
||||||
let recipient_user_id = action.recipient_user_id;
|
ActiveCall::global(cx)
|
||||||
let room = ActiveCall::global(cx).update(cx, |active_call, cx| {
|
.update(cx, |active_call, cx| {
|
||||||
active_call.get_or_create(&self.client, &self.user_store, cx)
|
active_call.invite(action.recipient_user_id, cx)
|
||||||
});
|
|
||||||
cx.spawn_weak(|_, mut cx| async move {
|
|
||||||
let room = room.await?;
|
|
||||||
room.update(&mut cx, |room, cx| room.call(recipient_user_id, cx))
|
|
||||||
.await?;
|
|
||||||
anyhow::Ok(())
|
|
||||||
})
|
})
|
||||||
.detach();
|
.detach_and_log_err(cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use call::ActiveCall;
|
use call::ActiveCall;
|
||||||
use client::{incoming_call::IncomingCall, Client, UserStore};
|
use client::{incoming_call::IncomingCall, UserStore};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
elements::*,
|
elements::*,
|
||||||
|
@ -14,7 +12,7 @@ use util::ResultExt;
|
||||||
|
|
||||||
impl_internal_actions!(incoming_call_notification, [RespondToCall]);
|
impl_internal_actions!(incoming_call_notification, [RespondToCall]);
|
||||||
|
|
||||||
pub fn init(client: Arc<Client>, user_store: ModelHandle<UserStore>, cx: &mut MutableAppContext) {
|
pub fn init(user_store: ModelHandle<UserStore>, cx: &mut MutableAppContext) {
|
||||||
cx.add_action(IncomingCallNotification::respond_to_call);
|
cx.add_action(IncomingCallNotification::respond_to_call);
|
||||||
|
|
||||||
let mut incoming_call = user_store.read(cx).incoming_call();
|
let mut incoming_call = user_store.read(cx).incoming_call();
|
||||||
|
@ -34,13 +32,7 @@ pub fn init(client: Arc<Client>, user_store: ModelHandle<UserStore>, cx: &mut Mu
|
||||||
kind: WindowKind::PopUp,
|
kind: WindowKind::PopUp,
|
||||||
is_movable: false,
|
is_movable: false,
|
||||||
},
|
},
|
||||||
|_| {
|
|_| IncomingCallNotification::new(incoming_call, user_store.clone()),
|
||||||
IncomingCallNotification::new(
|
|
||||||
incoming_call,
|
|
||||||
client.clone(),
|
|
||||||
user_store.clone(),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
notification_window = Some(window_id);
|
notification_window = Some(window_id);
|
||||||
}
|
}
|
||||||
|
@ -56,29 +48,18 @@ struct RespondToCall {
|
||||||
|
|
||||||
pub struct IncomingCallNotification {
|
pub struct IncomingCallNotification {
|
||||||
call: IncomingCall,
|
call: IncomingCall,
|
||||||
client: Arc<Client>,
|
|
||||||
user_store: ModelHandle<UserStore>,
|
user_store: ModelHandle<UserStore>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IncomingCallNotification {
|
impl IncomingCallNotification {
|
||||||
pub fn new(
|
pub fn new(call: IncomingCall, user_store: ModelHandle<UserStore>) -> Self {
|
||||||
call: IncomingCall,
|
Self { call, user_store }
|
||||||
client: Arc<Client>,
|
|
||||||
user_store: ModelHandle<UserStore>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
call,
|
|
||||||
client,
|
|
||||||
user_store,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn respond_to_call(&mut self, action: &RespondToCall, cx: &mut ViewContext<Self>) {
|
fn respond_to_call(&mut self, action: &RespondToCall, cx: &mut ViewContext<Self>) {
|
||||||
if action.accept {
|
if action.accept {
|
||||||
ActiveCall::global(cx)
|
ActiveCall::global(cx)
|
||||||
.update(cx, |active_call, cx| {
|
.update(cx, |active_call, cx| active_call.join(&self.call, cx))
|
||||||
active_call.join(&self.call, &self.client, &self.user_store, cx)
|
|
||||||
})
|
|
||||||
.detach_and_log_err(cx);
|
.detach_and_log_err(cx);
|
||||||
} else {
|
} else {
|
||||||
self.user_store
|
self.user_store
|
||||||
|
|
|
@ -19,6 +19,7 @@ activity_indicator = { path = "../activity_indicator" }
|
||||||
assets = { path = "../assets" }
|
assets = { path = "../assets" }
|
||||||
auto_update = { path = "../auto_update" }
|
auto_update = { path = "../auto_update" }
|
||||||
breadcrumbs = { path = "../breadcrumbs" }
|
breadcrumbs = { path = "../breadcrumbs" }
|
||||||
|
call = { path = "../call" }
|
||||||
chat_panel = { path = "../chat_panel" }
|
chat_panel = { path = "../chat_panel" }
|
||||||
cli = { path = "../cli" }
|
cli = { path = "../cli" }
|
||||||
collab_ui = { path = "../collab_ui" }
|
collab_ui = { path = "../collab_ui" }
|
||||||
|
@ -103,17 +104,19 @@ tree-sitter-typescript = "0.20.1"
|
||||||
url = "2.2"
|
url = "2.2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
text = { path = "../text", features = ["test-support"] }
|
call = { path = "../call", features = ["test-support"] }
|
||||||
|
client = { path = "../client", features = ["test-support"] }
|
||||||
editor = { path = "../editor", features = ["test-support"] }
|
editor = { path = "../editor", features = ["test-support"] }
|
||||||
gpui = { path = "../gpui", features = ["test-support"] }
|
gpui = { path = "../gpui", features = ["test-support"] }
|
||||||
language = { path = "../language", features = ["test-support"] }
|
language = { path = "../language", features = ["test-support"] }
|
||||||
lsp = { path = "../lsp", features = ["test-support"] }
|
lsp = { path = "../lsp", features = ["test-support"] }
|
||||||
project = { path = "../project", features = ["test-support"] }
|
project = { path = "../project", features = ["test-support"] }
|
||||||
rpc = { path = "../rpc", features = ["test-support"] }
|
rpc = { path = "../rpc", features = ["test-support"] }
|
||||||
client = { path = "../client", features = ["test-support"] }
|
|
||||||
settings = { path = "../settings", features = ["test-support"] }
|
settings = { path = "../settings", features = ["test-support"] }
|
||||||
|
text = { path = "../text", features = ["test-support"] }
|
||||||
util = { path = "../util", features = ["test-support"] }
|
util = { path = "../util", features = ["test-support"] }
|
||||||
workspace = { path = "../workspace", features = ["test-support"] }
|
workspace = { path = "../workspace", features = ["test-support"] }
|
||||||
|
|
||||||
env_logger = "0.9"
|
env_logger = "0.9"
|
||||||
serde_json = { version = "1.0", features = ["preserve_order"] }
|
serde_json = { version = "1.0", features = ["preserve_order"] }
|
||||||
unindent = "0.1.7"
|
unindent = "0.1.7"
|
||||||
|
|
|
@ -107,7 +107,7 @@ fn main() {
|
||||||
project::Project::init(&client);
|
project::Project::init(&client);
|
||||||
client::Channel::init(&client);
|
client::Channel::init(&client);
|
||||||
client::init(client.clone(), cx);
|
client::init(client.clone(), cx);
|
||||||
collab_ui::init(client.clone(), user_store.clone(), cx);
|
collab_ui::init(user_store.clone(), cx);
|
||||||
command_palette::init(cx);
|
command_palette::init(cx);
|
||||||
editor::init(cx);
|
editor::init(cx);
|
||||||
go_to_line::init(cx);
|
go_to_line::init(cx);
|
||||||
|
|
|
@ -217,6 +217,7 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::MutableAppContext) {
|
||||||
);
|
);
|
||||||
|
|
||||||
activity_indicator::init(cx);
|
activity_indicator::init(cx);
|
||||||
|
call::init(app_state.client.clone(), app_state.user_store.clone(), cx);
|
||||||
settings::KeymapFileContent::load_defaults(cx);
|
settings::KeymapFileContent::load_defaults(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue