Merge pull request #2213 from zed-industries/per-project-follow-status

Julia created

Differentiate between follow state on a per-project basis

Change summary

crates/call/src/room.rs                      | 17 +++++++++--------
crates/collab/src/db.rs                      |  1 +
crates/collab/src/tests/integration_tests.rs |  4 ++--
crates/collab_ui/src/collab_titlebar_item.rs | 22 ++++++++++++++--------
crates/rpc/proto/zed.proto                   |  1 +
crates/rpc/src/rpc.rs                        |  2 +-
6 files changed, 28 insertions(+), 19 deletions(-)

Detailed changes

crates/call/src/room.rs 🔗

@@ -55,7 +55,7 @@ pub struct Room {
     leave_when_empty: bool,
     client: Arc<Client>,
     user_store: ModelHandle<UserStore>,
-    follows_by_leader_id: HashMap<PeerId, Vec<PeerId>>,
+    follows_by_leader_id_project_id: HashMap<(PeerId, u64), Vec<PeerId>>,
     subscriptions: Vec<client::Subscription>,
     pending_room_update: Option<Task<()>>,
     maintain_connection: Option<Task<Option<()>>>,
@@ -149,7 +149,7 @@ impl Room {
             pending_room_update: None,
             client,
             user_store,
-            follows_by_leader_id: Default::default(),
+            follows_by_leader_id_project_id: Default::default(),
             maintain_connection: Some(maintain_connection),
         }
     }
@@ -462,9 +462,9 @@ impl Room {
         self.participant_user_ids.contains(&user_id)
     }
 
-    pub fn followers_for(&self, leader_id: PeerId) -> &[PeerId] {
-        self.follows_by_leader_id
-            .get(&leader_id)
+    pub fn followers_for(&self, leader_id: PeerId, project_id: u64) -> &[PeerId] {
+        self.follows_by_leader_id_project_id
+            .get(&(leader_id, project_id))
             .map_or(&[], |v| v.as_slice())
     }
 
@@ -634,8 +634,9 @@ impl Room {
                     }
                 }
 
-                this.follows_by_leader_id.clear();
+                this.follows_by_leader_id_project_id.clear();
                 for follower in room.followers {
+                    let project_id = follower.project_id;
                     let (leader, follower) = match (follower.leader_id, follower.follower_id) {
                         (Some(leader), Some(follower)) => (leader, follower),
 
@@ -646,8 +647,8 @@ impl Room {
                     };
 
                     let list = this
-                        .follows_by_leader_id
-                        .entry(leader)
+                        .follows_by_leader_id_project_id
+                        .entry((leader, project_id))
                         .or_insert(Vec::new());
                     if !list.contains(&follower) {
                         list.push(follower);

crates/collab/src/db.rs 🔗

@@ -1996,6 +1996,7 @@ impl Database {
             followers.push(proto::Follower {
                 leader_id: Some(db_follower.leader_connection().into()),
                 follower_id: Some(db_follower.follower_connection().into()),
+                project_id: db_follower.project_id.to_proto(),
             });
         }
 

crates/collab/src/tests/integration_tests.rs 🔗

@@ -5934,7 +5934,7 @@ async fn test_following(
         active_call.read_with(*cx, |call, cx| {
             let room = call.room().unwrap().read(cx);
             assert_eq!(
-                room.followers_for(peer_id_a),
+                room.followers_for(peer_id_a, project_id),
                 &[peer_id_b, peer_id_c],
                 "checking followers for A as {name}"
             );
@@ -5956,7 +5956,7 @@ async fn test_following(
         active_call.read_with(*cx, |call, cx| {
             let room = call.room().unwrap().read(cx);
             assert_eq!(
-                room.followers_for(peer_id_a),
+                room.followers_for(peer_id_a, project_id),
                 &[peer_id_b],
                 "checking followers for A as {name}"
             );

crates/collab_ui/src/collab_titlebar_item.rs 🔗

@@ -640,16 +640,21 @@ impl CollabTitlebarItem {
         theme: &Theme,
         cx: &mut RenderContext<Self>,
     ) -> ElementBox {
+        let project_id = workspace.read(cx).project().read(cx).remote_id();
         let room = ActiveCall::global(cx).read(cx).room();
         let is_being_followed = workspace.read(cx).is_being_followed(peer_id);
         let followed_by_self = room
-            .map(|room| {
-                is_being_followed
-                    && room
-                        .read(cx)
-                        .followers_for(peer_id)
-                        .iter()
-                        .any(|&follower| Some(follower) == workspace.read(cx).client().peer_id())
+            .and_then(|room| {
+                Some(
+                    is_being_followed
+                        && room
+                            .read(cx)
+                            .followers_for(peer_id, project_id?)
+                            .iter()
+                            .any(|&follower| {
+                                Some(follower) == workspace.read(cx).client().peer_id()
+                            }),
+                )
             })
             .unwrap_or(false);
 
@@ -680,8 +685,9 @@ impl CollabTitlebarItem {
                     ))
                     .with_children(
                         (|| {
+                            let project_id = project_id?;
                             let room = room?.read(cx);
-                            let followers = room.followers_for(peer_id);
+                            let followers = room.followers_for(peer_id, project_id);
 
                             Some(followers.into_iter().flat_map(|&follower| {
                                 let remote_participant =

crates/rpc/proto/zed.proto 🔗

@@ -231,6 +231,7 @@ message ParticipantProject {
 message Follower {
     PeerId leader_id = 1;
     PeerId follower_id = 2;
+    uint64 project_id = 3;
 }
 
 message ParticipantLocation {

crates/rpc/src/rpc.rs 🔗

@@ -6,4 +6,4 @@ pub use conn::Connection;
 pub use peer::*;
 mod macros;
 
-pub const PROTOCOL_VERSION: u32 = 48;
+pub const PROTOCOL_VERSION: u32 = 49;