Improved Notification to manage autohide on list. (#177)
This commit is contained in:
parent
409f597100
commit
1dbf809e99
2 changed files with 47 additions and 52 deletions
|
|
@ -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),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue