1#[cfg(any(
2 all(
3 target_os = "macos",
4 feature = "livekit-cross-platform",
5 not(feature = "livekit-macos"),
6 ),
7 all(not(target_os = "macos"), feature = "livekit-cross-platform"),
8))]
9mod cross_platform {
10 use crate::{
11 item::{Item, ItemEvent},
12 ItemNavHistory, WorkspaceId,
13 };
14 use call::{RemoteVideoTrack, RemoteVideoTrackView};
15 use client::{proto::PeerId, User};
16 use gpui::{
17 div, AppContext, EventEmitter, FocusHandle, FocusableView, InteractiveElement,
18 ParentElement, Render, SharedString, Styled, View, ViewContext, VisualContext,
19 WindowContext,
20 };
21 use std::sync::Arc;
22 use ui::{prelude::*, Icon, IconName};
23
24 pub enum Event {
25 Close,
26 }
27
28 pub struct SharedScreen {
29 pub peer_id: PeerId,
30 user: Arc<User>,
31 nav_history: Option<ItemNavHistory>,
32 view: View<RemoteVideoTrackView>,
33 focus: FocusHandle,
34 }
35
36 impl SharedScreen {
37 pub fn new(
38 track: RemoteVideoTrack,
39 peer_id: PeerId,
40 user: Arc<User>,
41 cx: &mut ViewContext<Self>,
42 ) -> Self {
43 let view = cx.new_view(|cx| RemoteVideoTrackView::new(track.clone(), cx));
44 cx.subscribe(&view, |_, _, ev, cx| match ev {
45 call::RemoteVideoTrackViewEvent::Close => cx.emit(Event::Close),
46 })
47 .detach();
48 Self {
49 view,
50 peer_id,
51 user,
52 nav_history: Default::default(),
53 focus: cx.focus_handle(),
54 }
55 }
56 }
57
58 impl EventEmitter<Event> for SharedScreen {}
59
60 impl FocusableView for SharedScreen {
61 fn focus_handle(&self, _: &AppContext) -> FocusHandle {
62 self.focus.clone()
63 }
64 }
65 impl Render for SharedScreen {
66 fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
67 div()
68 .bg(cx.theme().colors().editor_background)
69 .track_focus(&self.focus)
70 .key_context("SharedScreen")
71 .size_full()
72 .child(self.view.clone())
73 }
74 }
75
76 impl Item for SharedScreen {
77 type Event = Event;
78
79 fn tab_tooltip_text(&self, _: &AppContext) -> Option<SharedString> {
80 Some(format!("{}'s screen", self.user.github_login).into())
81 }
82
83 fn deactivated(&mut self, cx: &mut ViewContext<Self>) {
84 if let Some(nav_history) = self.nav_history.as_mut() {
85 nav_history.push::<()>(None, cx);
86 }
87 }
88
89 fn tab_icon(&self, _cx: &WindowContext) -> Option<Icon> {
90 Some(Icon::new(IconName::Screen))
91 }
92
93 fn tab_content_text(&self, _cx: &WindowContext) -> Option<SharedString> {
94 Some(format!("{}'s screen", self.user.github_login).into())
95 }
96
97 fn telemetry_event_text(&self) -> Option<&'static str> {
98 None
99 }
100
101 fn set_nav_history(&mut self, history: ItemNavHistory, _: &mut ViewContext<Self>) {
102 self.nav_history = Some(history);
103 }
104
105 fn clone_on_split(
106 &self,
107 _workspace_id: Option<WorkspaceId>,
108 cx: &mut ViewContext<Self>,
109 ) -> Option<View<Self>> {
110 Some(cx.new_view(|cx| Self {
111 view: self.view.update(cx, |view, cx| view.clone(cx)),
112 peer_id: self.peer_id,
113 user: self.user.clone(),
114 nav_history: Default::default(),
115 focus: cx.focus_handle(),
116 }))
117 }
118
119 fn to_item_events(event: &Self::Event, mut f: impl FnMut(ItemEvent)) {
120 match event {
121 Event::Close => f(ItemEvent::CloseItem),
122 }
123 }
124 }
125}
126
127#[cfg(any(
128 all(
129 target_os = "macos",
130 feature = "livekit-cross-platform",
131 not(feature = "livekit-macos"),
132 ),
133 all(not(target_os = "macos"), feature = "livekit-cross-platform"),
134))]
135pub use cross_platform::*;
136
137#[cfg(any(
138 all(target_os = "macos", feature = "livekit-macos"),
139 all(
140 not(target_os = "macos"),
141 feature = "livekit-macos",
142 not(feature = "livekit-cross-platform")
143 )
144))]
145mod macos {
146 use crate::{
147 item::{Item, ItemEvent},
148 ItemNavHistory, WorkspaceId,
149 };
150 use anyhow::Result;
151 use call::participant::{Frame, RemoteVideoTrack};
152 use client::{proto::PeerId, User};
153 use futures::StreamExt;
154 use gpui::{
155 div, surface, AppContext, EventEmitter, FocusHandle, FocusableView, InteractiveElement,
156 ParentElement, Render, SharedString, Styled, Task, View, ViewContext, VisualContext,
157 WindowContext,
158 };
159 use std::sync::{Arc, Weak};
160 use ui::{prelude::*, Icon, IconName};
161
162 pub enum Event {
163 Close,
164 }
165
166 pub struct SharedScreen {
167 track: Weak<RemoteVideoTrack>,
168 frame: Option<Frame>,
169 pub peer_id: PeerId,
170 user: Arc<User>,
171 nav_history: Option<ItemNavHistory>,
172 _maintain_frame: Task<Result<()>>,
173 focus: FocusHandle,
174 }
175
176 impl SharedScreen {
177 pub fn new(
178 track: Arc<RemoteVideoTrack>,
179 peer_id: PeerId,
180 user: Arc<User>,
181 cx: &mut ViewContext<Self>,
182 ) -> Self {
183 cx.focus_handle();
184 let mut frames = track.frames();
185 Self {
186 track: Arc::downgrade(&track),
187 frame: None,
188 peer_id,
189 user,
190 nav_history: Default::default(),
191 _maintain_frame: cx.spawn(|this, mut cx| async move {
192 while let Some(frame) = frames.next().await {
193 this.update(&mut cx, |this, cx| {
194 this.frame = Some(frame);
195 cx.notify();
196 })?;
197 }
198 this.update(&mut cx, |_, cx| cx.emit(Event::Close))?;
199 Ok(())
200 }),
201 focus: cx.focus_handle(),
202 }
203 }
204 }
205
206 impl EventEmitter<Event> for SharedScreen {}
207
208 impl FocusableView for SharedScreen {
209 fn focus_handle(&self, _: &AppContext) -> FocusHandle {
210 self.focus.clone()
211 }
212 }
213 impl Render for SharedScreen {
214 fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
215 div()
216 .bg(cx.theme().colors().editor_background)
217 .track_focus(&self.focus)
218 .key_context("SharedScreen")
219 .size_full()
220 .children(
221 self.frame
222 .as_ref()
223 .map(|frame| surface(frame.image()).size_full()),
224 )
225 }
226 }
227
228 impl Item for SharedScreen {
229 type Event = Event;
230
231 fn tab_tooltip_text(&self, _: &AppContext) -> Option<SharedString> {
232 Some(format!("{}'s screen", self.user.github_login).into())
233 }
234
235 fn deactivated(&mut self, cx: &mut ViewContext<Self>) {
236 if let Some(nav_history) = self.nav_history.as_mut() {
237 nav_history.push::<()>(None, cx);
238 }
239 }
240
241 fn tab_icon(&self, _cx: &WindowContext) -> Option<Icon> {
242 Some(Icon::new(IconName::Screen))
243 }
244
245 fn tab_content_text(&self, _cx: &WindowContext) -> Option<SharedString> {
246 Some(format!("{}'s screen", self.user.github_login).into())
247 }
248
249 fn telemetry_event_text(&self) -> Option<&'static str> {
250 None
251 }
252
253 fn set_nav_history(&mut self, history: ItemNavHistory, _: &mut ViewContext<Self>) {
254 self.nav_history = Some(history);
255 }
256
257 fn clone_on_split(
258 &self,
259 _workspace_id: Option<WorkspaceId>,
260 cx: &mut ViewContext<Self>,
261 ) -> Option<View<Self>> {
262 let track = self.track.upgrade()?;
263 Some(cx.new_view(|cx| Self::new(track, self.peer_id, self.user.clone(), cx)))
264 }
265
266 fn to_item_events(event: &Self::Event, mut f: impl FnMut(ItemEvent)) {
267 match event {
268 Event::Close => f(ItemEvent::CloseItem),
269 }
270 }
271 }
272}
273
274#[cfg(any(
275 all(target_os = "macos", feature = "livekit-macos"),
276 all(
277 not(target_os = "macos"),
278 feature = "livekit-macos",
279 not(feature = "livekit-cross-platform")
280 )
281))]
282pub use macos::*;