refactor(ags notifs): clarify code, add way to slide in from right, fix clear button, etc.
This commit is contained in:
parent
ed3f8f6eb1
commit
ad02510b10
4 changed files with 144 additions and 157 deletions
|
@ -1,6 +1,8 @@
|
||||||
import Applications from 'resource:///com/github/Aylur/ags/service/applications.js';
|
import Applications from 'resource:///com/github/Aylur/ags/service/applications.js';
|
||||||
|
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 { Box, Icon, Label, Button } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
import { lookUpIcon, execAsync } from 'resource:///com/github/Aylur/ags/utils.js';
|
import { lookUpIcon, execAsync, timeout } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||||
|
|
||||||
import GLib from 'gi://GLib';
|
import GLib from 'gi://GLib';
|
||||||
|
|
||||||
|
@ -87,10 +89,20 @@ const NotificationIcon = notif => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ({
|
// Make a variable to connect to for Widgets
|
||||||
|
// to know when there are notifs or not
|
||||||
|
export const HasNotifs = Variable(false);
|
||||||
|
|
||||||
|
export const Notification = ({
|
||||||
notif,
|
notif,
|
||||||
|
slideIn = 'Left',
|
||||||
command = () => {},
|
command = () => {},
|
||||||
} = {}) => {
|
} = {}) => {
|
||||||
|
if (!notif)
|
||||||
|
return;
|
||||||
|
|
||||||
|
HasNotifs.value = Notifications.notifications.length > 0;
|
||||||
|
|
||||||
const BlockedApps = [
|
const BlockedApps = [
|
||||||
'Spotify',
|
'Spotify',
|
||||||
];
|
];
|
||||||
|
@ -100,9 +112,11 @@ export default ({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Gesture({
|
// Init notif
|
||||||
|
const notifWidget = Gesture({
|
||||||
maxOffset: 200,
|
maxOffset: 200,
|
||||||
command: () => command(),
|
command: () => command(),
|
||||||
|
slideIn,
|
||||||
properties: [
|
properties: [
|
||||||
['hovered', false],
|
['hovered', false],
|
||||||
['id', notif.id],
|
['id', notif.id],
|
||||||
|
@ -115,77 +129,93 @@ export default ({
|
||||||
if (w._hovered)
|
if (w._hovered)
|
||||||
w._hovered = false;
|
w._hovered = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
child: Box({
|
|
||||||
className: `notification ${notif.urgency}`,
|
|
||||||
vexpand: false,
|
|
||||||
// Notification
|
|
||||||
child: Box({
|
|
||||||
vertical: true,
|
|
||||||
children: [
|
|
||||||
// Content
|
|
||||||
Box({
|
|
||||||
children: [
|
|
||||||
NotificationIcon(notif),
|
|
||||||
Box({
|
|
||||||
hexpand: true,
|
|
||||||
vertical: true,
|
|
||||||
children: [
|
|
||||||
// Top of Content
|
|
||||||
Box({
|
|
||||||
children: [
|
|
||||||
Label({
|
|
||||||
className: 'title',
|
|
||||||
xalign: 0,
|
|
||||||
justification: 'left',
|
|
||||||
hexpand: true,
|
|
||||||
maxWidthChars: 24,
|
|
||||||
truncate: 'end',
|
|
||||||
wrap: true,
|
|
||||||
label: notif.summary,
|
|
||||||
useMarkup: notif.summary.startsWith('<'),
|
|
||||||
}),
|
|
||||||
Label({
|
|
||||||
className: 'time',
|
|
||||||
valign: 'start',
|
|
||||||
label: setTime(notif.time),
|
|
||||||
}),
|
|
||||||
EventBox({
|
|
||||||
reset: false,
|
|
||||||
child: Button({
|
|
||||||
className: 'close-button',
|
|
||||||
valign: 'start',
|
|
||||||
onClicked: () => notif.close(),
|
|
||||||
child: Icon('window-close-symbolic'),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
Label({
|
|
||||||
className: 'description',
|
|
||||||
hexpand: true,
|
|
||||||
useMarkup: true,
|
|
||||||
xalign: 0,
|
|
||||||
justification: 'left',
|
|
||||||
label: notif.body,
|
|
||||||
wrap: true,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
// Actions
|
|
||||||
Box({
|
|
||||||
className: 'actions',
|
|
||||||
children: notif.actions.map(action => Button({
|
|
||||||
className: 'action-button',
|
|
||||||
onClicked: () => notif.invoke(action.id),
|
|
||||||
hexpand: true,
|
|
||||||
child: Label(action.label),
|
|
||||||
})),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 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}`,
|
||||||
|
vexpand: false,
|
||||||
|
// Notification
|
||||||
|
child: Box({
|
||||||
|
vertical: true,
|
||||||
|
children: [
|
||||||
|
// Content
|
||||||
|
Box({
|
||||||
|
children: [
|
||||||
|
NotificationIcon(notif),
|
||||||
|
Box({
|
||||||
|
hexpand: true,
|
||||||
|
vertical: true,
|
||||||
|
children: [
|
||||||
|
// Top of Content
|
||||||
|
Box({
|
||||||
|
children: [
|
||||||
|
Label({
|
||||||
|
className: 'title',
|
||||||
|
xalign: 0,
|
||||||
|
justification: 'left',
|
||||||
|
hexpand: true,
|
||||||
|
maxWidthChars: 24,
|
||||||
|
truncate: 'end',
|
||||||
|
wrap: true,
|
||||||
|
label: notif.summary,
|
||||||
|
useMarkup: notif.summary.startsWith('<'),
|
||||||
|
}),
|
||||||
|
Label({
|
||||||
|
className: 'time',
|
||||||
|
valign: 'start',
|
||||||
|
label: setTime(notif.time),
|
||||||
|
}),
|
||||||
|
EventBox({
|
||||||
|
reset: false,
|
||||||
|
child: Button({
|
||||||
|
className: 'close-button',
|
||||||
|
valign: 'start',
|
||||||
|
onClicked: () => notif.close(),
|
||||||
|
child: Icon('window-close-symbolic'),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
Label({
|
||||||
|
className: 'description',
|
||||||
|
hexpand: true,
|
||||||
|
useMarkup: true,
|
||||||
|
xalign: 0,
|
||||||
|
justification: 'left',
|
||||||
|
label: notif.body,
|
||||||
|
wrap: true,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
// Actions
|
||||||
|
Box({
|
||||||
|
className: 'actions',
|
||||||
|
children: notif.actions.map(action => Button({
|
||||||
|
className: 'action-button',
|
||||||
|
onClicked: () => notif.invoke(action.id),
|
||||||
|
hexpand: true,
|
||||||
|
child: Label(action.label),
|
||||||
|
})),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
return notifWidget;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,45 +1,16 @@
|
||||||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
|
||||||
import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js';
|
import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js';
|
||||||
import { Button, Label, Box, Icon, Scrollable, Revealer } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Button, Label, Box, Icon, Scrollable, Revealer } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
import { timeout } from 'resource:///com/github/Aylur/ags/utils.js';
|
|
||||||
|
|
||||||
import Notification from './base.js';
|
import { Notification, HasNotifs } from './base.js';
|
||||||
import PopupWindow from '../misc/popup.js';
|
import PopupWindow from '../misc/popup.js';
|
||||||
import EventBox from '../misc/cursorbox.js';
|
import EventBox from '../misc/cursorbox.js';
|
||||||
|
|
||||||
|
|
||||||
|
// Needs to be wrapped to still have onHover when disabled
|
||||||
const ClearButton = () => EventBox({
|
const ClearButton = () => EventBox({
|
||||||
child: Button({
|
child: Button({
|
||||||
onPrimaryClickRelease: button => {
|
onPrimaryClickRelease: () => Notifications.clear(),
|
||||||
button._popups.children.forEach(ch => {
|
binds: [['sensitive', HasNotifs]],
|
||||||
ch.child.setStyle(ch.child._slideLeft);
|
|
||||||
ch.sensitive = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
button._notifList.children.forEach(ch => {
|
|
||||||
if (ch.child) {
|
|
||||||
ch.child.setStyle(ch.child._slideRight);
|
|
||||||
ch.sensitive = false;
|
|
||||||
}
|
|
||||||
timeout(500, () => {
|
|
||||||
button._notifList.remove(ch);
|
|
||||||
Notifications.clear();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
properties: [
|
|
||||||
['notifList'],
|
|
||||||
['popups'],
|
|
||||||
],
|
|
||||||
connections: [[Notifications, button => {
|
|
||||||
if (!button._notifList)
|
|
||||||
button._notifList = NotificationList;
|
|
||||||
|
|
||||||
if (!button._popups)
|
|
||||||
button._popups = App.getWindow('notifications').child.children[0].child;
|
|
||||||
|
|
||||||
button.sensitive = Notifications.notifications.length > 0;
|
|
||||||
}]],
|
|
||||||
child: Box({
|
child: Box({
|
||||||
children: [
|
children: [
|
||||||
Label('Clear '),
|
Label('Clear '),
|
||||||
|
@ -66,16 +37,21 @@ const Header = () => Box({
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const NotificationList = Box({
|
const NotificationList = () => Box({
|
||||||
vertical: true,
|
vertical: true,
|
||||||
valign: 'start',
|
|
||||||
vexpand: true,
|
vexpand: true,
|
||||||
|
valign: 'start',
|
||||||
|
binds: [['visible', HasNotifs]],
|
||||||
connections: [
|
connections: [
|
||||||
[Notifications, (box, id) => {
|
[Notifications, (box, id) => {
|
||||||
if (box.children.length == 0) {
|
if (box.children.length == 0) {
|
||||||
for (const notif of Notifications.notifications) {
|
for (const notif of Notifications.notifications) {
|
||||||
|
if (!notif)
|
||||||
|
return;
|
||||||
|
|
||||||
const NewNotif = Notification({
|
const NewNotif = Notification({
|
||||||
notif,
|
notif,
|
||||||
|
slideIn: 'Right',
|
||||||
command: () => notif.close(),
|
command: () => notif.close(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -90,6 +66,7 @@ const NotificationList = Box({
|
||||||
|
|
||||||
const NewNotif = Notification({
|
const NewNotif = Notification({
|
||||||
notif,
|
notif,
|
||||||
|
slideIn: 'Right',
|
||||||
command: () => notif.close(),
|
command: () => notif.close(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -103,23 +80,17 @@ const NotificationList = Box({
|
||||||
[Notifications, (box, id) => {
|
[Notifications, (box, id) => {
|
||||||
for (const ch of box.children) {
|
for (const ch of box.children) {
|
||||||
if (ch._id == id) {
|
if (ch._id == id) {
|
||||||
ch.child.setStyle(ch.child._slideRight);
|
ch.slideAway('Right');
|
||||||
ch.sensitive = false;
|
|
||||||
timeout(500, () => box.remove(ch));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 'closed'],
|
}, 'closed'],
|
||||||
|
|
||||||
[Notifications, box => box.visible = Notifications.notifications.length > 0],
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const Placeholder = () => Revealer({
|
const Placeholder = () => Revealer({
|
||||||
transition: 'crossfade',
|
transition: 'crossfade',
|
||||||
connections: [[Notifications, box => {
|
binds: [['revealChild', HasNotifs, 'value', value => !value]],
|
||||||
box.revealChild = Notifications.notifications.length === 0;
|
|
||||||
}]],
|
|
||||||
child: Box({
|
child: Box({
|
||||||
className: 'placeholder',
|
className: 'placeholder',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
|
@ -149,7 +120,7 @@ const NotificationCenterWidget = () => Box({
|
||||||
className: 'notification-list',
|
className: 'notification-list',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: [
|
children: [
|
||||||
NotificationList,
|
NotificationList(),
|
||||||
Placeholder(),
|
Placeholder(),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -7,6 +7,7 @@ const display = Gdk.Display.get_default();
|
||||||
|
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
|
slideIn = 'Left',
|
||||||
maxOffset = 150,
|
maxOffset = 150,
|
||||||
startMargin = 0,
|
startMargin = 0,
|
||||||
endMargin = 300,
|
endMargin = 300,
|
||||||
|
@ -87,6 +88,7 @@ export default ({
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Put a threshold on if a click is actually dragging
|
||||||
self.get_parent()._dragging = Math.abs(offset) > 10;
|
self.get_parent()._dragging = Math.abs(offset) > 10;
|
||||||
|
|
||||||
if (widget.window)
|
if (widget.window)
|
||||||
|
@ -94,9 +96,9 @@ export default ({
|
||||||
}, 'drag-update'],
|
}, 'drag-update'],
|
||||||
|
|
||||||
[gesture, self => {
|
[gesture, self => {
|
||||||
// ?
|
// Make it slide in on init
|
||||||
if (!self._ready) {
|
if (!self._ready) {
|
||||||
self.setStyle(slideLeft);
|
self.setStyle(slideIn === 'Left' ? slideLeft : slideRight);
|
||||||
|
|
||||||
timeout(500, () => self.setStyle(`${TRANSITION} margin: unset; opacity: 1;`));
|
timeout(500, () => self.setStyle(`${TRANSITION} margin: unset; opacity: 1;`));
|
||||||
timeout(1000, () => self._ready = true);
|
timeout(1000, () => self._ready = true);
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js';
|
import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js';
|
||||||
import { Box, Revealer, Window } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box, Window } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
import { interval, timeout } from 'resource:///com/github/Aylur/ags/utils.js';
|
import { interval } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||||
|
|
||||||
import GLib from 'gi://GLib';
|
import GLib from 'gi://GLib';
|
||||||
|
|
||||||
import Notification from './base.js';
|
import { Notification } from './base.js';
|
||||||
|
|
||||||
|
|
||||||
// TODO: clean up code
|
|
||||||
const Popups = () => Box({
|
const Popups = () => Box({
|
||||||
vertical: true,
|
vertical: true,
|
||||||
properties: [
|
properties: [
|
||||||
|
@ -21,6 +20,7 @@ const Popups = () => Box({
|
||||||
});
|
});
|
||||||
|
|
||||||
if (NewNotif) {
|
if (NewNotif) {
|
||||||
|
// use this instead of add to put it at the top
|
||||||
box.pack_end(NewNotif, false, false, 0);
|
box.pack_end(NewNotif, false, false, 0);
|
||||||
box.show_all();
|
box.show_all();
|
||||||
}
|
}
|
||||||
|
@ -30,28 +30,21 @@ const Popups = () => Box({
|
||||||
['dismiss', (box, id, force = false) => {
|
['dismiss', (box, id, force = false) => {
|
||||||
for (const ch of box.children) {
|
for (const ch of box.children) {
|
||||||
if (ch._id == id) {
|
if (ch._id == id) {
|
||||||
|
// If notif isn't hovered or was closed, slide away
|
||||||
if (!ch._hovered || force) {
|
if (!ch._hovered || force) {
|
||||||
ch.child.setStyle(ch.child._slideLeft);
|
ch.slideAway('Left');
|
||||||
ch.sensitive = false;
|
|
||||||
timeout(400, () => {
|
|
||||||
ch.child.setStyle(ch.child._squeezeLeft);
|
|
||||||
timeout(500, () => box.remove(ch));
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If notif is hovered, delay close
|
||||||
else if (ch._hovered) {
|
else if (ch._hovered) {
|
||||||
ch.interval = interval(2000, () => {
|
ch.interval = interval(2000, () => {
|
||||||
if (!ch._hovered) {
|
if (!ch._hovered && ch.interval) {
|
||||||
if (ch.interval) {
|
ch.slideAway('Left');
|
||||||
ch.child.setStyle(ch.child._slideLeft);
|
|
||||||
ch.sensitive = false;
|
GLib.source_remove(ch.interval);
|
||||||
timeout(400, () => {
|
ch.interval = undefined;
|
||||||
ch.child.setStyle(ch.child._squeezeLeft);
|
return;
|
||||||
timeout(500, () => box.remove(ch));
|
|
||||||
});
|
|
||||||
GLib.source_remove(ch.interval);
|
|
||||||
ch.interval = undefined;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -66,22 +59,13 @@ const Popups = () => Box({
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const PopupList = ({ transition = 'none' } = {}) => Box({
|
|
||||||
className: 'notifications-popup-list',
|
|
||||||
style: 'padding: 1px',
|
|
||||||
children: [
|
|
||||||
Revealer({
|
|
||||||
transition,
|
|
||||||
connections: [[Notifications, self => {
|
|
||||||
self.revealChild = self.child.children.length > 0;
|
|
||||||
}]],
|
|
||||||
child: Popups(),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
export default () => Window({
|
export default () => Window({
|
||||||
name: 'notifications',
|
name: 'notifications',
|
||||||
anchor: ['top', 'left'],
|
anchor: ['top', 'left'],
|
||||||
child: PopupList(),
|
child: Box({
|
||||||
|
style: `min-height:1px;
|
||||||
|
min-width:1px;
|
||||||
|
padding: 1px;`,
|
||||||
|
children: [Popups()],
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue