Allow adding write access to guests
This commit is contained in:
parent
ca0c06b577
commit
844d161c40
16 changed files with 349 additions and 145 deletions
|
@ -37,7 +37,7 @@ use ui::{
|
|||
use util::{maybe, ResultExt, TryFutureExt};
|
||||
use workspace::{
|
||||
dock::{DockPosition, Panel, PanelEvent},
|
||||
notifications::NotifyResultExt,
|
||||
notifications::{NotifyResultExt, NotifyTaskExt},
|
||||
Workspace,
|
||||
};
|
||||
|
||||
|
@ -140,6 +140,7 @@ enum ListEntry {
|
|||
user: Arc<User>,
|
||||
peer_id: Option<PeerId>,
|
||||
is_pending: bool,
|
||||
role: proto::ChannelRole,
|
||||
},
|
||||
ParticipantProject {
|
||||
project_id: u64,
|
||||
|
@ -151,10 +152,6 @@ enum ListEntry {
|
|||
peer_id: Option<PeerId>,
|
||||
is_last: bool,
|
||||
},
|
||||
GuestCount {
|
||||
count: usize,
|
||||
has_visible_participants: bool,
|
||||
},
|
||||
IncomingRequest(Arc<User>),
|
||||
OutgoingRequest(Arc<User>),
|
||||
ChannelInvite(Arc<Channel>),
|
||||
|
@ -384,14 +381,10 @@ 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 };
|
||||
let mut non_guest_count = if room.read_only() { 0 } else { 1 };
|
||||
|
||||
if let Some(channel_id) = room.channel_id() {
|
||||
self.entries.push(ListEntry::ChannelNotes { channel_id });
|
||||
self.entries.push(ListEntry::ChannelChat { channel_id });
|
||||
guest_count_ix = self.entries.len();
|
||||
}
|
||||
|
||||
// Populate the active user.
|
||||
|
@ -410,12 +403,13 @@ impl CollabPanel {
|
|||
&Default::default(),
|
||||
executor.clone(),
|
||||
));
|
||||
if !matches.is_empty() && !room.read_only() {
|
||||
if !matches.is_empty() {
|
||||
let user_id = user.id;
|
||||
self.entries.push(ListEntry::CallParticipant {
|
||||
user,
|
||||
peer_id: None,
|
||||
is_pending: false,
|
||||
role: room.local_participant().role,
|
||||
});
|
||||
let mut projects = room.local_participant().projects.iter().peekable();
|
||||
while let Some(project) = projects.next() {
|
||||
|
@ -442,12 +436,6 @@ impl CollabPanel {
|
|||
room.remote_participants()
|
||||
.iter()
|
||||
.filter_map(|(_, participant)| {
|
||||
if participant.role == proto::ChannelRole::Guest {
|
||||
guest_count += 1;
|
||||
return None;
|
||||
} else {
|
||||
non_guest_count += 1;
|
||||
}
|
||||
Some(StringMatchCandidate {
|
||||
id: participant.user.id as usize,
|
||||
string: participant.user.github_login.clone(),
|
||||
|
@ -455,7 +443,7 @@ impl CollabPanel {
|
|||
})
|
||||
}),
|
||||
);
|
||||
let matches = executor.block(match_strings(
|
||||
let mut matches = executor.block(match_strings(
|
||||
&self.match_candidates,
|
||||
&query,
|
||||
true,
|
||||
|
@ -463,6 +451,15 @@ impl CollabPanel {
|
|||
&Default::default(),
|
||||
executor.clone(),
|
||||
));
|
||||
matches.sort_by(|a, b| {
|
||||
let a_is_guest = room.role_for_user(a.candidate_id as u64)
|
||||
== Some(proto::ChannelRole::Guest);
|
||||
let b_is_guest = room.role_for_user(b.candidate_id as u64)
|
||||
== Some(proto::ChannelRole::Guest);
|
||||
a_is_guest
|
||||
.cmp(&b_is_guest)
|
||||
.then_with(|| a.string.cmp(&b.string))
|
||||
});
|
||||
for mat in matches {
|
||||
let user_id = mat.candidate_id as u64;
|
||||
let participant = &room.remote_participants()[&user_id];
|
||||
|
@ -470,6 +467,7 @@ impl CollabPanel {
|
|||
user: participant.user.clone(),
|
||||
peer_id: Some(participant.peer_id),
|
||||
is_pending: false,
|
||||
role: participant.role,
|
||||
});
|
||||
let mut projects = participant.projects.iter().peekable();
|
||||
while let Some(project) = projects.next() {
|
||||
|
@ -488,15 +486,6 @@ impl CollabPanel {
|
|||
});
|
||||
}
|
||||
}
|
||||
if guest_count > 0 {
|
||||
self.entries.insert(
|
||||
guest_count_ix,
|
||||
ListEntry::GuestCount {
|
||||
count: guest_count,
|
||||
has_visible_participants: non_guest_count > 0,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Populate pending participants.
|
||||
self.match_candidates.clear();
|
||||
|
@ -521,6 +510,7 @@ impl CollabPanel {
|
|||
user: room.pending_participants()[mat.candidate_id].clone(),
|
||||
peer_id: None,
|
||||
is_pending: true,
|
||||
role: proto::ChannelRole::Member,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -834,13 +824,19 @@ impl CollabPanel {
|
|||
user: &Arc<User>,
|
||||
peer_id: Option<PeerId>,
|
||||
is_pending: bool,
|
||||
role: proto::ChannelRole,
|
||||
is_selected: bool,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> ListItem {
|
||||
let user_id = user.id;
|
||||
let is_current_user =
|
||||
self.user_store.read(cx).current_user().map(|user| user.id) == Some(user.id);
|
||||
self.user_store.read(cx).current_user().map(|user| user.id) == Some(user_id);
|
||||
let tooltip = format!("Follow {}", user.github_login);
|
||||
|
||||
let is_call_admin = ActiveCall::global(cx).read(cx).room().is_some_and(|room| {
|
||||
room.read(cx).local_participant().role == proto::ChannelRole::Admin
|
||||
});
|
||||
|
||||
ListItem::new(SharedString::from(user.github_login.clone()))
|
||||
.start_slot(Avatar::new(user.avatar_uri.clone()))
|
||||
.child(Label::new(user.github_login.clone()))
|
||||
|
@ -853,17 +849,27 @@ impl CollabPanel {
|
|||
.on_click(move |_, cx| Self::leave_call(cx))
|
||||
.tooltip(|cx| Tooltip::text("Leave Call", cx))
|
||||
.into_any_element()
|
||||
} else if role == proto::ChannelRole::Guest {
|
||||
Label::new("Guest").color(Color::Muted).into_any_element()
|
||||
} else {
|
||||
div().into_any_element()
|
||||
})
|
||||
.when_some(peer_id, |this, peer_id| {
|
||||
this.tooltip(move |cx| Tooltip::text(tooltip.clone(), cx))
|
||||
.when_some(peer_id, |el, peer_id| {
|
||||
if role == proto::ChannelRole::Guest {
|
||||
return el;
|
||||
}
|
||||
el.tooltip(move |cx| Tooltip::text(tooltip.clone(), cx))
|
||||
.on_click(cx.listener(move |this, _, cx| {
|
||||
this.workspace
|
||||
.update(cx, |workspace, cx| workspace.follow(peer_id, cx))
|
||||
.ok();
|
||||
}))
|
||||
})
|
||||
.when(is_call_admin && role == proto::ChannelRole::Guest, |el| {
|
||||
el.on_secondary_mouse_down(cx.listener(move |this, event: &MouseDownEvent, cx| {
|
||||
this.deploy_participant_context_menu(event.position, user_id, cx)
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
fn render_participant_project(
|
||||
|
@ -986,41 +992,6 @@ impl CollabPanel {
|
|||
.tooltip(move |cx| Tooltip::text("Open Chat", cx))
|
||||
}
|
||||
|
||||
fn render_guest_count(
|
||||
&self,
|
||||
count: usize,
|
||||
has_visible_participants: bool,
|
||||
is_selected: bool,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> impl IntoElement {
|
||||
let manageable_channel_id = ActiveCall::global(cx).read(cx).room().and_then(|room| {
|
||||
let room = room.read(cx);
|
||||
if room.local_participant_is_admin() {
|
||||
room.channel_id()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
ListItem::new("guest_count")
|
||||
.selected(is_selected)
|
||||
.start_slot(
|
||||
h_stack()
|
||||
.gap_1()
|
||||
.child(render_tree_branch(!has_visible_participants, false, cx))
|
||||
.child(""),
|
||||
)
|
||||
.child(Label::new(if count == 1 {
|
||||
format!("{} guest", count)
|
||||
} else {
|
||||
format!("{} guests", count)
|
||||
}))
|
||||
.when_some(manageable_channel_id, |el, channel_id| {
|
||||
el.tooltip(move |cx| Tooltip::text("Manage Members", cx))
|
||||
.on_click(cx.listener(move |this, _, cx| this.manage_members(channel_id, cx)))
|
||||
})
|
||||
}
|
||||
|
||||
fn has_subchannels(&self, ix: usize) -> bool {
|
||||
self.entries.get(ix).map_or(false, |entry| {
|
||||
if let ListEntry::Channel { has_children, .. } = entry {
|
||||
|
@ -1031,6 +1002,47 @@ impl CollabPanel {
|
|||
})
|
||||
}
|
||||
|
||||
fn deploy_participant_context_menu(
|
||||
&mut self,
|
||||
position: Point<Pixels>,
|
||||
user_id: u64,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
let this = cx.view().clone();
|
||||
|
||||
let context_menu = ContextMenu::build(cx, |context_menu, cx| {
|
||||
context_menu.entry(
|
||||
"Allow Write Access",
|
||||
None,
|
||||
cx.handler_for(&this, move |_, cx| {
|
||||
ActiveCall::global(cx)
|
||||
.update(cx, |call, cx| {
|
||||
let Some(room) = call.room() else {
|
||||
return Task::ready(Ok(()));
|
||||
};
|
||||
room.update(cx, |room, cx| {
|
||||
room.set_participant_role(user_id, proto::ChannelRole::Member, cx)
|
||||
})
|
||||
})
|
||||
.detach_and_notify_err(cx)
|
||||
}),
|
||||
)
|
||||
});
|
||||
|
||||
cx.focus_view(&context_menu);
|
||||
let subscription =
|
||||
cx.subscribe(&context_menu, |this, _, _: &DismissEvent, cx| {
|
||||
if this.context_menu.as_ref().is_some_and(|context_menu| {
|
||||
context_menu.0.focus_handle(cx).contains_focused(cx)
|
||||
}) {
|
||||
cx.focus_self();
|
||||
}
|
||||
this.context_menu.take();
|
||||
cx.notify();
|
||||
});
|
||||
self.context_menu = Some((context_menu, position, subscription));
|
||||
}
|
||||
|
||||
fn deploy_channel_context_menu(
|
||||
&mut self,
|
||||
position: Point<Pixels>,
|
||||
|
@ -1242,18 +1254,6 @@ impl CollabPanel {
|
|||
});
|
||||
}
|
||||
}
|
||||
ListEntry::GuestCount { .. } => {
|
||||
let Some(room) = ActiveCall::global(cx).read(cx).room() else {
|
||||
return;
|
||||
};
|
||||
let room = room.read(cx);
|
||||
let Some(channel_id) = room.channel_id() else {
|
||||
return;
|
||||
};
|
||||
if room.local_participant_is_admin() {
|
||||
self.manage_members(channel_id, cx)
|
||||
}
|
||||
}
|
||||
ListEntry::Channel { channel, .. } => {
|
||||
let is_active = maybe!({
|
||||
let call_channel = ActiveCall::global(cx)
|
||||
|
@ -1788,8 +1788,9 @@ impl CollabPanel {
|
|||
user,
|
||||
peer_id,
|
||||
is_pending,
|
||||
role,
|
||||
} => self
|
||||
.render_call_participant(user, *peer_id, *is_pending, is_selected, cx)
|
||||
.render_call_participant(user, *peer_id, *is_pending, *role, is_selected, cx)
|
||||
.into_any_element(),
|
||||
ListEntry::ParticipantProject {
|
||||
project_id,
|
||||
|
@ -1809,12 +1810,6 @@ 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,
|
||||
has_visible_participants,
|
||||
} => self
|
||||
.render_guest_count(*count, *has_visible_participants, is_selected, cx)
|
||||
.into_any_element(),
|
||||
ListEntry::ChannelNotes { channel_id } => self
|
||||
.render_channel_notes(*channel_id, is_selected, cx)
|
||||
.into_any_element(),
|
||||
|
@ -2621,11 +2616,6 @@ impl PartialEq for ListEntry {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
ListEntry::GuestCount { .. } => {
|
||||
if let ListEntry::GuestCount { .. } = other {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue