From 3bca1c29e21a902b3b14045a6bbbb1ef34aebefb Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 10 May 2022 18:33:39 -0600 Subject: [PATCH] Present a blank notification upon receipt of a contact request --- crates/client/src/user.rs | 30 ++++++++++------- crates/contacts_panel/src/contacts_panel.rs | 34 +++++++++++++++++-- crates/contacts_panel/src/notifications.rs | 36 +++++++++++++++++++++ crates/workspace/src/workspace.rs | 8 ++--- crates/zed/src/zed.rs | 3 +- 5 files changed, 90 insertions(+), 21 deletions(-) create mode 100644 crates/contacts_panel/src/notifications.rs diff --git a/crates/client/src/user.rs b/crates/client/src/user.rs index 1874822774..3a2ea1a725 100644 --- a/crates/client/src/user.rs +++ b/crates/client/src/user.rs @@ -54,7 +54,9 @@ pub struct UserStore { _maintain_current_user: Task<()>, } -pub enum Event {} +pub enum Event { + NotifyIncomingRequest(Arc), +} impl Entity for UserStore { type Event = Event; @@ -182,12 +184,14 @@ impl UserStore { let mut incoming_requests = Vec::new(); for request in message.incoming_requests { - incoming_requests.push( - this.update(&mut cx, |this, cx| { - this.fetch_user(request.requester_id, cx) - }) - .await?, - ); + incoming_requests.push({ + let user = this + .update(&mut cx, |this, cx| { + this.fetch_user(request.requester_id, cx) + }) + .await?; + (user, request.should_notify) + }); } let mut outgoing_requests = Vec::new(); @@ -224,14 +228,18 @@ impl UserStore { this.incoming_contact_requests .retain(|user| !removed_incoming_requests.contains(&user.id)); // Update existing incoming requests and insert new ones - for request in incoming_requests { + for (user, should_notify) in incoming_requests { + if should_notify { + cx.emit(Event::NotifyIncomingRequest(user.clone())); + } + match this .incoming_contact_requests - .binary_search_by_key(&&request.github_login, |contact| { + .binary_search_by_key(&&user.github_login, |contact| { &contact.github_login }) { - Ok(ix) => this.incoming_contact_requests[ix] = request, - Err(ix) => this.incoming_contact_requests.insert(ix, request), + Ok(ix) => this.incoming_contact_requests[ix] = user, + Err(ix) => this.incoming_contact_requests.insert(ix, user), } } diff --git a/crates/contacts_panel/src/contacts_panel.rs b/crates/contacts_panel/src/contacts_panel.rs index 5d96a1b0c2..792aeb1e22 100644 --- a/crates/contacts_panel/src/contacts_panel.rs +++ b/crates/contacts_panel/src/contacts_panel.rs @@ -1,4 +1,5 @@ mod contact_finder; +mod notifications; use client::{Contact, User, UserStore}; use editor::{Cancel, Editor}; @@ -9,13 +10,14 @@ use gpui::{ impl_actions, platform::CursorStyle, Element, ElementBox, Entity, LayoutContext, ModelHandle, MutableAppContext, RenderContext, - Subscription, View, ViewContext, ViewHandle, + Subscription, View, ViewContext, ViewHandle, WeakViewHandle, }; +use notifications::IncomingRequestNotification; use serde::Deserialize; use settings::Settings; use std::sync::Arc; use theme::IconButton; -use workspace::{AppState, JoinProject}; +use workspace::{AppState, JoinProject, Workspace}; impl_actions!( contacts_panel, @@ -60,7 +62,11 @@ pub fn init(cx: &mut MutableAppContext) { } impl ContactsPanel { - pub fn new(app_state: Arc, cx: &mut ViewContext) -> Self { + pub fn new( + app_state: Arc, + workspace: WeakViewHandle, + cx: &mut ViewContext, + ) -> Self { let user_query_editor = cx.add_view(|cx| { let mut editor = Editor::single_line( Some(|theme| theme.contacts_panel.user_query_editor.clone()), @@ -77,6 +83,28 @@ impl ContactsPanel { }) .detach(); + cx.subscribe(&app_state.user_store, { + let user_store = app_state.user_store.clone(); + move |_, _, event, cx| match event { + client::Event::NotifyIncomingRequest(user) => { + if let Some(workspace) = workspace.upgrade(cx) { + workspace.update(cx, |workspace, cx| { + workspace.show_notification( + cx.add_view(|_| { + IncomingRequestNotification::new( + user.clone(), + user_store.clone(), + ) + }), + cx, + ) + }) + } + } + } + }) + .detach(); + let mut this = Self { list_state: ListState::new(0, Orientation::Top, 1000., { let this = cx.weak_handle(); diff --git a/crates/contacts_panel/src/notifications.rs b/crates/contacts_panel/src/notifications.rs new file mode 100644 index 0000000000..d2ef5176e3 --- /dev/null +++ b/crates/contacts_panel/src/notifications.rs @@ -0,0 +1,36 @@ +use client::{User, UserStore}; +use gpui::{color::Color, elements::*, Entity, ModelHandle, View}; +use std::sync::Arc; +use workspace::Notification; + +pub struct IncomingRequestNotification { + user: Arc, + user_store: ModelHandle, +} + +impl Entity for IncomingRequestNotification { + type Event = (); +} + +impl View for IncomingRequestNotification { + fn ui_name() -> &'static str { + "IncomingRequestNotification" + } + + fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> ElementBox { + Empty::new() + .constrained() + .with_height(200.) + .contained() + .with_background_color(Color::red()) + .boxed() + } +} + +impl Notification for IncomingRequestNotification {} + +impl IncomingRequestNotification { + pub fn new(user: Arc, user_store: ModelHandle) -> Self { + Self { user, user_store } + } +} diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 94b0a82f53..f0e39126cc 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -1732,11 +1732,7 @@ impl Workspace { } } - fn render_notifications( - &self, - theme: &theme::Workspace, - cx: &mut RenderContext, - ) -> Option { + fn render_notifications(&self, theme: &theme::Workspace) -> Option { if self.notifications.is_empty() { None } else { @@ -2094,7 +2090,7 @@ impl View for Workspace { .top() .boxed() })) - .with_children(self.render_notifications(&theme.workspace, cx)) + .with_children(self.render_notifications(&theme.workspace)) .flex(1.0, true) .boxed(), ) diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 77e400e02f..d4938501b8 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -172,7 +172,8 @@ pub fn build_workspace( }); let project_panel = ProjectPanel::new(project, cx); - let contact_panel = cx.add_view(|cx| ContactsPanel::new(app_state.clone(), cx)); + let contact_panel = + cx.add_view(|cx| ContactsPanel::new(app_state.clone(), workspace.weak_handle(), cx)); workspace.left_sidebar().update(cx, |sidebar, cx| { sidebar.add_item("icons/folder-tree-solid-14.svg", project_panel.into(), cx)