Show guests in fewer places

This commit is contained in:
Conrad Irwin 2024-01-03 14:44:09 -07:00
parent c3402024bc
commit 1930258d39
7 changed files with 100 additions and 26 deletions

View file

@ -43,6 +43,7 @@ pub struct LocalParticipant {
pub struct RemoteParticipant { pub struct RemoteParticipant {
pub user: Arc<User>, pub user: Arc<User>,
pub peer_id: proto::PeerId, pub peer_id: proto::PeerId,
pub role: proto::ChannelRole,
pub projects: Vec<proto::ParticipantProject>, pub projects: Vec<proto::ParticipantProject>,
pub location: ParticipantLocation, pub location: ParticipantLocation,
pub participant_index: ParticipantIndex, pub participant_index: ParticipantIndex,

View file

@ -610,6 +610,12 @@ impl Room {
.find(|p| p.peer_id == peer_id) .find(|p| p.peer_id == peer_id)
} }
pub fn role_for_user(&self, user_id: u64) -> Option<proto::ChannelRole> {
self.remote_participants
.get(&user_id)
.map(|participant| participant.role)
}
pub fn pending_participants(&self) -> &[Arc<User>] { pub fn pending_participants(&self) -> &[Arc<User>] {
&self.pending_participants &self.pending_participants
} }
@ -784,6 +790,7 @@ impl Room {
}); });
} }
let role = participant.role();
let location = ParticipantLocation::from_proto(participant.location) let location = ParticipantLocation::from_proto(participant.location)
.unwrap_or(ParticipantLocation::External); .unwrap_or(ParticipantLocation::External);
if let Some(remote_participant) = if let Some(remote_participant) =
@ -792,8 +799,11 @@ impl Room {
remote_participant.peer_id = peer_id; remote_participant.peer_id = peer_id;
remote_participant.projects = participant.projects; remote_participant.projects = participant.projects;
remote_participant.participant_index = participant_index; 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.location = location;
remote_participant.role = role;
cx.emit(Event::ParticipantLocationChanged { cx.emit(Event::ParticipantLocationChanged {
participant_id: peer_id, participant_id: peer_id,
}); });
@ -807,6 +817,7 @@ impl Room {
peer_id, peer_id,
projects: participant.projects, projects: participant.projects,
location, location,
role,
muted: true, muted: true,
speaking: false, speaking: false,
video_tracks: Default::default(), video_tracks: Default::default(),
@ -1251,9 +1262,9 @@ impl Room {
.unwrap_or(false) .unwrap_or(false)
} }
pub fn can_publish(&self) -> bool { pub fn read_only(&self) -> bool {
self.local_participant().role == proto::ChannelRole::Member !(self.local_participant().role == proto::ChannelRole::Member
|| self.local_participant().role == proto::ChannelRole::Admin || self.local_participant().role == proto::ChannelRole::Admin)
} }
pub fn is_speaking(&self) -> bool { pub fn is_speaking(&self) -> bool {

View file

@ -7,8 +7,8 @@ use workspace::Workspace;
#[gpui::test] #[gpui::test]
async fn test_channel_guests( async fn test_channel_guests(
executor: BackgroundExecutor, executor: BackgroundExecutor,
mut cx_a: &mut TestAppContext, cx_a: &mut TestAppContext,
mut cx_b: &mut TestAppContext, cx_b: &mut TestAppContext,
) { ) {
let mut server = TestServer::start(executor.clone()).await; let mut server = TestServer::start(executor.clone()).await;
let client_a = server.create_client(cx_a, "user_a").await; let client_a = server.create_client(cx_a, "user_a").await;
@ -37,15 +37,13 @@ async fn test_channel_guests(
.await; .await;
let active_call_a = cx_a.read(ActiveCall::global); 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 // Client A shares a project in the channel
active_call_a active_call_a
.update(cx_a, |call, cx| call.join_channel(channel_id, cx)) .update(cx_a, |call, cx| call.join_channel(channel_id, cx))
.await .await
.unwrap(); .unwrap();
let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await; let (project_a, _) = 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_id = active_call_a let project_id = active_call_a
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx)) .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await .await

View file

@ -172,7 +172,7 @@ impl ChannelView {
cx.notify(); cx.notify();
}), }),
ChannelBufferEvent::ChannelChanged => { ChannelBufferEvent::ChannelChanged => {
self.editor.update(cx, |editor, cx| { self.editor.update(cx, |_, cx| {
cx.emit(editor::EditorEvent::TitleChanged); cx.emit(editor::EditorEvent::TitleChanged);
cx.notify() cx.notify()
}); });

View file

@ -151,6 +151,9 @@ enum ListEntry {
peer_id: Option<PeerId>, peer_id: Option<PeerId>,
is_last: bool, is_last: bool,
}, },
GuestCount {
count: usize,
},
IncomingRequest(Arc<User>), IncomingRequest(Arc<User>),
OutgoingRequest(Arc<User>), OutgoingRequest(Arc<User>),
ChannelInvite(Arc<Channel>), ChannelInvite(Arc<Channel>),
@ -380,10 +383,13 @@ impl CollabPanel {
if !self.collapsed_sections.contains(&Section::ActiveCall) { if !self.collapsed_sections.contains(&Section::ActiveCall) {
let room = room.read(cx); 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() { if let Some(channel_id) = room.channel_id() {
self.entries.push(ListEntry::ChannelNotes { 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. // Populate the active user.
@ -402,7 +408,7 @@ impl CollabPanel {
&Default::default(), &Default::default(),
executor.clone(), executor.clone(),
)); ));
if !matches.is_empty() { if !matches.is_empty() && !room.read_only() {
let user_id = user.id; let user_id = user.id;
self.entries.push(ListEntry::CallParticipant { self.entries.push(ListEntry::CallParticipant {
user, user,
@ -430,13 +436,21 @@ impl CollabPanel {
// Populate remote participants. // Populate remote participants.
self.match_candidates.clear(); self.match_candidates.clear();
self.match_candidates self.match_candidates
.extend(room.remote_participants().iter().map(|(_, participant)| { .extend(
StringMatchCandidate { room.remote_participants()
id: participant.user.id as usize, .iter()
string: participant.user.github_login.clone(), .filter_map(|(_, participant)| {
char_bag: participant.user.github_login.chars().collect(), 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( let matches = executor.block(match_strings(
&self.match_candidates, &self.match_candidates,
&query, &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. // Populate pending participants.
self.match_candidates.clear(); self.match_candidates.clear();
@ -959,6 +977,34 @@ impl CollabPanel {
.tooltip(move |cx| Tooltip::text("Open Chat", cx)) .tooltip(move |cx| Tooltip::text("Open Chat", cx))
} }
fn render_guest_count(
&self,
count: usize,
is_selected: bool,
cx: &mut ViewContext<Self>,
) -> 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 { fn has_subchannels(&self, ix: usize) -> bool {
self.entries.get(ix).map_or(false, |entry| { self.entries.get(ix).map_or(false, |entry| {
if let ListEntry::Channel { has_children, .. } = 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, .. } => { ListEntry::Channel { channel, .. } => {
let is_active = maybe!({ let is_active = maybe!({
let call_channel = ActiveCall::global(cx) let call_channel = ActiveCall::global(cx)
@ -1735,6 +1786,9 @@ impl CollabPanel {
ListEntry::ParticipantScreen { peer_id, is_last } => self ListEntry::ParticipantScreen { peer_id, is_last } => self
.render_participant_screen(*peer_id, *is_last, is_selected, cx) .render_participant_screen(*peer_id, *is_last, is_selected, cx)
.into_any_element(), .into_any_element(),
ListEntry::GuestCount { count } => self
.render_guest_count(*count, is_selected, cx)
.into_any_element(),
ListEntry::ChannelNotes { channel_id } => self ListEntry::ChannelNotes { channel_id } => self
.render_channel_notes(*channel_id, is_selected, cx) .render_channel_notes(*channel_id, is_selected, cx)
.into_any_element(), .into_any_element(),
@ -2504,6 +2558,11 @@ impl PartialEq for ListEntry {
return true; return true;
} }
} }
ListEntry::GuestCount { .. } => {
if let ListEntry::GuestCount { .. } = other {
return true;
}
}
} }
false false
} }

View file

@ -10,6 +10,7 @@ use gpui::{
}; };
use project::{Project, RepositoryEntry}; use project::{Project, RepositoryEntry};
use recent_projects::RecentProjects; use recent_projects::RecentProjects;
use rpc::proto;
use std::sync::Arc; use std::sync::Arc;
use theme::{ActiveTheme, PlayerColors}; use theme::{ActiveTheme, PlayerColors};
use ui::{ use ui::{
@ -173,9 +174,9 @@ impl Render for CollabTitlebarItem {
let is_muted = room.is_muted(cx); let is_muted = room.is_muted(cx);
let is_deafened = room.is_deafened().unwrap_or(false); let is_deafened = room.is_deafened().unwrap_or(false);
let is_screen_sharing = room.is_screen_sharing(); 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( this.child(
Button::new( Button::new(
"toggle_sharing", "toggle_sharing",
@ -204,7 +205,7 @@ impl Render for CollabTitlebarItem {
.detach_and_log_err(cx); .detach_and_log_err(cx);
}), }),
) )
.when(can_publish, |this| { .when(!read_only, |this| {
this.child( this.child(
IconButton::new( IconButton::new(
"mute-microphone", "mute-microphone",
@ -233,7 +234,7 @@ impl Render for CollabTitlebarItem {
.icon_size(IconSize::Small) .icon_size(IconSize::Small)
.selected(is_deafened) .selected(is_deafened)
.tooltip(move |cx| { .tooltip(move |cx| {
if can_publish { if !read_only {
Tooltip::with_meta( Tooltip::with_meta(
"Deafen Audio", "Deafen Audio",
None, None,
@ -246,7 +247,7 @@ impl Render for CollabTitlebarItem {
}) })
.on_click(move |_, cx| crate::toggle_deafen(&Default::default(), cx)), .on_click(move |_, cx| crate::toggle_deafen(&Default::default(), cx)),
) )
.when(can_publish, |this| { .when(!read_only, |this| {
this.child( this.child(
IconButton::new("screen-share", ui::Icon::Screen) IconButton::new("screen-share", ui::Icon::Screen)
.style(ButtonStyle::Subtle) .style(ButtonStyle::Subtle)
@ -420,6 +421,10 @@ impl CollabTitlebarItem {
project_id: Option<u64>, project_id: Option<u64>,
current_user: &Arc<User>, current_user: &Arc<User>,
) -> Option<FacePile> { ) -> Option<FacePile> {
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 followers = project_id.map_or(&[] as &[_], |id| room.followers_for(peer_id, id));
let pile = FacePile::default() let pile = FacePile::default()

View file

@ -1,7 +1,7 @@
use gpui::{hsla, Hsla}; use gpui::Hsla;
use serde_derive::Deserialize; 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)] #[derive(Debug, Clone, Copy, Deserialize, Default)]
pub struct PlayerColor { pub struct PlayerColor {