1use crate::{
2 ItemNavHistory, WorkspaceId,
3 item::{Item, ItemEvent},
4};
5use call::{RemoteVideoTrack, RemoteVideoTrackView, Room};
6use client::{User, proto::PeerId};
7use gpui::{
8 AppContext as _, Entity, EventEmitter, FocusHandle, Focusable, InteractiveElement,
9 ParentElement, Render, SharedString, Styled, div,
10};
11use std::sync::Arc;
12use ui::{Icon, IconName, prelude::*};
13
14pub enum Event {
15 Close,
16}
17
18pub struct SharedScreen {
19 pub peer_id: PeerId,
20 user: Arc<User>,
21 nav_history: Option<ItemNavHistory>,
22 view: Entity<RemoteVideoTrackView>,
23 focus: FocusHandle,
24}
25
26impl SharedScreen {
27 pub fn new(
28 track: RemoteVideoTrack,
29 peer_id: PeerId,
30 user: Arc<User>,
31 room: Entity<Room>,
32 window: &mut Window,
33 cx: &mut Context<Self>,
34 ) -> Self {
35 let my_sid = track.sid();
36 cx.subscribe(&room, move |_, _, ev, cx| {
37 if let call::room::Event::RemoteVideoTrackUnsubscribed { sid } = ev
38 && sid == &my_sid
39 {
40 cx.emit(Event::Close)
41 }
42 })
43 .detach();
44
45 let view = cx.new(|cx| RemoteVideoTrackView::new(track.clone(), window, cx));
46 cx.subscribe(&view, |_, _, ev, cx| match ev {
47 call::RemoteVideoTrackViewEvent::Close => cx.emit(Event::Close),
48 })
49 .detach();
50 Self {
51 view,
52 peer_id,
53 user,
54 nav_history: Default::default(),
55 focus: cx.focus_handle(),
56 }
57 }
58}
59
60impl EventEmitter<Event> for SharedScreen {}
61
62impl Focusable for SharedScreen {
63 fn focus_handle(&self, _: &App) -> FocusHandle {
64 self.focus.clone()
65 }
66}
67impl Render for SharedScreen {
68 fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
69 div()
70 .bg(cx.theme().colors().editor_background)
71 .track_focus(&self.focus)
72 .key_context("SharedScreen")
73 .size_full()
74 .child(self.view.clone())
75 }
76}
77
78impl Item for SharedScreen {
79 type Event = Event;
80
81 fn tab_tooltip_text(&self, _: &App) -> Option<SharedString> {
82 Some(format!("{}'s screen", self.user.github_login).into())
83 }
84
85 fn deactivated(&mut self, _window: &mut Window, cx: &mut Context<Self>) {
86 if let Some(nav_history) = self.nav_history.as_mut() {
87 nav_history.push::<()>(None, cx);
88 }
89 }
90
91 fn tab_icon(&self, _window: &Window, _cx: &App) -> Option<Icon> {
92 Some(Icon::new(IconName::Screen))
93 }
94
95 fn tab_content_text(&self, _detail: usize, _cx: &App) -> SharedString {
96 format!("{}'s screen", self.user.github_login).into()
97 }
98
99 fn telemetry_event_text(&self) -> Option<&'static str> {
100 None
101 }
102
103 fn set_nav_history(
104 &mut self,
105 history: ItemNavHistory,
106 _window: &mut Window,
107 _cx: &mut Context<Self>,
108 ) {
109 self.nav_history = Some(history);
110 }
111
112 fn clone_on_split(
113 &self,
114 _workspace_id: Option<WorkspaceId>,
115 window: &mut Window,
116 cx: &mut Context<Self>,
117 ) -> Option<Entity<Self>> {
118 Some(cx.new(|cx| Self {
119 view: self.view.update(cx, |view, cx| view.clone(window, cx)),
120 peer_id: self.peer_id,
121 user: self.user.clone(),
122 nav_history: Default::default(),
123 focus: cx.focus_handle(),
124 }))
125 }
126
127 fn to_item_events(event: &Self::Event, mut f: impl FnMut(ItemEvent)) {
128 match event {
129 Event::Close => f(ItemEvent::CloseItem),
130 }
131 }
132}