From 1930258d397acc516a6ba6a2edd2e08b49b13fc1 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Wed, 3 Jan 2024 14:44:09 -0700 Subject: [PATCH] Show guests in fewer places --- crates/call/src/participant.rs | 1 + crates/call/src/room.rs | 19 ++++- .../collab/src/tests/channel_guest_tests.rs | 8 +- crates/collab_ui/src/channel_view.rs | 2 +- crates/collab_ui/src/collab_panel.rs | 77 ++++++++++++++++--- crates/collab_ui/src/collab_titlebar_item.rs | 15 ++-- crates/theme/src/styles/players.rs | 4 +- 7 files changed, 100 insertions(+), 26 deletions(-) diff --git a/crates/call/src/participant.rs b/crates/call/src/participant.rs index 5f3d2827f8..9faefc63c3 100644 --- a/crates/call/src/participant.rs +++ b/crates/call/src/participant.rs @@ -43,6 +43,7 @@ pub struct LocalParticipant { pub struct RemoteParticipant { pub user: Arc, pub peer_id: proto::PeerId, + pub role: proto::ChannelRole, pub projects: Vec, pub location: ParticipantLocation, pub participant_index: ParticipantIndex, diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index 03a6b942b2..4561e6d807 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -610,6 +610,12 @@ impl Room { .find(|p| p.peer_id == peer_id) } + pub fn role_for_user(&self, user_id: u64) -> Option { + self.remote_participants + .get(&user_id) + .map(|participant| participant.role) + } + pub fn pending_participants(&self) -> &[Arc] { &self.pending_participants } @@ -784,6 +790,7 @@ impl Room { }); } + let role = participant.role(); let location = ParticipantLocation::from_proto(participant.location) .unwrap_or(ParticipantLocation::External); if let Some(remote_participant) = @@ -792,8 +799,11 @@ impl Room { remote_participant.peer_id = peer_id; remote_participant.projects = participant.projects; remote_participant.participant_index = participant_index; - if location != remote_participant.location { + if location != remote_participant.location + || role != remote_participant.role + { remote_participant.location = location; + remote_participant.role = role; cx.emit(Event::ParticipantLocationChanged { participant_id: peer_id, }); @@ -807,6 +817,7 @@ impl Room { peer_id, projects: participant.projects, location, + role, muted: true, speaking: false, video_tracks: Default::default(), @@ -1251,9 +1262,9 @@ impl Room { .unwrap_or(false) } - pub fn can_publish(&self) -> bool { - self.local_participant().role == proto::ChannelRole::Member - || self.local_participant().role == proto::ChannelRole::Admin + pub fn read_only(&self) -> bool { + !(self.local_participant().role == proto::ChannelRole::Member + || self.local_participant().role == proto::ChannelRole::Admin) } pub fn is_speaking(&self) -> bool { diff --git a/crates/collab/src/tests/channel_guest_tests.rs b/crates/collab/src/tests/channel_guest_tests.rs index 78dd57be02..e2051c44a0 100644 --- a/crates/collab/src/tests/channel_guest_tests.rs +++ b/crates/collab/src/tests/channel_guest_tests.rs @@ -7,8 +7,8 @@ use workspace::Workspace; #[gpui::test] async fn test_channel_guests( executor: BackgroundExecutor, - mut cx_a: &mut TestAppContext, - mut cx_b: &mut TestAppContext, + cx_a: &mut TestAppContext, + cx_b: &mut TestAppContext, ) { let mut server = TestServer::start(executor.clone()).await; let client_a = server.create_client(cx_a, "user_a").await; @@ -37,15 +37,13 @@ async fn test_channel_guests( .await; let active_call_a = cx_a.read(ActiveCall::global); - let active_call_b = cx_b.read(ActiveCall::global); // Client A shares a project in the channel active_call_a .update(cx_a, |call, cx| call.join_channel(channel_id, cx)) .await .unwrap(); - let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await; - let worktree_a = project_a.read_with(cx_a, |project, _| project.worktrees().next().unwrap()); + let (project_a, _) = client_a.build_local_project("/a", cx_a).await; let project_id = active_call_a .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx)) .await diff --git a/crates/collab_ui/src/channel_view.rs b/crates/collab_ui/src/channel_view.rs index 27873b1067..ce68acfbd8 100644 --- a/crates/collab_ui/src/channel_view.rs +++ b/crates/collab_ui/src/channel_view.rs @@ -172,7 +172,7 @@ impl ChannelView { cx.notify(); }), ChannelBufferEvent::ChannelChanged => { - self.editor.update(cx, |editor, cx| { + self.editor.update(cx, |_, cx| { cx.emit(editor::EditorEvent::TitleChanged); cx.notify() }); diff --git a/crates/collab_ui/src/collab_panel.rs b/crates/collab_ui/src/collab_panel.rs index 3ed07e5bd1..457a31ff5d 100644 --- a/crates/collab_ui/src/collab_panel.rs +++ b/crates/collab_ui/src/collab_panel.rs @@ -151,6 +151,9 @@ enum ListEntry { peer_id: Option, is_last: bool, }, + GuestCount { + count: usize, + }, IncomingRequest(Arc), OutgoingRequest(Arc), ChannelInvite(Arc), @@ -380,10 +383,13 @@ impl CollabPanel { if !self.collapsed_sections.contains(&Section::ActiveCall) { let room = room.read(cx); + let mut guest_count_ix = 0; + let mut guest_count = if room.read_only() { 1 } else { 0 }; if let Some(channel_id) = room.channel_id() { self.entries.push(ListEntry::ChannelNotes { channel_id }); - self.entries.push(ListEntry::ChannelChat { channel_id }) + self.entries.push(ListEntry::ChannelChat { channel_id }); + guest_count_ix = self.entries.len(); } // Populate the active user. @@ -402,7 +408,7 @@ impl CollabPanel { &Default::default(), executor.clone(), )); - if !matches.is_empty() { + if !matches.is_empty() && !room.read_only() { let user_id = user.id; self.entries.push(ListEntry::CallParticipant { user, @@ -430,13 +436,21 @@ impl CollabPanel { // Populate remote participants. self.match_candidates.clear(); self.match_candidates - .extend(room.remote_participants().iter().map(|(_, participant)| { - StringMatchCandidate { - id: participant.user.id as usize, - string: participant.user.github_login.clone(), - char_bag: participant.user.github_login.chars().collect(), - } - })); + .extend( + room.remote_participants() + .iter() + .filter_map(|(_, participant)| { + if participant.role == proto::ChannelRole::Guest { + guest_count += 1; + return None; + } + Some(StringMatchCandidate { + id: participant.user.id as usize, + string: participant.user.github_login.clone(), + char_bag: participant.user.github_login.chars().collect(), + }) + }), + ); let matches = executor.block(match_strings( &self.match_candidates, &query, @@ -470,6 +484,10 @@ impl CollabPanel { }); } } + if guest_count > 0 { + self.entries + .insert(guest_count_ix, ListEntry::GuestCount { count: guest_count }); + } // Populate pending participants. self.match_candidates.clear(); @@ -959,6 +977,34 @@ impl CollabPanel { .tooltip(move |cx| Tooltip::text("Open Chat", cx)) } + fn render_guest_count( + &self, + count: usize, + is_selected: bool, + cx: &mut ViewContext, + ) -> impl IntoElement { + // TODO! disable manage_members for guests. + ListItem::new("guest_count") + .selected(is_selected) + .on_click(cx.listener(move |this, _, cx| { + if let Some(channel_id) = ActiveCall::global(cx).read(cx).channel_id(cx) { + this.manage_members(channel_id, cx) + } + })) + .start_slot( + h_stack() + .gap_1() + .child(render_tree_branch(false, cx)) + .child(""), + ) + .child(Label::new(if count == 1 { + format!("{} guest", count) + } else { + format!("{} guests", count) + })) + .tooltip(move |cx| Tooltip::text("Manage Members", cx)) + } + fn has_subchannels(&self, ix: usize) -> bool { self.entries.get(ix).map_or(false, |entry| { if let ListEntry::Channel { has_children, .. } = entry { @@ -1180,6 +1226,11 @@ impl CollabPanel { }); } } + ListEntry::GuestCount { .. } => { + if let Some(channel_id) = ActiveCall::global(cx).read(cx).channel_id(cx) { + self.manage_members(channel_id, cx) + } + } ListEntry::Channel { channel, .. } => { let is_active = maybe!({ let call_channel = ActiveCall::global(cx) @@ -1735,6 +1786,9 @@ impl CollabPanel { ListEntry::ParticipantScreen { peer_id, is_last } => self .render_participant_screen(*peer_id, *is_last, is_selected, cx) .into_any_element(), + ListEntry::GuestCount { count } => self + .render_guest_count(*count, is_selected, cx) + .into_any_element(), ListEntry::ChannelNotes { channel_id } => self .render_channel_notes(*channel_id, is_selected, cx) .into_any_element(), @@ -2504,6 +2558,11 @@ impl PartialEq for ListEntry { return true; } } + ListEntry::GuestCount { .. } => { + if let ListEntry::GuestCount { .. } = other { + return true; + } + } } false } diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index a3f82b1f5f..81a71da27e 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -10,6 +10,7 @@ use gpui::{ }; use project::{Project, RepositoryEntry}; use recent_projects::RecentProjects; +use rpc::proto; use std::sync::Arc; use theme::{ActiveTheme, PlayerColors}; use ui::{ @@ -173,9 +174,9 @@ impl Render for CollabTitlebarItem { let is_muted = room.is_muted(cx); let is_deafened = room.is_deafened().unwrap_or(false); let is_screen_sharing = room.is_screen_sharing(); - let can_publish = room.can_publish(); + let read_only = room.read_only(); - this.when(is_local && can_publish, |this| { + this.when(is_local && !read_only, |this| { this.child( Button::new( "toggle_sharing", @@ -204,7 +205,7 @@ impl Render for CollabTitlebarItem { .detach_and_log_err(cx); }), ) - .when(can_publish, |this| { + .when(!read_only, |this| { this.child( IconButton::new( "mute-microphone", @@ -233,7 +234,7 @@ impl Render for CollabTitlebarItem { .icon_size(IconSize::Small) .selected(is_deafened) .tooltip(move |cx| { - if can_publish { + if !read_only { Tooltip::with_meta( "Deafen Audio", None, @@ -246,7 +247,7 @@ impl Render for CollabTitlebarItem { }) .on_click(move |_, cx| crate::toggle_deafen(&Default::default(), cx)), ) - .when(can_publish, |this| { + .when(!read_only, |this| { this.child( IconButton::new("screen-share", ui::Icon::Screen) .style(ButtonStyle::Subtle) @@ -420,6 +421,10 @@ impl CollabTitlebarItem { project_id: Option, current_user: &Arc, ) -> Option { + if room.role_for_user(user.id) == Some(proto::ChannelRole::Guest) { + return None; + } + let followers = project_id.map_or(&[] as &[_], |id| room.followers_for(peer_id, id)); let pile = FacePile::default() diff --git a/crates/theme/src/styles/players.rs b/crates/theme/src/styles/players.rs index 089de24723..d4d27e7123 100644 --- a/crates/theme/src/styles/players.rs +++ b/crates/theme/src/styles/players.rs @@ -1,7 +1,7 @@ -use gpui::{hsla, Hsla}; +use gpui::Hsla; use serde_derive::Deserialize; -use crate::{amber, blue, gray, jade, lime, orange, pink, purple, red}; +use crate::{amber, blue, jade, lime, orange, pink, purple, red}; #[derive(Debug, Clone, Copy, Deserialize, Default)] pub struct PlayerColor {