feat(agsV2): make popups disappear after time
All checks were successful
Discord / discord commits (push) Has been skipped
All checks were successful
Discord / discord commits (push) Has been skipped
This commit is contained in:
parent
2ee60de237
commit
8ee3530330
5 changed files with 134 additions and 6 deletions
60
nixosModules/ags/v2/widgets/misc/smooth-progress.tsx
Normal file
60
nixosModules/ags/v2/widgets/misc/smooth-progress.tsx
Normal 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);
|
|
@ -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(
|
||||||
|
|
|
@ -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) => (
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue