diff --git a/crates/client/src/user.rs b/crates/client/src/user.rs index 3a2ea1a725..a0f0884294 100644 --- a/crates/client/src/user.rs +++ b/crates/client/src/user.rs @@ -55,7 +55,8 @@ pub struct UserStore { } pub enum Event { - NotifyIncomingRequest(Arc), + ContactRequested(Arc), + ContactRequestCancelled(Arc), } impl Entity for UserStore { @@ -225,12 +226,18 @@ impl UserStore { } // Remove incoming contact requests - this.incoming_contact_requests - .retain(|user| !removed_incoming_requests.contains(&user.id)); + this.incoming_contact_requests.retain(|user| { + if removed_incoming_requests.contains(&user.id) { + cx.emit(Event::ContactRequestCancelled(user.clone())); + false + } else { + true + } + }); // Update existing incoming requests and insert new ones for (user, should_notify) in incoming_requests { if should_notify { - cx.emit(Event::NotifyIncomingRequest(user.clone())); + cx.emit(Event::ContactRequested(user.clone())); } match this diff --git a/crates/contacts_panel/src/contact_notifications.rs b/crates/contacts_panel/src/contact_notifications.rs new file mode 100644 index 0000000000..894c1f4138 --- /dev/null +++ b/crates/contacts_panel/src/contact_notifications.rs @@ -0,0 +1,58 @@ +use client::{User, UserStore}; +use gpui::{color::Color, elements::*, Entity, ModelHandle, View, ViewContext}; +use std::sync::Arc; +use workspace::Notification; + +pub struct IncomingRequestNotification { + user: Arc, + user_store: ModelHandle, +} + +pub enum Event { + Dismiss, +} + +impl Entity for IncomingRequestNotification { + type Event = 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 { + fn should_dismiss_notification_on_event(&self, event: &::Event) -> bool { + matches!(event, Event::Dismiss) + } +} + +impl IncomingRequestNotification { + pub fn new( + user: Arc, + user_store: ModelHandle, + cx: &mut ViewContext, + ) -> Self { + let user_id = user.id; + cx.subscribe(&user_store, move |_, _, event, cx| { + if let client::Event::ContactRequestCancelled(user) = event { + if user.id == user_id { + cx.emit(Event::Dismiss); + } + } + }) + .detach(); + + Self { user, user_store } + } +} diff --git a/crates/contacts_panel/src/contacts_panel.rs b/crates/contacts_panel/src/contacts_panel.rs index 792aeb1e22..68fb8e1f26 100644 --- a/crates/contacts_panel/src/contacts_panel.rs +++ b/crates/contacts_panel/src/contacts_panel.rs @@ -1,7 +1,8 @@ mod contact_finder; -mod notifications; +mod contact_notifications; use client::{Contact, User, UserStore}; +use contact_notifications::IncomingRequestNotification; use editor::{Cancel, Editor}; use fuzzy::{match_strings, StringMatchCandidate}; use gpui::{ @@ -12,7 +13,6 @@ use gpui::{ Element, ElementBox, Entity, LayoutContext, ModelHandle, MutableAppContext, RenderContext, Subscription, View, ViewContext, ViewHandle, WeakViewHandle, }; -use notifications::IncomingRequestNotification; use serde::Deserialize; use settings::Settings; use std::sync::Arc; @@ -86,14 +86,15 @@ impl ContactsPanel { cx.subscribe(&app_state.user_store, { let user_store = app_state.user_store.clone(); move |_, _, event, cx| match event { - client::Event::NotifyIncomingRequest(user) => { + client::Event::ContactRequested(user) => { if let Some(workspace) = workspace.upgrade(cx) { workspace.update(cx, |workspace, cx| { workspace.show_notification( - cx.add_view(|_| { + cx.add_view(|cx| { IncomingRequestNotification::new( user.clone(), user_store.clone(), + cx, ) }), cx, @@ -101,6 +102,7 @@ impl ContactsPanel { }) } } + _ => {} } }) .detach(); diff --git a/crates/contacts_panel/src/notifications.rs b/crates/contacts_panel/src/notifications.rs deleted file mode 100644 index d2ef5176e3..0000000000 --- a/crates/contacts_panel/src/notifications.rs +++ /dev/null @@ -1,36 +0,0 @@ -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 f0e39126cc..b077b82518 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -604,13 +604,20 @@ impl WeakItemHandle for WeakViewHandle { } } -pub trait Notification: View {} +pub trait Notification: View { + fn should_dismiss_notification_on_event(&self, event: &::Event) -> bool; +} pub trait NotificationHandle { + fn id(&self) -> usize; fn to_any(&self) -> AnyViewHandle; } impl NotificationHandle for ViewHandle { + fn id(&self) -> usize { + self.id() + } + fn to_any(&self) -> AnyViewHandle { self.into() } @@ -996,10 +1003,27 @@ impl Workspace { notification: ViewHandle, cx: &mut ViewContext, ) { + cx.subscribe(¬ification, |this, handle, event, cx| { + if handle.read(cx).should_dismiss_notification_on_event(event) { + this.dismiss_notification(handle.id(), cx); + } + }) + .detach(); self.notifications.push(Box::new(notification)); cx.notify(); } + fn dismiss_notification(&mut self, id: usize, cx: &mut ViewContext) { + self.notifications.retain(|handle| { + if handle.id() == id { + cx.notify(); + false + } else { + true + } + }); + } + pub fn items<'a>( &'a self, cx: &'a AppContext,