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