import Gtk from "gi://Gtk?version=3.0" import AstalNetwork from "gi://AstalNetwork" import { type Binding, Variable, bind } from "astal" import Dropdown from "./Dropdown" const CONNECTING = [40, 50, 60, 70, 80, 90] function strongest(aps: AstalNetwork.AccessPoint[]) { const bySsid = new Map() for (const ap of aps) { const ssid = ap.ssid ?? "" const best = bySsid.get(ssid) if (!best || ap.strength > best.strength) bySsid.set(ssid, ap) } return [...bySsid.values()].sort((a, b) => b.strength - a.strength) } function WifiRow( ap: AstalNetwork.AccessPoint, activeSsid: Binding, connect: (ap: AstalNetwork.AccessPoint) => void, ) { return ( ) } export function WifiWidget(gdkmonitor: Gdk.Monitor) { const wifi = AstalNetwork.get_default().wifi if (!wifi) return { button: null, popup: null } const open = Variable(false) const pendingAP = Variable(null) const failed = Variable("") const status = Variable.derive( [bind(wifi, "scanning"), bind(wifi, "state"), bind(wifi, "ssid"), failed], (scanning, state, ssid, fail) => { if (scanning) return "scanning…" if (CONNECTING.includes(state)) return `connecting to ${ssid ?? "network"}…` return fail }, ) const activeSsid = bind(wifi, "active-access-point").as((ap) => ap?.ssid ?? "") function connect(ap: AstalNetwork.AccessPoint) { if (ap.requires_password) { failed.set("") pendingAP.set(ap) } else { ap.activate() .then(() => failed.set("")) .catch(() => failed.set(`failed to connect to ${ap.ssid ?? "network"}`)) } } const passwordEntry = ( ap !== null)} placeholderText={pendingAP().as( (ap) => (ap ? `password for ${ap.ssid ?? "network"}` : ""), )} onActivate={(self) => { const ap = pendingAP.get() if (!ap || !self.text) return ap.activate(self.text) .then(() => { pendingAP.set(null) self.text = "" }) .catch(() => failed.set(`failed to connect to ${ap.ssid ?? "network"}`) ) }} /> ) const button = ( ) const popup = ( ) open.subscribe((v) => { if (v) { wifi.scan() } else { pendingAP.set(null) failed.set("") passwordEntry.text = "" } }) return { button, popup } }