Highlight face pile which local user is following

Julia created

Change summary

crates/call/src/room.rs                      |  2 
crates/collab_ui/src/collab_titlebar_item.rs | 70 +++++++++++++--------
crates/collab_ui/src/collab_ui.rs            |  2 
crates/workspace/src/workspace.rs            |  4 
4 files changed, 46 insertions(+), 32 deletions(-)

Detailed changes

crates/call/src/room.rs 🔗

@@ -459,7 +459,7 @@ impl Room {
         self.participant_user_ids.contains(&user_id)
     }
 
-    pub fn follows(&self, leader_id: PeerId) -> &[PeerId] {
+    pub fn followers_for(&self, leader_id: PeerId) -> &[PeerId] {
         self.follows_by_leader_id
             .get(&leader_id)
             .map_or(&[], |v| v.as_slice())

crates/collab_ui/src/collab_titlebar_item.rs 🔗

@@ -12,8 +12,8 @@ use gpui::{
     elements::*,
     geometry::{rect::RectF, vector::vec2f, PathBuilder},
     json::{self, ToJson},
-    Border, CursorStyle, Entity, ImageData, ModelHandle, MouseButton, MutableAppContext,
-    RenderContext, Subscription, View, ViewContext, ViewHandle, WeakViewHandle,
+    CursorStyle, Entity, ImageData, ModelHandle, MouseButton, MutableAppContext, RenderContext,
+    Subscription, View, ViewContext, ViewHandle, WeakViewHandle,
 };
 use settings::Settings;
 use std::{ops::Range, sync::Arc};
@@ -581,9 +581,10 @@ impl CollabTitlebarItem {
         theme: &Theme,
         cx: &mut RenderContext<Self>,
     ) -> ElementBox {
-        let is_followed = workspace.read(cx).is_following(peer_id);
+        let room = ActiveCall::global(cx).read(cx).room();
+        let is_being_followed = workspace.read(cx).is_being_followed(peer_id);
 
-        let mut avatar_style;
+        let avatar_style;
         if let Some(location) = location {
             if let ParticipantLocation::SharedProject { project_id } = location {
                 if Some(project_id) == workspace.read(cx).project().read(cx).remote_id() {
@@ -598,23 +599,14 @@ impl CollabTitlebarItem {
             avatar_style = theme.workspace.titlebar.avatar;
         }
 
-        let mut replica_color = None;
-        if let Some(replica_id) = replica_id {
-            let color = theme.editor.replica_selection_style(replica_id).cursor;
-            replica_color = Some(color);
-            if is_followed {
-                avatar_style.border = Border::all(1.0, color);
-            }
-        }
-
         let content = Stack::new()
             .with_children(user.avatar.as_ref().map(|avatar| {
-                Flex::row()
+                let flex = Flex::row()
                     .with_child(Self::render_face(avatar.clone(), avatar_style, theme))
                     .with_children(
                         (|| {
-                            let room = ActiveCall::global(cx).read(cx).room()?.read(cx);
-                            let followers = room.follows(peer_id);
+                            let room = room?.read(cx);
+                            let followers = room.followers_for(peer_id);
 
                             Some(followers.into_iter().flat_map(|&follower| {
                                 let avatar = room
@@ -639,18 +631,40 @@ impl CollabTitlebarItem {
                         })()
                         .into_iter()
                         .flatten(),
-                    )
-                    .boxed()
-            }))
-            .with_children(replica_color.map(|replica_color| {
-                AvatarRibbon::new(replica_color)
-                    .constrained()
-                    .with_width(theme.workspace.titlebar.avatar_ribbon.width)
-                    .with_height(theme.workspace.titlebar.avatar_ribbon.height)
-                    .aligned()
-                    .bottom()
-                    .boxed()
+                    );
+
+                let room = ActiveCall::global(cx).read(cx).room();
+                if let (Some(replica_id), Some(room)) = (replica_id, room) {
+                    let followed_by_self = is_being_followed
+                        && room
+                            .read(cx)
+                            .followers_for(peer_id)
+                            .iter()
+                            .any(|&follower| {
+                                Some(follower) == workspace.read(cx).client().peer_id()
+                            });
+
+                    if followed_by_self {
+                        let color = theme.editor.replica_selection_style(replica_id).selection;
+                        return flex.contained().with_background_color(color).boxed();
+                    }
+                }
+
+                flex.boxed()
             }))
+            .with_children((|| {
+                let replica_id = replica_id?;
+                let color = theme.editor.replica_selection_style(replica_id).cursor;
+                Some(
+                    AvatarRibbon::new(color)
+                        .constrained()
+                        .with_width(theme.workspace.titlebar.avatar_ribbon.width)
+                        .with_height(theme.workspace.titlebar.avatar_ribbon.height)
+                        .aligned()
+                        .bottom()
+                        .boxed(),
+                )
+            })())
             .contained()
             .with_margin_left(theme.workspace.titlebar.avatar_margin)
             .boxed();
@@ -664,7 +678,7 @@ impl CollabTitlebarItem {
                     })
                     .with_tooltip::<ToggleFollow, _>(
                         peer_id.as_u64() as usize,
-                        if is_followed {
+                        if is_being_followed {
                             format!("Unfollow {}", user.github_login)
                         } else {
                             format!("Follow {}", user.github_login)

crates/collab_ui/src/collab_ui.rs 🔗

@@ -117,7 +117,7 @@ fn join_project(action: &JoinProject, app_state: Arc<AppState>, cx: &mut Mutable
                     });
 
                 if let Some(follow_peer_id) = follow_peer_id {
-                    if !workspace.is_following(follow_peer_id) {
+                    if !workspace.is_being_followed(follow_peer_id) {
                         workspace
                             .toggle_follow(&ToggleFollow(follow_peer_id), cx)
                             .map(|follow| follow.detach_and_log_err(cx));

crates/workspace/src/workspace.rs 🔗

@@ -1828,11 +1828,11 @@ impl Workspace {
         None
     }
 
-    pub fn is_following(&self, peer_id: PeerId) -> bool {
+    pub fn is_being_followed(&self, peer_id: PeerId) -> bool {
         self.follower_states_by_leader.contains_key(&peer_id)
     }
 
-    pub fn is_followed(&self, peer_id: PeerId) -> bool {
+    pub fn is_followed_by(&self, peer_id: PeerId) -> bool {
         self.leader_state.followers.contains(&peer_id)
     }