pragma Singleton import QtQuick import Quickshell.Io import "." as S QtObject { id: root // Connection state property string ifname: "" property string essid: "" property string state: "disconnected" // "disconnected" | "wifi" | "eth" | "linked" property string ipAddr: "" property string signal: "" // Wi-Fi networks and radio state property var networks: [] property bool wifiEnabled: true function refresh() { _statusProc.running = true; _scannerProc.running = true; } function setWifi(enabled) { _radioProc._state = enabled ? "on" : "off"; _radioProc.running = true; } function connectNetwork(uuid) { _connectProc._uuid = uuid; _connectProc.running = true; } function disconnectNetwork(uuid) { _disconnectProc._uuid = uuid; _disconnectProc.running = true; } // Status polling property Process _statusProc: Process { running: S.Modules.network.enable command: ["sh", "-c", "line=$(nmcli -t -f NAME,TYPE,DEVICE connection show --active 2>/dev/null | head -1); if [ -z \"$line\" ]; then dev=$(nmcli -t -f DEVICE,STATE device 2>/dev/null | grep ':connected' | grep -v ':unmanaged\\|:unavailable\\|:disconnected\\|:connecting' | head -1 | cut -d: -f1); [ -n \"$dev\" ] && line=\"linked:linked:$dev\"; fi; [ -z \"$line\" ] && exit 0; echo \"$line\"; dev=$(echo \"$line\" | cut -d: -f3); ip=$(nmcli -t -f IP4.ADDRESS device show \"$dev\" 2>/dev/null | head -1 | cut -d: -f2); echo \"ip:${ip:-}\"; sig=$(nmcli -t -f GENERAL.SIGNAL device show \"$dev\" 2>/dev/null | head -1 | cut -d: -f2); echo \"sig:${sig:-}\""] stdout: StdioCollector { onStreamFinished: { const lines = text.trim().split("\n"); if (!lines[0]) { root.state = "disconnected"; root.essid = ""; root.ifname = ""; root.ipAddr = ""; root.signal = ""; return; } const parts = lines[0].split(":"); root.essid = parts[0] || ""; root.ifname = parts[2] || ""; if ((parts[1] || "").includes("wireless")) root.state = "wifi"; else if (parts[0] === "linked") root.state = "linked"; else root.state = "eth"; root.ipAddr = ""; root.signal = ""; for (let i = 1; i < lines.length; i++) { if (lines[i].startsWith("ip:")) root.ipAddr = lines[i].slice(3); else if (lines[i].startsWith("sig:")) root.signal = lines[i].slice(4); } } } } // Event-driven monitor property Process _monitor: Process { running: S.Modules.network.enable command: ["nmcli", "monitor"] stdout: SplitParser { splitMarker: "\n" onRead: _debounce.restart() } } property Timer _debounce: Timer { interval: 300 onTriggered: root.refresh() } // Fallback poll property Timer _fallbackPoll: Timer { interval: 60000 running: S.Modules.network.enable repeat: true onTriggered: root.refresh() } // Wi-Fi scanner (connections + available SSIDs) property Process _scannerProc: Process { running: true command: ["sh", "-c", "echo '---RADIO---';" + "nmcli radio wifi 2>/dev/null;" + "echo '---CONNS---';" + "nmcli -t -f NAME,UUID,TYPE,ACTIVE connection show 2>/dev/null;" + "echo '---WIFI---';" + "nmcli -t -f SSID,SIGNAL device wifi list --rescan no 2>/dev/null"] stdout: StdioCollector { onStreamFinished: { const radioSection = text.split("---CONNS---")[0].split("---RADIO---")[1] || ""; root.wifiEnabled = radioSection.trim() === "enabled"; const sections = text.split("---WIFI---"); const connLines = (sections[0] || "").split("---CONNS---")[1] || ""; const wifiLines = sections[1] || ""; const visible = {}; for (const l of wifiLines.trim().split("\n")) { if (!l) continue; const parts = l.split(":"); const ssid = parts[0]; if (ssid) visible[ssid] = parseInt(parts[1]) || 0; } const nets = []; for (const l of connLines.trim().split("\n")) { if (!l) continue; const parts = l.split(":"); const name = parts[0]; const uuid = parts[1]; const type = parts[2] || ""; const active = parts[3] === "yes"; const isWifi = type.includes("wireless"); if (isWifi && !(name in visible)) continue; nets.push({ name: name, uuid: uuid, isWifi: isWifi, active: active, signal: isWifi ? (visible[name] || 0) : -1 }); } nets.sort((a, b) => { if (a.active !== b.active) return a.active ? -1 : 1; if (a.signal >= 0 && b.signal >= 0) return b.signal - a.signal; return a.name.localeCompare(b.name); }); root.networks = nets; } } } // Action processes property Process _radioProc: Process { property string _state: "" command: ["nmcli", "radio", "wifi", _state] onRunningChanged: if (!running) root.refresh() } property Process _connectProc: Process { property string _uuid: "" command: ["nmcli", "connection", "up", _uuid] onRunningChanged: if (!running) root.refresh() } property Process _disconnectProc: Process { property string _uuid: "" command: ["nmcli", "connection", "down", _uuid] onRunningChanged: if (!running) root.refresh() } }