WIP

Antonio Scandurra created

Change summary

Cargo.lock                                  |  1 
crates/client/src/user.rs                   |  8 +++
crates/collab/src/rpc.rs                    | 17 -------
crates/contacts_panel/Cargo.toml            |  1 
crates/contacts_panel/src/contacts_panel.rs | 48 +++++++++++++++++++---
5 files changed, 52 insertions(+), 23 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -935,6 +935,7 @@ dependencies = [
  "fuzzy",
  "gpui",
  "postage",
+ "serde",
  "settings",
  "theme",
  "util",

crates/client/src/user.rs 🔗

@@ -237,6 +237,14 @@ impl UserStore {
         &self.outgoing_contact_requests
     }
 
+    pub fn has_outgoing_contact_request(&self, user: &User) -> bool {
+        self.outgoing_contact_requests
+            .binary_search_by_key(&&user.github_login, |requested_user| {
+                &requested_user.github_login
+            })
+            .is_ok()
+    }
+
     pub fn request_contact(&self, responder_id: u64) -> impl Future<Output = Result<()>> {
         let client = self.client.upgrade();
         async move {

crates/collab/src/rpc.rs 🔗

@@ -276,6 +276,7 @@ impl Server {
                 store.add_connection(connection_id, user_id);
                 this.peer.send(connection_id, store.build_initial_contacts_update(contacts))?;
             }
+            // this.update_user_contacts(user_id).await?;
 
             let handle_io = handle_io.fuse();
             futures::pin_mut!(handle_io);
@@ -354,22 +355,8 @@ impl Server {
             });
         }
 
-        let contacts_to_update = self
-            .app_state
-            .db
-            .get_contacts(removed_connection.user_id)
+        self.update_user_contacts(removed_connection.user_id)
             .await?;
-        let store = self.store().await;
-        let mut update = proto::UpdateContacts::default();
-        update
-            .contacts
-            .push(store.contact_for_user(removed_connection.user_id));
-
-        for user_id in contacts_to_update.current {
-            for connection_id in store.connection_ids_for_user(user_id) {
-                self.peer.send(connection_id, update.clone()).trace_err();
-            }
-        }
 
         Ok(())
     }

crates/contacts_panel/Cargo.toml 🔗

@@ -18,3 +18,4 @@ util = { path = "../util" }
 workspace = { path = "../workspace" }
 futures = "0.3"
 postage = { version = "0.4.1", features = ["futures-traits"] }
+serde = { version = "1", features = ["derive"] }

crates/contacts_panel/src/contacts_panel.rs 🔗

@@ -5,15 +5,19 @@ use gpui::{
     anyhow,
     elements::*,
     geometry::{rect::RectF, vector::vec2f},
+    impl_actions,
     platform::CursorStyle,
     Element, ElementBox, Entity, LayoutContext, ModelHandle, RenderContext, Subscription, Task,
     View, ViewContext, ViewHandle,
 };
+use serde::Deserialize;
 use settings::Settings;
 use std::sync::Arc;
 use util::ResultExt;
 use workspace::{AppState, JoinProject};
 
+impl_actions!(contacts_panel, [RequestContact]);
+
 pub struct ContactsPanel {
     list_state: ListState,
     contacts: Vec<Arc<Contact>>,
@@ -24,6 +28,9 @@ pub struct ContactsPanel {
     _maintain_contacts: Subscription,
 }
 
+#[derive(Clone, Deserialize)]
+pub struct RequestContact(pub u64);
+
 impl ContactsPanel {
     pub fn new(app_state: Arc<AppState>, cx: &mut ViewContext<Self>) -> Self {
         let user_query_editor = cx.add_view(|cx| {
@@ -86,8 +93,10 @@ impl ContactsPanel {
                         } else {
                             let potential_contact_ix = ix - 2 - this.contacts.len();
                             Self::render_potential_contact(
-                                &this.potential_contacts[potential_contact_ix],
+                                this.potential_contacts[potential_contact_ix].clone(),
+                                this.user_store.clone(),
                                 theme,
+                                cx,
                             )
                         }
                     }
@@ -278,7 +287,16 @@ impl ContactsPanel {
             .boxed()
     }
 
-    fn render_potential_contact(contact: &User, theme: &theme::ContactsPanel) -> ElementBox {
+    fn render_potential_contact(
+        contact: Arc<User>,
+        user_store: ModelHandle<UserStore>,
+        theme: &theme::ContactsPanel,
+        cx: &mut LayoutContext,
+    ) -> ElementBox {
+        enum RequestContactButton {}
+
+        let requested_contact = user_store.read(cx).has_outgoing_contact_request(&contact);
+
         Flex::row()
             .with_children(contact.avatar.clone().map(|avatar| {
                 Image::new(avatar)
@@ -299,12 +317,26 @@ impl ContactsPanel {
                 .boxed(),
             )
             .with_child(
-                Label::new("+".to_string(), theme.edit_contact.text.clone())
-                    .contained()
-                    .with_style(theme.edit_contact.container)
-                    .aligned()
-                    .flex_float()
-                    .boxed(),
+                MouseEventHandler::new::<RequestContactButton, _, _>(
+                    contact.id as usize,
+                    cx,
+                    |_, _| {
+                        let label = if requested_contact { "-" } else { "+" };
+                        Label::new(label.to_string(), theme.edit_contact.text.clone())
+                            .contained()
+                            .with_style(theme.edit_contact.container)
+                            .aligned()
+                            .flex_float()
+                            .boxed()
+                    },
+                )
+                .on_click(move |_, cx| {
+                    if requested_contact {
+                    } else {
+                        cx.dispatch_action(RequestContact(contact.id));
+                    }
+                })
+                .boxed(),
             )
             .constrained()
             .with_height(theme.row_height)