shared_screen.rs

  1use crate::participant::{Frame, RemoteVideoTrack};
  2use anyhow::Result;
  3use client::{proto::PeerId, User};
  4use futures::StreamExt;
  5use gpui::{
  6    div, img, AppContext, Div, Element, Entity, EventEmitter, FocusHandle, FocusableView,
  7    ImageData, Img, MouseButton, ParentElement, Render, SharedString, Task, View, ViewContext,
  8    VisualContext, WindowContext,
  9};
 10use smallvec::SmallVec;
 11use std::{
 12    borrow::Cow,
 13    sync::{Arc, Weak},
 14};
 15use workspace::{
 16    item::{Item, ItemEvent},
 17    ItemNavHistory, WorkspaceId,
 18};
 19
 20pub enum Event {
 21    Close,
 22}
 23
 24pub struct SharedScreen {
 25    track: Weak<RemoteVideoTrack>,
 26    frame: Option<Frame>,
 27    pub peer_id: PeerId,
 28    user: Arc<User>,
 29    nav_history: Option<ItemNavHistory>,
 30    _maintain_frame: Task<Result<()>>,
 31    focus: FocusHandle,
 32}
 33
 34impl SharedScreen {
 35    pub fn new(
 36        track: &Arc<RemoteVideoTrack>,
 37        peer_id: PeerId,
 38        user: Arc<User>,
 39        cx: &mut ViewContext<Self>,
 40    ) -> Self {
 41        cx.focus_handle();
 42        let mut frames = track.frames();
 43        Self {
 44            track: Arc::downgrade(track),
 45            frame: None,
 46            peer_id,
 47            user,
 48            nav_history: Default::default(),
 49            _maintain_frame: cx.spawn(|this, mut cx| async move {
 50                while let Some(frame) = frames.next().await {
 51                    this.update(&mut cx, |this, cx| {
 52                        this.frame = Some(frame);
 53                        cx.notify();
 54                    })?;
 55                }
 56                this.update(&mut cx, |_, cx| cx.emit(Event::Close))?;
 57                Ok(())
 58            }),
 59            focus: cx.focus_handle(),
 60        }
 61    }
 62}
 63
 64impl EventEmitter<Event> for SharedScreen {}
 65impl EventEmitter<workspace::item::ItemEvent> for SharedScreen {}
 66
 67impl FocusableView for SharedScreen {
 68    fn focus_handle(&self, cx: &AppContext) -> FocusHandle {
 69        self.focus.clone()
 70    }
 71}
 72impl Render for SharedScreen {
 73    type Element = Div;
 74    fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
 75        let frame = self.frame.clone();
 76        div().children(frame.map(|frame| {
 77            img().data(Arc::new(ImageData::new(image::ImageBuffer::new(
 78                frame.width() as u32,
 79                frame.height() as u32,
 80            ))))
 81        }))
 82    }
 83}
 84// impl View for SharedScreen {
 85//     fn ui_name() -> &'static str {
 86//         "SharedScreen"
 87//     }
 88
 89//     fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
 90//         enum Focus {}
 91
 92//         let frame = self.frame.clone();
 93//         MouseEventHandler::new::<Focus, _>(0, cx, |_, cx| {
 94//             Canvas::new(move |bounds, _, _, cx| {
 95//                 if let Some(frame) = frame.clone() {
 96//                     let size = constrain_size_preserving_aspect_ratio(
 97//                         bounds.size(),
 98//                         vec2f(frame.width() as f32, frame.height() as f32),
 99//                     );
100//                     let origin = bounds.origin() + (bounds.size() / 2.) - size / 2.;
101//                     cx.scene().push_surface(gpui::platform::mac::Surface {
102//                         bounds: RectF::new(origin, size),
103//                         image_buffer: frame.image(),
104//                     });
105//                 }
106//             })
107//             .contained()
108//             .with_style(theme::current(cx).shared_screen)
109//         })
110//         .on_down(MouseButton::Left, |_, _, cx| cx.focus_parent())
111//         .into_any()
112//     }
113// }
114
115impl Item for SharedScreen {
116    fn tab_tooltip_text(&self, _: &AppContext) -> Option<SharedString> {
117        Some(format!("{}'s screen", self.user.github_login).into())
118    }
119    fn deactivated(&mut self, cx: &mut ViewContext<Self>) {
120        if let Some(nav_history) = self.nav_history.as_mut() {
121            nav_history.push::<()>(None, cx);
122        }
123    }
124
125    fn tab_content(&self, _: Option<usize>, _: &WindowContext<'_>) -> gpui::AnyElement {
126        div().child("Shared screen").into_any()
127        // Flex::row()
128        //     .with_child(
129        //         Svg::new("icons/desktop.svg")
130        //             .with_color(style.label.text.color)
131        //             .constrained()
132        //             .with_width(style.type_icon_width)
133        //             .aligned()
134        //             .contained()
135        //             .with_margin_right(style.spacing),
136        //     )
137        //     .with_child(
138        //         Label::new(
139        //             format!("{}'s screen", self.user.github_login),
140        //             style.label.clone(),
141        //         )
142        //         .aligned(),
143        //     )
144        //     .into_any()
145    }
146
147    fn set_nav_history(&mut self, history: ItemNavHistory, _: &mut ViewContext<Self>) {
148        self.nav_history = Some(history);
149    }
150
151    fn clone_on_split(
152        &self,
153        _workspace_id: WorkspaceId,
154        cx: &mut ViewContext<Self>,
155    ) -> Option<View<Self>> {
156        let track = self.track.upgrade()?;
157        Some(cx.build_view(|cx| Self::new(&track, self.peer_id, self.user.clone(), cx)))
158    }
159}