Build the Panama Hyprland desktop

This commit is contained in:
Gabriel Brown
2026-08-17 10:32:55 -04:00
parent 67033f2a31
commit 5248883e4b
190 changed files with 18554 additions and 34 deletions
@@ -0,0 +1,274 @@
// The wifi picker. This is the reason the quick settings panel exists: the
// user must never have to drop to nmcli to join a network.
//
// Everything here goes through Quickshell.Networking (NetworkManager over
// DBus) — no shelling out.
import QtQuick
import Quickshell
import Quickshell.Widgets
import Quickshell.Networking
import qs.config
import qs.widgets
Item {
id: root
// The WifiDevice, or null while NetworkManager is still enumerating.
property var device: null
// True while the section is open. Drives the NM scan request so we are not
// burning radio time scanning for a list nobody is looking at.
property bool active: false
property alias maxHeight: list.maxHeight
// SSID whose inline password field is open, and the last failure.
property string passwordFor: ""
property string failedSsid: ""
property string failedText: ""
implicitHeight: list.implicitHeight
// GNOME's ordering: the current network, then saved ones, then by signal.
readonly property var networks: {
if (!root.device || !root.device.networks)
return [];
const list = root.device.networks.values.slice();
list.sort((a, b) => {
if (a.connected !== b.connected)
return a.connected ? -1 : 1;
if (a.known !== b.known)
return a.known ? -1 : 1;
return b.signalStrength - a.signalStrength;
});
return list;
}
function syncScanner(): void {
if (root.device)
root.device.scannerEnabled = root.active;
}
onActiveChanged: root.syncScanner()
onDeviceChanged: root.syncScanner()
Component.onCompleted: root.syncScanner()
Component.onDestruction: {
if (root.device)
root.device.scannerEnabled = false;
}
function signalIcon(strength: real): string {
if (strength >= 0.8)
return "network-wireless-signal-excellent-symbolic";
if (strength >= 0.55)
return "network-wireless-signal-good-symbolic";
if (strength >= 0.3)
return "network-wireless-signal-ok-symbolic";
if (strength > 0.05)
return "network-wireless-signal-weak-symbolic";
return "network-wireless-signal-none-symbolic";
}
// NM's failure reasons are useful but not English.
function failureText(reason): string {
switch (reason) {
case ConnectionFailReason.NoSecrets:
return "Wrong password";
case ConnectionFailReason.WifiAuthTimeout:
return "Authentication timed out";
case ConnectionFailReason.WifiNetworkLost:
return "Network out of range";
default:
return "Couldn't connect";
}
}
function isSecured(network): bool {
return network.security !== WifiSecurityType.Open && network.security !== WifiSecurityType.Owe && network.security !== WifiSecurityType.Unknown;
}
// Left click on a row. Saved and open networks connect immediately;
// anything else reveals the password field rather than failing silently.
function activate(network): void {
root.failedSsid = "";
if (network.connected)
return;
if (network.known || !root.isSecured(network)) {
root.passwordFor = "";
network.connect();
return;
}
root.passwordFor = root.passwordFor === network.name ? "" : network.name;
}
ScrollColumn {
id: list
anchors.fill: parent
maxHeight: 340
Item {
width: parent.width
height: 30
visible: root.networks.length > 0
Text {
anchors.left: parent.left
anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter
text: "Available networks"
color: Theme.fgMuted
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.DemiBold
}
}
Text {
width: parent.width
visible: root.networks.length === 0
topPadding: 12
bottomPadding: 12
horizontalAlignment: Text.AlignHCenter
text: root.device ? (Networking.wifiEnabled ? "Scanning…" : "Wi-Fi is off") : "No Wi-Fi adapter"
color: Theme.fgMuted
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSize
}
Repeater {
model: root.networks
Column {
id: entry
required property var modelData
width: parent.width
spacing: 0
readonly property bool secured: root.isSecured(entry.modelData)
readonly property string ssid: entry.modelData.name
// Reported by NM when a connection attempt gives up. Bad
// passwords land here, so re-open the field to retry.
Connections {
target: entry.modelData
function onConnectionFailed(reason) {
root.failedSsid = entry.ssid;
root.failedText = root.failureText(reason);
if (entry.secured && !entry.modelData.known)
root.passwordFor = entry.ssid;
}
}
RowButton {
width: parent.width
icon: root.signalIcon(entry.modelData.signalStrength)
iconFallback: "network-wireless-symbolic"
label: entry.ssid !== "" ? entry.ssid : "Hidden network"
selected: entry.modelData.connected
sublabel: {
if (entry.modelData.stateChanging)
return "Connecting…";
if (entry.modelData.connected)
return "Connected";
if (root.failedSsid === entry.ssid)
return root.failedText;
if (entry.modelData.known)
return "Saved";
return "";
}
onClicked: root.activate(entry.modelData)
ThemedIcon {
anchors.verticalCenter: parent.verticalCenter
size: 14
visible: entry.secured
tint: Theme.fgMuted
icon: "network-wireless-encrypted-symbolic"
iconFallback: "changes-prevent-symbolic"
}
IconButton {
visible: entry.modelData.connected
size: 26
iconSize: 13
icon: "window-close-symbolic"
onClicked: entry.modelData.disconnect()
}
}
Section {
id: pskSection
width: parent.width
expanded: root.passwordFor === entry.ssid
onExpandedChanged: {
if (pskSection.expanded)
pskInput.forceActiveFocus();
else
pskInput.text = "";
}
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 10
anchors.rightMargin: 10
height: 42
y: 4
radius: Theme.cardRadius - 2
border.width: 1
border.color: Theme.alpha(Theme.accent, 0.4)
color: Theme.alpha(Theme.fg, 0.08)
TextInput {
id: pskInput
anchors.left: parent.left
anchors.leftMargin: 12
anchors.right: sendButton.left
anchors.rightMargin: 6
anchors.verticalCenter: parent.verticalCenter
echoMode: TextInput.Password
color: Theme.fg
selectionColor: Theme.alpha(Theme.accent, 0.5)
selectedTextColor: Theme.fg
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSize
clip: true
onAccepted: {
if (pskInput.text.length > 0) {
root.failedSsid = "";
entry.modelData.connectWithPsk(pskInput.text);
root.passwordFor = "";
}
}
Text {
anchors.fill: parent
verticalAlignment: Text.AlignVCenter
visible: pskInput.text === ""
text: "Password"
color: Theme.fgMuted
font: pskInput.font
}
}
IconButton {
id: sendButton
anchors.right: parent.right
anchors.rightMargin: 4
anchors.verticalCenter: parent.verticalCenter
size: 30
iconSize: 15
icon: "go-next-symbolic"
onClicked: pskInput.accepted()
}
}
}
}
}
}
}