1mod participant;
2pub mod room;
3
4use anyhow::{anyhow, Result};
5use client::{incoming_call::IncomingCall, Client, UserStore};
6use gpui::{AppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Subscription, Task};
7pub use participant::ParticipantLocation;
8use project::Project;
9pub use room::Room;
10use std::sync::Arc;
11
12pub fn init(client: Arc<Client>, user_store: ModelHandle<UserStore>, cx: &mut MutableAppContext) {
13 let active_call = cx.add_model(|_| ActiveCall::new(client, user_store));
14 cx.set_global(active_call);
15}
16
17pub struct ActiveCall {
18 room: Option<(ModelHandle<Room>, Vec<Subscription>)>,
19 client: Arc<Client>,
20 user_store: ModelHandle<UserStore>,
21}
22
23impl Entity for ActiveCall {
24 type Event = room::Event;
25}
26
27impl ActiveCall {
28 fn new(client: Arc<Client>, user_store: ModelHandle<UserStore>) -> Self {
29 Self {
30 room: None,
31 client,
32 user_store,
33 }
34 }
35
36 pub fn global(cx: &AppContext) -> ModelHandle<Self> {
37 cx.global::<ModelHandle<Self>>().clone()
38 }
39
40 pub fn invite(
41 &mut self,
42 recipient_user_id: u64,
43 initial_project: Option<ModelHandle<Project>>,
44 cx: &mut ModelContext<Self>,
45 ) -> Task<Result<()>> {
46 let room = self.room.as_ref().map(|(room, _)| room.clone());
47 let client = self.client.clone();
48 let user_store = self.user_store.clone();
49 cx.spawn(|this, mut cx| async move {
50 let room = if let Some(room) = room {
51 room
52 } else {
53 cx.update(|cx| Room::create(client, user_store, cx)).await?
54 };
55
56 let initial_project_id = if let Some(initial_project) = initial_project {
57 let room_id = room.read_with(&cx, |room, _| room.id());
58 Some(
59 initial_project
60 .update(&mut cx, |project, cx| project.share(room_id, cx))
61 .await?,
62 )
63 } else {
64 None
65 };
66
67 this.update(&mut cx, |this, cx| this.set_room(Some(room.clone()), cx));
68 room.update(&mut cx, |room, cx| {
69 room.call(recipient_user_id, initial_project_id, cx)
70 })
71 .await?;
72
73 Ok(())
74 })
75 }
76
77 pub fn join(&mut self, call: &IncomingCall, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
78 if self.room.is_some() {
79 return Task::ready(Err(anyhow!("cannot join while on another call")));
80 }
81
82 let join = Room::join(call, self.client.clone(), self.user_store.clone(), cx);
83 cx.spawn(|this, mut cx| async move {
84 let room = join.await?;
85 this.update(&mut cx, |this, cx| this.set_room(Some(room.clone()), cx));
86 Ok(())
87 })
88 }
89
90 fn set_room(&mut self, room: Option<ModelHandle<Room>>, cx: &mut ModelContext<Self>) {
91 if room.as_ref() != self.room.as_ref().map(|room| &room.0) {
92 if let Some(room) = room {
93 let subscriptions = vec![
94 cx.observe(&room, |_, _, cx| cx.notify()),
95 cx.subscribe(&room, |_, _, event, cx| cx.emit(event.clone())),
96 ];
97 self.room = Some((room, subscriptions));
98 } else {
99 self.room = None;
100 }
101 cx.notify();
102 }
103 }
104
105 pub fn room(&self) -> Option<&ModelHandle<Room>> {
106 self.room.as_ref().map(|(room, _)| room)
107 }
108}