import app from "ags/gtk3/app" import { Astal, Gtk } from "ags/gtk3" import { createState } from "ags" import { createPoll, interval } from "ags/time" import { sh, shell } from "../lib/utils" import { ClaudeUsageCard } from "./ClaudeUsage" import { CardHeader, StatRow } from "./WidgetCard" export const QUICKSETTINGS_WINDOW = "quick-settings" const closePanel = () => app.toggle_window(QUICKSETTINGS_WINDOW) function pollBool(command: string, intervalMs: number) { const [value, setValue] = createState(false) const refresh = () => sh(command).then((out) => setValue(out.trim() === "on")) refresh() interval(intervalMs, refresh) return [value, setValue] as const } const volume = createPoll( 0, 1000, shell("pamixer --get-volume 2>/dev/null || echo 0"), (stdout) => Number(stdout.trim()) || 0, ) const [muted, setMuted] = pollBool( "pamixer --get-mute 2>/dev/null | grep -qx true && echo on || echo off", 1000, ) const brightness = createPoll( 0, 2000, shell("brightnessctl -m 2>/dev/null | cut -d, -f4 | tr -d '%' || echo 0"), (stdout) => Number(stdout.trim()) || 0, ) const [bluetoothOn] = pollBool( "bluetoothctl show 2>/dev/null | grep -q 'Powered: yes' && echo on || echo off", 2000, ) const [doNotDisturb, setDoNotDisturb] = pollBool( "makoctl mode 2>/dev/null | grep -qx do-not-disturb && echo on || echo off", 2000, ) const [nightLight, setNightLight] = pollBool( "pgrep -x hyprsunset >/dev/null && echo on || echo off", 2000, ) const clock = createPoll("", 1000, shell("date '+%H:%M'"), (stdout) => stdout.trim()) const today = createPoll("", 10000, shell("date '+%A, %B %-d'"), (stdout) => stdout.trim()) type Media = { title: string artist: string artUrl: string status: string length: number position: number } const mediaCommand = "playerctl metadata -f '{{title}}|||{{artist}}|||{{mpris:artUrl}}|||{{status}}|||{{mpris:length}}|||{{position}}' " + "2>/dev/null || echo 'No Media||||||Stopped|||0|||0'" const media = createPoll( { title: "No Media", artist: "", artUrl: "", status: "Stopped", length: 0, position: 0 }, 1000, shell(mediaCommand), (stdout) => { const parts = stdout.split("|||") return { title: parts[0]?.trim() || "No Media", artist: parts[1]?.trim() || "", artUrl: (parts[2]?.trim() || "").replace(/^file:\/\//, ""), status: parts[3]?.trim() || "Stopped", length: Number(parts[4]) || 0, position: Number(parts[5]) || 0, } }, ) function Header() { return ( ) } function Tile({ icon, label, active, onClicked, }: { icon: string label: string active?: any onClicked: () => void }) { return ( ) } function Toggles() { return ( { closePanel(); sh("omarchy-launch-wifi") }} /> { closePanel() sh("omarchy-launch-bluetooth") }} /> { closePanel() sh("blob_wallpaper") }} /> { setDoNotDisturb(!doNotDisturb.get()) sh("makoctl mode -t do-not-disturb") }} /> { setNightLight(!nightLight.get()) sh("omarchy-toggle-nightlight") }} /> { closePanel(); sh("omarchy-capture-screenrecording") }} /> { closePanel(); sh("hyprpicker -a") }} /> ) } function VolumeSlider() { return ( { self.connect("value-changed", () => { if (self.dragging) { sh(`pamixer --set-volume ${Math.round(self.value)}`) } }) }} /> ) } function BrightnessSlider() { return ( ) } function MediaPlayer() { return ( m.title !== "No Media")}> m.artUrl ? `background-image: url('${m.artUrl}');` : "background-color: alpha(@color0, 0.5);", )} /> ) } const monthName = createPoll("", 60000, shell("date '+%B %Y'"), (stdout) => stdout.trim()) const monthGrid = createPoll( "", 60000, shell("cal | sed '1d'"), (stdout) => stdout.replace(/\s+$/, ""), ) function CalendarSection() { return ( ) } const uptime = createPoll("", 60000, shell("uptime -p"), (stdout) => stdout.trim().replace(/^up /, ""), ) function UptimeCard() { return ( ) } type Weather = { ok: boolean; icon: string; place: string; temp: string; wind: string } function parseWeather(raw: string): Weather { const parts = raw.split(" · ") if (parts.length < 3) return { ok: false, icon: "", place: raw, temp: "", wind: "" } const match = parts[0].match(/^(\S+)\s*(.*)$/) return { ok: true, icon: match ? match[1] : "", place: match ? match[2].trim() : parts[0].trim(), temp: parts[1].replace(/^Temp\s*/, ""), wind: parts[2].replace(/^Wind\s*/, ""), } } const weather = createPoll( { ok: false, icon: "", place: "Loading...", temp: "", wind: "" }, 600000, shell("omarchy-weather-status"), (stdout) => parseWeather(stdout.trim()), ) function WeatherCard() { return ( w.icon)} title={weather.as((w) => w.place)} /> ) } function LeftPanel() { return ( ) } function RightPanel() { return ( ) } export default function QuickSettings() { const { TOP } = Astal.WindowAnchor return (
) }