diff --git a/devices/wim/config/ags/js/notifications/base.js b/devices/wim/config/ags/js/notifications/base.js index 121f3d6..d1c8fe1 100644 --- a/devices/wim/config/ags/js/notifications/base.js +++ b/devices/wim/config/ags/js/notifications/base.js @@ -1,6 +1,8 @@ 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 { 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'; @@ -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, + slideIn = 'Left', command = () => {}, } = {}) => { + if (!notif) + return; + + HasNotifs.value = Notifications.notifications.length > 0; + const BlockedApps = [ 'Spotify', ]; @@ -100,9 +112,11 @@ export default ({ return; } - return Gesture({ + // Init notif + const notifWidget = Gesture({ maxOffset: 200, command: () => command(), + slideIn, properties: [ ['hovered', false], ['id', notif.id], @@ -115,77 +129,93 @@ export default ({ if (w._hovered) 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; }; diff --git a/devices/wim/config/ags/js/notifications/center.js b/devices/wim/config/ags/js/notifications/center.js index 77c6e9e..d8ae408 100644 --- a/devices/wim/config/ags/js/notifications/center.js +++ b/devices/wim/config/ags/js/notifications/center.js @@ -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 { 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 EventBox from '../misc/cursorbox.js'; +// Needs to be wrapped to still have onHover when disabled const ClearButton = () => EventBox({ child: Button({ - onPrimaryClickRelease: button => { - button._popups.children.forEach(ch => { - 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; - }]], + onPrimaryClickRelease: () => Notifications.clear(), + binds: [['sensitive', HasNotifs]], child: Box({ children: [ Label('Clear '), @@ -66,16 +37,21 @@ const Header = () => Box({ ], }); -const NotificationList = Box({ +const NotificationList = () => Box({ vertical: true, - valign: 'start', 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(), }); @@ -90,6 +66,7 @@ const NotificationList = Box({ const NewNotif = Notification({ notif, + slideIn: 'Right', command: () => notif.close(), }); @@ -103,23 +80,17 @@ const NotificationList = Box({ [Notifications, (box, id) => { for (const ch of box.children) { if (ch._id == id) { - ch.child.setStyle(ch.child._slideRight); - ch.sensitive = false; - timeout(500, () => box.remove(ch)); + ch.slideAway('Right'); return; } } }, 'closed'], - - [Notifications, box => box.visible = Notifications.notifications.length > 0], ], }); const Placeholder = () => Revealer({ transition: 'crossfade', - connections: [[Notifications, box => { - box.revealChild = Notifications.notifications.length === 0; - }]], + binds: [['revealChild', HasNotifs, 'value', value => !value]], child: Box({ className: 'placeholder', vertical: true, @@ -149,7 +120,7 @@ const NotificationCenterWidget = () => Box({ className: 'notification-list', vertical: true, children: [ - NotificationList, + NotificationList(), Placeholder(), ], }), diff --git a/devices/wim/config/ags/js/notifications/gesture.js b/devices/wim/config/ags/js/notifications/gesture.js index 73cfd1b..1cb0f7d 100644 --- a/devices/wim/config/ags/js/notifications/gesture.js +++ b/devices/wim/config/ags/js/notifications/gesture.js @@ -7,6 +7,7 @@ const display = Gdk.Display.get_default(); export default ({ + slideIn = 'Left', maxOffset = 150, startMargin = 0, 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; if (widget.window) @@ -94,9 +96,9 @@ export default ({ }, 'drag-update'], [gesture, self => { - // ? + // Make it slide in on init if (!self._ready) { - self.setStyle(slideLeft); + self.setStyle(slideIn === 'Left' ? slideLeft : slideRight); timeout(500, () => self.setStyle(`${TRANSITION} margin: unset; opacity: 1;`)); timeout(1000, () => self._ready = true); diff --git a/devices/wim/config/ags/js/notifications/popup.js b/devices/wim/config/ags/js/notifications/popup.js index 6579fcc..00f0a29 100644 --- a/devices/wim/config/ags/js/notifications/popup.js +++ b/devices/wim/config/ags/js/notifications/popup.js @@ -1,13 +1,12 @@ import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js'; -import { Box, Revealer, Window } from 'resource:///com/github/Aylur/ags/widget.js'; -import { interval, timeout } from 'resource:///com/github/Aylur/ags/utils.js'; +import { Box, Window } 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 { Notification } from './base.js'; -// TODO: clean up code const Popups = () => Box({ vertical: true, properties: [ @@ -21,6 +20,7 @@ const Popups = () => Box({ }); if (NewNotif) { + // use this instead of add to put it at the top box.pack_end(NewNotif, false, false, 0); box.show_all(); } @@ -30,28 +30,21 @@ const Popups = () => Box({ ['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.child.setStyle(ch.child._slideLeft); - ch.sensitive = false; - timeout(400, () => { - ch.child.setStyle(ch.child._squeezeLeft); - timeout(500, () => box.remove(ch)); - }); + ch.slideAway('Left'); return; } + + // If notif is hovered, delay close else if (ch._hovered) { ch.interval = interval(2000, () => { - if (!ch._hovered) { - if (ch.interval) { - ch.child.setStyle(ch.child._slideLeft); - ch.sensitive = false; - timeout(400, () => { - ch.child.setStyle(ch.child._squeezeLeft); - timeout(500, () => box.remove(ch)); - }); - GLib.source_remove(ch.interval); - ch.interval = undefined; - } + if (!ch._hovered && ch.interval) { + ch.slideAway('Left'); + + GLib.source_remove(ch.interval); + ch.interval = undefined; + return; } }); } @@ -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({ name: 'notifications', anchor: ['top', 'left'], - child: PopupList(), + child: Box({ + style: `min-height:1px; + min-width:1px; + padding: 1px;`, + children: [Popups()], + }), });