Absolute pain of the iterator kind (start laying out a user's followers)

This commit is contained in:
Julia 2023-02-03 18:20:24 -05:00
parent 2592ec7265
commit 58c41778e7
3 changed files with 70 additions and 26 deletions

View file

@ -55,7 +55,7 @@ pub struct Room {
leave_when_empty: bool, leave_when_empty: bool,
client: Arc<Client>, client: Arc<Client>,
user_store: ModelHandle<UserStore>, user_store: ModelHandle<UserStore>,
follows_by_leader_id: HashMap<PeerId, HashSet<PeerId>>, follows_by_leader_id: HashMap<PeerId, Vec<PeerId>>,
subscriptions: Vec<client::Subscription>, subscriptions: Vec<client::Subscription>,
pending_room_update: Option<Task<()>>, pending_room_update: Option<Task<()>>,
maintain_connection: Option<Task<Option<()>>>, maintain_connection: Option<Task<Option<()>>>,
@ -459,6 +459,12 @@ impl Room {
self.participant_user_ids.contains(&user_id) self.participant_user_ids.contains(&user_id)
} }
pub fn follows(&self, leader_id: PeerId) -> &[PeerId] {
self.follows_by_leader_id
.get(&leader_id)
.map_or(&[], |v| v.as_slice())
}
async fn handle_room_updated( async fn handle_room_updated(
this: ModelHandle<Self>, this: ModelHandle<Self>,
envelope: TypedEnvelope<proto::RoomUpdated>, envelope: TypedEnvelope<proto::RoomUpdated>,
@ -636,10 +642,13 @@ impl Room {
} }
}; };
this.follows_by_leader_id let list = this
.follows_by_leader_id
.entry(leader) .entry(leader)
.or_insert(Default::default()) .or_insert(Vec::new());
.insert(follower); if !list.contains(&follower) {
list.push(follower);
}
} }
this.pending_room_update.take(); this.pending_room_update.take();

View file

@ -12,11 +12,11 @@ use gpui::{
elements::*, elements::*,
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, ImageData, ModelHandle, MouseButton, MutableAppContext,
Subscription, View, ViewContext, ViewHandle, WeakViewHandle, RenderContext, Subscription, View, ViewContext, ViewHandle, WeakViewHandle,
}; };
use settings::Settings; use settings::Settings;
use std::ops::Range; use std::{ops::Range, sync::Arc};
use theme::Theme; use theme::Theme;
use util::ResultExt; use util::ResultExt;
use workspace::{FollowNextCollaborator, JoinProject, ToggleFollow, Workspace}; use workspace::{FollowNextCollaborator, JoinProject, ToggleFollow, Workspace};
@ -510,11 +510,7 @@ impl CollabTitlebarItem {
Some(self.render_face_pile( Some(self.render_face_pile(
&user, &user,
replica_id, replica_id,
Some(( Some((participant.peer_id, participant.location)),
participant.peer_id,
&user.github_login,
participant.location,
)),
workspace, workspace,
theme, theme,
cx, cx,
@ -564,18 +560,23 @@ impl CollabTitlebarItem {
&self, &self,
user: &User, user: &User,
replica_id: Option<ReplicaId>, replica_id: Option<ReplicaId>,
peer: Option<(PeerId, &str, ParticipantLocation)>, peer_id_and_location: Option<(PeerId, ParticipantLocation)>,
workspace: &ViewHandle<Workspace>, workspace: &ViewHandle<Workspace>,
theme: &Theme, theme: &Theme,
cx: &mut RenderContext<Self>, cx: &mut RenderContext<Self>,
) -> ElementBox { ) -> ElementBox {
let is_followed = peer.map_or(false, |(peer_id, _, _)| { let is_followed = peer_id_and_location.map_or(false, |(peer_id, _)| {
workspace.read(cx).is_following(peer_id) workspace.read(cx).is_following(peer_id)
}); });
let room = ActiveCall::global(cx).read(cx).room();
let get_followers = |leader_id: PeerId| -> &[PeerId] {
room.map_or(&[], |room| room.read(cx).follows(leader_id))
};
let mut avatar_style; let mut avatar_style;
if let Some((_, _, location)) = peer.as_ref() { if let Some((_, location)) = peer_id_and_location {
if let ParticipantLocation::SharedProject { project_id } = *location { if let ParticipantLocation::SharedProject { project_id } = location {
if Some(project_id) == workspace.read(cx).project().read(cx).remote_id() { if Some(project_id) == workspace.read(cx).project().read(cx).remote_id() {
avatar_style = theme.workspace.titlebar.avatar; avatar_style = theme.workspace.titlebar.avatar;
} else { } else {
@ -599,11 +600,36 @@ impl CollabTitlebarItem {
let content = Stack::new() let content = Stack::new()
.with_children(user.avatar.as_ref().map(|avatar| { .with_children(user.avatar.as_ref().map(|avatar| {
Image::new(avatar.clone()) Flex::row()
.with_style(avatar_style) .with_child(Self::render_face(avatar.clone(), avatar_style, theme))
.constrained() .with_children(
.with_width(theme.workspace.titlebar.avatar_width) peer_id_and_location
.aligned() .map(|(peer_id, _)| {
get_followers(peer_id)
.into_iter()
.map(|&follower| {
room.map(|room| {
room.read(cx)
.remote_participant_for_peer_id(follower)
.map(|participant| {
participant.user.avatar.as_ref().map(|avatar| {
Self::render_face(
avatar.clone(),
avatar_style,
theme,
)
})
})
.flatten()
})
.flatten()
})
.flatten()
})
.into_iter()
.flatten(),
)
.with_reversed_paint_order()
.boxed() .boxed()
})) }))
.with_children(replica_color.map(|replica_color| { .with_children(replica_color.map(|replica_color| {
@ -621,7 +647,7 @@ impl CollabTitlebarItem {
.with_margin_left(theme.workspace.titlebar.avatar_margin) .with_margin_left(theme.workspace.titlebar.avatar_margin)
.boxed(); .boxed();
if let Some((peer_id, peer_github_login, location)) = peer { if let Some((peer_id, location)) = peer_id_and_location {
if let Some(replica_id) = replica_id { if let Some(replica_id) = replica_id {
MouseEventHandler::<ToggleFollow>::new(replica_id.into(), cx, move |_, _| content) MouseEventHandler::<ToggleFollow>::new(replica_id.into(), cx, move |_, _| content)
.with_cursor_style(CursorStyle::PointingHand) .with_cursor_style(CursorStyle::PointingHand)
@ -631,9 +657,9 @@ impl CollabTitlebarItem {
.with_tooltip::<ToggleFollow, _>( .with_tooltip::<ToggleFollow, _>(
peer_id.as_u64() as usize, peer_id.as_u64() as usize,
if is_followed { if is_followed {
format!("Unfollow {}", peer_github_login) format!("Unfollow {}", user.github_login)
} else { } else {
format!("Follow {}", peer_github_login) format!("Follow {}", user.github_login)
}, },
Some(Box::new(FollowNextCollaborator)), Some(Box::new(FollowNextCollaborator)),
theme.tooltip.clone(), theme.tooltip.clone(),
@ -654,7 +680,7 @@ impl CollabTitlebarItem {
}) })
.with_tooltip::<JoinProject, _>( .with_tooltip::<JoinProject, _>(
peer_id.as_u64() as usize, peer_id.as_u64() as usize,
format!("Follow {} into external project", peer_github_login), format!("Follow {} into external project", user.github_login),
Some(Box::new(FollowNextCollaborator)), Some(Box::new(FollowNextCollaborator)),
theme.tooltip.clone(), theme.tooltip.clone(),
cx, cx,
@ -668,6 +694,15 @@ impl CollabTitlebarItem {
} }
} }
fn render_face(avatar: Arc<ImageData>, avatar_style: ImageStyle, theme: &Theme) -> ElementBox {
Image::new(avatar)
.with_style(avatar_style)
.constrained()
.with_width(theme.workspace.titlebar.avatar_width)
.aligned()
.boxed()
}
fn render_connection_status( fn render_connection_status(
&self, &self,
workspace: &ViewHandle<Workspace>, workspace: &ViewHandle<Workspace>,

View file

@ -837,7 +837,7 @@ impl Workspace {
&self.project &self.project
} }
pub fn client(&self) -> &Arc<Client> { pub fn client(&self) -> &Client {
&self.client &self.client
} }