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,
client: Arc<Client>,
user_store: ModelHandle<UserStore>,
follows_by_leader_id: HashMap<PeerId, HashSet<PeerId>>,
follows_by_leader_id: HashMap<PeerId, Vec<PeerId>>,
subscriptions: Vec<client::Subscription>,
pending_room_update: Option<Task<()>>,
maintain_connection: Option<Task<Option<()>>>,
@ -459,6 +459,12 @@ impl Room {
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(
this: ModelHandle<Self>,
envelope: TypedEnvelope<proto::RoomUpdated>,
@ -636,10 +642,13 @@ impl Room {
}
};
this.follows_by_leader_id
let list = this
.follows_by_leader_id
.entry(leader)
.or_insert(Default::default())
.insert(follower);
.or_insert(Vec::new());
if !list.contains(&follower) {
list.push(follower);
}
}
this.pending_room_update.take();

View file

@ -12,11 +12,11 @@ use gpui::{
elements::*,
geometry::{rect::RectF, vector::vec2f, PathBuilder},
json::{self, ToJson},
Border, CursorStyle, Entity, ModelHandle, MouseButton, MutableAppContext, RenderContext,
Subscription, View, ViewContext, ViewHandle, WeakViewHandle,
Border, CursorStyle, Entity, ImageData, ModelHandle, MouseButton, MutableAppContext,
RenderContext, Subscription, View, ViewContext, ViewHandle, WeakViewHandle,
};
use settings::Settings;
use std::ops::Range;
use std::{ops::Range, sync::Arc};
use theme::Theme;
use util::ResultExt;
use workspace::{FollowNextCollaborator, JoinProject, ToggleFollow, Workspace};
@ -510,11 +510,7 @@ impl CollabTitlebarItem {
Some(self.render_face_pile(
&user,
replica_id,
Some((
participant.peer_id,
&user.github_login,
participant.location,
)),
Some((participant.peer_id, participant.location)),
workspace,
theme,
cx,
@ -564,18 +560,23 @@ impl CollabTitlebarItem {
&self,
user: &User,
replica_id: Option<ReplicaId>,
peer: Option<(PeerId, &str, ParticipantLocation)>,
peer_id_and_location: Option<(PeerId, ParticipantLocation)>,
workspace: &ViewHandle<Workspace>,
theme: &Theme,
cx: &mut RenderContext<Self>,
) -> 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)
});
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;
if let Some((_, _, location)) = peer.as_ref() {
if let ParticipantLocation::SharedProject { project_id } = *location {
if let Some((_, location)) = peer_id_and_location {
if let ParticipantLocation::SharedProject { project_id } = location {
if Some(project_id) == workspace.read(cx).project().read(cx).remote_id() {
avatar_style = theme.workspace.titlebar.avatar;
} else {
@ -599,11 +600,36 @@ impl CollabTitlebarItem {
let content = Stack::new()
.with_children(user.avatar.as_ref().map(|avatar| {
Image::new(avatar.clone())
.with_style(avatar_style)
.constrained()
.with_width(theme.workspace.titlebar.avatar_width)
.aligned()
Flex::row()
.with_child(Self::render_face(avatar.clone(), avatar_style, theme))
.with_children(
peer_id_and_location
.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()
}))
.with_children(replica_color.map(|replica_color| {
@ -621,7 +647,7 @@ impl CollabTitlebarItem {
.with_margin_left(theme.workspace.titlebar.avatar_margin)
.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 {
MouseEventHandler::<ToggleFollow>::new(replica_id.into(), cx, move |_, _| content)
.with_cursor_style(CursorStyle::PointingHand)
@ -631,9 +657,9 @@ impl CollabTitlebarItem {
.with_tooltip::<ToggleFollow, _>(
peer_id.as_u64() as usize,
if is_followed {
format!("Unfollow {}", peer_github_login)
format!("Unfollow {}", user.github_login)
} else {
format!("Follow {}", peer_github_login)
format!("Follow {}", user.github_login)
},
Some(Box::new(FollowNextCollaborator)),
theme.tooltip.clone(),
@ -654,7 +680,7 @@ impl CollabTitlebarItem {
})
.with_tooltip::<JoinProject, _>(
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)),
theme.tooltip.clone(),
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(
&self,
workspace: &ViewHandle<Workspace>,

View file

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