pragma Singleton import Quickshell import Quickshell.Io import QtQuick Singleton { id: root readonly property list connections: [] readonly property list savedNetworks: [] readonly property Connection active: connections.find(c => c.active) ?? null property bool wifiEnabled: true readonly property bool scanning: rescanProc.running property string lastNetworkAttempt: "" property string lastErrorMessage: "" property string message: "" readonly property string icon: { if (!active) return "signal_wifi_off"; if (active.type === "ethernet") return "settings_ethernet"; if (active.strength >= 75) return "network_wifi"; else if (active.strength >= 50) return "network_wifi_3_bar"; else if (active.strength >= 25) return "network_wifi_2_bar"; else return "network_wifi_1_bar"; } readonly property string wifiLabel: { const activeWifi = connections.find(c => c.active && c.type === "wifi"); if (activeWifi) return activeWifi.name; return "Wi-Fi"; } readonly property string wifiStatus: { const activeWifi = connections.find(c => c.active && c.type === "wifi"); if (activeWifi) return "Connected"; if (wifiEnabled) return "On"; return "Off"; } readonly property string label: { if (active) return active.name; if (wifiEnabled) return "Wi-Fi"; return "Wi-Fi"; } readonly property string status: { if (active) return "Connected"; if (wifiEnabled) return "On"; return "Off"; } function enableWifi(enabled: bool): void { enableWifiProc.exec(["nmcli", "radio", "wifi", enabled ? "on" : "off"]); } function toggleWifi(): void { enableWifi(!wifiEnabled); } function rescan(): void { rescanProc.running = true; } function connect(connection: Connection, password: string): void { if (connection.type === "wifi") { root.lastNetworkAttempt = connection.name; root.lastErrorMessage = ""; root.message = ""; if (password && password.length > 0) { connectProc.exec(["nmcli", "dev", "wifi", "connect", connection.name, "password", password]); } else { connectProc.exec(["nmcli", "dev", "wifi", "connect", connection.name]); } } else if (connection.type === "ethernet") { ethConnectProc.exec(["nmcli", "connection", "up", connection.uuid]); } } function disconnect(): void { if (!active) return; if (active.type === "wifi") { disconnectProc.exec(["nmcli", "connection", "down", active.name]); } else if (active.type === "ethernet") { ethDisconnectProc.exec(["nmcli", "connection", "down", active.uuid]); } } Process { running: true command: ["nmcli", "m"] stdout: SplitParser { onRead: { getWifiStatus(); updateConnections(); } } } function getWifiStatus(): void { wifiStatusProc.running = true; } function updateConnections(): void { getWifiNetworks.running = true; getEthConnections.running = true; getSavedNetworks.running = true; } Process { id: wifiStatusProc running: true command: ["nmcli", "radio", "wifi"] environment: ({ LANG: "C.UTF-8", LC_ALL: "C.UTF-8" }) stdout: StdioCollector { onStreamFinished: { root.wifiEnabled = text.trim() === "enabled"; if (!root.wifiEnabled) { root.lastErrorMessage = ""; root.message = ""; root.lastNetworkAttempt = ""; } } } } Process { id: enableWifiProc onExited: updateConnections() } Process { id: rescanProc command: ["nmcli", "dev", "wifi", "list", "--rescan", "yes"] onExited: updateConnections() } Process { id: connectProc stdout: StdioCollector { } stderr: StdioCollector { onStreamFinished: { if (text.includes("Error") || text.includes("incorrect")) { root.lastErrorMessage = "Incorrect password"; } } } onExited: { if (exitCode === 0) { root.message = "ok"; root.lastErrorMessage = ""; } else { root.message = root.lastErrorMessage !== "" ? root.lastErrorMessage : "Connection failed"; } updateConnections(); } } Process { id: disconnectProc onExited: updateConnections() } Process { id: ethConnectProc onExited: updateConnections() } Process { id: ethDisconnectProc onExited: updateConnections() } Process { id: getSavedNetworks running: true command: ["nmcli", "-g", "NAME,TYPE", "connection", "show"] environment: ({ LANG: "C.UTF-8", LC_ALL: "C.UTF-8" }) stdout: StdioCollector { onStreamFinished: { const lines = text.trim().split("\n"); const wifiConnections = lines .map(line => line.split(":")) .filter(parts => parts[1] === "802-11-wireless") .map(parts => parts[0]); root.savedNetworks = wifiConnections; } } } Process { id: getWifiNetworks running: true command: ["nmcli", "-g", "ACTIVE,SIGNAL,FREQ,SSID,BSSID,SECURITY", "d", "w"] environment: ({ LANG: "C.UTF-8", LC_ALL: "C.UTF-8" }) stdout: StdioCollector { onStreamFinished: { const PLACEHOLDER = "STRINGWHICHHOPEFULLYWONTBEUSED"; const rep = new RegExp("\\\\:", "g"); const rep2 = new RegExp(PLACEHOLDER, "g"); const allNetworks = text.trim().split("\n").map(n => { const net = n.replace(rep, PLACEHOLDER).split(":"); return { type: "wifi", active: net[0] === "yes", strength: parseInt(net[1]), frequency: parseInt(net[2]), name: net[3]?.replace(rep2, ":") ?? "", bssid: net[4]?.replace(rep2, ":") ?? "", security: net[5] ?? "", saved: root.savedNetworks.includes(net[3] ?? ""), uuid: "", device: "" }; }).filter(n => n.name && n.name.length > 0); const networkMap = new Map(); for (const network of allNetworks) { const existing = networkMap.get(network.name); if (!existing) { networkMap.set(network.name, network); } else { if (network.active && !existing.active) { networkMap.set(network.name, network); } else if (!network.active && !existing.active && network.strength > existing.strength) { networkMap.set(network.name, network); } } } mergeConnections(Array.from(networkMap.values()), "wifi"); } } } Process { id: getEthConnections running: true command: ["nmcli", "-g", "NAME,UUID,TYPE,DEVICE,STATE", "connection", "show"] environment: ({ LANG: "C.UTF-8", LC_ALL: "C.UTF-8" }) stdout: StdioCollector { onStreamFinished: { const lines = text.trim().split("\n"); const ethConns = lines .map(line => line.split(":")) .filter(parts => parts[2] === "802-3-ethernet" || parts[2] === "gsm" || parts[2] === "bluetooth") .map(parts => ({ type: "ethernet", name: parts[0], uuid: parts[1], device: parts[3], active: parts[4] === "activated", strength: 100, frequency: 0, bssid: "", security: "", saved: true })); mergeConnections(ethConns, "ethernet"); } } } function mergeConnections(newConns: var, connType: string): void { const rConns = root.connections; const destroyed = rConns.filter(rc => rc.type === connType && !newConns.find(nc => connType === "wifi" ? (nc.frequency === rc.frequency && nc.name === rc.name && nc.bssid === rc.bssid) : nc.uuid === rc.uuid )); for (const conn of destroyed) rConns.splice(rConns.indexOf(conn), 1).forEach(c => c.destroy()); for (const conn of newConns) { const match = rConns.find(c => connType === "wifi" ? (c.frequency === conn.frequency && c.name === conn.name && c.bssid === conn.bssid) : c.uuid === conn.uuid ); if (match) { match.lastIpcObject = conn; } else { rConns.push(connComp.createObject(root, { lastIpcObject: conn })); } } } component Connection: QtObject { required property var lastIpcObject readonly property string type: lastIpcObject.type readonly property string name: lastIpcObject.name readonly property string uuid: lastIpcObject.uuid readonly property string device: lastIpcObject.device readonly property bool active: lastIpcObject.active readonly property int strength: lastIpcObject.strength readonly property int frequency: lastIpcObject.frequency readonly property string bssid: lastIpcObject.bssid readonly property string security: lastIpcObject.security readonly property bool isSecure: security.length > 0 readonly property bool saved: lastIpcObject.saved } Component { id: connComp; Connection { } } }