forked from Shinonome/dots-hyprland
ags: sync
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
const { Gio, Gdk, GLib, Gtk } = imports.gi;
|
||||
import { App, Widget, Utils } from '../../imports.js';
|
||||
const { Box, Button, CenterBox, Label, Revealer } = Widget;
|
||||
const { Gio } = imports.gi;
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
const { Box, Button, Label } = Widget;
|
||||
import { MaterialIcon } from "../../lib/materialicon.js";
|
||||
import { getCalendarLayout } from "../../lib/calendarlayout.js";
|
||||
import { setupCursorHover } from "../../lib/cursorhover.js";
|
||||
|
||||
@@ -1,113 +1,137 @@
|
||||
// This file is for the notification widget on the sidebar
|
||||
// This file is for the notification list on the sidebar
|
||||
// For the popup notifications, see onscreendisplay.js
|
||||
// The actual widget for each single notification is in lib/notification.js
|
||||
|
||||
const { GLib, Gtk } = imports.gi;
|
||||
import { Service, Utils, Widget } from '../../imports.js';
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js';
|
||||
const { lookUpIcon, timeout } = Utils;
|
||||
const { Box, Icon, Scrollable, Label, Button, Revealer } = Widget;
|
||||
const { Box, Button, Label, Scrollable, Stack } = Widget;
|
||||
import { MaterialIcon } from "../../lib/materialicon.js";
|
||||
import { setupCursorHover } from "../../lib/cursorhover.js";
|
||||
import Notification from "../../lib/notification.js";
|
||||
|
||||
const NotificationList = Box({
|
||||
vertical: true,
|
||||
vpack: 'start',
|
||||
className: 'spacing-v-5-revealer',
|
||||
connections: [
|
||||
[Notifications, (box, id) => {
|
||||
if (box.children.length == 0) {
|
||||
Notifications.notifications
|
||||
.forEach(n => {
|
||||
box.pack_end(Notification({
|
||||
notifObject: n,
|
||||
isPopup: false,
|
||||
}), false, false, 0)
|
||||
});
|
||||
box.show_all();
|
||||
}
|
||||
else if (id) {
|
||||
export default (props) => {
|
||||
const notifEmptyContent = Box({
|
||||
homogeneous: true,
|
||||
children: [Box({
|
||||
vertical: true,
|
||||
vpack: 'center',
|
||||
className: 'txt spacing-v-10',
|
||||
children: [
|
||||
Box({
|
||||
vertical: true,
|
||||
className: 'spacing-v-5',
|
||||
children: [
|
||||
MaterialIcon('notifications_active', 'badonkers'),
|
||||
Label({ label: 'No notifications', className: 'txt-small' }),
|
||||
]
|
||||
}),
|
||||
]
|
||||
})]
|
||||
});
|
||||
const notificationList = Box({
|
||||
vertical: true,
|
||||
vpack: 'start',
|
||||
className: 'spacing-v-5-revealer',
|
||||
setup: (self) => self
|
||||
.hook(Notifications, (box, id) => {
|
||||
if (box.get_children().length == 0) { // On init there's no notif, or 1st notif
|
||||
Notifications.notifications
|
||||
.forEach(n => {
|
||||
box.pack_end(Notification({
|
||||
notifObject: n,
|
||||
isPopup: false,
|
||||
}), false, false, 0)
|
||||
});
|
||||
box.show_all();
|
||||
return;
|
||||
}
|
||||
// 2nd or later notif
|
||||
const notif = Notifications.getNotification(id);
|
||||
|
||||
const NewNotif = Notification({
|
||||
notifObject: notif,
|
||||
isPopup: false,
|
||||
});
|
||||
|
||||
if (NewNotif) {
|
||||
box.pack_end(NewNotif, false, false, 0);
|
||||
box.show_all();
|
||||
}
|
||||
}
|
||||
}, 'notified'],
|
||||
|
||||
[Notifications, (box, id) => {
|
||||
if (!id) return;
|
||||
for (const ch of box.children) {
|
||||
if (ch._id === id) {
|
||||
ch._destroyWithAnims();
|
||||
}, 'notified')
|
||||
.hook(Notifications, (box, id) => {
|
||||
if (!id) return;
|
||||
for (const ch of box.children) {
|
||||
if (ch._id === id) {
|
||||
ch.attribute.destroyWithAnims();
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 'closed'],
|
||||
|
||||
[Notifications, box => box.visible = Notifications.notifications.length > 0],
|
||||
],
|
||||
});
|
||||
|
||||
export default (props) => {
|
||||
const listTitle = Revealer({
|
||||
revealChild: false,
|
||||
connections: [[Notifications, (revealer) => {
|
||||
revealer.revealChild = (Notifications.notifications.length > 0);
|
||||
}]],
|
||||
}, 'closed')
|
||||
,
|
||||
});
|
||||
const ListActionButton = (icon, name, action) => Button({
|
||||
className: 'notif-listaction-btn',
|
||||
onClicked: action,
|
||||
child: Box({
|
||||
vpack: 'start',
|
||||
className: 'sidebar-group-invisible txt',
|
||||
className: 'spacing-h-5',
|
||||
children: [
|
||||
MaterialIcon(icon, 'norm'),
|
||||
Label({
|
||||
hexpand: true,
|
||||
xalign: 0,
|
||||
className: 'txt-title-small',
|
||||
label: 'Notifications',
|
||||
}),
|
||||
Button({
|
||||
className: 'notif-closeall-btn',
|
||||
onClicked: () => {
|
||||
Notifications.clear();
|
||||
},
|
||||
child: Box({
|
||||
className: 'spacing-h-5',
|
||||
children: [
|
||||
MaterialIcon('clear_all', 'norm'),
|
||||
Label({
|
||||
className: 'txt-small',
|
||||
label: 'Clear',
|
||||
})
|
||||
]
|
||||
}),
|
||||
setup: button => {
|
||||
setupCursorHover(button);
|
||||
},
|
||||
className: 'txt-small',
|
||||
label: name,
|
||||
})
|
||||
]
|
||||
})
|
||||
}),
|
||||
setup: setupCursorHover,
|
||||
});
|
||||
const listContents = Scrollable({
|
||||
const silenceButton = ListActionButton('notifications_paused', 'Silence', (self) => {
|
||||
Notifications.dnd = !Notifications.dnd;
|
||||
self.toggleClassName('notif-listaction-btn-enabled', Notifications.dnd);
|
||||
});
|
||||
const clearButton = ListActionButton('clear_all', 'Clear', () => {
|
||||
notificationList.get_children().forEach(ch => ch.destroy());
|
||||
Notifications.clear();
|
||||
});
|
||||
const listTitle = Box({
|
||||
vpack: 'start',
|
||||
className: 'sidebar-group-invisible txt spacing-h-5',
|
||||
children: [
|
||||
Label({
|
||||
hexpand: true,
|
||||
xalign: 0,
|
||||
className: 'txt-title-small margin-left-10',
|
||||
// ^ (extra margin on the left so that it looks similarly spaced
|
||||
// when compared to borderless "Clear" button on the right)
|
||||
label: 'Notifications',
|
||||
}),
|
||||
silenceButton,
|
||||
clearButton,
|
||||
]
|
||||
});
|
||||
const notifList = Scrollable({
|
||||
hexpand: true,
|
||||
hscroll: 'never',
|
||||
vscroll: 'automatic',
|
||||
child: Box({
|
||||
vexpand: true,
|
||||
children: [NotificationList],
|
||||
})
|
||||
// homogeneous: true,
|
||||
children: [notificationList],
|
||||
}),
|
||||
setup: (self) => {
|
||||
const vScrollbar = self.get_vscrollbar();
|
||||
vScrollbar.get_style_context().add_class('sidebar-scrollbar');
|
||||
}
|
||||
});
|
||||
const listContents = Stack({
|
||||
transition: 'crossfade',
|
||||
transitionDuration: 150,
|
||||
items: [
|
||||
['empty', notifEmptyContent],
|
||||
['list', notifList]
|
||||
],
|
||||
setup: (self) => self
|
||||
.hook(Notifications, (self) => self.shown = (Notifications.notifications.length > 0 ? 'list' : 'empty'))
|
||||
,
|
||||
});
|
||||
listContents.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
|
||||
const vScrollbar = listContents.get_vscrollbar();
|
||||
vScrollbar.get_style_context().add_class('sidebar-scrollbar');
|
||||
return Box({
|
||||
...props,
|
||||
className: 'sidebar-group-invisible spacing-v-5',
|
||||
className: 'sidebar-group spacing-v-5',
|
||||
vertical: true,
|
||||
children: [
|
||||
listTitle,
|
||||
|
||||
@@ -1,28 +1,40 @@
|
||||
import { Widget, Utils, Service } from '../../imports.js';
|
||||
const { GLib } = imports.gi;
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
|
||||
import Bluetooth from 'resource:///com/github/Aylur/ags/service/bluetooth.js';
|
||||
import Network from 'resource:///com/github/Aylur/ags/service/network.js';
|
||||
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
||||
const { execAsync, exec } = Utils;
|
||||
import { BluetoothIndicator, NetworkIndicator } from "../../lib/statusicons.js";
|
||||
import { setupCursorHover } from "../../lib/cursorhover.js";
|
||||
import { MaterialIcon } from '../../lib/materialicon.js';
|
||||
|
||||
function expandTilde(path) {
|
||||
if (path.startsWith('~')) {
|
||||
console.log(GLib.get_home_dir() + path.slice(1));
|
||||
return GLib.get_home_dir() + path.slice(1);
|
||||
} else {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
export const ToggleIconWifi = (props = {}) => Widget.Button({
|
||||
className: 'txt-small sidebar-iconbutton',
|
||||
tooltipText: 'Wifi | Right-click to configure',
|
||||
onClicked: Network.toggleWifi,
|
||||
onClicked: () => Network.toggleWifi(),
|
||||
onSecondaryClickRelease: () => {
|
||||
execAsync(['bash', '-c', 'XDG_CURRENT_DESKTOP="gnome" gnome-control-center wifi', '&']);
|
||||
App.closeWindow('sideright');
|
||||
},
|
||||
child: NetworkIndicator(),
|
||||
connections: [
|
||||
[Network, button => {
|
||||
button.toggleClassName('sidebar-button-active', Network.wifi?.internet == 'connected' || Network.wired?.internet == 'connected')
|
||||
}],
|
||||
[Network, button => {
|
||||
setup: (self) => {
|
||||
setupCursorHover(self);
|
||||
self.hook(Network, button => {
|
||||
button.toggleClassName('sidebar-button-active', [Network.wifi?.internet, Network.wired?.internet].includes('connected'))
|
||||
button.tooltipText = (`${Network.wifi?.ssid} | Right-click to configure` || 'Unknown');
|
||||
}],
|
||||
],
|
||||
setup: setupCursorHover,
|
||||
});
|
||||
},
|
||||
...props,
|
||||
});
|
||||
|
||||
@@ -31,21 +43,22 @@ export const ToggleIconBluetooth = (props = {}) => Widget.Button({
|
||||
tooltipText: 'Bluetooth | Right-click to configure',
|
||||
onClicked: () => {
|
||||
const status = Bluetooth?.enabled;
|
||||
if (status)
|
||||
if (status)
|
||||
exec('rfkill block bluetooth');
|
||||
else
|
||||
else
|
||||
exec('rfkill unblock bluetooth');
|
||||
},
|
||||
onSecondaryClickRelease: () => {
|
||||
execAsync(['bash', '-c', 'blueberry &']);
|
||||
App.closeWindow('sideright');
|
||||
},
|
||||
child: BluetoothIndicator(),
|
||||
connections: [
|
||||
[Bluetooth, button => {
|
||||
setup: (self) => {
|
||||
setupCursorHover(self);
|
||||
self.hook(Bluetooth, button => {
|
||||
button.toggleClassName('sidebar-button-active', Bluetooth?.enabled)
|
||||
}],
|
||||
],
|
||||
setup: setupCursorHover,
|
||||
});
|
||||
},
|
||||
...props,
|
||||
});
|
||||
|
||||
@@ -69,24 +82,24 @@ export const HyprToggleIcon = (icon, name, hyprlandConfigValue, props = {}) => W
|
||||
})
|
||||
|
||||
export const ModuleNightLight = (props = {}) => Widget.Button({ // TODO: Make this work
|
||||
properties: [
|
||||
['enabled', false],
|
||||
['yellowlight', undefined],
|
||||
],
|
||||
attribute: {
|
||||
enabled: false,
|
||||
yellowlight: undefined,
|
||||
},
|
||||
className: 'txt-small sidebar-iconbutton',
|
||||
tooltipText: 'Night Light',
|
||||
onClicked: (self) => {
|
||||
self._enabled = !self._enabled;
|
||||
self.toggleClassName('sidebar-button-active', self._enabled);
|
||||
// if (self._enabled) Utils.execAsync(['bash', '-c', 'wlsunset & disown'])
|
||||
if (self._enabled) Utils.execAsync('wlsunset')
|
||||
self.attribute.enabled = !self.attribute.enabled;
|
||||
self.toggleClassName('sidebar-button-active', self.attribute.enabled);
|
||||
// if (self.attribute.enabled) Utils.execAsync(['bash', '-c', 'wlsunset & disown'])
|
||||
if (self.attribute.enabled) Utils.execAsync('wlsunset')
|
||||
else Utils.execAsync('pkill wlsunset');
|
||||
},
|
||||
child: MaterialIcon('nightlight', 'norm'),
|
||||
setup: (self) => {
|
||||
setupCursorHover(self);
|
||||
self._enabled = !!exec('pidof wlsunset');
|
||||
self.toggleClassName('sidebar-button-active', self._enabled);
|
||||
self.attribute.enabled = !!exec('pidof wlsunset');
|
||||
self.toggleClassName('sidebar-button-active', self.attribute.enabled);
|
||||
},
|
||||
...props,
|
||||
});
|
||||
@@ -95,15 +108,22 @@ export const ModuleInvertColors = (props = {}) => Widget.Button({
|
||||
className: 'txt-small sidebar-iconbutton',
|
||||
tooltipText: 'Color inversion',
|
||||
onClicked: (button) => {
|
||||
const shaderPath = JSON.parse(exec('hyprctl -j getoption decoration:screen_shader')).str;
|
||||
if (shaderPath != "[[EMPTY]]" && shaderPath != "") {
|
||||
execAsync(['bash', '-c', `hyprctl keyword decoration:screen_shader ''`]).catch(print);
|
||||
button.toggleClassName('sidebar-button-active', false);
|
||||
}
|
||||
else {
|
||||
execAsync(['bash', '-c', `hyprctl keyword decoration:screen_shader ~/.config/hypr/shaders/invert.frag`]).catch(print);
|
||||
button.toggleClassName('sidebar-button-active', true);
|
||||
}
|
||||
// const shaderPath = JSON.parse(exec('hyprctl -j getoption decoration:screen_shader')).str;
|
||||
Hyprland.sendMessage('j/getoption decoration:screen_shader')
|
||||
.then((output) => {
|
||||
const shaderPath = JSON.parse(output)["str"].trim();
|
||||
console.log(output)
|
||||
console.log(shaderPath)
|
||||
if (shaderPath != "[[EMPTY]]" && shaderPath != "") {
|
||||
execAsync(['bash', '-c', `hyprctl keyword decoration:screen_shader '[[EMPTY]]'`]).catch(print);
|
||||
button.toggleClassName('sidebar-button-active', false);
|
||||
}
|
||||
else {
|
||||
Hyprland.sendMessage(`j/keyword decoration:screen_shader ${expandTilde('~/.config/hypr/shaders/invert.frag')}`)
|
||||
.catch(print);
|
||||
button.toggleClassName('sidebar-button-active', true);
|
||||
}
|
||||
})
|
||||
},
|
||||
child: MaterialIcon('invert_colors', 'norm'),
|
||||
setup: setupCursorHover,
|
||||
@@ -111,17 +131,17 @@ export const ModuleInvertColors = (props = {}) => Widget.Button({
|
||||
})
|
||||
|
||||
export const ModuleIdleInhibitor = (props = {}) => Widget.Button({ // TODO: Make this work
|
||||
properties: [
|
||||
['enabled', false],
|
||||
['inhibitor', undefined],
|
||||
],
|
||||
attribute: {
|
||||
enabled: false,
|
||||
inhibitor: undefined,
|
||||
},
|
||||
className: 'txt-small sidebar-iconbutton',
|
||||
tooltipText: 'Keep system awake',
|
||||
onClicked: (self) => {
|
||||
self._enabled = !self._enabled;
|
||||
self.toggleClassName('sidebar-button-active', self._enabled);
|
||||
if (self._enabled) {
|
||||
self._inhibitor = Utils.subprocess(
|
||||
self.attribute.enabled = !self.attribute.enabled;
|
||||
self.toggleClassName('sidebar-button-active', self.attribute.enabled);
|
||||
if (self.attribute.enabled) {
|
||||
self.attribute.inhibitor = Utils.subprocess(
|
||||
['wayland-idle-inhibitor.py'],
|
||||
(output) => print(output),
|
||||
(err) => logError(err),
|
||||
@@ -129,7 +149,7 @@ export const ModuleIdleInhibitor = (props = {}) => Widget.Button({ // TODO: Make
|
||||
);
|
||||
}
|
||||
else {
|
||||
self._inhibitor.force_exit();
|
||||
self.attribute.inhibitor.force_exit();
|
||||
}
|
||||
},
|
||||
child: MaterialIcon('coffee', 'norm'),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const { GLib, Gdk, Gtk } = imports.gi;
|
||||
import { Utils, Widget } from '../../imports.js';
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
const { execAsync, exec } = Utils;
|
||||
const { Box, EventBox } = Widget;
|
||||
import {
|
||||
@@ -17,44 +17,19 @@ import {
|
||||
import ModuleNotificationList from "./notificationlist.js";
|
||||
import { ModuleCalendar } from "./calendar.js";
|
||||
|
||||
// const NUM_OF_TOGGLES_PER_LINE = 5;
|
||||
// const togglesFlowBox = Widget.FlowBox({
|
||||
// className: 'sidebar-group spacing-h-10',
|
||||
// setup: (self) => {
|
||||
// self.set_max_children_per_line(NUM_OF_TOGGLES_PER_LINE);
|
||||
// self.add(ToggleIconWifi({ hexpand: true }));
|
||||
// self.add(ToggleIconBluetooth({ hexpand: true }));
|
||||
// self.add(HyprToggleIcon('mouse', 'Raw input', 'input:force_no_accel', { hexpand: true }));
|
||||
// self.add(HyprToggleIcon('front_hand', 'No touchpad while typing', 'input:touchpad:disable_while_typing', { hexpand: true }));
|
||||
// self.add(ModuleNightLight({ hexpand: true }));
|
||||
// // Setup flowbox rearrange
|
||||
// self.connect('child-activated', (self, child) => {
|
||||
// if (child.get_index() === 0) {
|
||||
// self.reorder_child(child, self.get_children().length - 1);
|
||||
// } else {
|
||||
// self.reorder_child(child, 0);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// })
|
||||
|
||||
const timeRow = Box({
|
||||
className: 'spacing-h-5 sidebar-group-invisible-morehorizpad',
|
||||
children: [
|
||||
// Widget.Label({
|
||||
// className: 'txt-title txt',
|
||||
// connections: [[5000, label => {
|
||||
// label.label = GLib.DateTime.new_now_local().format("%H:%M");
|
||||
// }]],
|
||||
// }),
|
||||
Widget.Label({
|
||||
hpack: 'center',
|
||||
className: 'txt-small txt',
|
||||
connections: [[5000, label => {
|
||||
execAsync(['bash', '-c', `uptime -p | sed -e 's/up //;s/ hours,/h/;s/ minutes/m/'`]).then(upTimeString => {
|
||||
label.label = `System uptime: ${upTimeString}`;
|
||||
}).catch(print);
|
||||
}]],
|
||||
setup: (self) => self
|
||||
.poll(5000, label => {
|
||||
execAsync(['bash', '-c', `uptime -p | sed -e 's/up //;s/ hours,/h/;s/ minutes/m/'`]).then(upTimeString => {
|
||||
label.label = `Uptime: ${upTimeString}`;
|
||||
}).catch(print);
|
||||
})
|
||||
,
|
||||
}),
|
||||
Widget.Box({ hexpand: true }),
|
||||
// ModuleEditIcon({ hpack: 'end' }), // TODO: Make this work
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const { Gio, Gdk, GLib, Gtk } = imports.gi;
|
||||
import { App, Widget, Utils } from '../../imports.js';
|
||||
const { Box, Button, CenterBox, Label, Revealer } = Widget;
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
const { Box, Button, Label, Revealer } = Widget;
|
||||
import { MaterialIcon } from "../../lib/materialicon.js";
|
||||
import Todo from "../../services/todo.js";
|
||||
import { setupCursorHover } from "../../lib/cursorhover.js";
|
||||
@@ -73,33 +73,36 @@ const todoListItem = (task, id, isDone, isEven = false) => {
|
||||
}
|
||||
|
||||
const todoItems = (isDone) => Widget.Scrollable({
|
||||
hscroll: 'never',
|
||||
vscroll: 'automatic',
|
||||
child: Widget.Box({
|
||||
vertical: true,
|
||||
connections: [[Todo, (self) => {
|
||||
self.children = Todo.todo_json.map((task, i) => {
|
||||
if (task.done != isDone) return null;
|
||||
return todoListItem(task, i, isDone);
|
||||
})
|
||||
if (self.children.length == 0) {
|
||||
self.homogeneous = true;
|
||||
self.children = [
|
||||
Widget.Box({
|
||||
hexpand: true,
|
||||
vertical: true,
|
||||
vpack: 'center',
|
||||
className: 'txt',
|
||||
children: [
|
||||
MaterialIcon(`${isDone ? 'checklist' : 'check_circle'}`, 'badonkers'),
|
||||
Label({ label: `${isDone ? 'Finished tasks will go here' : 'Nothing here!'}` })
|
||||
]
|
||||
})
|
||||
]
|
||||
}
|
||||
else self.homogeneous = false;
|
||||
}, 'updated']]
|
||||
setup: (self) => self
|
||||
.hook(Todo, (self) => {
|
||||
self.children = Todo.todo_json.map((task, i) => {
|
||||
if (task.done != isDone) return null;
|
||||
return todoListItem(task, i, isDone);
|
||||
})
|
||||
if (self.children.length == 0) {
|
||||
self.homogeneous = true;
|
||||
self.children = [
|
||||
Widget.Box({
|
||||
hexpand: true,
|
||||
vertical: true,
|
||||
vpack: 'center',
|
||||
className: 'txt',
|
||||
children: [
|
||||
MaterialIcon(`${isDone ? 'checklist' : 'check_circle'}`, 'badonkers'),
|
||||
Label({ label: `${isDone ? 'Finished tasks will go here' : 'Nothing here!'}` })
|
||||
]
|
||||
})
|
||||
]
|
||||
}
|
||||
else self.homogeneous = false;
|
||||
}, 'updated')
|
||||
,
|
||||
}),
|
||||
setup: (listContents) => {
|
||||
listContents.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
|
||||
const vScrollbar = listContents.get_vscrollbar();
|
||||
vScrollbar.get_style_context().add_class('sidebar-scrollbar');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user