231 lines
10 KiB
JavaScript
231 lines
10 KiB
JavaScript
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 Mpris from 'resource:///com/github/Aylur/ags/service/mpris.js';
|
|
const { Box, Button, EventBox, Label, Overlay, Revealer, Scrollable } = Widget;
|
|
const { execAsync, exec } = Utils;
|
|
import { AnimatedCircProg } from "../../.commonwidgets/cairo_circularprogress.js";
|
|
import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
|
|
import { showMusicControls } from '../../../variables.js';
|
|
|
|
const CUSTOM_MODULE_CONTENT_INTERVAL_FILE = `${GLib.get_user_cache_dir()}/ags/user/scripts/custom-module-interval.txt`;
|
|
const CUSTOM_MODULE_CONTENT_SCRIPT = `${GLib.get_user_cache_dir()}/ags/user/scripts/custom-module-poll.sh`;
|
|
const CUSTOM_MODULE_LEFTCLICK_SCRIPT = `${GLib.get_user_cache_dir()}/ags/user/scripts/custom-module-leftclick.sh`;
|
|
const CUSTOM_MODULE_RIGHTCLICK_SCRIPT = `${GLib.get_user_cache_dir()}/ags/user/scripts/custom-module-rightclick.sh`;
|
|
const CUSTOM_MODULE_MIDDLECLICK_SCRIPT = `${GLib.get_user_cache_dir()}/ags/user/scripts/custom-module-middleclick.sh`;
|
|
const CUSTOM_MODULE_SCROLLUP_SCRIPT = `${GLib.get_user_cache_dir()}/ags/user/scripts/custom-module-scrollup.sh`;
|
|
const CUSTOM_MODULE_SCROLLDOWN_SCRIPT = `${GLib.get_user_cache_dir()}/ags/user/scripts/custom-module-scrolldown.sh`;
|
|
|
|
function trimTrackTitle(title) {
|
|
if (!title) return '';
|
|
const cleanPatterns = [
|
|
/【[^】]*】/, // Touhou n weeb stuff
|
|
" [FREE DOWNLOAD]", // F-777
|
|
];
|
|
cleanPatterns.forEach((expr) => title = title.replace(expr, ''));
|
|
return title;
|
|
}
|
|
|
|
const BarGroup = ({ child }) => Box({
|
|
className: 'bar-group-margin bar-sides',
|
|
children: [
|
|
Box({
|
|
className: 'bar-group bar-group-standalone bar-group-pad-system',
|
|
children: [child],
|
|
}),
|
|
]
|
|
});
|
|
|
|
const BarResource = (name, icon, command, circprogClassName = 'bar-batt-circprog', textClassName = 'txt-onSurfaceVariant', iconClassName = 'bar-batt') => {
|
|
const resourceCircProg = AnimatedCircProg({
|
|
className: `${circprogClassName}`,
|
|
vpack: 'center',
|
|
hpack: 'center',
|
|
});
|
|
const resourceProgress = Box({
|
|
homogeneous: true,
|
|
children: [Overlay({
|
|
child: Box({
|
|
vpack: 'center',
|
|
className: `${iconClassName}`,
|
|
homogeneous: true,
|
|
children: [
|
|
MaterialIcon(icon, 'small'),
|
|
],
|
|
}),
|
|
overlays: [resourceCircProg]
|
|
})]
|
|
});
|
|
const resourceLabel = Label({
|
|
className: `txt-smallie ${textClassName}`,
|
|
});
|
|
const widget = Button({
|
|
onClicked: () => Utils.execAsync(['bash', '-c', `${userOptions.apps.taskManager}`]).catch(print),
|
|
child: Box({
|
|
className: `spacing-h-4 ${textClassName}`,
|
|
children: [
|
|
resourceProgress,
|
|
resourceLabel,
|
|
],
|
|
setup: (self) => self.poll(5000, () => execAsync(['bash', '-c', command])
|
|
.then((output) => {
|
|
resourceCircProg.css = `font-size: ${Number(output)}px;`;
|
|
resourceLabel.label = `${Math.round(Number(output))}%`;
|
|
widget.tooltipText = `${name}: ${Math.round(Number(output))}%`;
|
|
}).catch(print))
|
|
,
|
|
})
|
|
});
|
|
return widget;
|
|
}
|
|
|
|
const TrackProgress = () => {
|
|
const _updateProgress = (circprog) => {
|
|
const mpris = Mpris.getPlayer('');
|
|
if (!mpris) return;
|
|
// Set circular progress value
|
|
circprog.css = `font-size: ${Math.max(mpris.position / mpris.length * 100, 0)}px;`
|
|
}
|
|
return AnimatedCircProg({
|
|
className: 'bar-music-circprog',
|
|
vpack: 'center', hpack: 'center',
|
|
extraSetup: (self) => self
|
|
.hook(Mpris, _updateProgress)
|
|
.poll(3000, _updateProgress)
|
|
,
|
|
})
|
|
}
|
|
|
|
const switchToRelativeWorkspace = async (self, num) => {
|
|
try {
|
|
const Hyprland = (await import('resource:///com/github/Aylur/ags/service/hyprland.js')).default;
|
|
Hyprland.messageAsync(`dispatch workspace ${num > 0 ? '+' : ''}${num}`).catch(print);
|
|
} catch {
|
|
execAsync([`${App.configDir}/scripts/sway/swayToRelativeWs.sh`, `${num}`]).catch(print);
|
|
}
|
|
}
|
|
|
|
export default () => {
|
|
// TODO: use cairo to make button bounce smaller on click, if that's possible
|
|
const playingState = Box({ // Wrap a box cuz overlay can't have margins itself
|
|
homogeneous: true,
|
|
children: [Overlay({
|
|
child: Box({
|
|
vpack: 'center',
|
|
className: 'bar-music-playstate',
|
|
homogeneous: true,
|
|
children: [Label({
|
|
vpack: 'center',
|
|
className: 'bar-music-playstate-txt',
|
|
justification: 'center',
|
|
setup: (self) => self.hook(Mpris, label => {
|
|
const mpris = Mpris.getPlayer('');
|
|
label.label = `${mpris !== null && mpris.playBackStatus == 'Playing' ? 'pause' : 'play_arrow'}`;
|
|
}),
|
|
})],
|
|
setup: (self) => self.hook(Mpris, label => {
|
|
const mpris = Mpris.getPlayer('');
|
|
if (!mpris) return;
|
|
label.toggleClassName('bar-music-playstate-playing', mpris !== null && mpris.playBackStatus == 'Playing');
|
|
label.toggleClassName('bar-music-playstate', mpris !== null || mpris.playBackStatus == 'Paused');
|
|
}),
|
|
}),
|
|
overlays: [
|
|
TrackProgress(),
|
|
]
|
|
})]
|
|
});
|
|
const trackTitle = Label({
|
|
hexpand: true,
|
|
className: 'txt-smallie bar-music-txt',
|
|
truncate: 'end',
|
|
maxWidthChars: 1, // Doesn't matter, just needs to be non negative
|
|
setup: (self) => self.hook(Mpris, label => {
|
|
const mpris = Mpris.getPlayer('');
|
|
if (mpris)
|
|
label.label = `${trimTrackTitle(mpris.trackTitle)} • ${mpris.trackArtists.join(', ')}`;
|
|
else
|
|
label.label = 'No media';
|
|
}),
|
|
})
|
|
const musicStuff = Box({
|
|
className: 'spacing-h-10',
|
|
hexpand: true,
|
|
children: [
|
|
playingState,
|
|
trackTitle,
|
|
]
|
|
})
|
|
const SystemResourcesOrCustomModule = () => {
|
|
// Check if $XDG_CACHE_HOME/ags/user/scripts/custom-module-poll.sh exists
|
|
if (GLib.file_test(CUSTOM_MODULE_CONTENT_SCRIPT, GLib.FileTest.EXISTS)) {
|
|
const interval = Number(Utils.readFile(CUSTOM_MODULE_CONTENT_INTERVAL_FILE)) || 5000;
|
|
return BarGroup({
|
|
child: Button({
|
|
child: Label({
|
|
className: 'txt-smallie txt-onSurfaceVariant',
|
|
useMarkup: true,
|
|
setup: (self) => Utils.timeout(1, () => {
|
|
self.label = exec(CUSTOM_MODULE_CONTENT_SCRIPT);
|
|
self.poll(interval, (self) => {
|
|
const content = exec(CUSTOM_MODULE_CONTENT_SCRIPT);
|
|
self.label = content;
|
|
})
|
|
})
|
|
}),
|
|
onPrimaryClickRelease: () => execAsync(CUSTOM_MODULE_LEFTCLICK_SCRIPT).catch(print),
|
|
onSecondaryClickRelease: () => execAsync(CUSTOM_MODULE_RIGHTCLICK_SCRIPT).catch(print),
|
|
onMiddleClickRelease: () => execAsync(CUSTOM_MODULE_MIDDLECLICK_SCRIPT).catch(print),
|
|
onScrollUp: () => execAsync(CUSTOM_MODULE_SCROLLUP_SCRIPT).catch(print),
|
|
onScrollDown: () => execAsync(CUSTOM_MODULE_SCROLLDOWN_SCRIPT).catch(print),
|
|
})
|
|
});
|
|
} else return BarGroup({
|
|
child: Box({
|
|
children: [
|
|
BarResource('RAM Usage', 'memory', `LANG=C free | awk '/^Mem/ {printf("%.2f\\n", ($3/$2) * 100)}'`,
|
|
'bar-ram-circprog', 'bar-ram-txt', 'bar-ram-icon'),
|
|
Revealer({
|
|
revealChild: true,
|
|
transition: 'slide_left',
|
|
transitionDuration: userOptions.animations.durationLarge,
|
|
child: Box({
|
|
className: 'spacing-h-10 margin-left-10',
|
|
children: [
|
|
BarResource('Swap Usage', 'swap_horiz', `LANG=C free | awk '/^Swap/ {if ($2 > 0) printf("%.2f\\n", ($3/$2) * 100); else print "0";}'`,
|
|
'bar-swap-circprog', 'bar-swap-txt', 'bar-swap-icon'),
|
|
BarResource('CPU Usage', 'settings_motion_mode', `LANG=C top -bn1 | grep Cpu | sed 's/\\,/\\./g' | awk '{print $2}'`,
|
|
'bar-cpu-circprog', 'bar-cpu-txt', 'bar-cpu-icon'),
|
|
]
|
|
}),
|
|
setup: (self) => self.hook(Mpris, label => {
|
|
const mpris = Mpris.getPlayer('');
|
|
self.revealChild = (!mpris);
|
|
}),
|
|
})
|
|
],
|
|
})
|
|
});
|
|
}
|
|
return EventBox({
|
|
onScrollUp: (self) => switchToRelativeWorkspace(self, -1),
|
|
onScrollDown: (self) => switchToRelativeWorkspace(self, +1),
|
|
child: Box({
|
|
className: 'spacing-h-4',
|
|
children: [
|
|
SystemResourcesOrCustomModule(),
|
|
EventBox({
|
|
child: BarGroup({ child: musicStuff }),
|
|
onPrimaryClick: () => showMusicControls.setValue(!showMusicControls.value),
|
|
onSecondaryClick: () => execAsync(['bash', '-c', 'playerctl next || playerctl position `bc <<< "100 * $(playerctl metadata mpris:length) / 1000000 / 100"` &']).catch(print),
|
|
onMiddleClick: () => execAsync('playerctl play-pause').catch(print),
|
|
setup: (self) => self.on('button-press-event', (self, event) => {
|
|
if (event.get_button()[1] === 8) // Side button
|
|
execAsync('playerctl previous').catch(print)
|
|
}),
|
|
})
|
|
]
|
|
})
|
|
});
|
|
}
|