Avoid using global for Room and extract that logic into ActiveCall

This commit is contained in:
Antonio Scandurra 2022-09-29 10:48:51 +02:00
parent 04d194924e
commit 634f9de7e6
3 changed files with 63 additions and 77 deletions

View file

@ -9,7 +9,7 @@ use gpui::{
ViewHandle, ViewHandle,
}; };
use menu::{Confirm, SelectNext, SelectPrev}; use menu::{Confirm, SelectNext, SelectPrev};
use room::Room; use room::{ActiveCall, Room};
use settings::Settings; use settings::Settings;
use theme::IconButton; use theme::IconButton;
@ -80,7 +80,7 @@ pub enum Event {
} }
pub struct ContactsPopover { pub struct ContactsPopover {
room: Option<(ModelHandle<Room>, Subscription)>, room_subscription: Option<Subscription>,
entries: Vec<ContactEntry>, entries: Vec<ContactEntry>,
match_candidates: Vec<StringMatchCandidate>, match_candidates: Vec<StringMatchCandidate>,
list_state: ListState, list_state: ListState,
@ -161,18 +161,20 @@ impl ContactsPopover {
} }
}); });
let active_call = ActiveCall::global(cx);
let mut subscriptions = Vec::new(); let mut subscriptions = Vec::new();
subscriptions.push(cx.observe(&user_store, |this, _, cx| this.update_entries(cx))); subscriptions.push(cx.observe(&user_store, |this, _, cx| this.update_entries(cx)));
subscriptions.push(cx.observe(&active_call, |this, active_call, cx| {
let weak_self = cx.weak_handle(); if let Some(room) = active_call.read(cx).room().cloned() {
subscriptions.push(Room::observe(cx, move |room, cx| { this.room_subscription = Some(cx.observe(&room, |_, _, cx| cx.notify()));
if let Some(this) = weak_self.upgrade(cx) { } else {
this.update(cx, |this, cx| this.set_room(room, cx)); this.room_subscription = None;
} }
cx.notify();
})); }));
let mut this = Self { let mut this = Self {
room: None, room_subscription: None,
list_state, list_state,
selection: None, selection: None,
collapsed_sections: Default::default(), collapsed_sections: Default::default(),
@ -187,17 +189,6 @@ impl ContactsPopover {
this this
} }
fn set_room(&mut self, room: Option<ModelHandle<Room>>, cx: &mut ViewContext<Self>) {
if let Some(room) = room {
let observation = cx.observe(&room, |_, _, cx| cx.notify());
self.room = Some((room, observation));
} else {
self.room = None;
}
cx.notify();
}
fn clear_filter(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) { fn clear_filter(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
let did_clear = self.filter_editor.update(cx, |editor, cx| { let did_clear = self.filter_editor.update(cx, |editor, cx| {
if editor.buffer().read(cx).len(cx) > 0 { if editor.buffer().read(cx).len(cx) > 0 {
@ -394,7 +385,7 @@ impl ContactsPopover {
} }
fn render_active_call(&self, cx: &mut RenderContext<Self>) -> Option<ElementBox> { fn render_active_call(&self, cx: &mut RenderContext<Self>) -> Option<ElementBox> {
let (room, _) = self.room.as_ref()?; let room = ActiveCall::global(cx).read(cx).room()?;
let theme = &cx.global::<Settings>().theme.contacts_panel; let theme = &cx.global::<Settings>().theme.contacts_panel;
Some( Some(
@ -642,13 +633,12 @@ impl ContactsPopover {
} }
fn call(&mut self, action: &Call, cx: &mut ViewContext<Self>) { fn call(&mut self, action: &Call, cx: &mut ViewContext<Self>) {
let client = self.client.clone();
let user_store = self.user_store.clone();
let recipient_user_id = action.recipient_user_id; let recipient_user_id = action.recipient_user_id;
let room = ActiveCall::global(cx).update(cx, |active_call, cx| {
active_call.get_or_create(&self.client, &self.user_store, cx)
});
cx.spawn_weak(|_, mut cx| async move { cx.spawn_weak(|_, mut cx| async move {
let room = cx let room = room.await?;
.update(|cx| Room::get_or_create(&client, &user_store, cx))
.await?;
room.update(&mut cx, |room, cx| room.call(recipient_user_id, cx)) room.update(&mut cx, |room, cx| room.call(recipient_user_id, cx))
.await?; .await?;
anyhow::Ok(()) anyhow::Ok(())

View file

@ -1,5 +1,9 @@
use crate::Room; use crate::Room;
use gpui::{Entity, ModelHandle, MutableAppContext}; use anyhow::{anyhow, Result};
use client::{call::Call, Client, UserStore};
use gpui::{Entity, ModelContext, ModelHandle, MutableAppContext, Task};
use std::sync::Arc;
use util::ResultExt;
#[derive(Default)] #[derive(Default)]
pub struct ActiveCall { pub struct ActiveCall {
@ -13,43 +17,66 @@ impl Entity for ActiveCall {
impl ActiveCall { impl ActiveCall {
pub fn global(cx: &mut MutableAppContext) -> ModelHandle<Self> { pub fn global(cx: &mut MutableAppContext) -> ModelHandle<Self> {
if cx.has_global::<ModelHandle<Self>>() { if cx.has_global::<ModelHandle<Self>>() {
cx.global::<ModelHandle<Self>>().clone()
} else {
let active_call = cx.add_model(|_| ActiveCall::default()); let active_call = cx.add_model(|_| ActiveCall::default());
cx.set_global(active_call.clone()); cx.set_global(active_call.clone());
active_call active_call
} else {
cx.global::<ModelHandle<Self>>().clone()
} }
} }
pub fn observe<F>(cx: &mut MutableAppContext, mut callback: F) -> gpui::Subscription
where
F: 'static + FnMut(Option<ModelHandle<Room>>, &mut MutableAppContext),
{
cx.observe_default_global::<Option<ModelHandle<Room>>, _>(move |cx| {
let room = cx.global::<Option<ModelHandle<Room>>>().clone();
callback(room, cx);
})
}
pub fn get_or_create( pub fn get_or_create(
&mut self,
client: &Arc<Client>, client: &Arc<Client>,
user_store: &ModelHandle<UserStore>, user_store: &ModelHandle<UserStore>,
cx: &mut MutableAppContext, cx: &mut ModelContext<Self>,
) -> Task<Result<ModelHandle<Room>>> { ) -> Task<Result<ModelHandle<Room>>> {
if let Some(room) = cx.global::<Option<ModelHandle<Room>>>() { if let Some(room) = self.room.clone() {
Task::ready(Ok(room.clone())) Task::ready(Ok(room))
} else { } else {
let client = client.clone(); let client = client.clone();
let user_store = user_store.clone(); let user_store = user_store.clone();
cx.spawn(|mut cx| async move { cx.spawn(|this, mut cx| async move {
let room = cx.update(|cx| Room::create(client, user_store, cx)).await?; let room = cx.update(|cx| Room::create(client, user_store, cx)).await?;
cx.update(|cx| cx.set_global(Some(room.clone()))); this.update(&mut cx, |this, cx| {
this.room = Some(room.clone());
cx.notify();
});
Ok(room) Ok(room)
}) })
} }
} }
pub fn clear(cx: &mut MutableAppContext) { pub fn join(
cx.set_global::<Option<ModelHandle<Room>>>(None); &mut self,
call: &Call,
client: &Arc<Client>,
user_store: &ModelHandle<UserStore>,
cx: &mut ModelContext<Self>,
) -> Task<Result<ModelHandle<Room>>> {
if self.room.is_some() {
return Task::ready(Err(anyhow!("cannot join while on another call")));
}
let join = Room::join(call, client.clone(), user_store.clone(), cx);
cx.spawn(|this, mut cx| async move {
let room = join.await?;
this.update(&mut cx, |this, cx| {
this.room = Some(room.clone());
cx.notify();
});
Ok(room)
})
}
pub fn room(&self) -> Option<&ModelHandle<Room>> {
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();
}
} }
} }

View file

@ -1,6 +1,7 @@
mod active_call; mod active_call;
mod participant; mod participant;
pub use active_call::ActiveCall;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use client::{call::Call, proto, Client, PeerId, TypedEnvelope, User, UserStore}; use client::{call::Call, proto, Client, PeerId, TypedEnvelope, User, UserStore};
use collections::HashMap; use collections::HashMap;
@ -32,38 +33,6 @@ impl Entity for Room {
} }
impl Room { impl Room {
pub fn observe<F>(cx: &mut MutableAppContext, mut callback: F) -> gpui::Subscription
where
F: 'static + FnMut(Option<ModelHandle<Self>>, &mut MutableAppContext),
{
cx.observe_default_global::<Option<ModelHandle<Self>>, _>(move |cx| {
let room = cx.global::<Option<ModelHandle<Self>>>().clone();
callback(room, cx);
})
}
pub fn get_or_create(
client: &Arc<Client>,
user_store: &ModelHandle<UserStore>,
cx: &mut MutableAppContext,
) -> Task<Result<ModelHandle<Self>>> {
if let Some(room) = cx.global::<Option<ModelHandle<Self>>>() {
Task::ready(Ok(room.clone()))
} else {
let client = client.clone();
let user_store = user_store.clone();
cx.spawn(|mut cx| async move {
let room = cx.update(|cx| Room::create(client, user_store, cx)).await?;
cx.update(|cx| cx.set_global(Some(room.clone())));
Ok(room)
})
}
}
pub fn clear(cx: &mut MutableAppContext) {
cx.set_global::<Option<ModelHandle<Self>>>(None);
}
fn new( fn new(
id: u64, id: u64,
client: Arc<Client>, client: Arc<Client>,