Improved Notification to manage autohide on list. (#177)

This commit is contained in:
Jason Lee 2024-08-24 00:26:16 +08:00 committed by GitHub
parent 409f597100
commit 1dbf809e99
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 47 additions and 52 deletions

View file

@ -1,4 +1,4 @@
use std::{any::TypeId, sync::Arc, time::Duration}; use std::{any::TypeId, collections::VecDeque, sync::Arc, time::Duration};
use gpui::{ use gpui::{
div, prelude::FluentBuilder, px, Animation, AnimationExt, ClickEvent, DismissEvent, ElementId, div, prelude::FluentBuilder, px, Animation, AnimationExt, ClickEvent, DismissEvent, ElementId,
@ -165,19 +165,6 @@ impl Notification {
self self
} }
fn perform_autohide(&self, cx: &mut ViewContext<Self>) {
if !self.autohide {
return;
}
// Sleep for 5 seconds to autohide the notification
cx.spawn(|view, mut cx| async move {
Timer::after(Duration::from_secs(5)).await;
let _ = view.update(&mut cx, |_, cx| cx.emit(DismissEvent));
})
.detach();
}
fn dismiss(&mut self, _: &ClickEvent, cx: &mut ViewContext<Self>) { fn dismiss(&mut self, _: &ClickEvent, cx: &mut ViewContext<Self>) {
cx.emit(DismissEvent); cx.emit(DismissEvent);
} }
@ -186,9 +173,6 @@ impl EventEmitter<DismissEvent> for Notification {}
impl FluentBuilder for Notification {} impl FluentBuilder for Notification {}
impl Render for Notification { impl Render for Notification {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement { fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
let group_id = "notification-group";
self.perform_autohide(cx);
let icon = match self.icon.clone() { let icon = match self.icon.clone() {
Some(icon) => icon, Some(icon) => icon,
None => match self.type_ { None => match self.type_ {
@ -206,11 +190,11 @@ impl Render for Notification {
}; };
div() div()
.w_96()
.id("notification") .id("notification")
.group("")
.occlude() .occlude()
.group(group_id)
.relative() .relative()
.w_96()
.border_1() .border_1()
.border_color(cx.theme().border) .border_color(cx.theme().border)
.bg(cx.theme().popover) .bg(cx.theme().popover)
@ -219,15 +203,7 @@ impl Render for Notification {
.py_2() .py_2()
.px_4() .px_4()
.gap_3() .gap_3()
.child( .child(div().absolute().top_3().left_4().child(icon))
div()
.absolute()
.map(|this| match self.title.is_some() {
true => this.top_3().left_4(),
false => this.top_2p5().left_4(),
})
.child(icon),
)
.child( .child(
v_flex() v_flex()
.pl_6() .pl_6()
@ -252,7 +228,7 @@ impl Render for Notification {
.top_1() .top_1()
.right_1() .right_1()
.invisible() .invisible()
.group_hover(group_id, |this| this.visible()) .group_hover("", |this| this.visible())
.child( .child(
Button::new("close", cx) Button::new("close", cx)
.icon(IconName::Close) .icon(IconName::Close)
@ -275,19 +251,23 @@ impl Render for Notification {
/// A list of notifications. /// A list of notifications.
pub struct NotificationList { pub struct NotificationList {
pub(crate) notifications: Vec<View<Notification>>, /// Notifications that will be auto hidden.
pub(crate) notifications: VecDeque<View<Notification>>,
expanded: bool,
} }
impl NotificationList { impl NotificationList {
pub fn new(_cx: &mut ViewContext<Self>) -> Self { pub fn new(_cx: &mut ViewContext<Self>) -> Self {
Self { Self {
notifications: Vec::new(), notifications: VecDeque::new(),
expanded: false,
} }
} }
pub fn push(&mut self, notification: impl Into<Notification>, cx: &mut ViewContext<Self>) { pub fn push(&mut self, notification: impl Into<Notification>, cx: &mut ViewContext<Self>) {
let notification = notification.into(); let notification = notification.into();
let id = notification.id.clone(); let id = notification.id.clone();
let autohide = notification.autohide;
// Remove the notification by id, for keep unique. // Remove the notification by id, for keep unique.
self.notifications.retain(|note| note.read(cx).id != id); self.notifications.retain(|note| note.read(cx).id != id);
@ -298,7 +278,24 @@ impl NotificationList {
}) })
.detach(); .detach();
self.notifications.push(notification); self.notifications.push_back(notification);
if autohide {
// Sleep for 5 seconds to autohide the notification
cx.spawn(|view, mut cx| async move {
Timer::after(Duration::from_secs(5)).await;
let _ = view.update(&mut cx, |view, cx| {
if let Some(ix) = view
.notifications
.iter()
.position(|note| note.read(cx).autohide)
{
view.notifications.remove(ix);
}
cx.notify()
});
})
.detach();
}
cx.notify(); cx.notify();
} }
@ -306,34 +303,37 @@ impl NotificationList {
self.notifications.clear(); self.notifications.clear();
cx.notify(); cx.notify();
} }
pub fn notifications(&self) -> Vec<View<Notification>> {
self.notifications.iter().cloned().collect()
}
} }
impl Render for NotificationList { impl Render for NotificationList {
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> impl IntoElement { fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> impl IntoElement {
let size = cx.viewport_size(); let size = cx.viewport_size();
let items = self.notifications.iter().rev().take(10).rev().cloned();
let last_10_notes = self
.notifications
.iter()
.rev()
.take(10)
.rev()
.cloned()
.collect::<Vec<_>>();
div() div()
.absolute() .absolute()
.flex()
.top_4() .top_4()
.bottom_4() .bottom_4()
.right_4() .right_4()
.justify_end() .justify_end()
.child( .child(
v_flex() v_flex()
.id("notification-list")
.absolute() .absolute()
.relative()
.right_0() .right_0()
.h(size.height) .h(size.height - px(8.))
.on_hover(cx.listener(|view, hovered, cx| {
view.expanded = *hovered;
cx.notify()
}))
.gap_3() .gap_3()
.children(last_10_notes), .children(items),
) )
} }
} }

View file

@ -1,6 +1,6 @@
use gpui::{ use gpui::{
div, AnyView, FocusHandle, ParentElement as _, Render, Styled, View, ViewContext, div, AnyView, FocusHandle, InteractiveElement, ParentElement as _, Render, Styled, View,
VisualContext as _, WindowContext, ViewContext, VisualContext as _, WindowContext,
}; };
use std::{ use std::{
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
@ -108,13 +108,7 @@ impl<'a> ContextModal for WindowContext<'a> {
} }
fn notifications(&self) -> Rc<Vec<View<Notification>>> { fn notifications(&self) -> Rc<Vec<View<Notification>>> {
Rc::new( Rc::new(Root::read(&self).notification.read(&self).notifications())
Root::read(&self)
.notification
.read(&self)
.notifications
.clone(),
)
} }
} }
impl<'a, V> ContextModal for ViewContext<'a, V> { impl<'a, V> ContextModal for ViewContext<'a, V> {
@ -218,6 +212,7 @@ impl Root {
impl Render for Root { impl Render for Root {
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> impl gpui::IntoElement { fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> impl gpui::IntoElement {
div() div()
.id("root")
.size_full() .size_full()
.text_color(cx.theme().foreground) .text_color(cx.theme().foreground)
.child(self.child.clone()) .child(self.child.clone())