mirror of
https://github.com/zoriya/ags.git
synced 2026-06-07 04:05:05 +00:00
notify::prop-name signals and bind transform method (#109)
This commit is contained in:
@@ -1,31 +1,33 @@
|
||||
const { Window, Box, Label, EventBox } = ags.Widget;
|
||||
import {
|
||||
NotificationList, DNDSwitch, ClearButton, PopupList,
|
||||
} from './widgets.js';
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||
import { execAsync, timeout } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
|
||||
const Header = () => Box({
|
||||
const Header = () => Widget.Box({
|
||||
className: 'header',
|
||||
children: [
|
||||
Label('Do Not Disturb'),
|
||||
Widget.Label('Do Not Disturb'),
|
||||
DNDSwitch(),
|
||||
Box({ hexpand: true }),
|
||||
Widget.Box({ hexpand: true }),
|
||||
ClearButton(),
|
||||
],
|
||||
});
|
||||
|
||||
const NotificationCenter = () => Window({
|
||||
const NotificationCenter = () => Widget.Window({
|
||||
name: 'notification-center',
|
||||
anchor: 'right top bottom',
|
||||
popup: true,
|
||||
focusable: true,
|
||||
child: Box({
|
||||
child: Widget.Box({
|
||||
children: [
|
||||
EventBox({
|
||||
Widget.EventBox({
|
||||
hexpand: true,
|
||||
connections: [['button-press-event', () =>
|
||||
ags.App.closeWindow('notification-center')]]
|
||||
App.closeWindow('notification-center')]]
|
||||
}),
|
||||
Box({
|
||||
Widget.Box({
|
||||
vertical: true,
|
||||
children: [
|
||||
Header(),
|
||||
@@ -36,13 +38,13 @@ const NotificationCenter = () => Window({
|
||||
}),
|
||||
});
|
||||
|
||||
const NotificationsPopupWindow = () => Window({
|
||||
const NotificationsPopupWindow = () => Widget.Window({
|
||||
name: 'popup-window',
|
||||
anchor: 'top',
|
||||
child: PopupList(),
|
||||
});
|
||||
|
||||
ags.Utils.timeout(1000, () => ags.Utils.execAsync([
|
||||
timeout(500, () => execAsync([
|
||||
'notify-send',
|
||||
'Notification Center example',
|
||||
'To have the panel popup run "ags toggle-window notification-center"' +
|
||||
@@ -50,7 +52,7 @@ ags.Utils.timeout(1000, () => ags.Utils.execAsync([
|
||||
]).catch(console.error));
|
||||
|
||||
export default {
|
||||
style: ags.App.configDir + '/style.css',
|
||||
style: App.configDir + '/style.css',
|
||||
windows: [
|
||||
NotificationsPopupWindow(),
|
||||
NotificationCenter(),
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
const { Notifications } = ags.Service;
|
||||
const { lookUpIcon, timeout } = ags.Utils;
|
||||
const { Box, Icon, Label, EventBox, Button } = ags.Widget;
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import { lookUpIcon, timeout } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
|
||||
const NotificationIcon = ({ appEntry, appIcon, image }) => {
|
||||
if (image) {
|
||||
return Box({
|
||||
return Widget.Box({
|
||||
valign: 'start',
|
||||
hexpand: false,
|
||||
className: 'icon img',
|
||||
@@ -26,7 +25,7 @@ const NotificationIcon = ({ appEntry, appIcon, image }) => {
|
||||
if (lookUpIcon(appEntry))
|
||||
icon = appEntry;
|
||||
|
||||
return Box({
|
||||
return Widget.Box({
|
||||
valign: 'start',
|
||||
hexpand: false,
|
||||
className: 'icon',
|
||||
@@ -34,7 +33,7 @@ const NotificationIcon = ({ appEntry, appIcon, image }) => {
|
||||
min-width: 78px;
|
||||
min-height: 78px;
|
||||
`,
|
||||
children: [Icon({
|
||||
children: [Widget.Icon({
|
||||
icon, size: 58,
|
||||
halign: 'center', hexpand: true,
|
||||
valign: 'center', vexpand: true,
|
||||
@@ -42,40 +41,40 @@ const NotificationIcon = ({ appEntry, appIcon, image }) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const Notification = ({ id, summary, body, actions, urgency, ...icon }) => EventBox({
|
||||
className: `notification ${urgency}`,
|
||||
onPrimaryClick: () => Notifications.dismiss(id),
|
||||
export const Notification = n => Widget.EventBox({
|
||||
className: `notification ${n.urgency}`,
|
||||
onPrimaryClick: () => n.dismiss(),
|
||||
properties: [['hovered', false]],
|
||||
onHover: w => {
|
||||
if (w._hovered)
|
||||
onHover: self => {
|
||||
if (self._hovered)
|
||||
return;
|
||||
|
||||
// if there are action buttons and they are hovered
|
||||
// EventBox onHoverLost will fire off immediately,
|
||||
// so to prevent this we delay it
|
||||
timeout(300, () => w._hovered = true);
|
||||
timeout(300, () => self._hovered = true);
|
||||
},
|
||||
onHoverLost: w => {
|
||||
if (!w._hovered)
|
||||
onHoverLost: self => {
|
||||
if (!self._hovered)
|
||||
return;
|
||||
|
||||
w._hovered = false;
|
||||
Notifications.dismiss(id);
|
||||
self._hovered = false;
|
||||
n.dismiss();
|
||||
},
|
||||
vexpand: false,
|
||||
child: Box({
|
||||
child: Widget.Box({
|
||||
vertical: true,
|
||||
children: [
|
||||
Box({
|
||||
Widget.Box({
|
||||
children: [
|
||||
NotificationIcon(icon),
|
||||
Box({
|
||||
NotificationIcon(n),
|
||||
Widget.Box({
|
||||
hexpand: true,
|
||||
vertical: true,
|
||||
children: [
|
||||
Box({
|
||||
Widget.Box({
|
||||
children: [
|
||||
Label({
|
||||
Widget.Label({
|
||||
className: 'title',
|
||||
xalign: 0,
|
||||
justification: 'left',
|
||||
@@ -83,37 +82,37 @@ export const Notification = ({ id, summary, body, actions, urgency, ...icon }) =
|
||||
maxWidthChars: 24,
|
||||
truncate: 'end',
|
||||
wrap: true,
|
||||
label: summary,
|
||||
useMarkup: summary.startsWith('<'),
|
||||
label: n.summary,
|
||||
useMarkup: true,
|
||||
}),
|
||||
Button({
|
||||
Widget.Button({
|
||||
className: 'close-button',
|
||||
valign: 'start',
|
||||
child: Icon('window-close-symbolic'),
|
||||
onClicked: () => Notifications.close(id),
|
||||
child: Widget.Icon('window-close-symbolic'),
|
||||
onClicked: n.close.bind(n),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Label({
|
||||
Widget.Label({
|
||||
className: 'description',
|
||||
hexpand: true,
|
||||
useMarkup: true,
|
||||
xalign: 0,
|
||||
justification: 'left',
|
||||
label: body,
|
||||
label: n.body,
|
||||
wrap: true,
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Box({
|
||||
Widget.Box({
|
||||
className: 'actions',
|
||||
children: actions.map(action => Button({
|
||||
children: n.actions.map(({ id, label }) => Button({
|
||||
className: 'action-button',
|
||||
onClicked: () => Notifications.invoke(id, action.id),
|
||||
onClicked: () => n.invoke(id),
|
||||
hexpand: true,
|
||||
child: Label(action.label),
|
||||
child: Widget.Label(label),
|
||||
})),
|
||||
}),
|
||||
],
|
||||
|
||||
@@ -1,40 +1,38 @@
|
||||
import { Notification } from './notification.js';
|
||||
const { Gtk } = imports.gi;
|
||||
const { Notifications } = ags.Service;
|
||||
const { Scrollable, Box, Icon, Label, Widget, Button, Stack } = ags.Widget;
|
||||
import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js';
|
||||
import Gtk from 'gi://Gtk';
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
|
||||
const List = () => Box({
|
||||
const List = () => Widget.Box({
|
||||
vertical: true,
|
||||
vexpand: true,
|
||||
connections: [[Notifications, box => {
|
||||
box.children = Notifications.notifications
|
||||
connections: [[Notifications, self => {
|
||||
self.children = Notifications.notifications
|
||||
.reverse()
|
||||
.map(n => Notification(n));
|
||||
.map(Notification);
|
||||
|
||||
box.visible = Notifications.notifications.length > 0;
|
||||
self.visible = Notifications.notifications.length > 0;
|
||||
}]],
|
||||
});
|
||||
|
||||
const Placeholder = () => Box({
|
||||
const Placeholder = () => Widget.Box({
|
||||
className: 'placeholder',
|
||||
vertical: true,
|
||||
vexpand: true,
|
||||
valign: 'center',
|
||||
children: [
|
||||
Icon('notifications-disabled-symbolic'),
|
||||
Label('Your inbox is empty'),
|
||||
Widget.Icon('notifications-disabled-symbolic'),
|
||||
Widget.Label('Your inbox is empty'),
|
||||
],
|
||||
connections: [
|
||||
[Notifications, box => {
|
||||
box.visible = Notifications.notifications.length === 0;
|
||||
}],
|
||||
binds: [
|
||||
['visible', Notifications, 'notifications', n => n.length === 0],
|
||||
],
|
||||
});
|
||||
|
||||
export const NotificationList = () => Scrollable({
|
||||
export const NotificationList = () => Widget.Scrollable({
|
||||
hscroll: 'never',
|
||||
vscroll: 'automatic',
|
||||
child: Box({
|
||||
child: Widget.Box({
|
||||
className: 'list',
|
||||
vertical: true,
|
||||
children: [
|
||||
@@ -44,22 +42,19 @@ export const NotificationList = () => Scrollable({
|
||||
}),
|
||||
});
|
||||
|
||||
export const ClearButton = () => Button({
|
||||
onClicked: Notifications.clear,
|
||||
connections: [[Notifications, button => {
|
||||
button.sensitive = Notifications.notifications.length > 0;
|
||||
}]],
|
||||
child: Box({
|
||||
export const ClearButton = () => Widget.Button({
|
||||
onClicked: () => Notifications.clear(),
|
||||
binds: [
|
||||
['sensitive', Notifications, 'notifications', n => n.length > 0],
|
||||
],
|
||||
child: Widget.Box({
|
||||
children: [
|
||||
Label('Clear'),
|
||||
Stack({
|
||||
items: [
|
||||
['true', Icon('user-trash-full-symbolic')],
|
||||
['false', Icon('user-trash-symbolic')],
|
||||
Widget.Label('Clear'),
|
||||
Widget.Icon({
|
||||
binds: [
|
||||
['icon', Notifications, 'notifications', n =>
|
||||
`user-trash-${n.length > 0 ? 'full-' : ''}symbolic`],
|
||||
],
|
||||
connections: [[Notifications, stack => {
|
||||
stack.shown = `${Notifications.notifications.length > 0}`;
|
||||
}]],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
@@ -68,19 +63,15 @@ export const ClearButton = () => Button({
|
||||
export const DNDSwitch = () => Widget({
|
||||
type: Gtk.Switch,
|
||||
valign: 'center',
|
||||
connections: [
|
||||
['notify::active', ({ active }) => {
|
||||
Notifications.dnd = active;
|
||||
}],
|
||||
],
|
||||
connections: [['notify::active', ({ active }) => {
|
||||
Notifications.dnd = active;
|
||||
}]],
|
||||
});
|
||||
|
||||
export const PopupList = () => Box({
|
||||
export const PopupList = () => Widget.Box({
|
||||
className: 'list',
|
||||
style: 'padding: 1px;', // so it shows up
|
||||
vertical: true,
|
||||
connections: [[Notifications, box => {
|
||||
box.children = Array.from(Notifications.popups.values())
|
||||
.map(n => Notification(n));
|
||||
}]],
|
||||
binds: [['children', Notifications, 'popups',
|
||||
popups => popups.map(Notification)]],
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user