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    elements::*,
 11    geometry::{rect::RectF, vector::vec2f},
 12    platform::MouseButton,
 13    AppContext, Entity, Task, View, ViewContext,
 14};
 15use settings::Settings;
 16use smallvec::SmallVec;
 17use std::{
 18    borrow::Cow,
 19    sync::{Arc, Weak},
 20};
 21
 22pub enum Event {
 23    Close,
 24}
 25
 26pub struct SharedScreen {
 27    track: Weak<RemoteVideoTrack>,
 28    frame: Option<Frame>,
 29    pub peer_id: PeerId,
 30    user: Arc<User>,
 31    nav_history: Option<ItemNavHistory>,
 32    _maintain_frame: Task<Result<()>>,
 33}
 34
 35impl SharedScreen {
 36    pub fn new(
 37        track: &Arc<RemoteVideoTrack>,
 38        peer_id: PeerId,
 39        user: Arc<User>,
 40        cx: &mut ViewContext<Self>,
 41    ) -> Self {
 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        }
 60    }
 61}
 62
 63impl Entity for SharedScreen {
 64    type Event = Event;
 65}
 66
 67impl View for SharedScreen {
 68    fn ui_name() -> &'static str {
 69        "SharedScreen"
 70    }
 71
 72    fn render(&mut self, cx: &mut ViewContext<Self>) -> Element<Self> {
 73        enum Focus {}
 74
 75        let frame = self.frame.clone();
 76        MouseEventHandler::<Focus, _>::new(0, cx, |_, cx| {
 77            Canvas::new(move |scene, bounds, _, _, _| {
 78                if let Some(frame) = frame.clone() {
 79                    let size = constrain_size_preserving_aspect_ratio(
 80                        bounds.size(),
 81                        vec2f(frame.width() as f32, frame.height() as f32),
 82                    );
 83                    let origin = bounds.origin() + (bounds.size() / 2.) - size / 2.;
 84                    scene.push_surface(gpui::platform::mac::Surface {
 85                        bounds: RectF::new(origin, size),
 86                        image_buffer: frame.image(),
 87                    });
 88                }
 89            })
 90            .contained()
 91            .with_style(cx.global::<Settings>().theme.shared_screen)
 92            .boxed()
 93        })
 94        .on_down(MouseButton::Left, |_, _, cx| cx.focus_parent_view())
 95        .boxed()
 96    }
 97}
 98
 99impl Item for SharedScreen {
100    fn tab_tooltip_text(&self, _: &AppContext) -> Option<Cow<str>> {
101        Some(format!("{}'s screen", self.user.github_login).into())
102    }
103    fn deactivated(&mut self, cx: &mut ViewContext<Self>) {
104        if let Some(nav_history) = self.nav_history.as_ref() {
105            nav_history.push::<()>(None, cx);
106        }
107    }
108
109    fn tab_content<V: View>(
110        &self,
111        _: Option<usize>,
112        style: &theme::Tab,
113        _: &AppContext,
114    ) -> gpui::Element<V> {
115        Flex::row()
116            .with_child(
117                Svg::new("icons/disable_screen_sharing_12.svg")
118                    .with_color(style.label.text.color)
119                    .constrained()
120                    .with_width(style.type_icon_width)
121                    .aligned()
122                    .contained()
123                    .with_margin_right(style.spacing)
124                    .boxed(),
125            )
126            .with_child(
127                Label::new(
128                    format!("{}'s screen", self.user.github_login),
129                    style.label.clone(),
130                )
131                .aligned()
132                .boxed(),
133            )
134            .boxed()
135    }
136
137    fn set_nav_history(&mut self, history: ItemNavHistory, _: &mut ViewContext<Self>) {
138        self.nav_history = Some(history);
139    }
140
141    fn clone_on_split(
142        &self,
143        _workspace_id: WorkspaceId,
144        cx: &mut ViewContext<Self>,
145    ) -> Option<Self> {
146        let track = self.track.upgrade()?;
147        Some(Self::new(&track, self.peer_id, self.user.clone(), cx))
148    }
149
150    fn to_item_events(event: &Self::Event) -> SmallVec<[ItemEvent; 2]> {
151        match event {
152            Event::Close => smallvec::smallvec!(ItemEvent::CloseItem),
153        }
154    }
155}