import type SideBar from "@/modules/sidebar";
import type { Monitor } from "@/services/monitors";
import Players from "@/services/players";
import Updates from "@/services/updates";
import { getAppCategoryIcon } from "@/utils/icons";
import { ellipsize } from "@/utils/strings";
import { bindCurrentTime, osIcon } from "@/utils/system";
import type { AstalWidget } from "@/utils/types";
import { setupCustomTooltip } from "@/utils/widgets";
import type PopupWindow from "@/widgets/popupwindow";
import ScreenCorner from "@/widgets/screencorner";
import { execAsync, Variable } from "astal";
import Binding, { bind, kebabify } from "astal/binding";
import { App, Astal, Gtk } from "astal/gtk3";
import { bar as config } from "config";
import AstalBattery from "gi://AstalBattery";
import AstalBluetooth from "gi://AstalBluetooth";
import AstalHyprland from "gi://AstalHyprland";
import AstalNetwork from "gi://AstalNetwork";
import AstalNotifd from "gi://AstalNotifd";
import AstalTray from "gi://AstalTray";
import AstalWp from "gi://AstalWp";
const hyprland = AstalHyprland.get_default();
const getBatteryIcon = (perc: number) => {
if (perc < 0.1) return "";
if (perc < 0.2) return "";
if (perc < 0.3) return "";
if (perc < 0.4) return "";
if (perc < 0.5) return "";
if (perc < 0.6) return "";
if (perc < 0.7) return "";
if (perc < 0.8) return "";
if (perc < 0.9) return "";
return "";
};
const formatSeconds = (sec: number) => {
if (sec >= 3600) {
const hours = Math.floor(sec / 3600);
let str = `${hours} hour${hours === 1 ? "" : "s"}`;
const mins = Math.floor((sec % 3600) / 60);
if (mins > 0) str += ` ${mins} minute${mins === 1 ? "" : "s"}`;
return str;
} else if (sec >= 60) {
const mins = Math.floor(sec / 60);
return `${mins} minute${mins === 1 ? "" : "s"}`;
} else return `${sec} second${sec === 1 ? "" : "s"}`;
};
const hookFocusedClientProp = (
self: AstalWidget,
prop: keyof AstalHyprland.Client,
callback: (c: AstalHyprland.Client | null) => void
) => {
let id: number | null = null;
let lastClient: AstalHyprland.Client | null = null;
self.hook(hyprland, "notify::focused-client", () => {
if (id) lastClient?.disconnect(id);
lastClient = hyprland.focusedClient; // Can be null
id = lastClient?.connect(`notify::${kebabify(prop)}`, () => callback(lastClient));
callback(lastClient);
});
self.connect("destroy", () => id && lastClient?.disconnect(id));
callback(lastClient);
};
const togglePopup = (self: JSX.Element, event: Astal.ClickEvent, name: string) => {
const popup = App.get_window(name) as PopupWindow | null;
if (popup) {
if (popup.visible) popup.hide();
else popup.popup_at_widget(self, event);
}
};
const switchPane = (name: string) => {
const sidebar = App.get_window("sidebar") as SideBar | null;
if (sidebar) {
if (sidebar.visible && sidebar.shown.get() === name) sidebar.hide();
else sidebar.show();
sidebar.shown.set(name);
}
};
const OSIcon = () => (
);
const ActiveWindow = () => (
{
const title = Variable("");
const updateTooltip = (c: AstalHyprland.Client | null) =>
title.set(c?.class && c?.title ? `${c.class}: ${c.title}` : "");
hookFocusedClientProp(self, "class", updateTooltip);
hookFocusedClientProp(self, "title", updateTooltip);
updateTooltip(hyprland.focusedClient);
const window = setupCustomTooltip(self, bind(title));
if (window) {
self.hook(title, (_, v) => !v && window.hide());
self.hook(window, "map", () => !title.get() && window.hide());
}
}}
>
);
const MediaPlaying = () => {
const players = Players.get_default();
const getLabel = (fallback = "") =>
players.lastPlayer ? `${players.lastPlayer.title} - ${players.lastPlayer.artist}` : fallback;
return (
);
};
const Workspace = ({ idx }: { idx: number }) => {
let wsId = hyprland.focusedWorkspace
? Math.floor((hyprland.focusedWorkspace.id - 1) / config.modules.workspaces.shown.get()) *
config.modules.workspaces.shown.get() +
idx
: idx;
return (