// Copyright (C) 2026 Danilo M. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as // published by the Free Software Foundation. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. import Quickshell.Networking import QtQuick import "../.." // One wifi network. A row click connects; a secured unknown network reveals // an inline password field instead. The click area is declared first so the // buttons and the field, declared later, sit above it. Rectangle { id: row required property var net required property var entry property bool prompting: false property string psk: "" implicitHeight: col.implicitHeight + 16 radius: 8 color: entry.connected ? Qt.alpha(Theme.accent, 0.10) : Qt.alpha(Theme.surface, 0.35) MouseArea { anchors.fill: parent enabled: !row.prompting cursorShape: Qt.PointingHandCursor onClicked: row.activate() } Column { id: col anchors { left: parent.left; right: parent.right; top: parent.top; margins: 10 } spacing: 8 Item { width: parent.width implicitHeight: Math.max(nameText.implicitHeight, actions.implicitHeight) Text { id: nameText anchors { left: parent.left; right: actions.left; rightMargin: 8; verticalCenter: parent.verticalCenter } elide: Text.ElideRight text: row.entry.name font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 2; bold: row.entry.connected } color: row.entry.connected ? Theme.accent : Theme.text } Row { id: actions anchors { right: parent.right; verticalCenter: parent.verticalCenter } spacing: 6 Text { anchors.verticalCenter: parent.verticalCenter visible: row.secured() text: "\uf023" font { family: Theme.iconFamily; pixelSize: Theme.fontSize - 4 } color: Theme.overlay } Text { anchors.verticalCenter: parent.verticalCenter text: Math.round((row.entry.signalStrength ?? 0) * 100) + "%" font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 } color: Theme.overlay } Button { visible: row.entry.connected text: "Disconnect" onClicked: row.net.disconnectNetwork(row.entry) } Button { visible: !row.entry.connected && row.entry.known text: "Forget" danger: true onClicked: row.net.forget(row.entry) } } } Row { width: parent.width spacing: 8 visible: row.prompting TextInput { id: pskField width: parent.width - connectBtn.width - parent.spacing echoMode: TextInput.Password text: row.psk onTextChanged: row.psk = text font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 2 } color: Theme.text Component.onCompleted: forceActiveFocus() Keys.onReturnPressed: row.submit() Keys.onEscapePressed: { row.prompting = false; row.psk = ""; } Rectangle { anchors.fill: parent anchors.margins: -5 z: -1 radius: 6 color: Qt.alpha(Theme.surface, 0.9) border.width: 1 border.color: Qt.alpha(Theme.text, 0.15) } } Button { id: connectBtn text: "Connect" onClicked: row.submit() } } } function secured() { return entry.security !== WifiSecurityType.Open && entry.security !== WifiSecurityType.Owe; } function activate() { if (entry.connected) { net.disconnectNetwork(entry); return; } if (entry.known || !secured()) { net.connect(entry); return; } row.prompting = true; pskField.forceActiveFocus(); } function submit() { if (row.psk === "") return; net.connectWithPsk(entry, row.psk); row.psk = ""; row.prompting = false; } }