diff --git a/Cargo.lock b/Cargo.lock index bca506d7e3..98bcfe5a91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -935,6 +935,7 @@ dependencies = [ "fuzzy", "gpui", "postage", + "serde", "settings", "theme", "util", diff --git a/crates/client/src/user.rs b/crates/client/src/user.rs index 984fe4126c..a32a4b179a 100644 --- a/crates/client/src/user.rs +++ b/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> { let client = self.client.upgrade(); async move { diff --git a/crates/collab/src/rpc.rs b/crates/collab/src/rpc.rs index e976984d85..548744ca76 100644 --- a/crates/collab/src/rpc.rs +++ b/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(()) } diff --git a/crates/contacts_panel/Cargo.toml b/crates/contacts_panel/Cargo.toml index 8e76bce22b..e511b9d030 100644 --- a/crates/contacts_panel/Cargo.toml +++ b/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"] } diff --git a/crates/contacts_panel/src/contacts_panel.rs b/crates/contacts_panel/src/contacts_panel.rs index 7c187ba7ee..affdded6e5 100644 --- a/crates/contacts_panel/src/contacts_panel.rs +++ b/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>, @@ -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, cx: &mut ViewContext) -> 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_store: ModelHandle, + 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::( + 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)