Start on `PeoplePanel::render`

Antonio Scandurra , Max Brunsfeld , and Nathan Sobo created

Co-Authored-By: Max Brunsfeld <max@zed.dev>
Co-Authored-By: Nathan Sobo <nathan@zed.dev>

Change summary

zed/src/people_panel.rs | 96 +++++++++++++++++++++++++++++++++++++++---
zed/src/theme.rs        | 11 ++++
zed/src/workspace.rs    |  6 +
3 files changed, 104 insertions(+), 9 deletions(-)

Detailed changes

zed/src/people_panel.rs 🔗

@@ -1,17 +1,99 @@
 use gpui::{
-    elements::Empty, Element, ElementBox, Entity, ModelHandle, RenderContext, View, ViewContext,
+    elements::*, Element, ElementBox, Entity, ModelHandle, RenderContext, View, ViewContext,
 };
+use postage::watch;
 
-use crate::user::UserStore;
+use crate::{
+    theme::Theme,
+    user::{Collaborator, UserStore},
+    Settings,
+};
 
 pub struct PeoplePanel {
+    collaborators: ListState,
     user_store: ModelHandle<UserStore>,
 }
 
 impl PeoplePanel {
-    pub fn new(user_store: ModelHandle<UserStore>, cx: &mut ViewContext<Self>) -> Self {
-        cx.observe(&user_store, |_, _, cx| cx.notify());
-        Self { user_store }
+    pub fn new(
+        user_store: ModelHandle<UserStore>,
+        settings: watch::Receiver<Settings>,
+        cx: &mut ViewContext<Self>,
+    ) -> Self {
+        cx.observe(&user_store, Self::update_collaborators);
+        Self {
+            collaborators: ListState::new(
+                user_store.read(cx).collaborators().len(),
+                Orientation::Top,
+                1000.,
+                {
+                    let user_store = user_store.clone();
+                    move |ix, cx| {
+                        let user_store = user_store.read(cx);
+                        let settings = settings.borrow();
+                        Self::render_collaborator(&user_store.collaborators()[ix], &settings.theme)
+                    }
+                },
+            ),
+            user_store,
+        }
+    }
+
+    fn update_collaborators(&mut self, _: ModelHandle<UserStore>, cx: &mut ViewContext<Self>) {
+        self.collaborators
+            .reset(self.user_store.read(cx).collaborators().len());
+        cx.notify();
+    }
+
+    fn render_collaborator(collaborator: &Collaborator, theme: &Theme) -> ElementBox {
+        Flex::column()
+            .with_child(
+                Flex::row()
+                    .with_children(collaborator.user.avatar.clone().map(|avatar| {
+                        ConstrainedBox::new(
+                            Image::new(avatar)
+                                .with_style(theme.people_panel.worktree_host_avatar)
+                                .boxed(),
+                        )
+                        .with_width(20.)
+                        .boxed()
+                    }))
+                    .with_child(
+                        Label::new(
+                            collaborator.user.github_login.clone(),
+                            theme.people_panel.collaborator_username.clone(),
+                        )
+                        .boxed(),
+                    )
+                    .boxed(),
+            )
+            .with_children(collaborator.worktrees.iter().map(|worktree| {
+                Flex::row()
+                    .with_child(
+                        Container::new(
+                            Label::new(
+                                worktree.root_name.clone(),
+                                theme.people_panel.worktree_name.text.clone(),
+                            )
+                            .boxed(),
+                        )
+                        .with_style(theme.people_panel.worktree_name.container)
+                        .boxed(),
+                    )
+                    .with_children(worktree.participants.iter().filter_map(|participant| {
+                        participant.avatar.clone().map(|avatar| {
+                            ConstrainedBox::new(
+                                Image::new(avatar)
+                                    .with_style(theme.people_panel.worktree_guest_avatar)
+                                    .boxed(),
+                            )
+                            .with_width(16.)
+                            .boxed()
+                        })
+                    }))
+                    .boxed()
+            }))
+            .boxed()
     }
 }
 
@@ -26,7 +108,7 @@ impl View for PeoplePanel {
         "PeoplePanel"
     }
 
-    fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox {
-        Empty::new().boxed()
+    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+        List::new(self.collaborators.clone()).boxed()
     }
 }

zed/src/theme.rs 🔗

@@ -23,6 +23,7 @@ pub struct Theme {
     pub name: String,
     pub workspace: Workspace,
     pub chat_panel: ChatPanel,
+    pub people_panel: PeoplePanel,
     pub selector: Selector,
     pub editor: EditorStyle,
     pub syntax: SyntaxTheme,
@@ -103,6 +104,16 @@ pub struct ChatPanel {
     pub hovered_sign_in_prompt: TextStyle,
 }
 
+#[derive(Deserialize)]
+pub struct PeoplePanel {
+    #[serde(flatten)]
+    pub container: ContainerStyle,
+    pub collaborator_username: TextStyle,
+    pub worktree_name: ContainedText,
+    pub worktree_host_avatar: ImageStyle,
+    pub worktree_guest_avatar: ImageStyle,
+}
+
 #[derive(Deserialize)]
 pub struct ChatMessage {
     #[serde(flatten)]

zed/src/workspace.rs 🔗

@@ -381,8 +381,10 @@ impl Workspace {
         );
         right_sidebar.add_item(
             "icons/user-16.svg",
-            cx.add_view(|cx| PeoplePanel::new(app_state.user_store.clone(), cx))
-                .into(),
+            cx.add_view(|cx| {
+                PeoplePanel::new(app_state.user_store.clone(), app_state.settings.clone(), cx)
+            })
+            .into(),
         );
 
         let mut current_user = app_state.user_store.read(cx).watch_current_user().clone();