nova-shell/modules/Network.qml

110 lines
3.8 KiB
QML

import QtQuick
import Quickshell
import Quickshell.Io
import "." as M
M.BarSection {
id: root
spacing: M.Theme.moduleSpacing
tooltip: ""
property string ifname: ""
property string essid: ""
property string state: "disconnected"
property string ipAddr: ""
property string signal: ""
Process {
id: proc
running: true
command: ["sh", "-c", "line=$(nmcli -t -f NAME,TYPE,DEVICE connection show --active 2>/dev/null | head -1); if [ -z \"$line\" ]; then dev=$(nmcli -t -f DEVICE,STATE device 2>/dev/null | grep ':connected' | grep -v ':unmanaged\\|:unavailable\\|:disconnected\\|:connecting' | head -1 | cut -d: -f1); [ -n \"$dev\" ] && line=\"linked:linked:$dev\"; fi; [ -z \"$line\" ] && exit 0; echo \"$line\"; dev=$(echo \"$line\" | cut -d: -f3); ip=$(nmcli -t -f IP4.ADDRESS device show \"$dev\" 2>/dev/null | head -1 | cut -d: -f2); echo \"ip:${ip:-}\"; sig=$(nmcli -t -f GENERAL.SIGNAL device show \"$dev\" 2>/dev/null | head -1 | cut -d: -f2); echo \"sig:${sig:-}\""]
stdout: StdioCollector {
onStreamFinished: {
const lines = text.trim().split("\n");
if (!lines[0]) {
root.state = "disconnected";
root.essid = "";
root.ifname = "";
root.ipAddr = "";
root.signal = "";
return;
}
const parts = lines[0].split(":");
root.essid = parts[0] || "";
root.ifname = parts[2] || "";
if ((parts[1] || "").includes("wireless"))
root.state = "wifi";
else if (parts[0] === "linked")
root.state = "linked";
else
root.state = "eth";
// Parse extra info lines
root.ipAddr = "";
root.signal = "";
for (let i = 1; i < lines.length; i++) {
if (lines[i].startsWith("ip:"))
root.ipAddr = lines[i].slice(3);
else if (lines[i].startsWith("sig:"))
root.signal = lines[i].slice(4);
}
}
}
}
// Event-driven: re-poll on any network change
Process {
id: monitor
running: true
command: ["nmcli", "monitor"]
stdout: SplitParser {
splitMarker: "\n"
onRead: _debounce.restart()
}
}
Timer {
id: _debounce
interval: 300
onTriggered: {
proc.running = true;
networkMenu.triggerRefresh();
}
}
// Fallback poll
Timer {
interval: 60000
running: true
repeat: true
onTriggered: proc.running = true
}
M.BarIcon {
icon: {
if (root.state === "wifi")
return "\uF1EB";
if (root.state === "eth")
return "\uDB80\uDE00";
if (root.state === "linked")
return "\uDB85\uDE16";
return "\uDB82\uDCFD";
}
color: root.state === "disconnected" ? M.Theme.base08 : root.accentColor
anchors.verticalCenter: parent.verticalCenter
}
M.BarLabel {
visible: root.state === "wifi"
label: root.essid
color: root.state === "disconnected" ? M.Theme.base08 : root.accentColor
anchors.verticalCenter: parent.verticalCenter
}
required property var bar
readonly property bool _anyHover: root._hovered || networkMenu.panelHovered || networkMenu._busy
M.NetworkMenu {
id: networkMenu
showPanel: root._anyHover
screen: QsWindow.window?.screen ?? null
anchorItem: root
accentColor: root.accentColor
}
}