feat(agsV2): make popups disappear after time
All checks were successful
Discord / discord commits (push) Has been skipped

This commit is contained in:
matt1432 2024-10-16 12:04:15 -04:00
parent 2ee60de237
commit 8ee3530330
5 changed files with 134 additions and 6 deletions

View file

@ -0,0 +1,60 @@
import { bind } from 'astal';
import { Gtk, Widget } from 'astal/gtk3';
import { register, property } from 'astal/gobject';
type SmoothProgressProps = Widget.BoxProps & {
transition_duration?: string
};
@register()
class SmoothProgress extends Widget.Box {
@property(Number)
declare fraction: number;
@property(String)
declare transition_duration: string;
constructor({
transition_duration = '1s',
...rest
}: SmoothProgressProps = {}) {
super(rest);
this.transition_duration = transition_duration;
const background = (
<box
className="background"
hexpand
vexpand
halign={Gtk.Align.FILL}
valign={Gtk.Align.FILL}
/>
);
const progress = (
<box
className="progress"
vexpand
valign={Gtk.Align.FILL}
css={bind(this, 'fraction').as((fraction) => {
return `
transition: margin-right ${this.transition_duration} linear;
margin-right: ${
Math.abs(fraction - 1) * background.get_allocated_width()
}px;
`;
})}
/>
);
this.add((
<overlay overlay={progress}>
{background}
</overlay>
));
this.show_all();
}
}
export default (props?: SmoothProgressProps) => new SmoothProgress(props);

View file

@ -1,6 +1,8 @@
import { Gdk, Gtk, Widget } from 'astal/gtk3'; import { Gdk, Gtk, Widget } from 'astal/gtk3';
import { register, property } from 'astal/gobject'; import { register, property } from 'astal/gobject';
import { idle } from 'astal'; import { idle, interval } from 'astal';
import AstalIO from 'gi://AstalIO?version=0.1';
import AstalNotifd from 'gi://AstalNotifd?version=0.1'; import AstalNotifd from 'gi://AstalNotifd?version=0.1';
const Notifications = AstalNotifd.get_default(); const Notifications = AstalNotifd.get_default();
@ -61,6 +63,8 @@ const defaultStyle = `${TRANSITION} margin: unset; opacity: 1;`;
type NotifGestureWrapperProps = Widget.BoxProps & { type NotifGestureWrapperProps = Widget.BoxProps & {
id: number id: number
slide_in_from?: 'Left' | 'Right' slide_in_from?: 'Left' | 'Right'
popup_timer?: number
setup_notif?: (self: NotifGestureWrapper) => void
}; };
@register() @register()
@ -71,6 +75,11 @@ export class NotifGestureWrapper extends Widget.EventBox {
readonly slide_in_from: 'Left' | 'Right'; readonly slide_in_from: 'Left' | 'Right';
private timer_object: AstalIO.Time | undefined;
@property(Number)
declare popup_timer: number;
@property(Boolean) @property(Boolean)
declare dragging: boolean; declare dragging: boolean;
@ -125,11 +134,19 @@ export class NotifGestureWrapper extends Widget.EventBox {
(this.get_child() as Widget.Revealer).revealChild = false; (this.get_child() as Widget.Revealer).revealChild = false;
setTimeout(() => { setTimeout(() => {
// Kill notif and update HasNotifs after anim is done // Kill notif if specified
if (force) { if (force) {
Notifications.get_notification(this.id)?.dismiss(); Notifications.get_notification(this.id)?.dismiss();
} }
// Make sure we cleanup any references to this instance
this.timer_object?.cancel();
NotifGestureWrapper.popups.delete(this.id);
// Update HasNotifs
HasNotifs.set(Notifications.get_notifications().length > 0); HasNotifs.set(Notifications.get_notifications().length > 0);
// Get rid of disappeared widget
this.destroy(); this.destroy();
}, ANIM_DURATION); }, ANIM_DURATION);
}, ANIM_DURATION - 100); }, ANIM_DURATION - 100);
@ -138,12 +155,18 @@ export class NotifGestureWrapper extends Widget.EventBox {
constructor({ constructor({
id, id,
slide_in_from = 'Left', slide_in_from = 'Left',
popup_timer = 0,
setup_notif = () => { /**/ },
...rest ...rest
}: NotifGestureWrapperProps) { }: NotifGestureWrapperProps) {
super(); super();
setup_notif(this);
this.id = id; this.id = id;
this.dragging = false;
this.slide_in_from = slide_in_from; this.slide_in_from = slide_in_from;
this.popup_timer = popup_timer;
this.dragging = false;
// OnClick // OnClick
this.connect('button-press-event', () => { this.connect('button-press-event', () => {
@ -189,6 +212,20 @@ export class NotifGestureWrapper extends Widget.EventBox {
)); ));
}); });
// Handle timeout before sliding away if it is a popup
if (this.popup_timer !== 0) {
this.timer_object = interval(1000, () => {
if (!this.hovered) {
if (this.popup_timer === 0) {
this.slideAway('Left');
}
else {
this.popup_timer--;
}
}
});
}
const gesture = Gtk.GestureDrag.new(this); const gesture = Gtk.GestureDrag.new(this);
this.add( this.add(

View file

@ -10,6 +10,7 @@ import AstalNotifd from 'gi://AstalNotifd?version=0.1';
const Notifications = AstalNotifd.get_default(); const Notifications = AstalNotifd.get_default();
import NotifGestureWrapper from './gesture'; import NotifGestureWrapper from './gesture';
import SmoothProgress from '../misc/smooth-progress';
// Make a variable to connect to for Widgets // Make a variable to connect to for Widgets
@ -22,7 +23,9 @@ const setTime = (time: number): string => {
.format('%H:%M') ?? ''; .format('%H:%M') ?? '';
}; };
const NotifIcon = ({ notifObj }: { notifObj: AstalNotifd.Notification }) => { const NotifIcon = ({ notifObj }: {
notifObj: AstalNotifd.Notification
}) => {
let icon: string; let icon: string;
if (notifObj.get_image() !== '') { if (notifObj.get_image() !== '') {
@ -89,6 +92,7 @@ const BlockedApps = [
export const Notification = ({ export const Notification = ({
id = 0, id = 0,
popup_timer = 0,
}): ReturnType<typeof NotifGestureWrapper> | undefined => { }): ReturnType<typeof NotifGestureWrapper> | undefined => {
const notifObj = Notifications.get_notification(id); const notifObj = Notifications.get_notification(id);
@ -104,8 +108,18 @@ export const Notification = ({
HasNotifs.set(Notifications.get_notifications().length > 0); HasNotifs.set(Notifications.get_notifications().length > 0);
const progress = SmoothProgress({ className: 'smooth-progress' });
return ( return (
<NotifGestureWrapper id={id}> <NotifGestureWrapper
id={id}
popup_timer={popup_timer}
setup_notif={(self) => {
self.connect('notify::popup-timer', () => {
progress.fraction = self.popup_timer / 5;
});
}}
>
<box vertical className={`notification ${notifObj.urgency} widget`}> <box vertical className={`notification ${notifObj.urgency} widget`}>
{/* Content */} {/* Content */}
<box> <box>
@ -165,6 +179,8 @@ export const Notification = ({
</box> </box>
</box> </box>
{progress}
{/* Actions */} {/* Actions */}
<box className="actions"> <box className="actions">
{notifObj.get_actions().map((action) => ( {notifObj.get_actions().map((action) => (

View file

@ -17,7 +17,7 @@ export default () => (
return; return;
} }
const NewNotif = Notification({ id }); const NewNotif = Notification({ id, popup_timer: 5 });
if (NewNotif) { if (NewNotif) {
// Use this instead of add to put it at the top // Use this instead of add to put it at the top

View file

@ -29,4 +29,19 @@
.action-button {} .action-button {}
} }
.smooth-progress {
min-height: 7px;
margin: 3px;
.background {
background-color: darken($window_bg_color, 3%);
border-radius: 3px;
}
.progress {
background-color: $accent-color;
border-radius: 3px;
}
}
} }