mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-27 12:54:42 +00:00
Merge pull request #1806 from zed-industries/pending-state-when-calling
Show a `Calling` indicator right away when initiating a call
This commit is contained in:
commit
af74d5409a
2 changed files with 80 additions and 32 deletions
|
@ -3,6 +3,7 @@ pub mod room;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use client::{proto, Client, TypedEnvelope, User, UserStore};
|
use client::{proto, Client, TypedEnvelope, User, UserStore};
|
||||||
|
use collections::HashSet;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext,
|
AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext,
|
||||||
Subscription, Task, WeakModelHandle,
|
Subscription, Task, WeakModelHandle,
|
||||||
|
@ -27,8 +28,9 @@ pub struct IncomingCall {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ActiveCall {
|
pub struct ActiveCall {
|
||||||
location: Option<WeakModelHandle<Project>>,
|
|
||||||
room: Option<(ModelHandle<Room>, Vec<Subscription>)>,
|
room: Option<(ModelHandle<Room>, Vec<Subscription>)>,
|
||||||
|
location: Option<WeakModelHandle<Project>>,
|
||||||
|
pending_invites: HashSet<u64>,
|
||||||
incoming_call: (
|
incoming_call: (
|
||||||
watch::Sender<Option<IncomingCall>>,
|
watch::Sender<Option<IncomingCall>>,
|
||||||
watch::Receiver<Option<IncomingCall>>,
|
watch::Receiver<Option<IncomingCall>>,
|
||||||
|
@ -51,6 +53,7 @@ impl ActiveCall {
|
||||||
Self {
|
Self {
|
||||||
room: None,
|
room: None,
|
||||||
location: None,
|
location: None,
|
||||||
|
pending_invites: Default::default(),
|
||||||
incoming_call: watch::channel(),
|
incoming_call: watch::channel(),
|
||||||
_subscriptions: vec![
|
_subscriptions: vec![
|
||||||
client.add_request_handler(cx.handle(), Self::handle_incoming_call),
|
client.add_request_handler(cx.handle(), Self::handle_incoming_call),
|
||||||
|
@ -113,33 +116,49 @@ impl ActiveCall {
|
||||||
) -> Task<Result<()>> {
|
) -> Task<Result<()>> {
|
||||||
let client = self.client.clone();
|
let client = self.client.clone();
|
||||||
let user_store = self.user_store.clone();
|
let user_store = self.user_store.clone();
|
||||||
cx.spawn(|this, mut cx| async move {
|
if !self.pending_invites.insert(recipient_user_id) {
|
||||||
if let Some(room) = this.read_with(&cx, |this, _| this.room().cloned()) {
|
return Task::ready(Err(anyhow!("user was already invited")));
|
||||||
let initial_project_id = if let Some(initial_project) = initial_project {
|
}
|
||||||
Some(
|
|
||||||
room.update(&mut cx, |room, cx| room.share_project(initial_project, cx))
|
|
||||||
.await?,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
room.update(&mut cx, |room, cx| {
|
cx.notify();
|
||||||
room.call(recipient_user_id, initial_project_id, cx)
|
cx.spawn(|this, mut cx| async move {
|
||||||
})
|
let invite = async {
|
||||||
.await?;
|
if let Some(room) = this.read_with(&cx, |this, _| this.room().cloned()) {
|
||||||
} else {
|
let initial_project_id = if let Some(initial_project) = initial_project {
|
||||||
let room = cx
|
Some(
|
||||||
.update(|cx| {
|
room.update(&mut cx, |room, cx| {
|
||||||
Room::create(recipient_user_id, initial_project, client, user_store, cx)
|
room.share_project(initial_project, cx)
|
||||||
|
})
|
||||||
|
.await?,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
room.update(&mut cx, |room, cx| {
|
||||||
|
room.call(recipient_user_id, initial_project_id, cx)
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
|
} else {
|
||||||
|
let room = cx
|
||||||
|
.update(|cx| {
|
||||||
|
Room::create(recipient_user_id, initial_project, client, user_store, cx)
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
this.update(&mut cx, |this, cx| this.set_room(Some(room.clone()), cx))
|
this.update(&mut cx, |this, cx| this.set_room(Some(room), cx))
|
||||||
.await?;
|
.await?;
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(())
|
let result = invite.await;
|
||||||
|
this.update(&mut cx, |this, cx| {
|
||||||
|
this.pending_invites.remove(&recipient_user_id);
|
||||||
|
cx.notify();
|
||||||
|
});
|
||||||
|
result
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,4 +293,8 @@ impl ActiveCall {
|
||||||
pub fn room(&self) -> Option<&ModelHandle<Room>> {
|
pub fn room(&self) -> Option<&ModelHandle<Room>> {
|
||||||
self.room.as_ref().map(|(room, _)| room)
|
self.room.as_ref().map(|(room, _)| room)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pending_invites(&self) -> &HashSet<u64> {
|
||||||
|
&self.pending_invites
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,10 @@ enum ContactEntry {
|
||||||
},
|
},
|
||||||
IncomingRequest(Arc<User>),
|
IncomingRequest(Arc<User>),
|
||||||
OutgoingRequest(Arc<User>),
|
OutgoingRequest(Arc<User>),
|
||||||
Contact(Arc<Contact>),
|
Contact {
|
||||||
|
contact: Arc<Contact>,
|
||||||
|
calling: bool,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for ContactEntry {
|
impl PartialEq for ContactEntry {
|
||||||
|
@ -121,8 +124,13 @@ impl PartialEq for ContactEntry {
|
||||||
return user_1.id == user_2.id;
|
return user_1.id == user_2.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ContactEntry::Contact(contact_1) => {
|
ContactEntry::Contact {
|
||||||
if let ContactEntry::Contact(contact_2) = other {
|
contact: contact_1, ..
|
||||||
|
} => {
|
||||||
|
if let ContactEntry::Contact {
|
||||||
|
contact: contact_2, ..
|
||||||
|
} = other
|
||||||
|
{
|
||||||
return contact_1.user.id == contact_2.user.id;
|
return contact_1.user.id == contact_2.user.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -255,8 +263,9 @@ impl ContactList {
|
||||||
is_selected,
|
is_selected,
|
||||||
cx,
|
cx,
|
||||||
),
|
),
|
||||||
ContactEntry::Contact(contact) => Self::render_contact(
|
ContactEntry::Contact { contact, calling } => Self::render_contact(
|
||||||
contact,
|
contact,
|
||||||
|
*calling,
|
||||||
&this.project,
|
&this.project,
|
||||||
&theme.contact_list,
|
&theme.contact_list,
|
||||||
is_selected,
|
is_selected,
|
||||||
|
@ -349,8 +358,8 @@ impl ContactList {
|
||||||
let section = *section;
|
let section = *section;
|
||||||
self.toggle_expanded(&ToggleExpanded(section), cx);
|
self.toggle_expanded(&ToggleExpanded(section), cx);
|
||||||
}
|
}
|
||||||
ContactEntry::Contact(contact) => {
|
ContactEntry::Contact { contact, calling } => {
|
||||||
if contact.online && !contact.busy {
|
if contact.online && !contact.busy && !calling {
|
||||||
self.call(
|
self.call(
|
||||||
&Call {
|
&Call {
|
||||||
recipient_user_id: contact.user.id,
|
recipient_user_id: contact.user.id,
|
||||||
|
@ -621,9 +630,13 @@ impl ContactList {
|
||||||
if !matches.is_empty() {
|
if !matches.is_empty() {
|
||||||
self.entries.push(ContactEntry::Header(section));
|
self.entries.push(ContactEntry::Header(section));
|
||||||
if !self.collapsed_sections.contains(§ion) {
|
if !self.collapsed_sections.contains(§ion) {
|
||||||
|
let active_call = &ActiveCall::global(cx).read(cx);
|
||||||
for mat in matches {
|
for mat in matches {
|
||||||
let contact = &contacts[mat.candidate_id];
|
let contact = &contacts[mat.candidate_id];
|
||||||
self.entries.push(ContactEntry::Contact(contact.clone()));
|
self.entries.push(ContactEntry::Contact {
|
||||||
|
contact: contact.clone(),
|
||||||
|
calling: active_call.pending_invites().contains(&contact.user.id),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -968,13 +981,14 @@ impl ContactList {
|
||||||
|
|
||||||
fn render_contact(
|
fn render_contact(
|
||||||
contact: &Contact,
|
contact: &Contact,
|
||||||
|
calling: bool,
|
||||||
project: &ModelHandle<Project>,
|
project: &ModelHandle<Project>,
|
||||||
theme: &theme::ContactList,
|
theme: &theme::ContactList,
|
||||||
is_selected: bool,
|
is_selected: bool,
|
||||||
cx: &mut RenderContext<Self>,
|
cx: &mut RenderContext<Self>,
|
||||||
) -> ElementBox {
|
) -> ElementBox {
|
||||||
let online = contact.online;
|
let online = contact.online;
|
||||||
let busy = contact.busy;
|
let busy = contact.busy || calling;
|
||||||
let user_id = contact.user.id;
|
let user_id = contact.user.id;
|
||||||
let initial_project = project.clone();
|
let initial_project = project.clone();
|
||||||
let mut element =
|
let mut element =
|
||||||
|
@ -986,7 +1000,7 @@ impl ContactList {
|
||||||
Empty::new()
|
Empty::new()
|
||||||
.collapsed()
|
.collapsed()
|
||||||
.contained()
|
.contained()
|
||||||
.with_style(if contact.busy {
|
.with_style(if busy {
|
||||||
theme.contact_status_busy
|
theme.contact_status_busy
|
||||||
} else {
|
} else {
|
||||||
theme.contact_status_free
|
theme.contact_status_free
|
||||||
|
@ -1020,6 +1034,17 @@ impl ContactList {
|
||||||
.flex(1., true)
|
.flex(1., true)
|
||||||
.boxed(),
|
.boxed(),
|
||||||
)
|
)
|
||||||
|
.with_children(if calling {
|
||||||
|
Some(
|
||||||
|
Label::new("Calling".to_string(), theme.calling_indicator.text.clone())
|
||||||
|
.contained()
|
||||||
|
.with_style(theme.calling_indicator.container)
|
||||||
|
.aligned()
|
||||||
|
.boxed(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
})
|
||||||
.constrained()
|
.constrained()
|
||||||
.with_height(theme.row_height)
|
.with_height(theme.row_height)
|
||||||
.contained()
|
.contained()
|
||||||
|
@ -1164,7 +1189,7 @@ impl ContactList {
|
||||||
let initial_project = action.initial_project.clone();
|
let initial_project = action.initial_project.clone();
|
||||||
ActiveCall::global(cx)
|
ActiveCall::global(cx)
|
||||||
.update(cx, |call, cx| {
|
.update(cx, |call, cx| {
|
||||||
call.invite(recipient_user_id, initial_project.clone(), cx)
|
call.invite(recipient_user_id, initial_project, cx)
|
||||||
})
|
})
|
||||||
.detach_and_log_err(cx);
|
.detach_and_log_err(cx);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue