| @@ -8,7 +8,9 @@ Singleton { |
| 8 | 8 | | id: root |
| 9 | 9 | | |
| 10 | 10 | | property bool active: false // NetPage sets this while visible (faster polling + rescan) |
| 11 | | − | property bool wired: false |
| 11 | + | property var wiredDevs: [] // [{dev, name, ip, usb}] connected ethernet-type devices (incl. USB tethering) |
| 12 | + | readonly property bool wired: wiredDevs.length > 0 |
| 13 | + | readonly property string wiredIcon: wiredDevs.length > 0 && wiredDevs[0].usb ? Theme.iPhone : Theme.iEthernet |
| 12 | 14 | | property bool wifiEnabled: true |
| 13 | 15 | | property string wifiDevice: "" |
| 14 | 16 | | property var raw: [] // [{inUse, ssid, signal, security}] |
| @@ -46,6 +48,34 @@ Singleton { |
| 46 | 48 | | return out |
| 47 | 49 | | } |
| 48 | 50 | | |
| 51 | + | // `nmcli device show` output (terse): one block per device, blank line between. |
| 52 | + | // Android USB tethering (and USB ethernet dongles) show up as type "ethernet". |
| 53 | + | function parseShow(text) { |
| 54 | + | var devs = [], cur = null, lines = text.split("\n") |
| 55 | + | for (var i = 0; i < lines.length; i++) { |
| 56 | + | if (lines[i] === "") continue |
| 57 | + | var f = parseTerse(lines[i]), key = f[0], val = f.slice(1).join(":") |
| 58 | + | if (key === "GENERAL.DEVICE") { cur = { dev: val, type: "", state: "", name: "", ip: "" }; devs.push(cur) } |
| 59 | + | else if (cur === null) continue |
| 60 | + | else if (key === "GENERAL.TYPE") cur.type = val |
| 61 | + | else if (key === "GENERAL.STATE") cur.state = val |
| 62 | + | else if (key === "GENERAL.CONNECTION") cur.name = val |
| 63 | + | else if (key.indexOf("IP4.ADDRESS") === 0 && cur.ip === "") cur.ip = val |
| 64 | + | } |
| 65 | + | var wired = [] |
| 66 | + | for (var j = 0; j < devs.length; j++) { |
| 67 | + | var d = devs[j] |
| 68 | + | if (d.type === "wifi") wifiDevice = d.dev |
| 69 | + | var up = d.state.indexOf("connected") >= 0 && d.state.indexOf("disconnected") < 0 |
| 70 | + | if (d.type === "ethernet" && up) |
| 71 | + | wired.push({ |
| 72 | + | dev: d.dev, name: d.name !== "" ? d.name : d.dev, ip: d.ip, |
| 73 | + | usb: /^usb|^enx|u\d+(c\d+)?(i\d+)?$/.test(d.dev) |
| 74 | + | }) |
| 75 | + | } |
| 76 | + | wiredDevs = wired |
| 77 | + | } |
| 78 | + | |
| 49 | 79 | | function build(list, saved) { |
| 50 | 80 | | var out = [] |
| 51 | 81 | | for (var i = 0; i < list.length; i++) { |
| @@ -123,6 +153,7 @@ Singleton { |
| 123 | 153 | | } |
| 124 | 154 | | } |
| 125 | 155 | | |
| 156 | + | function disconnectDev(dev) { run(["device", "disconnect", dev]) } |
| 126 | 157 | | function disconnect() { if (wifiDevice !== "") run(["device", "disconnect", wifiDevice]) } |
| 127 | 158 | | function forget(ssid) { run(["connection", "delete", "id", ssid]) } |
| 128 | 159 | | function setWifi(on) { run(["radio", "wifi", on ? "on" : "off"]) } |
| @@ -156,19 +187,8 @@ Singleton { |
| 156 | 187 | | |
| 157 | 188 | | Process { |
| 158 | 189 | | id: devProc |
| 159 | | − | command: ["nmcli", "-t", "-f", "DEVICE,TYPE,STATE", "device"] |
| 160 | | − | stdout: StdioCollector { |
| 161 | | − | onStreamFinished: { |
| 162 | | − | var lines = text.split("\n"), wired = false |
| 163 | | − | for (var i = 0; i < lines.length; i++) { |
| 164 | | − | var f = root.parseTerse(lines[i]) |
| 165 | | − | if (f.length < 3) continue |
| 166 | | − | if (f[1] === "wifi") root.wifiDevice = f[0] |
| 167 | | − | if (f[1] === "ethernet" && f[2] === "connected") wired = true |
| 168 | | − | } |
| 169 | | − | root.wired = wired |
| 170 | | − | } |
| 171 | | − | } |
| 190 | + | command: ["nmcli", "-t", "-f", "GENERAL.DEVICE,GENERAL.TYPE,GENERAL.STATE,GENERAL.CONNECTION,IP4.ADDRESS", "device", "show"] |
| 191 | + | stdout: StdioCollector { onStreamFinished: root.parseShow(text) } |
| 172 | 192 | | } |
| 173 | 193 | | |
| 174 | 194 | | Process { |