diff --git a/settings/hyprland.nix b/settings/hyprland.nix index ed072d4..7da3b7e 100644 --- a/settings/hyprland.nix +++ b/settings/hyprland.nix @@ -595,14 +595,56 @@ in font.pixelSize: 14 } + property var wifiNetworks: [] + Process { - id: nmEditorProc - command: ["${pkgs.networkmanagerapplet}/bin/nm-connection-editor"] + id: wifiScanProc + command: ["${pkgs.networkmanager}/bin/nmcli", "-t", "-f", "SSID,SIGNAL,SECURITY,IN-USE", "device", "wifi", "list", "--rescan", "auto"] + stdout: SplitParser { + onRead: data => { + let fields = data.split(":"); + if (fields.length < 4 || fields[0] === "") return; + let nets = netWidget.wifiNetworks; + // Avoid duplicates + for (let i = 0; i < nets.length; i++) { + if (nets[i].ssid === fields[0]) return; + } + nets.push({ + ssid: fields[0], + signal: parseInt(fields[1]) || 0, + security: fields[2], + active: fields[3] === "*" + }); + netWidget.wifiNetworks = nets; + } + } + } + + Process { + id: wifiConnectProc + property string targetSsid: "" + command: ["${pkgs.networkmanager}/bin/nmcli", "device", "wifi", "connect", targetSsid] + } + + Process { + id: netDisconnectProc + command: ["${pkgs.networkmanager}/bin/nmcli", "device", "disconnect", "wlan0"] } MouseArea { anchors.fill: parent - onClicked: nmEditorProc.running = true + onClicked: { + if (netDropdown.justDismissed) return; + if (netDropdown.visible) { + netDropdown.visible = false; + } else { + netWidget.wifiNetworks = []; + wifiScanProc.running = true; + let pos = netWidget.mapToItem(bar.contentItem, netWidget.width / 2, 0); + netDropdown.dropdownX = pos.x; + netDropdown.visible = true; + } + } } } @@ -917,6 +959,150 @@ in } } + // Network dropdown + BarDropdown { + id: netDropdown + fullWidth: netDropdownCol.width + 24 + fullHeight: netDropdownCol.height + 16 + + Column { + id: netDropdownCol + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.topMargin: 8 + width: 220 + spacing: 4 + + // Current connection header + Text { + width: parent.width + text: netWidget.netState === "connected" + ? "\u{f05a9} " + netWidget.netConn + : "\u{f05aa} Not connected" + color: "#${c.base05}" + font.family: "FiraMono Nerd Font" + font.pixelSize: 13 + font.weight: Font.Medium + elide: Text.ElideRight + } + + // Disconnect button (when connected) + Rectangle { + visible: netWidget.netState === "connected" + width: parent.width + height: 28 + color: disconnectMouse.containsMouse ? "#${c.base02}" : "transparent" + radius: 4 + + Text { + anchors.centerIn: parent + text: "Disconnect" + color: "#${c.base08}" + font.family: "FiraMono Nerd Font" + font.pixelSize: 12 + } + + MouseArea { + id: disconnectMouse + anchors.fill: parent + hoverEnabled: true + onClicked: { + netDisconnectProc.running = true; + netDropdown.visible = false; + } + } + } + + // Separator + Rectangle { + width: parent.width - 20 + anchors.horizontalCenter: parent.horizontalCenter + height: 1 + color: "#${c.base03}" + } + + // Available networks header + Text { + text: "Available networks" + color: "#${c.base03}" + font.family: "FiraMono Nerd Font" + font.pixelSize: 11 + topPadding: 2 + } + + // Network list + Repeater { + model: netWidget.wifiNetworks + + Rectangle { + required property var modelData + width: 220 + height: 32 + color: netItemMouse.containsMouse ? "#${c.base02}" : "transparent" + radius: 4 + + Row { + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 8 + anchors.right: parent.right + anchors.rightMargin: 8 + spacing: 8 + + // Signal icon + Text { + text: { + let s = modelData.signal; + if (s >= 75) return "\u{f05a9}"; + if (s >= 50) return "\u{f05a9}"; + if (s >= 25) return "\u{f05a9}"; + return "\u{f05aa}"; + } + color: modelData.active ? "#${c.base0B}" : "#${c.base04}" + font.family: "FiraMono Nerd Font" + font.pixelSize: 13 + anchors.verticalCenter: parent.verticalCenter + } + + // SSID + Text { + text: modelData.ssid + color: modelData.active ? "#${c.base0B}" : "#${c.base05}" + font.family: "FiraMono Nerd Font" + font.pixelSize: 12 + elide: Text.ElideRight + width: 140 + anchors.verticalCenter: parent.verticalCenter + } + + // Lock icon for secured networks + Text { + visible: modelData.security !== "" && modelData.security !== "--" + text: "\u{f0341}" + color: "#${c.base03}" + font.family: "FiraMono Nerd Font" + font.pixelSize: 10 + anchors.verticalCenter: parent.verticalCenter + } + } + + MouseArea { + id: netItemMouse + anchors.fill: parent + hoverEnabled: true + onClicked: { + if (!modelData.active) { + wifiConnectProc.targetSsid = modelData.ssid; + wifiConnectProc.running = true; + } + netDropdown.visible = false; + } + } + } + } + } + } + // Calendar popup BarDropdown { id: calPopup