feat: check for matcha availability

We want to check if matcha will be available both as a binary and as a
daemon, as it needs to be running in the background. If those are not
met, the idle inhibitor cannot be shown.
This commit is contained in:
Anthony Rodriguez 2025-02-16 13:05:34 +01:00
parent 5a918d507a
commit eb7c276914
Signed by: nezia
SSH key fingerprint: SHA256:R/ue1eTzTHUoo77lJD/3fSUsyL4AwvcHImU5BAZai+8
7 changed files with 63 additions and 21 deletions

2
app.ts
View file

@ -1,6 +1,6 @@
import { App } from "astal/gtk4"; import { App } from "astal/gtk4";
import style from "./style.scss"; import style from "./style.scss";
import Bar from "./widget/Bar"; import Bar from "@/widget/Bar";
App.start({ App.start({
css: style, css: style,

View file

@ -31,6 +31,8 @@
network network
tray tray
wireplumber wireplumber
pkgs.brightnessctl
matcha.packages.${pkgs.system}.default
]; ];
in { in {
packages.${system} = { packages.${system} = {

19
src/lib/utils.ts Normal file
View file

@ -0,0 +1,19 @@
import { execAsync } from "astal";
// https://github.com/andre-brandao/hyprshell/blob/bb26e6a1f9afa924b3bb4acfbf822e8fed37221e/src/lib/utils.ts
/**
* @returns true if all of the `bins` are found
*/
export function dependencies(...bins: string[]) {
const missing = bins.filter((bin) => {
execAsync(`which ${bin}`)
.then(() => true)
.catch(() => false);
});
if (missing.length > 0) {
console.warn(Error(`missing dependencies: ${missing.join(", ")}`));
}
return missing.length === 0;
}

View file

@ -1,11 +1,12 @@
import { Astal, Gtk, Gdk } from "astal/gtk4"; import { Astal, Gtk, Gdk } from "astal/gtk4";
import { Variable, GLib, bind, execAsync, exec } from "astal"; import { Variable, GLib, bind, exec } from "astal";
import Battery from "gi://AstalBattery"; import Battery from "gi://AstalBattery";
import Bluetooth from "gi://AstalBluetooth"; import Bluetooth from "gi://AstalBluetooth";
import Wp from "gi://AstalWp"; import Wp from "gi://AstalWp";
import Network from "gi://AstalNetwork"; import Network from "gi://AstalNetwork";
import Hyprland from "gi://AstalHyprland"; import Hyprland from "gi://AstalHyprland";
import Brightness from "../service/brightness"; import Brightness from "@/service/brightness";
import { dependencies } from "@/lib/utils";
const network = Network.get_default(); const network = Network.get_default();
const wifi = bind(network, "wifi"); const wifi = bind(network, "wifi");
@ -102,25 +103,41 @@ function Time({ format = "%H:%M - %A %e." }) {
); );
} }
function IdleInhibitor() { type IdleState = "active" | "inactive" | "unknown";
const icon = Variable(getIcon());
function getIcon() { function IdleInhibitor() {
const state = exec("matcha --status"); /*
const enabled = state.match(/on/g); * matcha needs additional checking to ensure the daemon is properly running
return enabled ? "my-caffeine-on-symbolic" : "my-caffeine-off-symbolic"; */
function isDaemonRunning() {
try {
exec("matcha --status");
return true;
} catch {
return false;
}
} }
if (!dependencies("matcha") || !isDaemonRunning()) return <></>;
const state = Variable<IdleState>("unknown");
function toggle() { function toggle() {
exec("matcha --toggle"); exec("matcha --toggle");
icon.set(getIcon()); const response = exec("matcha --status");
const enabled = response.match(/on/g);
state.set(enabled ? "active" : "inactive");
} }
return ( return (
<box cssName="IdleInhibitor"> <box cssName="IdleInhibitor">
<button <button
onClicked={() => toggle()} onClicked={() => toggle()}
iconName={bind(icon).as((iconName) => iconName)} iconName={bind(state).as((s) =>
s === "active"
? "my-caffeine-on-symbolic"
: "my-caffeine-off-symbolic",
)}
/> />
</box> </box>
); );

View file

@ -1,12 +1,16 @@
{ {
"$schema": "https://json.schemastore.org/tsconfig", "$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": { "compilerOptions": {
"experimentalDecorators": true, "experimentalDecorators": true,
"jsx": "react-jsx", "jsx": "react-jsx",
"jsxImportSource": "astal/gtk4", "jsxImportSource": "astal/gtk4",
"module": "ES2022", "module": "ES2022",
"moduleResolution": "Bundler", "moduleResolution": "Bundler",
"strict": true, "strict": true,
"target": "ES2022" "target": "ES2022",
"paths": {
"@": ["./src"],
"@/*": ["./src/*"]
} }
}
} }