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| match ev {
37 call::room::Event::RemoteVideoTrackUnsubscribed { sid } => {
38 if sid == &my_sid {
39 cx.emit(Event::Close)
40 }
41 }
42 _ => {}
43 })
44 .detach();
45
46 let view = cx.new(|cx| RemoteVideoTrackView::new(track.clone(), window, cx));
47 cx.subscribe(&view, |_, _, ev, cx| match ev {
48 call::RemoteVideoTrackViewEvent::Close => cx.emit(Event::Close),
49 })
50 .detach();
51 Self {
52 view,
53 peer_id,
54 user,
55 nav_history: Default::default(),
56 focus: cx.focus_handle(),
57 }
58 }
59}
60
61impl EventEmitter<Event> for SharedScreen {}
62
63impl Focusable for SharedScreen {
64 fn focus_handle(&self, _: &App) -> FocusHandle {
65 self.focus.clone()
66 }
67}
68impl Render for SharedScreen {
69 fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
70 div()
71 .bg(cx.theme().colors().editor_background)
72 .track_focus(&self.focus)
73 .key_context("SharedScreen")
74 .size_full()
75 .child(self.view.clone())
76 }
77}
78
79impl Item for SharedScreen {
80 type Event = Event;
81
82 fn tab_tooltip_text(&self, _: &App) -> Option<SharedString> {
83 Some(format!("{}'s screen", self.user.github_login).into())
84 }
85
86 fn deactivated(&mut self, _window: &mut Window, cx: &mut Context<Self>) {
87 if let Some(nav_history) = self.nav_history.as_mut() {
88 nav_history.push::<()>(None, cx);
89 }
90 }
91
92 fn tab_icon(&self, _window: &Window, _cx: &App) -> Option<Icon> {
93 Some(Icon::new(IconName::Screen))
94 }
95
96 fn tab_content_text(&self, _detail: usize, _cx: &App) -> SharedString {
97 format!("{}'s screen", self.user.github_login).into()
98 }
99
100 fn telemetry_event_text(&self) -> Option<&'static str> {
101 None
102 }
103
104 fn set_nav_history(
105 &mut self,
106 history: ItemNavHistory,
107 _window: &mut Window,
108 _cx: &mut Context<Self>,
109 ) {
110 self.nav_history = Some(history);
111 }
112
113 fn clone_on_split(
114 &self,
115 _workspace_id: Option<WorkspaceId>,
116 window: &mut Window,
117 cx: &mut Context<Self>,
118 ) -> Option<Entity<Self>> {
119 Some(cx.new(|cx| Self {
120 view: self.view.update(cx, |view, cx| view.clone(window, cx)),
121 peer_id: self.peer_id,
122 user: self.user.clone(),
123 nav_history: Default::default(),
124 focus: cx.focus_handle(),
125 }))
126 }
127
128 fn to_item_events(event: &Self::Event, mut f: impl FnMut(ItemEvent)) {
129 match event {
130 Event::Close => f(ItemEvent::CloseItem),
131 }
132 }
133}