shared_screen.rs

  1use crate::{
  2    item::{Item, ItemEvent},
  3    ItemNavHistory, WorkspaceId,
  4};
  5use anyhow::Result;
  6use call::participant::{Frame, RemoteVideoTrack};
  7use client::{proto::PeerId, User};
  8use futures::StreamExt;
  9use gpui::{
 10    div, img, AppContext, Div, Element, EventEmitter, FocusHandle, Focusable, FocusableView,
 11    InteractiveElement, ParentElement, Render, SharedString, Styled, Task, View, ViewContext,
 12    VisualContext, WindowContext,
 13};
 14use std::sync::{Arc, Weak};
 15use ui::{h_stack, Icon, IconElement};
 16
 17pub enum Event {
 18    Close,
 19}
 20
 21pub struct SharedScreen {
 22    track: Weak<RemoteVideoTrack>,
 23    frame: Option<Frame>,
 24    pub peer_id: PeerId,
 25    user: Arc<User>,
 26    nav_history: Option<ItemNavHistory>,
 27    _maintain_frame: Task<Result<()>>,
 28    focus: FocusHandle,
 29}
 30
 31impl SharedScreen {
 32    pub fn new(
 33        track: &Arc<RemoteVideoTrack>,
 34        peer_id: PeerId,
 35        user: Arc<User>,
 36        cx: &mut ViewContext<Self>,
 37    ) -> Self {
 38        cx.focus_handle();
 39        let mut frames = track.frames();
 40        Self {
 41            track: Arc::downgrade(track),
 42            frame: None,
 43            peer_id,
 44            user,
 45            nav_history: Default::default(),
 46            _maintain_frame: cx.spawn(|this, mut cx| async move {
 47                while let Some(frame) = frames.next().await {
 48                    this.update(&mut cx, |this, cx| {
 49                        this.frame = Some(frame);
 50                        cx.notify();
 51                    })?;
 52                }
 53                this.update(&mut cx, |_, cx| cx.emit(Event::Close))?;
 54                Ok(())
 55            }),
 56            focus: cx.focus_handle(),
 57        }
 58    }
 59}
 60
 61impl EventEmitter<Event> for SharedScreen {}
 62impl EventEmitter<ItemEvent> for SharedScreen {}
 63
 64impl FocusableView for SharedScreen {
 65    fn focus_handle(&self, _: &AppContext) -> FocusHandle {
 66        self.focus.clone()
 67    }
 68}
 69impl Render for SharedScreen {
 70    type Element = Focusable<Div>;
 71
 72    fn render(&mut self, _: &mut ViewContext<Self>) -> Self::Element {
 73        div().track_focus(&self.focus).size_full().children(
 74            self.frame
 75                .as_ref()
 76                .map(|frame| img(frame.image()).size_full()),
 77        )
 78    }
 79}
 80
 81impl Item for SharedScreen {
 82    fn tab_tooltip_text(&self, _: &AppContext) -> Option<SharedString> {
 83        Some(format!("{}'s screen", self.user.github_login).into())
 84    }
 85    fn deactivated(&mut self, cx: &mut ViewContext<Self>) {
 86        if let Some(nav_history) = self.nav_history.as_mut() {
 87            nav_history.push::<()>(None, cx);
 88        }
 89    }
 90
 91    fn tab_content(&self, _: Option<usize>, _: &WindowContext<'_>) -> gpui::AnyElement {
 92        h_stack()
 93            .gap_1()
 94            .child(IconElement::new(Icon::Screen))
 95            .child(SharedString::from(format!(
 96                "{}'s screen",
 97                self.user.github_login
 98            )))
 99            .into_any()
100    }
101
102    fn set_nav_history(&mut self, history: ItemNavHistory, _: &mut ViewContext<Self>) {
103        self.nav_history = Some(history);
104    }
105
106    fn clone_on_split(
107        &self,
108        _workspace_id: WorkspaceId,
109        cx: &mut ViewContext<Self>,
110    ) -> Option<View<Self>> {
111        let track = self.track.upgrade()?;
112        Some(cx.build_view(|cx| Self::new(&track, self.peer_id, self.user.clone(), cx)))
113    }
114}