fix(ags notifs): refactor and make notifs work with latest ags
This commit is contained in:
parent
6a40c0141d
commit
b2e4c84545
5 changed files with 189 additions and 220 deletions
|
@ -4,8 +4,8 @@ import { exec } from 'resource:///com/github/Aylur/ags/utils.js';
|
|||
import Setup from './js/setup.js';
|
||||
import Powermenu from './js/powermenu.js';
|
||||
import * as Bar from './js/bar/main.js';
|
||||
//import NotifCenter from './js/notifications/center.js';
|
||||
//import NotifPopups from './js/notifications/popup.js';
|
||||
import NotifCenter from './js/notifications/center.js';
|
||||
import NotifPopups from './js/notifications/popup.js';
|
||||
import Calendar from './js/date.js';
|
||||
import QuickSettings from './js/quick-settings/main.js';
|
||||
//import Overview from './js/overview/main.js';
|
||||
|
@ -18,7 +18,6 @@ exec(`sassc ${scss} ${css}`);
|
|||
Setup();
|
||||
|
||||
|
||||
// FIXME: notification and overview stuff are bugged as of this ags commit
|
||||
export default {
|
||||
style: css,
|
||||
notificationPopupTimeout: 5000,
|
||||
|
@ -34,7 +33,7 @@ export default {
|
|||
windows: [
|
||||
AppLauncher(),
|
||||
Calendar(),
|
||||
//NotifCenter(),
|
||||
NotifCenter(),
|
||||
//Overview(),
|
||||
Powermenu(),
|
||||
QuickSettings(),
|
||||
|
@ -43,6 +42,6 @@ export default {
|
|||
Bar.BgGradient(),
|
||||
Corners.Bottomleft(),
|
||||
Corners.Bottomright(),
|
||||
//NotifPopups(),
|
||||
NotifPopups(),
|
||||
],
|
||||
};
|
||||
|
|
|
@ -2,7 +2,7 @@ import Applications from 'resource:///com/github/Aylur/ags/service/applications.
|
|||
import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js';
|
||||
import Variable from 'resource:///com/github/Aylur/ags/variable.js';
|
||||
import { Box, Icon, Label, Button } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import { lookUpIcon, execAsync, timeout } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
import { lookUpIcon, execAsync } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
|
||||
import GLib from 'gi://GLib';
|
||||
|
||||
|
@ -48,15 +48,17 @@ const NotificationIcon = notif => {
|
|||
return EventBox({
|
||||
onPrimaryClickRelease: iconCmd,
|
||||
child: Box({
|
||||
valign: 'start',
|
||||
vpack: 'start',
|
||||
hexpand: false,
|
||||
className: 'icon img',
|
||||
style: `background-image: url("${notif.image}");
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
min-width: 78px;
|
||||
min-height: 78px;`,
|
||||
css: `
|
||||
background-image: url("${notif.image}");
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
min-width: 78px;
|
||||
min-height: 78px;
|
||||
`,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
@ -73,16 +75,16 @@ const NotificationIcon = notif => {
|
|||
return EventBox({
|
||||
onPrimaryClickRelease: iconCmd,
|
||||
child: Box({
|
||||
valign: 'start',
|
||||
vpack: 'start',
|
||||
hexpand: false,
|
||||
className: 'icon',
|
||||
style: `min-width: 78px;
|
||||
min-height: 78px;`,
|
||||
css: `min-width: 78px;
|
||||
min-height: 78px;`,
|
||||
children: [Icon({
|
||||
icon, size: 58,
|
||||
halign: 'center',
|
||||
hpack: 'center',
|
||||
hexpand: true,
|
||||
valign: 'center',
|
||||
vpack: 'center',
|
||||
vexpand: true,
|
||||
})],
|
||||
}),
|
||||
|
@ -114,37 +116,11 @@ export const Notification = ({
|
|||
|
||||
// Init notif
|
||||
const notifWidget = Gesture({
|
||||
maxOffset: 200,
|
||||
command: () => command(),
|
||||
command,
|
||||
slideIn,
|
||||
properties: [
|
||||
['hovered', false],
|
||||
['id', notif.id],
|
||||
],
|
||||
onHover: w => {
|
||||
if (!w._hovered)
|
||||
w._hovered = true;
|
||||
},
|
||||
onHoverLost: w => {
|
||||
if (w._hovered)
|
||||
w._hovered = false;
|
||||
},
|
||||
id: notif.id,
|
||||
});
|
||||
|
||||
// Notif methods
|
||||
notifWidget.slideAway = side => {
|
||||
notifWidget.child.setStyle(notifWidget.child[`_slide${side}`]);
|
||||
notifWidget.sensitive = false;
|
||||
timeout(400, () => {
|
||||
notifWidget.child.setStyle(notifWidget.child[`_squeeze${side}`]);
|
||||
timeout(500, () => {
|
||||
HasNotifs.value = Notifications.notifications.length > 0;
|
||||
notifWidget.get_parent().remove(notifWidget);
|
||||
notifWidget.destroy();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Add body to notif
|
||||
notifWidget.child.add(Box({
|
||||
className: `notification ${notif.urgency}`,
|
||||
|
@ -177,14 +153,14 @@ export const Notification = ({
|
|||
}),
|
||||
Label({
|
||||
className: 'time',
|
||||
valign: 'start',
|
||||
vpack: 'start',
|
||||
label: setTime(notif.time),
|
||||
}),
|
||||
EventBox({
|
||||
reset: false,
|
||||
child: Button({
|
||||
className: 'close-button',
|
||||
valign: 'start',
|
||||
vpack: 'start',
|
||||
onClicked: () => notif.close(),
|
||||
child: Icon('window-close-symbolic'),
|
||||
}),
|
||||
|
|
|
@ -2,10 +2,56 @@ import Notifications from 'resource:///com/github/Aylur/ags/service/notification
|
|||
import { Button, Label, Box, Icon, Scrollable, Revealer } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
|
||||
import { Notification, HasNotifs } from './base.js';
|
||||
import PopupWindow from '../misc/popup.js';
|
||||
import EventBox from '../misc/cursorbox.js';
|
||||
import PopupWindow from '../misc/popup.js';
|
||||
import EventBox from '../misc/cursorbox.js';
|
||||
|
||||
|
||||
const addNotif = (box, notif) => {
|
||||
if (!notif)
|
||||
return;
|
||||
|
||||
const NewNotif = Notification({
|
||||
notif,
|
||||
slideIn: 'Right',
|
||||
command: () => notif.close(),
|
||||
});
|
||||
|
||||
if (NewNotif) {
|
||||
box.pack_end(NewNotif, false, false, 0);
|
||||
box.show_all();
|
||||
}
|
||||
};
|
||||
|
||||
const NotificationList = () => Box({
|
||||
vertical: true,
|
||||
vexpand: true,
|
||||
vpack: 'start',
|
||||
binds: [['visible', HasNotifs]],
|
||||
setup: box => {
|
||||
// Get cached notifications
|
||||
const id = Notifications.connect('changed', () => {
|
||||
Notifications.notifications.forEach(notif => {
|
||||
addNotif(box, notif);
|
||||
});
|
||||
Notifications.disconnect(id);
|
||||
});
|
||||
},
|
||||
connections: [
|
||||
[Notifications, (box, id) => {
|
||||
if (!id)
|
||||
return;
|
||||
|
||||
addNotif(box, Notifications.getNotification(id));
|
||||
}, 'notified'],
|
||||
|
||||
[Notifications, (box, id) => {
|
||||
const notif = box.children.find(ch => ch._id === id);
|
||||
if (notif?.sensitive)
|
||||
notif.slideAway('Right');
|
||||
}, 'closed'],
|
||||
],
|
||||
});
|
||||
|
||||
// Needs to be wrapped to still have onHover when disabled
|
||||
const ClearButton = () => EventBox({
|
||||
child: Button({
|
||||
|
@ -37,65 +83,14 @@ const Header = () => Box({
|
|||
],
|
||||
});
|
||||
|
||||
const NotificationList = () => Box({
|
||||
vertical: true,
|
||||
vexpand: true,
|
||||
valign: 'start',
|
||||
binds: [['visible', HasNotifs]],
|
||||
connections: [
|
||||
[Notifications, (box, id) => {
|
||||
if (box.children.length == 0) {
|
||||
for (const notif of Notifications.notifications) {
|
||||
if (!notif)
|
||||
return;
|
||||
|
||||
const NewNotif = Notification({
|
||||
notif,
|
||||
slideIn: 'Right',
|
||||
command: () => notif.close(),
|
||||
});
|
||||
|
||||
if (NewNotif) {
|
||||
box.pack_end(NewNotif, false, false, 0);
|
||||
box.show_all();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (id) {
|
||||
const notif = Notifications.getNotification(id);
|
||||
|
||||
const NewNotif = Notification({
|
||||
notif,
|
||||
slideIn: 'Right',
|
||||
command: () => notif.close(),
|
||||
});
|
||||
|
||||
if (NewNotif) {
|
||||
box.pack_end(NewNotif, false, false, 0);
|
||||
box.show_all();
|
||||
}
|
||||
}
|
||||
}, 'notified'],
|
||||
|
||||
[Notifications, (box, id) => {
|
||||
for (const ch of box.children) {
|
||||
if (ch._id == id) {
|
||||
ch.slideAway('Right');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}, 'closed'],
|
||||
],
|
||||
});
|
||||
|
||||
const Placeholder = () => Revealer({
|
||||
transition: 'crossfade',
|
||||
binds: [['revealChild', HasNotifs, 'value', value => !value]],
|
||||
child: Box({
|
||||
className: 'placeholder',
|
||||
vertical: true,
|
||||
valign: 'center',
|
||||
halign: 'center',
|
||||
vpack: 'center',
|
||||
hpack: 'center',
|
||||
vexpand: true,
|
||||
hexpand: true,
|
||||
children: [
|
||||
|
@ -133,6 +128,6 @@ const NotificationCenterWidget = () => Box({
|
|||
export default () => PopupWindow({
|
||||
name: 'notification-center',
|
||||
anchor: ['top', 'right'],
|
||||
margin: [6, 60, 0, 0],
|
||||
margins: [6, 60, 0, 0],
|
||||
child: NotificationCenterWidget(),
|
||||
});
|
||||
|
|
|
@ -1,40 +1,43 @@
|
|||
import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js';
|
||||
import { Box, EventBox } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import { timeout } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
|
||||
import { HasNotifs } from './base.js';
|
||||
|
||||
import Gtk from 'gi://Gtk';
|
||||
import Gdk from 'gi://Gdk';
|
||||
const display = Gdk.Display.get_default();
|
||||
|
||||
|
||||
export default ({
|
||||
id,
|
||||
slideIn = 'Left',
|
||||
maxOffset = 150,
|
||||
maxOffset = 200,
|
||||
startMargin = 0,
|
||||
endMargin = 300,
|
||||
command = () => {},
|
||||
onHover = () => {},
|
||||
onHoverLost = () => {},
|
||||
child = '',
|
||||
children = [],
|
||||
properties = [[]],
|
||||
...props
|
||||
}) => {
|
||||
const widget = EventBox({
|
||||
...props,
|
||||
properties: [
|
||||
['dragging', false],
|
||||
...properties,
|
||||
],
|
||||
onHover: self => {
|
||||
self.window.set_cursor(Gdk.Cursor.new_from_name(display, 'grab'));
|
||||
onHover(self);
|
||||
if (!self._hovered)
|
||||
self._hovered = true;
|
||||
},
|
||||
onHoverLost: self => {
|
||||
self.window.set_cursor(null);
|
||||
onHoverLost(self);
|
||||
if (self._hovered)
|
||||
self._hovered = false;
|
||||
},
|
||||
});
|
||||
|
||||
// Properties
|
||||
widget._dragging = false;
|
||||
widget._hovered = false;
|
||||
widget._id = id;
|
||||
widget.ready = false;
|
||||
|
||||
const gesture = Gtk.GestureDrag.new(widget);
|
||||
|
||||
const TRANSITION = 'transition: margin 0.5s ease, opacity 0.5s ease;';
|
||||
|
@ -48,32 +51,45 @@ export default ({
|
|||
margin-right: -${Number(maxOffset + endMargin)}px;
|
||||
`;
|
||||
|
||||
const slideLeft = `${TRANSITION} ${MAX_LEFT} opacity: 0;`;
|
||||
const slideLeft = `${TRANSITION} ${MAX_LEFT} margin-top: 0px; margin-bottom: 0px; opacity: 0;`;
|
||||
const squeezeLeft = `${TRANSITION} ${MAX_LEFT} ${SQUEEZED} opacity: 0;`;
|
||||
const slideRight = `${TRANSITION} ${MAX_RIGHT} opacity: 0;`;
|
||||
const slideRight = `${TRANSITION} ${MAX_RIGHT} margin-top: 0px; margin-bottom: 0px; opacity: 0;`;
|
||||
const squeezeRight = `${TRANSITION} ${MAX_RIGHT} ${SQUEEZED} opacity: 0;`;
|
||||
const defaultStyle = `${TRANSITION} margin: unset; opacity: 1;`;
|
||||
|
||||
// Notif methods
|
||||
widget.slideAway = side => {
|
||||
// Slide away
|
||||
widget.child.setCss(side === 'Left' ? slideLeft : slideRight);
|
||||
|
||||
// Makie it uninteractable
|
||||
widget.sensitive = false;
|
||||
|
||||
timeout(400, () => {
|
||||
// Reduce height after sliding away
|
||||
widget.child?.setCss(side === 'Left' ? squeezeLeft : squeezeRight);
|
||||
|
||||
timeout(500, () => {
|
||||
// Kill notif and update HasNotifs after anim is done
|
||||
command();
|
||||
HasNotifs.value = Notifications.notifications.length > 0;
|
||||
widget.get_parent()?.remove(widget);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
widget.add(Box({
|
||||
properties: [
|
||||
['slideLeft', slideLeft],
|
||||
['squeezeLeft', squeezeLeft],
|
||||
['slideRight', slideRight],
|
||||
['squeezeRight', squeezeRight],
|
||||
['ready', false],
|
||||
],
|
||||
children: [
|
||||
...children,
|
||||
child,
|
||||
],
|
||||
style: squeezeLeft,
|
||||
css: squeezeLeft,
|
||||
connections: [
|
||||
|
||||
// When dragging
|
||||
[gesture, self => {
|
||||
var offset = gesture.get_offset()[1];
|
||||
|
||||
// Slide right
|
||||
if (offset >= 0) {
|
||||
self.setStyle(`
|
||||
self.setCss(`
|
||||
margin-top: 0px; margin-bottom: 0px; opacity: 1; transition: none;
|
||||
margin-left: ${Number(offset + startMargin)}px;
|
||||
margin-right: -${Number(offset + startMargin)}px;
|
||||
`);
|
||||
|
@ -82,26 +98,31 @@ export default ({
|
|||
// Slide left
|
||||
else {
|
||||
offset = Math.abs(offset);
|
||||
self.setStyle(`
|
||||
self.setCss(`
|
||||
margin-top: 0px; margin-bottom: 0px; opacity: 1; transition: none;
|
||||
margin-right: ${Number(offset + startMargin)}px;
|
||||
margin-left: -${Number(offset + startMargin)}px;
|
||||
`);
|
||||
}
|
||||
|
||||
// Put a threshold on if a click is actually dragging
|
||||
self.get_parent()._dragging = Math.abs(offset) > 10;
|
||||
|
||||
if (widget.window)
|
||||
widget.window.set_cursor(Gdk.Cursor.new_from_name(display, 'grabbing'));
|
||||
widget._dragging = Math.abs(offset) > 10;
|
||||
widget.window?.set_cursor(Gdk.Cursor.new_from_name(display, 'grabbing'));
|
||||
}, 'drag-update'],
|
||||
|
||||
|
||||
// On drag end
|
||||
[gesture, self => {
|
||||
// Make it slide in on init
|
||||
if (!self._ready) {
|
||||
self.setStyle(slideIn === 'Left' ? slideLeft : slideRight);
|
||||
if (!widget.ready) {
|
||||
// Reverse of slideAway, so it started at squeeze, then we go to slide
|
||||
self.setCss(slideIn === 'Left' ? slideLeft : slideRight);
|
||||
|
||||
timeout(500, () => self.setStyle(`${TRANSITION} margin: unset; opacity: 1;`));
|
||||
timeout(1000, () => self._ready = true);
|
||||
timeout(500, () => {
|
||||
// Then we got to center
|
||||
self.setCss(defaultStyle);
|
||||
timeout(500, () => widget.ready = true);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -109,35 +130,16 @@ export default ({
|
|||
|
||||
// If crosses threshold after letting go, slide away
|
||||
if (Math.abs(offset) > maxOffset) {
|
||||
// Slide away right
|
||||
if (offset > 0) {
|
||||
// Disable inputs during animation
|
||||
widget.sensitive = false;
|
||||
|
||||
self.setStyle(slideRight);
|
||||
timeout(500, () => self.setStyle(squeezeRight));
|
||||
}
|
||||
|
||||
// Slide away left
|
||||
else {
|
||||
// Disable inputs during animation
|
||||
widget.sensitive = false;
|
||||
|
||||
self.setStyle(slideLeft);
|
||||
timeout(500, () => self.setStyle(squeezeLeft));
|
||||
}
|
||||
|
||||
timeout(1000, () => {
|
||||
command();
|
||||
self.destroy();
|
||||
});
|
||||
if (offset > 0)
|
||||
widget.slideAway('Right');
|
||||
else
|
||||
widget.slideAway('Left');
|
||||
}
|
||||
else {
|
||||
self.setStyle(`${TRANSITION} margin: unset; opacity: 1;`);
|
||||
if (widget.window)
|
||||
widget.window.set_cursor(Gdk.Cursor.new_from_name(display, 'grab'));
|
||||
self.setCss(defaultStyle);
|
||||
widget.window?.set_cursor(Gdk.Cursor.new_from_name(display, 'grab'));
|
||||
|
||||
self.get_parent()._dragging = false;
|
||||
widget._dragging = false;
|
||||
}
|
||||
}, 'drag-end'],
|
||||
|
||||
|
|
|
@ -1,71 +1,68 @@
|
|||
import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js';
|
||||
import { Box, Window } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import { Box } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import { interval } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
|
||||
import GLib from 'gi://GLib';
|
||||
|
||||
import { Notification } from './base.js';
|
||||
import PopupWindow from '../misc/popup.js';
|
||||
|
||||
|
||||
const Popups = () => Box({
|
||||
vertical: true,
|
||||
properties: [
|
||||
['notify', (box, id) => {
|
||||
if (id) {
|
||||
const notif = Notifications.getNotification(id);
|
||||
const addPopup = (box, id) => {
|
||||
if (!id)
|
||||
return;
|
||||
|
||||
const NewNotif = Notification({
|
||||
notif,
|
||||
command: () => notif.dismiss(),
|
||||
});
|
||||
const notif = Notifications.getNotification(id);
|
||||
|
||||
if (NewNotif) {
|
||||
// use this instead of add to put it at the top
|
||||
box.pack_end(NewNotif, false, false, 0);
|
||||
box.show_all();
|
||||
}
|
||||
const NewNotif = Notification({
|
||||
notif,
|
||||
command: () => notif.dismiss(),
|
||||
});
|
||||
|
||||
if (NewNotif) {
|
||||
// use this instead of add to put it at the top
|
||||
box.pack_end(NewNotif, false, false, 0);
|
||||
box.show_all();
|
||||
}
|
||||
};
|
||||
|
||||
const handleDismiss = (box, id, force = false) => {
|
||||
const notif = box.children.find(ch => ch._id === id);
|
||||
if (!notif)
|
||||
return;
|
||||
|
||||
// If notif isn't hovered or was closed, slide away
|
||||
if (!notif._hovered || force) {
|
||||
notif.slideAway('Left');
|
||||
return;
|
||||
}
|
||||
|
||||
// If notif is hovered, delay close
|
||||
else if (notif._hovered) {
|
||||
notif.interval = interval(2000, () => {
|
||||
if (!notif._hovered && notif.interval) {
|
||||
notif.slideAway('Left');
|
||||
|
||||
GLib.source_remove(notif.interval);
|
||||
notif.interval = undefined;
|
||||
return;
|
||||
}
|
||||
}],
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
['dismiss', (box, id, force = false) => {
|
||||
for (const ch of box.children) {
|
||||
if (ch._id == id) {
|
||||
// If notif isn't hovered or was closed, slide away
|
||||
if (!ch._hovered || force) {
|
||||
ch.slideAway('Left');
|
||||
return;
|
||||
}
|
||||
|
||||
// If notif is hovered, delay close
|
||||
else if (ch._hovered) {
|
||||
ch.interval = interval(2000, () => {
|
||||
if (!ch._hovered && ch.interval) {
|
||||
ch.slideAway('Left');
|
||||
|
||||
GLib.source_remove(ch.interval);
|
||||
ch.interval = undefined;
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}],
|
||||
],
|
||||
connections: [
|
||||
[Notifications, (box, id) => box._notify(box, id), 'notified'],
|
||||
[Notifications, (box, id) => box._dismiss(box, id), 'dismissed'],
|
||||
[Notifications, (box, id) => box._dismiss(box, id, true), 'closed'],
|
||||
],
|
||||
});
|
||||
|
||||
export default () => Window({
|
||||
export default () => PopupWindow({
|
||||
name: 'notifications',
|
||||
anchor: ['top', 'left'],
|
||||
visible: true,
|
||||
transition: 'none',
|
||||
closeOnUnfocus: 'none',
|
||||
child: Box({
|
||||
style: `min-height:1px;
|
||||
min-width:1px;
|
||||
padding: 1px;`,
|
||||
children: [Popups()],
|
||||
vertical: true,
|
||||
connections: [
|
||||
[Notifications, (box, id) => addPopup(box, id), 'notified'],
|
||||
[Notifications, (box, id) => handleDismiss(box, id), 'dismissed'],
|
||||
[Notifications, (box, id) => handleDismiss(box, id, true), 'closed'],
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue