Add control to toggle screen-sharing

This commit is contained in:
Antonio Scandurra 2022-10-19 10:19:20 +02:00
parent 219793afcc
commit 773f569385
9 changed files with 131 additions and 12 deletions

View File

@ -0,0 +1,3 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11 0.666656H1C0.447917 0.666656 0 1.11457 0 1.66666V8.33332C0 8.88541 0.447917 9.33332 1 9.33332H5L4.66667 10.3333H3.16667C2.89167 10.3333 2.66667 10.5583 2.66667 10.8333C2.66667 11.1083 2.89167 11.3333 3.16667 11.3333H8.83333C9.10938 11.3333 9.33333 11.1094 9.33333 10.8333C9.33333 10.5573 9.10938 10.3333 8.83333 10.3333H7.33333L7 9.33332H11C11.5521 9.33332 12 8.88541 12 8.33332V1.66666C12 1.11457 11.5521 0.666656 11 0.666656ZM10.6667 7.99999H1.33333V1.99999H10.6667V7.99999Z" fill="#979DB4"/>
</svg>

After

Width:  |  Height:  |  Size: 611 B

View File

@ -0,0 +1,3 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.53324 9.90014H7.18324L6.88324 9.00014H7.63305L6.10211 7.80014H1.78324V4.41577L0.583236 3.47452V8.10014C0.583217 8.59702 0.986361 9.00014 1.46636 9.00014H5.04949L4.74949 9.90014H3.43324C3.1848 9.90014 2.98324 10.1017 2.98324 10.3501C2.98324 10.5986 3.1848 10.8001 3.43324 10.8001H8.51637C8.7648 10.8001 8.96637 10.5986 8.96637 10.3501C8.96637 10.1017 8.79762 9.90014 8.53324 9.90014ZM11.8276 9.99577L10.5507 8.99489C11.0234 8.96789 11.3999 8.57939 11.3999 8.09996V2.09995C11.3999 1.60308 10.9968 1.19995 10.4999 1.19995H1.5168C1.28617 1.19995 1.07786 1.28939 0.918674 1.43208L0.727799 1.29595C0.645299 1.23145 0.547423 1.19995 0.450673 1.19995C0.316986 1.19995 0.184611 1.2592 0.0961106 1.37226C-0.057452 1.56801 -0.023327 1.85095 0.172236 2.00414L11.2724 10.7041C11.4693 10.8579 11.7519 10.8226 11.9041 10.6276C12.0581 10.4321 12.0224 10.149 11.8274 9.99521L11.8276 9.99577ZM10.1832 7.80014H9.00968L2.11905 2.40014H10.1816L10.1832 7.80014Z" fill="#93A1A1"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -132,8 +132,6 @@ impl ActiveCall {
Room::create(recipient_user_id, initial_project, client, user_store, cx) Room::create(recipient_user_id, initial_project, client, user_store, cx)
}) })
.await?; .await?;
room.update(&mut cx, |room, cx| room.share_screen(cx))
.await?;
this.update(&mut cx, |this, cx| this.set_room(Some(room), cx)); this.update(&mut cx, |this, cx| this.set_room(Some(room), cx));
}; };

View File

@ -606,6 +606,12 @@ impl Room {
}) })
} }
pub fn is_screen_sharing(&self) -> bool {
self.live_kit
.as_ref()
.map_or(false, |live_kit| live_kit.screen_track.is_some())
}
pub fn share_screen(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> { pub fn share_screen(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
if self.status.is_offline() { if self.status.is_offline() {
return Task::ready(Err(anyhow!("room is offline"))); return Task::ready(Err(anyhow!("room is offline")));
@ -617,22 +623,49 @@ impl Room {
.first() .first()
.ok_or_else(|| anyhow!("no display found"))?; .ok_or_else(|| anyhow!("no display found"))?;
let track = LocalVideoTrack::screen_share_for_display(&display); let track = LocalVideoTrack::screen_share_for_display(&display);
let publication = this let publication = this
.upgrade(&cx)? .upgrade(&cx)
.ok_or_else(|| anyhow!("room was dropped"))?
.read_with(&cx, |this, _| { .read_with(&cx, |this, _| {
this.live_kit this.live_kit
.as_ref() .as_ref()
.map(|live_kit| live_kit.room.publish_video_track(&track)) .map(|live_kit| live_kit.room.publish_video_track(&track))
})? })
.ok_or_else(|| anyhow!("live-kit was not initialized"))?
.await?; .await?;
this.upgrade(&cx)?.update(cx, |this, _| { this.upgrade(&cx)
this.live_kit.as_mut()?.screen_track = Some(publication); .ok_or_else(|| anyhow!("room was dropped"))?
Some(()) .update(&mut cx, |this, cx| {
}) let live_kit = this
.live_kit
.as_mut()
.ok_or_else(|| anyhow!("live-kit was not initialized"))?;
live_kit.screen_track = Some(publication);
cx.notify();
Ok(())
})
}) })
} }
pub fn unshare_screen(&mut self, cx: &mut ModelContext<Self>) -> Result<()> {
if self.status.is_offline() {
return Err(anyhow!("room is offline"));
}
let live_kit = self
.live_kit
.as_mut()
.ok_or_else(|| anyhow!("live-kit was not initialized"))?;
let track = live_kit
.screen_track
.take()
.ok_or_else(|| anyhow!("screen was not shared"))?;
live_kit.room.unpublish_track(track);
cx.notify();
Ok(())
}
} }
struct LiveKitRoom { struct LiveKitRoom {

View File

@ -10,17 +10,21 @@ use gpui::{
geometry::{rect::RectF, vector::vec2f, PathBuilder}, geometry::{rect::RectF, vector::vec2f, PathBuilder},
json::{self, ToJson}, json::{self, ToJson},
Border, CursorStyle, Entity, ModelHandle, MouseButton, MutableAppContext, RenderContext, Border, CursorStyle, Entity, ModelHandle, MouseButton, MutableAppContext, RenderContext,
Subscription, View, ViewContext, ViewHandle, WeakViewHandle, Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle,
}; };
use settings::Settings; use settings::Settings;
use std::ops::Range; use std::ops::Range;
use theme::Theme; use theme::Theme;
use workspace::{FollowNextCollaborator, JoinProject, ToggleFollow, Workspace}; use workspace::{FollowNextCollaborator, JoinProject, ToggleFollow, Workspace};
actions!(collab, [ToggleCollaborationMenu, ShareProject]); actions!(
collab,
[ToggleCollaborationMenu, ToggleScreenSharing, ShareProject]
);
pub fn init(cx: &mut MutableAppContext) { pub fn init(cx: &mut MutableAppContext) {
cx.add_action(CollabTitlebarItem::toggle_contacts_popover); cx.add_action(CollabTitlebarItem::toggle_contacts_popover);
cx.add_action(CollabTitlebarItem::toggle_screen_sharing);
cx.add_action(CollabTitlebarItem::share_project); cx.add_action(CollabTitlebarItem::share_project);
} }
@ -48,10 +52,12 @@ impl View for CollabTitlebarItem {
}; };
let theme = cx.global::<Settings>().theme.clone(); let theme = cx.global::<Settings>().theme.clone();
let project = workspace.read(cx).project().read(cx);
let mut container = Flex::row(); let mut container = Flex::row();
container.add_children(self.render_toggle_screen_sharing_button(&theme, cx));
if workspace.read(cx).client().status().borrow().is_connected() { if workspace.read(cx).client().status().borrow().is_connected() {
let project = workspace.read(cx).project().read(cx);
if project.is_shared() if project.is_shared()
|| project.is_remote() || project.is_remote()
|| ActiveCall::global(cx).read(cx).room().is_none() || ActiveCall::global(cx).read(cx).room().is_none()
@ -169,6 +175,19 @@ impl CollabTitlebarItem {
cx.notify(); cx.notify();
} }
pub fn toggle_screen_sharing(&mut self, _: &ToggleScreenSharing, cx: &mut ViewContext<Self>) {
if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() {
let toggle_screen_sharing = room.update(cx, |room, cx| {
if room.is_screen_sharing() {
Task::ready(room.unshare_screen(cx))
} else {
room.share_screen(cx)
}
});
toggle_screen_sharing.detach_and_log_err(cx);
}
}
fn render_toggle_contacts_button( fn render_toggle_contacts_button(
&self, &self,
theme: &Theme, theme: &Theme,
@ -237,6 +256,43 @@ impl CollabTitlebarItem {
.boxed() .boxed()
} }
fn render_toggle_screen_sharing_button(
&self,
theme: &Theme,
cx: &mut RenderContext<Self>,
) -> Option<ElementBox> {
let active_call = ActiveCall::global(cx);
let room = active_call.read(cx).room().cloned()?;
let icon = if room.read(cx).is_screen_sharing() {
"icons/disable_screen_sharing_12.svg"
} else {
"icons/enable_screen_sharing_12.svg"
};
let titlebar = &theme.workspace.titlebar;
Some(
MouseEventHandler::<ToggleScreenSharing>::new(0, cx, |state, _| {
let style = titlebar.call_control.style_for(state, false);
Svg::new(icon)
.with_color(style.color)
.constrained()
.with_width(style.icon_width)
.aligned()
.constrained()
.with_width(style.button_width)
.with_height(style.button_width)
.contained()
.with_style(style.container)
.boxed()
})
.with_cursor_style(CursorStyle::PointingHand)
.on_click(MouseButton::Left, move |_, cx| {
cx.dispatch_action(ToggleScreenSharing);
})
.aligned()
.boxed(),
)
}
fn render_share_button(&self, theme: &Theme, cx: &mut RenderContext<Self>) -> ElementBox { fn render_share_button(&self, theme: &Theme, cx: &mut RenderContext<Self>) -> ElementBox {
enum Share {} enum Share {}

View File

@ -95,6 +95,13 @@ public func LKRoomPublishVideoTrack(room: UnsafeRawPointer, track: UnsafeRawPoin
} }
} }
@_cdecl("LKRoomUnpublishTrack")
public func LKRoomUnpublishTrack(room: UnsafeRawPointer, publication: UnsafeRawPointer) {
let room = Unmanaged<Room>.fromOpaque(room).takeUnretainedValue()
let publication = Unmanaged<LocalTrackPublication>.fromOpaque(publication).takeUnretainedValue()
room.localParticipant?.unpublish(publication: publication)
}
@_cdecl("LKRoomVideoTracksForRemoteParticipant") @_cdecl("LKRoomVideoTracksForRemoteParticipant")
public func LKRoomVideoTracksForRemoteParticipant(room: UnsafeRawPointer, participantId: CFString) -> CFArray? { public func LKRoomVideoTracksForRemoteParticipant(room: UnsafeRawPointer, participantId: CFString) -> CFArray? {
let room = Unmanaged<Room>.fromOpaque(room).takeUnretainedValue() let room = Unmanaged<Room>.fromOpaque(room).takeUnretainedValue()

View File

@ -48,6 +48,7 @@ extern "C" {
callback: extern "C" fn(*mut c_void, *mut c_void, CFStringRef), callback: extern "C" fn(*mut c_void, *mut c_void, CFStringRef),
callback_data: *mut c_void, callback_data: *mut c_void,
); );
fn LKRoomUnpublishTrack(room: *const c_void, publication: *const c_void);
fn LKRoomVideoTracksForRemoteParticipant( fn LKRoomVideoTracksForRemoteParticipant(
room: *const c_void, room: *const c_void,
participant_id: CFStringRef, participant_id: CFStringRef,
@ -134,6 +135,12 @@ impl Room {
async { rx.await.unwrap().context("error publishing video track") } async { rx.await.unwrap().context("error publishing video track") }
} }
pub fn unpublish_track(&self, publication: LocalTrackPublication) {
unsafe {
LKRoomUnpublishTrack(self.native_room, publication.0);
}
}
pub fn remote_video_tracks(&self, participant_id: &str) -> Vec<Arc<RemoteVideoTrack>> { pub fn remote_video_tracks(&self, participant_id: &str) -> Vec<Arc<RemoteVideoTrack>> {
unsafe { unsafe {
let tracks = LKRoomVideoTracksForRemoteParticipant( let tracks = LKRoomVideoTracksForRemoteParticipant(

View File

@ -79,6 +79,7 @@ pub struct Titlebar {
pub sign_in_prompt: Interactive<ContainedText>, pub sign_in_prompt: Interactive<ContainedText>,
pub outdated_warning: ContainedText, pub outdated_warning: ContainedText,
pub share_button: Interactive<ContainedText>, pub share_button: Interactive<ContainedText>,
pub call_control: Interactive<IconButton>,
pub toggle_contacts_button: Interactive<IconButton>, pub toggle_contacts_button: Interactive<IconButton>,
pub toggle_contacts_badge: ContainerStyle, pub toggle_contacts_badge: ContainerStyle,
} }

View File

@ -138,7 +138,18 @@ export default function workspace(theme: Theme) {
}, },
cornerRadius: 6, cornerRadius: 6,
}, },
callControl: {
cornerRadius: 6,
color: iconColor(theme, "secondary"),
iconWidth: 12,
buttonWidth: 20,
hover: {
background: backgroundColor(theme, "on300", "hovered"),
color: iconColor(theme, "active"),
},
},
toggleContactsButton: { toggleContactsButton: {
margin: { left: 6 },
cornerRadius: 6, cornerRadius: 6,
color: iconColor(theme, "secondary"), color: iconColor(theme, "secondary"),
iconWidth: 8, iconWidth: 8,