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 ( ); const BluetoothDevice = (device: AstalBluetooth.Device) => ( ); const Bluetooth = () => ( {bind(AstalBluetooth.get_default(), "devices").as(d => d.map(BluetoothDevice))} ); const StatusIcons = () => ( ); const PkgUpdates = () => ( ); const NotifCount = () => ( ); const Battery = () => { const className = Variable.derive( [bind(AstalBattery.get_default(), "percentage"), bind(AstalBattery.get_default(), "charging")], (p, c) => `module battery ${c ? "charging" : p < 0.2 ? "low" : ""}` ); const tooltip = Variable.derive( [bind(AstalBattery.get_default(), "timeToEmpty"), bind(AstalBattery.get_default(), "timeToFull")], (e, f) => (f > 0 ? `${formatSeconds(f)} until full` : `${formatSeconds(e)} remaining`) ); return ( setupCustomTooltip(self, bind(tooltip))} onDestroy={() => { className.drop(); tooltip.drop(); }} > ); }; const DateTime = () => ( ); const DateTimeVertical = () => ( ); const Power = () => (