202 lines
6.1 KiB
JavaScript
202 lines
6.1 KiB
JavaScript
const { Mpris, Hyprland, SystemTray, Audio } = ags.Service;
|
|
const { execAsync } = ags.Utils;
|
|
const { Box, Button, Label, Icon, CenterBox, Stack, Window } = ags.Widget;
|
|
|
|
const Workspaces = (monitor) => Box({
|
|
className: 'workspaces',
|
|
connections: [[Hyprland, box => {
|
|
if (monitor == 0) {
|
|
box.children = [1,2,3].map(i => Button({
|
|
onClicked: () => execAsync(`hyprctl dispatch workspace ${i}`),
|
|
onScrollUp: () => execAsync(`hyprctl dispatch workspace +1`),
|
|
onScrollDown: () => execAsync(`hyprctl dispatch workspace -1`),
|
|
child: Label({ label: `${i}` }),
|
|
className: Hyprland.active.workspace.id == i ? 'focused' : '',
|
|
}));
|
|
} else if (monitor == 1) {
|
|
box.children = [4,5,6].map(i => Button({
|
|
onClicked: () => execAsync(`hyprctl dispatch workspace ${i}`),
|
|
onScrollUp: () => execAsync(`hyprctl dispatch workspace +1`),
|
|
onScrollDown: () => execAsync(`hyprctl dispatch workspace -1`),
|
|
child: Label({ label: `${i}` }),
|
|
className: Hyprland.active.workspace.id == i ? 'focused' : '',
|
|
}));
|
|
}
|
|
}]],
|
|
});
|
|
|
|
|
|
const WindowTitle = () => Label({
|
|
connections: [[Hyprland, label => {
|
|
label.label = Hyprland.active.client.title || '';
|
|
label.toggleClassName('windowTitle', label.label);
|
|
}]],
|
|
});
|
|
|
|
const Volume = () => Button({
|
|
className: 'volume',
|
|
onScrollUp: () => execAsync('pamixer -i 10'),
|
|
onScrollDown: () => execAsync('pamixer -d 10'),
|
|
child: Box({
|
|
children: [
|
|
Stack({
|
|
items: [
|
|
// tuples of [string, Widget]
|
|
['101', Icon('audio-volume-overamplified-symbolic')],
|
|
['67', Icon('audio-volume-high-symbolic')],
|
|
['34', Icon('audio-volume-medium-symbolic')],
|
|
['1', Icon('audio-volume-low-symbolic')],
|
|
['0', Icon('audio-volume-muted-symbolic')],
|
|
],
|
|
connections: [[Audio, stack => {
|
|
if (!Audio.speaker)
|
|
return;
|
|
|
|
if (Audio.speaker.isMuted) {
|
|
stack.shown = '0';
|
|
return;
|
|
}
|
|
|
|
const show = [101, 67, 34, 1, 0].find(
|
|
threshold => threshold <= Audio.speaker.volume * 100);
|
|
|
|
stack.shown = `${show}`;
|
|
}, 'speaker-changed']],
|
|
}),
|
|
|
|
Label({
|
|
connections: [[Audio, label => {
|
|
if (!Audio.speaker)
|
|
return;
|
|
|
|
label.label = ` ${Math.ceil((Audio.speaker.volume * 100) / 10) * 10}%`; // round up to nearest 10
|
|
}, 'speaker-changed' ]],
|
|
}),
|
|
],
|
|
}),
|
|
});
|
|
|
|
const Media = () => Button({
|
|
className: 'media',
|
|
onPrimaryClick: () => Mpris.getPlayer('mpd')?.playPause(),
|
|
onScrollUp: () => Mpris.getPlayer('mpd')?.previous(),
|
|
onScrollDown: () => Mpris.getPlayer('mpd')?.next(),
|
|
|
|
child: Box({
|
|
children: [
|
|
Stack({
|
|
items: [
|
|
['paused', Icon('media-playback-pause-symbolic')],
|
|
['playing', Icon('media-playback-start-symbolic')],
|
|
['stopped', Icon('media-playback-stop-symbolic')],
|
|
],
|
|
|
|
connections: [[Mpris, stack => {
|
|
const mpris = Mpris.getPlayer('mpd');
|
|
|
|
switch (mpris.playBackStatus) {
|
|
case "Playing":
|
|
stack.shown = 'playing';
|
|
break;
|
|
case "Paused":
|
|
stack.shown = 'paused';
|
|
break;
|
|
default:
|
|
stack.shown = 'stopped';
|
|
}
|
|
}]],
|
|
}),
|
|
|
|
Label({
|
|
connections: [[Mpris, label => {
|
|
const mpris = Mpris.getPlayer('mpd');
|
|
if (!mpris || mpris.playBackStatus == "Stopped")
|
|
label.label = ' Stopped';
|
|
else
|
|
label.label = ` ${mpris.trackArtists.join(', ')} - ${mpris.trackTitle}`;
|
|
}]],
|
|
}),
|
|
],
|
|
}),
|
|
})
|
|
|
|
const SysTray = () => Box({
|
|
className: 'tray',
|
|
connections: [[SystemTray, box => {
|
|
box.children = SystemTray.items.map(item => Button({
|
|
className: 'tray-icon',
|
|
child: Icon(),
|
|
onPrimaryClick: (_, event) => item.activate(event),
|
|
onSecondaryClick: (_, event) => item.openMenu(event),
|
|
connections: [[item, button => {
|
|
button.child.icon = item.icon;
|
|
button.tooltipMarkup = item.tooltipMarkup;
|
|
}]],
|
|
}));
|
|
}]],
|
|
});
|
|
|
|
const Clock = () => Box({
|
|
className: 'date',
|
|
children: [
|
|
Icon({
|
|
icon: 'x-office-calendar-symbolic',
|
|
}),
|
|
|
|
Label({
|
|
connections: [
|
|
[1000, label => execAsync(['date', '+%a %d, %B %H:%M'])
|
|
.then(date => label.label = ' ' + date).catch(console.error)],
|
|
],
|
|
}),
|
|
],
|
|
});
|
|
|
|
const Left = (monitor) => Box({
|
|
children: [
|
|
Workspaces(monitor),
|
|
WindowTitle(),
|
|
],
|
|
});
|
|
|
|
const Center = () => Box({
|
|
children: [
|
|
Volume(),
|
|
Media(),
|
|
],
|
|
});
|
|
|
|
|
|
const Right = () => Box({
|
|
halign: 'end',
|
|
children: [
|
|
SysTray(),
|
|
Clock(),
|
|
],
|
|
});
|
|
|
|
const Bar = ({ monitor } = {}) => Window({
|
|
name: `bar-${monitor}`, // name has to be unique
|
|
className: 'bar',
|
|
monitor,
|
|
anchor: ['top', 'left', 'right'],
|
|
exclusive: true,
|
|
child: CenterBox({
|
|
startWidget: Left(`${monitor}`),
|
|
centerWidget: Center(),
|
|
endWidget: Right(),
|
|
}),
|
|
})
|
|
|
|
const scss = ags.App.configDir + '/style.scss';
|
|
const css = '/tmp/style-ags.css';
|
|
ags.Utils.exec(`sassc ${scss} ${css}`);
|
|
|
|
export default {
|
|
style: css,
|
|
windows: [
|
|
Bar({monitor: 0}),
|
|
Bar({monitor: 1}),
|
|
],
|
|
};
|