Show network connection details and gracefully handle iwd-only setups
Network panel now polls 'ip route get 1.1.1.1' for the active interface and renders a key/value grid with IP/CIDR, gateway, link speed + duplex (ethernet) or signal/freq/bitrate (Wi-Fi). One bash script collects everything in TSV. Wi-Fi list now works on Omarchy's default iwd+impala stack: when nmcli isn't installed, falls back to 'iwctl station <dev> get-networks' and parses the connected/SSID/signal/security columns. The list is hidden entirely when no Wi-Fi station device exists (ethernet-only machines). Right-click on the bar widget and the bottom 'Open Wi-Fi manager (Impala)' button both run omarchy-launch-wifi directly (was wrapped in extra OMARCHY_PATH= env that wasn't actually doing anything).
This commit is contained in:
@@ -11,10 +11,13 @@ Item {
|
|||||||
property var settings: ({})
|
property var settings: ({})
|
||||||
|
|
||||||
property bool popupOpen: false
|
property bool popupOpen: false
|
||||||
|
|
||||||
function closePopout() { popupOpen = false }
|
function closePopout() { popupOpen = false }
|
||||||
property var networks: []
|
|
||||||
|
// Live connection details from `ip` / /sys / iw.
|
||||||
|
property var info: ({}) // { iface, type, ip, prefix, gateway, speed, duplex, ssid, signal, freq, bitrate }
|
||||||
|
property var wifiNetworks: []
|
||||||
property bool scanning: false
|
property bool scanning: false
|
||||||
|
property bool wifiStationAvailable: false
|
||||||
|
|
||||||
readonly property string kind: bar ? bar.networkKind : "disconnected"
|
readonly property string kind: bar ? bar.networkKind : "disconnected"
|
||||||
readonly property string label: bar ? bar.networkLabel : ""
|
readonly property string label: bar ? bar.networkLabel : ""
|
||||||
@@ -31,38 +34,69 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function refresh() {
|
function refresh() {
|
||||||
if (!scanProc.running) {
|
if (!detailsProc.running) detailsProc.running = true
|
||||||
|
if (!wifiProc.running) {
|
||||||
scanning = true
|
scanning = true
|
||||||
scanProc.running = true
|
wifiProc.running = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateScan(raw) {
|
function formatSpeed(mbps) {
|
||||||
var list = []
|
var v = parseInt(mbps, 10)
|
||||||
|
if (!v || v < 0) return ""
|
||||||
|
if (v >= 1000) return (v / 1000).toFixed(v % 1000 === 0 ? 0 : 1) + " Gbps"
|
||||||
|
return v + " Mbps"
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatFreq(mhz) {
|
||||||
|
var v = parseFloat(mhz)
|
||||||
|
if (!v) return ""
|
||||||
|
return (v / 1000).toFixed(1) + " GHz"
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDetails(raw) {
|
||||||
|
var next = {}
|
||||||
var lines = String(raw || "").split("\n")
|
var lines = String(raw || "").split("\n")
|
||||||
|
for (var i = 0; i < lines.length; i++) {
|
||||||
|
var line = lines[i]
|
||||||
|
if (!line) continue
|
||||||
|
var idx = line.indexOf("\t")
|
||||||
|
if (idx === -1) continue
|
||||||
|
next[line.substring(0, idx)] = line.substring(idx + 1).trim()
|
||||||
|
}
|
||||||
|
info = next
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateWifi(raw) {
|
||||||
|
var lines = String(raw || "").split("\n")
|
||||||
|
var hasStation = false
|
||||||
|
var nets = []
|
||||||
for (var i = 0; i < lines.length; i++) {
|
for (var i = 0; i < lines.length; i++) {
|
||||||
var line = lines[i].trim()
|
var line = lines[i].trim()
|
||||||
if (!line) continue
|
if (!line) continue
|
||||||
|
if (line === "STATION_AVAILABLE") { hasStation = true; continue }
|
||||||
|
// Format: connected<TAB>ssid<TAB>signal<TAB>security
|
||||||
var parts = line.split("\t")
|
var parts = line.split("\t")
|
||||||
if (parts.length < 3) continue
|
if (parts.length < 3) continue
|
||||||
list.push({
|
nets.push({
|
||||||
inUse: parts[0] === "*",
|
connected: parts[0] === "1",
|
||||||
ssid: parts[1],
|
ssid: parts[1],
|
||||||
signalStrength: parseInt(parts[2], 10) || 0,
|
signal: parseInt(parts[2], 10) || 0,
|
||||||
security: parts[3] || ""
|
security: parts[3] || ""
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
list.sort(function(a, b) {
|
nets.sort(function(a, b) {
|
||||||
if (a.inUse !== b.inUse) return a.inUse ? -1 : 1
|
if (a.connected !== b.connected) return a.connected ? -1 : 1
|
||||||
return b.signalStrength - a.signalStrength
|
return b.signal - a.signal
|
||||||
})
|
})
|
||||||
networks = list
|
wifiNetworks = nets
|
||||||
|
wifiStationAvailable = hasStation
|
||||||
scanning = false
|
scanning = false
|
||||||
}
|
}
|
||||||
|
|
||||||
function wifiIconFor(signalStrength) {
|
function wifiIconFor(strength) {
|
||||||
var icons = ["", "", "", "", ""]
|
var icons = ["", "", "", "", ""]
|
||||||
var index = Math.max(0, Math.min(4, Math.ceil(signalStrength / 20) - 1))
|
var index = Math.max(0, Math.min(4, Math.ceil(strength / 20) - 1))
|
||||||
return icons[index]
|
return icons[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,12 +105,78 @@ Item {
|
|||||||
|
|
||||||
Component.onCompleted: refresh()
|
Component.onCompleted: refresh()
|
||||||
|
|
||||||
|
// Pulls everything we want about the active route's interface in one shot.
|
||||||
Process {
|
Process {
|
||||||
id: scanProc
|
id: detailsProc
|
||||||
command: ["bash", "-lc", "command -v nmcli >/dev/null && nmcli -t -f IN-USE,SSID,SIGNAL,SECURITY device wifi list --rescan no 2>/dev/null"]
|
command: ["bash", "-c", `
|
||||||
|
route_json=$(ip -j route get 1.1.1.1 2>/dev/null)
|
||||||
|
[[ -z $route_json ]] && exit 0
|
||||||
|
iface=$(echo "$route_json" | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d[0].get("dev",""))' 2>/dev/null)
|
||||||
|
gw=$(echo "$route_json" | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d[0].get("gateway",""))' 2>/dev/null)
|
||||||
|
src=$(echo "$route_json" | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d[0].get("prefsrc",""))' 2>/dev/null)
|
||||||
|
[[ -z $iface ]] && exit 0
|
||||||
|
prefix=$(ip -j addr show "$iface" 2>/dev/null | python3 -c 'import sys,json; d=json.load(sys.stdin); ai=d[0].get("addr_info",[]); print(next((str(a.get("prefixlen","")) for a in ai if a.get("family")=="inet"),""))' 2>/dev/null)
|
||||||
|
printf 'iface\\t%s\\n' "$iface"
|
||||||
|
printf 'ip\\t%s\\n' "$src"
|
||||||
|
printf 'prefix\\t%s\\n' "$prefix"
|
||||||
|
printf 'gateway\\t%s\\n' "$gw"
|
||||||
|
if [[ -d /sys/class/net/$iface/wireless ]]; then
|
||||||
|
printf 'type\\twifi\\n'
|
||||||
|
if command -v iw >/dev/null; then
|
||||||
|
link=$(iw dev "$iface" link 2>/dev/null)
|
||||||
|
[[ -n $link ]] && {
|
||||||
|
printf 'ssid\\t%s\\n' "$(echo "$link" | awk '/SSID:/ { sub(/.*SSID: /, ""); print; exit }')"
|
||||||
|
printf 'signal_dbm\\t%s\\n' "$(echo "$link" | awk '/signal:/ { print $2; exit }')"
|
||||||
|
printf 'freq\\t%s\\n' "$(echo "$link" | awk '/freq:/ { print $2; exit }')"
|
||||||
|
printf 'bitrate\\t%s %s\\n' "$(echo "$link" | awk '/tx bitrate:/ { print $3; exit }')" "$(echo "$link" | awk '/tx bitrate:/ { print $4; exit }')"
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
printf 'type\\tethernet\\n'
|
||||||
|
[[ -r /sys/class/net/$iface/speed ]] && printf 'speed\\t%s\\n' "$(cat /sys/class/net/$iface/speed)"
|
||||||
|
[[ -r /sys/class/net/$iface/duplex ]] && printf 'duplex\\t%s\\n' "$(cat /sys/class/net/$iface/duplex)"
|
||||||
|
fi
|
||||||
|
`]
|
||||||
stdout: StdioCollector {
|
stdout: StdioCollector {
|
||||||
waitForEnd: true
|
waitForEnd: true
|
||||||
onStreamFinished: root.updateScan(text)
|
onStreamFinished: root.updateDetails(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wi-Fi scan via nmcli OR iwctl, whichever is available. Emits TSV plus
|
||||||
|
// a STATION_AVAILABLE marker so the panel knows whether to render the list.
|
||||||
|
Process {
|
||||||
|
id: wifiProc
|
||||||
|
command: ["bash", "-c", `
|
||||||
|
if command -v nmcli >/dev/null; then
|
||||||
|
echo STATION_AVAILABLE
|
||||||
|
nmcli -t -f IN-USE,SSID,SIGNAL,SECURITY device wifi list --rescan no 2>/dev/null \
|
||||||
|
| awk -F: '{ printf "%s\\t%s\\t%s\\t%s\\n", ($1=="*" ? "1" : "0"), $2, $3, $4 }'
|
||||||
|
elif command -v iwctl >/dev/null; then
|
||||||
|
station=$(iwctl station list 2>/dev/null | sed -n 's/^[[:space:]]*\\(wl[a-z0-9]*\\)[[:space:]].*/\\1/p' | head -1)
|
||||||
|
[[ -n $station ]] && {
|
||||||
|
echo STATION_AVAILABLE
|
||||||
|
iwctl station "$station" get-networks 2>/dev/null \
|
||||||
|
| sed -e 's/\\x1b\\[[0-9;]*m//g' \
|
||||||
|
| awk 'NR > 4 && NF >= 2 {
|
||||||
|
connected = ($0 ~ /^>/) ? 1 : 0
|
||||||
|
line = $0
|
||||||
|
sub(/^[ >]+/, "", line)
|
||||||
|
# Last two columns are security and signal indicator (asterisks)
|
||||||
|
n = split(line, fields, /[ \\t]{2,}/)
|
||||||
|
ssid = fields[1]
|
||||||
|
security = (n >= 2) ? fields[2] : ""
|
||||||
|
signal_marks = (n >= 3) ? fields[3] : ""
|
||||||
|
gsub(/[^*]/, "", signal_marks)
|
||||||
|
signal_pct = length(signal_marks) * 25
|
||||||
|
printf "%d\\t%s\\t%d\\t%s\\n", connected, ssid, signal_pct, security
|
||||||
|
}'
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
`]
|
||||||
|
stdout: StdioCollector {
|
||||||
|
waitForEnd: true
|
||||||
|
onStreamFinished: root.updateWifi(text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,7 +191,7 @@ Item {
|
|||||||
tooltipText: bar ? bar.networkTooltip() : ""
|
tooltipText: bar ? bar.networkTooltip() : ""
|
||||||
|
|
||||||
onPressed: function(b) {
|
onPressed: function(b) {
|
||||||
if (b === Qt.RightButton) root.bar.run("OMARCHY_PATH=" + root.bar.shellQuote(root.bar.omarchyPath) + " " + root.bar.omarchyPath + "/bin/omarchy-launch-wifi")
|
if (b === Qt.RightButton) root.bar.run(root.bar.omarchyPath + "/bin/omarchy-launch-wifi")
|
||||||
else {
|
else {
|
||||||
root.popupOpen = !root.popupOpen
|
root.popupOpen = !root.popupOpen
|
||||||
if (root.popupOpen) root.refresh()
|
if (root.popupOpen) root.refresh()
|
||||||
@@ -104,111 +204,228 @@ Item {
|
|||||||
owner: root
|
owner: root
|
||||||
bar: root.bar
|
bar: root.bar
|
||||||
open: root.popupOpen
|
open: root.popupOpen
|
||||||
contentWidth: 320
|
contentWidth: 340
|
||||||
contentHeight: column.implicitHeight + 28
|
contentHeight: column.implicitHeight + 28
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: column
|
id: column
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 8
|
spacing: 12
|
||||||
|
|
||||||
Row {
|
// Header — interface name + type, refresh on the right.
|
||||||
|
Item {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: 8
|
height: Math.max(headerInfo.implicitHeight, refreshBtn.implicitHeight)
|
||||||
|
|
||||||
Text {
|
Row {
|
||||||
text: root.icon
|
id: headerInfo
|
||||||
color: root.bar.foreground
|
anchors.left: parent.left
|
||||||
font.family: root.bar.fontFamily
|
|
||||||
font.pixelSize: 16
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
spacing: 2
|
|
||||||
width: parent.width - 100
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
text: root.kind === "disconnected" ? "Disconnected" : (root.label || root.kind)
|
text: root.icon
|
||||||
color: root.bar.foreground
|
color: root.bar.foreground
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
font.pixelSize: 12
|
font.pixelSize: 22
|
||||||
font.bold: true
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
elide: Text.ElideRight
|
|
||||||
width: parent.width
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Column {
|
||||||
visible: root.kind !== "disconnected"
|
spacing: 2
|
||||||
text: root.kind === "wifi" ? "Wi-Fi · " + root.signalStrength + "%" : "Ethernet"
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
color: Qt.darker(root.bar.foreground, 1.4)
|
|
||||||
font.family: root.bar.fontFamily
|
|
||||||
font.pixelSize: 10
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Common.PillButton {
|
Text {
|
||||||
iconText: ""
|
text: root.info.iface || (root.kind === "disconnected" ? "Disconnected" : "No connection")
|
||||||
foreground: root.bar.foreground
|
color: root.bar.foreground
|
||||||
horizontalPadding: 8
|
font.family: root.bar.fontFamily
|
||||||
verticalPadding: 4
|
font.pixelSize: 13
|
||||||
active: root.scanning
|
font.bold: true
|
||||||
onClicked: {
|
}
|
||||||
if (scanProc.running) return
|
Text {
|
||||||
scanProc.command = ["bash", "-lc", "command -v nmcli >/dev/null && nmcli device wifi rescan 2>/dev/null; nmcli -t -f IN-USE,SSID,SIGNAL,SECURITY device wifi list --rescan no 2>/dev/null"]
|
text: {
|
||||||
root.refresh()
|
if (root.info.type === "wifi") {
|
||||||
}
|
var s = root.info.ssid || "Wi-Fi"
|
||||||
}
|
if (root.info.freq) s += " · " + root.formatFreq(root.info.freq)
|
||||||
}
|
return s
|
||||||
|
}
|
||||||
Rectangle {
|
if (root.info.type === "ethernet") return "Ethernet"
|
||||||
width: parent.width
|
return ""
|
||||||
height: 1
|
}
|
||||||
color: Qt.rgba(root.bar.foreground.r, root.bar.foreground.g, root.bar.foreground.b, 0.15)
|
visible: text !== ""
|
||||||
}
|
color: Qt.darker(root.bar.foreground, 1.4)
|
||||||
|
font.family: root.bar.fontFamily
|
||||||
Column {
|
font.pixelSize: 10
|
||||||
spacing: 2
|
|
||||||
width: parent.width
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: root.networks.slice(0, 6)
|
|
||||||
|
|
||||||
Common.PillButton {
|
|
||||||
required property var modelData
|
|
||||||
|
|
||||||
width: parent.width
|
|
||||||
iconText: root.wifiIconFor(modelData.signalStrength)
|
|
||||||
text: (modelData.ssid || "Hidden") + (modelData.security ? " · " : "") + (modelData.security || "")
|
|
||||||
foreground: root.bar.foreground
|
|
||||||
horizontalPadding: 10
|
|
||||||
verticalPadding: 6
|
|
||||||
active: modelData.inUse
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
if (modelData.inUse) return
|
|
||||||
if (actionProc.running) return
|
|
||||||
actionProc.command = ["bash", "-lc", "command -v nmcli >/dev/null && nmcli device wifi connect " + root.bar.shellQuote(modelData.ssid)]
|
|
||||||
actionProc.running = true
|
|
||||||
root.popupOpen = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Common.PillButton {
|
||||||
|
id: refreshBtn
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
iconText: ""
|
||||||
|
tooltipText: "Refresh"
|
||||||
|
tooltipBackground: root.bar.background
|
||||||
|
tooltipForeground: root.bar.foreground
|
||||||
|
foreground: root.bar.foreground
|
||||||
|
horizontalPadding: 8
|
||||||
|
verticalPadding: 4
|
||||||
|
iconSize: 14
|
||||||
|
active: root.scanning
|
||||||
|
onClicked: root.refresh()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
visible: !!root.info.iface
|
||||||
|
width: parent.width
|
||||||
|
height: 1
|
||||||
|
color: Qt.rgba(root.bar.foreground.r, root.bar.foreground.g, root.bar.foreground.b, 0.12)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connection details: IP, gateway, link speed, etc.
|
||||||
|
Grid {
|
||||||
|
visible: !!root.info.iface
|
||||||
|
width: parent.width
|
||||||
|
columns: 2
|
||||||
|
columnSpacing: 14
|
||||||
|
rowSpacing: 4
|
||||||
|
|
||||||
|
// IP address.
|
||||||
Text {
|
Text {
|
||||||
visible: root.networks.length === 0
|
visible: !!root.info.ip
|
||||||
text: root.scanning ? "Scanning…" : "No networks found"
|
text: "IP address"
|
||||||
color: Qt.darker(root.bar.foreground, 1.5)
|
color: Qt.darker(root.bar.foreground, 1.4)
|
||||||
font.family: root.bar.fontFamily
|
font.family: root.bar.fontFamily
|
||||||
font.pixelSize: 11
|
font.pixelSize: 11
|
||||||
}
|
}
|
||||||
|
Text {
|
||||||
|
visible: !!root.info.ip
|
||||||
|
text: (root.info.ip || "") + (root.info.prefix ? "/" + root.info.prefix : "")
|
||||||
|
color: root.bar.foreground
|
||||||
|
font.family: root.bar.fontFamily
|
||||||
|
font.pixelSize: 11
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gateway.
|
||||||
|
Text {
|
||||||
|
visible: !!root.info.gateway
|
||||||
|
text: "Gateway"
|
||||||
|
color: Qt.darker(root.bar.foreground, 1.4)
|
||||||
|
font.family: root.bar.fontFamily
|
||||||
|
font.pixelSize: 11
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
visible: !!root.info.gateway
|
||||||
|
text: root.info.gateway || ""
|
||||||
|
color: root.bar.foreground
|
||||||
|
font.family: root.bar.fontFamily
|
||||||
|
font.pixelSize: 11
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ethernet link speed / duplex.
|
||||||
|
Text {
|
||||||
|
visible: root.info.type === "ethernet" && !!root.info.speed
|
||||||
|
text: "Link"
|
||||||
|
color: Qt.darker(root.bar.foreground, 1.4)
|
||||||
|
font.family: root.bar.fontFamily
|
||||||
|
font.pixelSize: 11
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
visible: root.info.type === "ethernet" && !!root.info.speed
|
||||||
|
text: root.formatSpeed(root.info.speed || "") + (root.info.duplex ? " · " + root.info.duplex + " duplex" : "")
|
||||||
|
color: root.bar.foreground
|
||||||
|
font.family: root.bar.fontFamily
|
||||||
|
font.pixelSize: 11
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wi-Fi signal.
|
||||||
|
Text {
|
||||||
|
visible: root.info.type === "wifi" && !!root.info.signal_dbm
|
||||||
|
text: "Signal"
|
||||||
|
color: Qt.darker(root.bar.foreground, 1.4)
|
||||||
|
font.family: root.bar.fontFamily
|
||||||
|
font.pixelSize: 11
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
visible: root.info.type === "wifi" && !!root.info.signal_dbm
|
||||||
|
text: (root.info.signal_dbm || "") + " dBm"
|
||||||
|
color: root.bar.foreground
|
||||||
|
font.family: root.bar.fontFamily
|
||||||
|
font.pixelSize: 11
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wi-Fi tx bitrate.
|
||||||
|
Text {
|
||||||
|
visible: root.info.type === "wifi" && !!root.info.bitrate
|
||||||
|
text: "Link rate"
|
||||||
|
color: Qt.darker(root.bar.foreground, 1.4)
|
||||||
|
font.family: root.bar.fontFamily
|
||||||
|
font.pixelSize: 11
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
visible: root.info.type === "wifi" && !!root.info.bitrate
|
||||||
|
text: root.info.bitrate || ""
|
||||||
|
color: root.bar.foreground
|
||||||
|
font.family: root.bar.fontFamily
|
||||||
|
font.pixelSize: 11
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wi-Fi networks (only if a Wi-Fi station is available).
|
||||||
|
Rectangle {
|
||||||
|
visible: root.wifiStationAvailable
|
||||||
|
width: parent.width
|
||||||
|
height: 1
|
||||||
|
color: Qt.rgba(root.bar.foreground.r, root.bar.foreground.g, root.bar.foreground.b, 0.12)
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
visible: root.wifiStationAvailable
|
||||||
|
text: root.scanning ? "Scanning Wi-Fi…" : "Wi-Fi networks"
|
||||||
|
color: Qt.darker(root.bar.foreground, 1.4)
|
||||||
|
font.family: root.bar.fontFamily
|
||||||
|
font.pixelSize: 10
|
||||||
|
font.bold: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: root.wifiStationAvailable ? root.wifiNetworks.slice(0, 6) : []
|
||||||
|
|
||||||
|
Common.PillButton {
|
||||||
|
required property var modelData
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
iconText: root.wifiIconFor(modelData.signal)
|
||||||
|
text: (modelData.ssid || "Hidden") + (modelData.security ? " · " + modelData.security : "")
|
||||||
|
foreground: root.bar.foreground
|
||||||
|
horizontalPadding: 10
|
||||||
|
verticalPadding: 6
|
||||||
|
active: modelData.connected
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
if (modelData.connected) return
|
||||||
|
if (actionProc.running) return
|
||||||
|
if (Qt.platform.os) { /* keep linter happy */ }
|
||||||
|
// Prefer nmcli; fall back to iwctl. Both work as one-shot connects
|
||||||
|
// for open or already-known networks; secured networks pop the TUI.
|
||||||
|
actionProc.command = ["bash", "-c",
|
||||||
|
"if command -v nmcli >/dev/null; then" +
|
||||||
|
" nmcli device wifi connect " + root.bar.shellQuote(modelData.ssid) +
|
||||||
|
"; else" +
|
||||||
|
" " + root.bar.omarchyPath + "/bin/omarchy-launch-wifi" +
|
||||||
|
"; fi"]
|
||||||
|
actionProc.running = true
|
||||||
|
root.popupOpen = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Common.PillButton {
|
Common.PillButton {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconText: ""
|
iconText: ""
|
||||||
text: "Open Wi-Fi manager"
|
text: "Open Wi-Fi manager (Impala)"
|
||||||
foreground: root.bar.foreground
|
foreground: root.bar.foreground
|
||||||
horizontalPadding: 10
|
horizontalPadding: 10
|
||||||
verticalPadding: 6
|
verticalPadding: 6
|
||||||
|
|||||||
Reference in New Issue
Block a user