Assign unique color indices to room participants, use those instead of replica_ids

Co-authored-by: Conrad <conrad@zed.dev>
Co-authored-by: Antonio <antonio@zed.dev>
This commit is contained in:
Max Brunsfeld 2023-09-26 15:19:38 -06:00
parent 7711530704
commit 545b5e0161
35 changed files with 707 additions and 639 deletions

View file

@ -1,10 +1,12 @@
use anyhow::{anyhow, Result};
use call::ActiveCall;
use channel::{Channel, ChannelBuffer, ChannelBufferEvent, ChannelId};
use client::proto;
use clock::ReplicaId;
use client::{
proto::{self, PeerId},
Collaborator,
};
use collections::HashMap;
use editor::Editor;
use editor::{CollaborationHub, Editor};
use gpui::{
actions,
elements::{ChildView, Label},
@ -109,97 +111,44 @@ impl ChannelView {
cx: &mut ViewContext<Self>,
) -> Self {
let buffer = channel_buffer.read(cx).buffer();
let editor = cx.add_view(|cx| Editor::for_buffer(buffer, None, cx));
let editor = cx.add_view(|cx| {
let mut editor = Editor::for_buffer(buffer, None, cx);
editor.set_collaboration_hub(Box::new(ChannelBufferCollaborationHub(
channel_buffer.clone(),
)));
editor
});
let _editor_event_subscription = cx.subscribe(&editor, |_, _, e, cx| cx.emit(e.clone()));
cx.subscribe(&project, Self::handle_project_event).detach();
cx.subscribe(&channel_buffer, Self::handle_channel_buffer_event)
.detach();
let this = Self {
Self {
editor,
project,
channel_buffer,
remote_id: None,
_editor_event_subscription,
};
this.refresh_replica_id_map(cx);
this
}
}
pub fn channel(&self, cx: &AppContext) -> Arc<Channel> {
self.channel_buffer.read(cx).channel()
}
fn handle_project_event(
&mut self,
_: ModelHandle<Project>,
event: &project::Event,
cx: &mut ViewContext<Self>,
) {
match event {
project::Event::RemoteIdChanged(_) => {}
project::Event::DisconnectedFromHost => {}
project::Event::Closed => {}
project::Event::CollaboratorUpdated { .. } => {}
project::Event::CollaboratorLeft(_) => {}
project::Event::CollaboratorJoined(_) => {}
_ => return,
}
self.refresh_replica_id_map(cx);
}
fn handle_channel_buffer_event(
&mut self,
_: ModelHandle<ChannelBuffer>,
event: &ChannelBufferEvent,
cx: &mut ViewContext<Self>,
) {
match event {
ChannelBufferEvent::CollaboratorsChanged => {
self.refresh_replica_id_map(cx);
}
ChannelBufferEvent::Disconnected => self.editor.update(cx, |editor, cx| {
if let ChannelBufferEvent::Disconnected = event {
self.editor.update(cx, |editor, cx| {
editor.set_read_only(true);
cx.notify();
}),
})
}
}
/// Build a mapping of channel buffer replica ids to the corresponding
/// replica ids in the current project.
///
/// Using this mapping, a given user can be displayed with the same color
/// in the channel buffer as in other files in the project. Users who are
/// in the channel buffer but not the project will not have a color.
fn refresh_replica_id_map(&self, cx: &mut ViewContext<Self>) {
let mut project_replica_ids_by_channel_buffer_replica_id = HashMap::default();
let project = self.project.read(cx);
let channel_buffer = self.channel_buffer.read(cx);
project_replica_ids_by_channel_buffer_replica_id
.insert(channel_buffer.replica_id(cx), project.replica_id());
project_replica_ids_by_channel_buffer_replica_id.extend(
channel_buffer
.collaborators()
.iter()
.filter_map(|channel_buffer_collaborator| {
project
.collaborators()
.values()
.find_map(|project_collaborator| {
(project_collaborator.user_id == channel_buffer_collaborator.user_id)
.then_some((
channel_buffer_collaborator.replica_id as ReplicaId,
project_collaborator.replica_id,
))
})
}),
);
self.editor.update(cx, |editor, cx| {
editor.set_replica_id_map(Some(project_replica_ids_by_channel_buffer_replica_id), cx)
});
}
}
impl Entity for ChannelView {
@ -388,13 +337,9 @@ impl FollowableItem for ChannelView {
})
}
fn set_leader_replica_id(
&mut self,
leader_replica_id: Option<u16>,
cx: &mut ViewContext<Self>,
) {
fn set_leader_peer_id(&mut self, leader_peer_id: Option<PeerId>, cx: &mut ViewContext<Self>) {
self.editor.update(cx, |editor, cx| {
editor.set_leader_replica_id(leader_replica_id, cx)
editor.set_leader_peer_id(leader_peer_id, cx)
})
}
@ -406,3 +351,15 @@ impl FollowableItem for ChannelView {
false
}
}
struct ChannelBufferCollaborationHub(ModelHandle<ChannelBuffer>);
impl CollaborationHub for ChannelBufferCollaborationHub {
fn collaborators<'a>(&self, cx: &'a AppContext) -> &'a HashMap<PeerId, Collaborator> {
self.0.read(cx).collaborators()
}
fn user_color_indices<'a>(&self, cx: &'a AppContext) -> &'a HashMap<u64, theme::ColorIndex> {
self.0.read(cx).user_store().read(cx).color_indices()
}
}

View file

@ -923,9 +923,15 @@ impl CollabTitlebarItem {
.background_color
.unwrap_or_default();
if let Some(replica_id) = replica_id {
let color_index = self
.user_store
.read(cx)
.color_indices()
.get(&user_id)
.copied();
if let Some(color_index) = color_index {
if followed_by_self {
let selection = theme.editor.replica_selection_style(replica_id).selection;
let selection = theme.editor.replica_selection_style(color_index).selection;
background_color = Color::blend(selection, background_color);
background_color.a = 255;
}
@ -990,10 +996,10 @@ impl CollabTitlebarItem {
.contained()
.with_style(theme.titlebar.leader_selection);
if let Some(replica_id) = replica_id {
if let Some(color_index) = color_index {
if followed_by_self {
let color =
theme.editor.replica_selection_style(replica_id).selection;
theme.editor.replica_selection_style(color_index).selection;
container = container.with_background_color(color);
}
}
@ -1001,8 +1007,8 @@ impl CollabTitlebarItem {
container
}))
.with_children((|| {
let replica_id = replica_id?;
let color = theme.editor.replica_selection_style(replica_id).cursor;
let color_index = color_index?;
let color = theme.editor.replica_selection_style(color_index).cursor;
Some(
AvatarRibbon::new(color)
.constrained()