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 {}
 62
 63impl FocusableView for SharedScreen {
 64    fn focus_handle(&self, _: &AppContext) -> FocusHandle {
 65        self.focus.clone()
 66    }
 67}
 68impl Render for SharedScreen {
 69    type Element = Focusable<Div>;
 70
 71    fn render(&mut self, _: &mut ViewContext<Self>) -> Self::Element {
 72        div().track_focus(&self.focus).size_full().children(
 73            self.frame
 74                .as_ref()
 75                .map(|frame| img(frame.image()).size_full()),
 76        )
 77    }
 78}
 79
 80impl Item for SharedScreen {
 81    type Event = Event;
 82
 83    fn tab_tooltip_text(&self, _: &AppContext) -> Option<SharedString> {
 84        Some(format!("{}'s screen", self.user.github_login).into())
 85    }
 86
 87    fn deactivated(&mut self, cx: &mut ViewContext<Self>) {
 88        if let Some(nav_history) = self.nav_history.as_mut() {
 89            nav_history.push::<()>(None, cx);
 90        }
 91    }
 92
 93    fn tab_content(&self, _: Option<usize>, _: &WindowContext<'_>) -> gpui::AnyElement {
 94        h_stack()
 95            .gap_1()
 96            .child(IconElement::new(Icon::Screen))
 97            .child(SharedString::from(format!(
 98                "{}'s screen",
 99                self.user.github_login
100            )))
101            .into_any()
102    }
103
104    fn set_nav_history(&mut self, history: ItemNavHistory, _: &mut ViewContext<Self>) {
105        self.nav_history = Some(history);
106    }
107
108    fn clone_on_split(
109        &self,
110        _workspace_id: WorkspaceId,
111        cx: &mut ViewContext<Self>,
112    ) -> Option<View<Self>> {
113        let track = self.track.upgrade()?;
114        Some(cx.build_view(|cx| Self::new(&track, self.peer_id, self.user.clone(), cx)))
115    }
116
117    fn to_item_events(event: &Self::Event, mut f: impl FnMut(ItemEvent)) {
118        match event {
119            Event::Close => f(ItemEvent::CloseItem),
120        }
121    }
122}