mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-05 21:15:38 -05:00
1100 lines
38 KiB
QML
1100 lines
38 KiB
QML
pragma Singleton
|
|
|
|
pragma ComponentBehavior: Bound
|
|
|
|
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Io
|
|
import qs.Common
|
|
|
|
Singleton {
|
|
id: root
|
|
|
|
property int refCount: 0
|
|
property bool isActive: false
|
|
property string networkStatus: "disconnected"
|
|
property string primaryConnection: ""
|
|
|
|
property string ethernetIP: ""
|
|
property string ethernetInterface: ""
|
|
property bool ethernetConnected: false
|
|
property string ethernetConnectionUuid: ""
|
|
|
|
property var wiredConnections: []
|
|
|
|
property string wifiIP: ""
|
|
property string wifiInterface: ""
|
|
property bool wifiConnected: false
|
|
property bool wifiEnabled: true
|
|
property string wifiConnectionUuid: ""
|
|
property string wifiDevicePath: ""
|
|
property string activeAccessPointPath: ""
|
|
|
|
property string currentWifiSSID: ""
|
|
property int wifiSignalStrength: 0
|
|
property var wifiNetworks: []
|
|
property var savedConnections: []
|
|
property var ssidToConnectionName: {
|
|
|
|
}
|
|
property var wifiSignalIcon: {
|
|
if (!wifiConnected || networkStatus !== "wifi") {
|
|
return "wifi_off"
|
|
}
|
|
if (wifiSignalStrength >= 50) {
|
|
return "wifi"
|
|
}
|
|
if (wifiSignalStrength >= 25) {
|
|
return "wifi_2_bar"
|
|
}
|
|
return "wifi_1_bar"
|
|
}
|
|
|
|
property string userPreference: "auto" // "auto", "wifi", "ethernet"
|
|
property bool isConnecting: false
|
|
property string connectingSSID: ""
|
|
property string connectionError: ""
|
|
|
|
property bool isScanning: false
|
|
property bool autoScan: false
|
|
|
|
property bool wifiAvailable: true
|
|
property bool wifiToggling: false
|
|
property bool changingPreference: false
|
|
property string targetPreference: ""
|
|
property var savedWifiNetworks: []
|
|
property string connectionStatus: ""
|
|
property string lastConnectionError: ""
|
|
property bool passwordDialogShouldReopen: false
|
|
property bool autoRefreshEnabled: false
|
|
property string wifiPassword: ""
|
|
property string forgetSSID: ""
|
|
|
|
readonly property var lowPriorityCmd: ["nice", "-n", "19", "ionice", "-c3"]
|
|
|
|
property string networkInfoSSID: ""
|
|
property string networkInfoDetails: ""
|
|
property bool networkInfoLoading: false
|
|
|
|
property string networkWiredInfoUUID: ""
|
|
property string networkWiredInfoDetails: ""
|
|
property bool networkWiredInfoLoading: false
|
|
|
|
signal networksUpdated
|
|
signal connectionChanged
|
|
|
|
function splitNmcliFields(line) {
|
|
const parts = []
|
|
let cur = ""
|
|
let escape = false
|
|
for (var i = 0; i < line.length; i++) {
|
|
const ch = line[i]
|
|
if (escape) {
|
|
cur += ch
|
|
escape = false
|
|
} else if (ch === '\\') {
|
|
escape = true
|
|
} else if (ch === ':') {
|
|
parts.push(cur)
|
|
cur = ""
|
|
} else {
|
|
cur += ch
|
|
}
|
|
}
|
|
parts.push(cur)
|
|
return parts
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
root.userPreference = SettingsData.networkPreference
|
|
}
|
|
|
|
Component.onDestruction: {
|
|
nmStateMonitor.running = false
|
|
}
|
|
|
|
function activate() {
|
|
if (!isActive) {
|
|
isActive = true
|
|
console.log("LegacyNetworkService: Activating...")
|
|
initializeDBusMonitors()
|
|
}
|
|
}
|
|
|
|
function addRef() {
|
|
refCount++
|
|
if (refCount === 1) {
|
|
startAutoScan()
|
|
}
|
|
}
|
|
|
|
function removeRef() {
|
|
refCount = Math.max(0, refCount - 1)
|
|
if (refCount === 0) {
|
|
stopAutoScan()
|
|
}
|
|
}
|
|
|
|
function initializeDBusMonitors() {
|
|
nmStateMonitor.running = true
|
|
doRefreshNetworkState()
|
|
}
|
|
|
|
Process {
|
|
id: nmStateMonitor
|
|
command: lowPriorityCmd.concat(["gdbus", "monitor", "--system", "--dest", "org.freedesktop.NetworkManager"])
|
|
running: false
|
|
|
|
property var lastRefreshTime: 0
|
|
property int minRefreshInterval: 1000
|
|
|
|
stdout: SplitParser {
|
|
splitMarker: "\n"
|
|
onRead: line => {
|
|
const now = Date.now()
|
|
if (line.includes("PropertiesChanged") && line.includes("org.freedesktop.NetworkManager.AccessPoint")) {
|
|
if (line.includes("'Strength'") && root.activeAccessPointPath && line.includes(root.activeAccessPointPath)) {
|
|
parseSignalStrengthFromDbus(line)
|
|
}
|
|
return
|
|
}
|
|
|
|
if (line.includes("StateChanged") ||
|
|
line.includes("PrimaryConnectionChanged") ||
|
|
line.includes("WirelessEnabled") ||
|
|
(line.includes("ActiveConnection") && line.includes("State"))) {
|
|
|
|
if (now - nmStateMonitor.lastRefreshTime > nmStateMonitor.minRefreshInterval) {
|
|
nmStateMonitor.lastRefreshTime = now
|
|
refreshNetworkState()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
onExited: exitCode => {
|
|
if (exitCode !== 0 && !restartTimer.running) {
|
|
console.warn("NetworkManager monitor failed, restarting in 5s")
|
|
restartTimer.start()
|
|
}
|
|
}
|
|
}
|
|
|
|
Timer {
|
|
id: restartTimer
|
|
interval: 5000
|
|
running: false
|
|
onTriggered: nmStateMonitor.running = true
|
|
}
|
|
|
|
Timer {
|
|
id: refreshDebounceTimer
|
|
interval: 100
|
|
running: false
|
|
onTriggered: doRefreshNetworkState()
|
|
}
|
|
|
|
function refreshNetworkState() {
|
|
refreshDebounceTimer.restart()
|
|
}
|
|
|
|
function parseSignalStrengthFromDbus(line) {
|
|
const strengthMatch = line.match(/'Strength': <byte (0x[0-9a-fA-F]+)>/)
|
|
if (strengthMatch) {
|
|
const hexValue = strengthMatch[1]
|
|
const strength = parseInt(hexValue, 16)
|
|
if (strength >= 0 && strength <= 100) {
|
|
root.wifiSignalStrength = strength
|
|
}
|
|
}
|
|
}
|
|
|
|
function doRefreshNetworkState() {
|
|
updatePrimaryConnection()
|
|
updateDeviceStates()
|
|
updateActiveConnections()
|
|
updateWifiState()
|
|
if (root.refCount > 0 && root.wifiEnabled) {
|
|
scanWifiNetworks()
|
|
}
|
|
}
|
|
|
|
function updatePrimaryConnection() {
|
|
primaryConnectionQuery.running = true
|
|
}
|
|
|
|
Process {
|
|
id: primaryConnectionQuery
|
|
command: lowPriorityCmd.concat(["gdbus", "call", "--system", "--dest", "org.freedesktop.NetworkManager", "--object-path", "/org/freedesktop/NetworkManager", "--method", "org.freedesktop.DBus.Properties.Get", "org.freedesktop.NetworkManager", "PrimaryConnection"])
|
|
running: false
|
|
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
const match = text.match(/objectpath '([^']+)'/)
|
|
if (match && match[1] !== '/') {
|
|
root.primaryConnection = match[1]
|
|
getPrimaryConnectionType.running = true
|
|
} else {
|
|
root.primaryConnection = ""
|
|
root.networkStatus = "disconnected"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Process {
|
|
id: getPrimaryConnectionType
|
|
command: root.primaryConnection ? lowPriorityCmd.concat(["gdbus", "call", "--system", "--dest", "org.freedesktop.NetworkManager", "--object-path", root.primaryConnection, "--method", "org.freedesktop.DBus.Properties.Get", "org.freedesktop.NetworkManager.Connection.Active", "Type"]) : []
|
|
running: false
|
|
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
if (text.includes("802-3-ethernet")) {
|
|
root.networkStatus = "ethernet"
|
|
} else if (text.includes("802-11-wireless")) {
|
|
root.networkStatus = "wifi"
|
|
}
|
|
root.connectionChanged()
|
|
}
|
|
}
|
|
}
|
|
|
|
function updateDeviceStates() {
|
|
getEthernetDevice.running = true
|
|
getWifiDevice.running = true
|
|
}
|
|
|
|
Process {
|
|
id: getEthernetDevice
|
|
command: lowPriorityCmd.concat(["nmcli", "-t", "-f", "DEVICE,TYPE", "device"])
|
|
running: false
|
|
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
const lines = text.trim().split('\n')
|
|
let ethernetInterface = ""
|
|
|
|
for (const line of lines) {
|
|
const splitParts = line.split(':')
|
|
const device = splitParts[0]
|
|
const type = splitParts.length > 1 ? splitParts[1] : ""
|
|
if (type === "ethernet") {
|
|
ethernetInterface = device
|
|
break
|
|
}
|
|
}
|
|
|
|
if (ethernetInterface) {
|
|
root.ethernetInterface = ethernetInterface
|
|
getEthernetDevicePath.command = lowPriorityCmd.concat(["gdbus", "call", "--system", "--dest", "org.freedesktop.NetworkManager", "--object-path", "/org/freedesktop/NetworkManager", "--method", "org.freedesktop.NetworkManager.GetDeviceByIpIface", ethernetInterface])
|
|
getEthernetDevicePath.running = true
|
|
} else {
|
|
root.ethernetInterface = ""
|
|
root.ethernetConnected = false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Process {
|
|
id: getEthernetDevicePath
|
|
running: false
|
|
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
const match = text.match(/objectpath '([^']+)'/)
|
|
if (match && match[1] !== '/') {
|
|
checkEthernetState.command = lowPriorityCmd.concat(["gdbus", "call", "--system", "--dest", "org.freedesktop.NetworkManager", "--object-path", match[1], "--method", "org.freedesktop.DBus.Properties.Get", "org.freedesktop.NetworkManager.Device", "State"])
|
|
checkEthernetState.running = true
|
|
} else {
|
|
root.ethernetInterface = ""
|
|
root.ethernetConnected = false
|
|
}
|
|
}
|
|
}
|
|
|
|
onExited: exitCode => {
|
|
if (exitCode !== 0) {
|
|
root.ethernetInterface = ""
|
|
root.ethernetConnected = false
|
|
}
|
|
}
|
|
}
|
|
|
|
Process {
|
|
id: checkEthernetState
|
|
running: false
|
|
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
const isConnected = text.includes("uint32 100")
|
|
root.ethernetConnected = isConnected
|
|
if (isConnected) {
|
|
getEthernetIP.running = true
|
|
} else {
|
|
root.ethernetIP = ""
|
|
if (root.networkStatus === "ethernet") {
|
|
updatePrimaryConnection()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Process {
|
|
id: getEthernetIP
|
|
command: root.ethernetInterface ? lowPriorityCmd.concat(["ip", "-4", "addr", "show", root.ethernetInterface]) : []
|
|
running: false
|
|
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
const match = text.match(/inet (\d+\.\d+\.\d+\.\d+)/)
|
|
if (match) {
|
|
root.ethernetIP = match[1]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Process {
|
|
id: getWifiDevice
|
|
command: lowPriorityCmd.concat(["nmcli", "-t", "-f", "DEVICE,TYPE", "device"])
|
|
running: false
|
|
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
const lines = text.trim().split('\n')
|
|
let wifiInterface = ""
|
|
|
|
for (const line of lines) {
|
|
const splitParts = line.split(':')
|
|
const device = splitParts[0]
|
|
const type = splitParts.length > 1 ? splitParts[1] : ""
|
|
if (type === "wifi") {
|
|
wifiInterface = device
|
|
break
|
|
}
|
|
}
|
|
|
|
if (wifiInterface) {
|
|
root.wifiInterface = wifiInterface
|
|
getWifiDevicePath.command = lowPriorityCmd.concat(["gdbus", "call", "--system", "--dest", "org.freedesktop.NetworkManager", "--object-path", "/org/freedesktop/NetworkManager", "--method", "org.freedesktop.NetworkManager.GetDeviceByIpIface", wifiInterface])
|
|
getWifiDevicePath.running = true
|
|
} else {
|
|
root.wifiInterface = ""
|
|
root.wifiConnected = false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Process {
|
|
id: getWifiDevicePath
|
|
running: false
|
|
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
const match = text.match(/objectpath '([^']+)'/)
|
|
if (match && match[1] !== '/') {
|
|
root.wifiDevicePath = match[1]
|
|
checkWifiState.command = lowPriorityCmd.concat(["gdbus", "call", "--system", "--dest", "org.freedesktop.NetworkManager", "--object-path", match[1], "--method", "org.freedesktop.DBus.Properties.Get", "org.freedesktop.NetworkManager.Device", "State"])
|
|
checkWifiState.running = true
|
|
} else {
|
|
root.wifiInterface = ""
|
|
root.wifiConnected = false
|
|
root.wifiDevicePath = ""
|
|
root.activeAccessPointPath = ""
|
|
}
|
|
}
|
|
}
|
|
|
|
onExited: exitCode => {
|
|
if (exitCode !== 0) {
|
|
root.wifiInterface = ""
|
|
root.wifiConnected = false
|
|
}
|
|
}
|
|
}
|
|
|
|
Process {
|
|
id: checkWifiState
|
|
running: false
|
|
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
root.wifiConnected = text.includes("uint32 100")
|
|
if (root.wifiConnected) {
|
|
getWifiIP.running = true
|
|
getCurrentWifiInfo.running = true
|
|
getActiveAccessPoint.running = true
|
|
if (root.currentWifiSSID === "") {
|
|
if (root.wifiConnectionUuid) {
|
|
resolveWifiSSID.running = true
|
|
}
|
|
if (root.wifiInterface) {
|
|
resolveWifiSSIDFromDevice.running = true
|
|
}
|
|
}
|
|
} else {
|
|
root.wifiIP = ""
|
|
root.currentWifiSSID = ""
|
|
root.wifiSignalStrength = 0
|
|
root.activeAccessPointPath = ""
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Process {
|
|
id: getWifiIP
|
|
command: root.wifiInterface ? lowPriorityCmd.concat(["ip", "-4", "addr", "show", root.wifiInterface]) : []
|
|
running: false
|
|
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
const match = text.match(/inet (\d+\.\d+\.\d+\.\d+)/)
|
|
if (match) {
|
|
root.wifiIP = match[1]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Process {
|
|
id: getActiveAccessPoint
|
|
command: root.wifiDevicePath ? lowPriorityCmd.concat(["gdbus", "call", "--system", "--dest", "org.freedesktop.NetworkManager", "--object-path", root.wifiDevicePath, "--method", "org.freedesktop.DBus.Properties.Get", "org.freedesktop.NetworkManager.Device.Wireless", "ActiveAccessPoint"]) : []
|
|
running: false
|
|
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
const match = text.match(/objectpath '([^']+)'/)
|
|
if (match && match[1] !== '/') {
|
|
root.activeAccessPointPath = match[1]
|
|
} else {
|
|
root.activeAccessPointPath = ""
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Process {
|
|
id: getCurrentWifiInfo
|
|
command: root.wifiInterface ? lowPriorityCmd.concat(["nmcli", "-t", "-f", "ACTIVE,SIGNAL,SSID", "device", "wifi", "list", "ifname", root.wifiInterface, "--rescan", "no"]) : []
|
|
running: false
|
|
|
|
stdout: SplitParser {
|
|
splitMarker: "\n"
|
|
onRead: line => {
|
|
if (line.startsWith("yes:")) {
|
|
const rest = line.substring(4)
|
|
const parts = root.splitNmcliFields(rest)
|
|
if (parts.length >= 2) {
|
|
const signal = parseInt(parts[0])
|
|
console.log("Current WiFi signal strength:", signal)
|
|
root.wifiSignalStrength = isNaN(signal) ? 0 : signal
|
|
root.currentWifiSSID = parts[1]
|
|
console.log("Current WiFi SSID:", root.currentWifiSSID)
|
|
}
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function updateActiveConnections() {
|
|
getActiveConnections.running = true
|
|
}
|
|
|
|
Process {
|
|
id: getActiveConnections
|
|
command: lowPriorityCmd.concat(["nmcli", "-t", "-f", "UUID,TYPE,DEVICE,STATE", "connection", "show", "--active"])
|
|
running: false
|
|
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
const lines = text.trim().split('\n')
|
|
for (const line of lines) {
|
|
const parts = line.split(':')
|
|
if (parts.length >= 4) {
|
|
const uuid = parts[0]
|
|
const type = parts[1]
|
|
const device = parts[2]
|
|
const state = parts[3]
|
|
if (type === "802-3-ethernet" && state === "activated") {
|
|
root.ethernetConnectionUuid = uuid
|
|
} else if (type === "802-11-wireless" && state === "activated") {
|
|
root.wifiConnectionUuid = uuid
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Resolve SSID from active WiFi connection UUID when scans don't mark any row as ACTIVE.
|
|
Process {
|
|
id: resolveWifiSSID
|
|
command: root.wifiConnectionUuid ? lowPriorityCmd.concat(["nmcli", "-g", "802-11-wireless.ssid", "connection", "show", "uuid", root.wifiConnectionUuid]) : []
|
|
running: false
|
|
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
const ssid = text.trim()
|
|
if (ssid) {
|
|
root.currentWifiSSID = ssid
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fallback 2: Resolve SSID from device info (GENERAL.CONNECTION usually matches SSID for WiFi)
|
|
Process {
|
|
id: resolveWifiSSIDFromDevice
|
|
command: root.wifiInterface ? lowPriorityCmd.concat(["nmcli", "-t", "-f", "GENERAL.CONNECTION", "device", "show", root.wifiInterface]) : []
|
|
running: false
|
|
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
if (!root.currentWifiSSID) {
|
|
const name = text.trim()
|
|
if (name) {
|
|
root.currentWifiSSID = name
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function updateWifiState() {
|
|
checkWifiEnabled.running = true
|
|
}
|
|
|
|
Process {
|
|
id: checkWifiEnabled
|
|
command: lowPriorityCmd.concat(["gdbus", "call", "--system", "--dest", "org.freedesktop.NetworkManager", "--object-path", "/org/freedesktop/NetworkManager", "--method", "org.freedesktop.DBus.Properties.Get", "org.freedesktop.NetworkManager", "WirelessEnabled"])
|
|
running: false
|
|
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
root.wifiEnabled = text.includes("true")
|
|
root.wifiAvailable = true // Always available if we can check it
|
|
}
|
|
}
|
|
}
|
|
|
|
function scanWifi() {
|
|
if (root.isScanning || !root.wifiEnabled) {
|
|
return
|
|
}
|
|
|
|
root.isScanning = true
|
|
requestWifiScan.running = true
|
|
}
|
|
|
|
Process {
|
|
id: requestWifiScan
|
|
command: root.wifiInterface ? lowPriorityCmd.concat(["nmcli", "dev", "wifi", "rescan", "ifname", root.wifiInterface]) : []
|
|
running: false
|
|
|
|
onExited: exitCode => {
|
|
if (exitCode === 0) {
|
|
scanWifiNetworks()
|
|
} else {
|
|
console.warn("WiFi scan request failed")
|
|
root.isScanning = false
|
|
}
|
|
}
|
|
}
|
|
|
|
function scanWifiNetworks() {
|
|
if (!root.wifiInterface) {
|
|
root.isScanning = false
|
|
return
|
|
}
|
|
|
|
getWifiNetworks.running = true
|
|
getSavedConnections.running = true
|
|
}
|
|
|
|
Process {
|
|
id: getWifiNetworks
|
|
command: lowPriorityCmd.concat(["nmcli", "-t", "-f", "SSID,SIGNAL,SECURITY,BSSID", "dev", "wifi", "list", "ifname", root.wifiInterface])
|
|
running: false
|
|
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
const networks = []
|
|
const lines = text.trim().split('\n')
|
|
const seen = new Set()
|
|
|
|
for (const line of lines) {
|
|
const parts = root.splitNmcliFields(line)
|
|
if (parts.length >= 4 && parts[0]) {
|
|
const ssid = parts[0]
|
|
if (!seen.has(ssid)) {
|
|
seen.add(ssid)
|
|
const signal = parseInt(parts[1]) || 0
|
|
|
|
networks.push({
|
|
"ssid": ssid,
|
|
"signal": signal,
|
|
"secured": parts[2] !== "",
|
|
"bssid": parts[3],
|
|
"connected": ssid === root.currentWifiSSID,
|
|
"saved": false
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
networks.sort((a, b) => b.signal - a.signal)
|
|
root.wifiNetworks = networks
|
|
root.isScanning = false
|
|
root.networksUpdated()
|
|
}
|
|
}
|
|
}
|
|
|
|
Process {
|
|
id: getSavedConnections
|
|
command: lowPriorityCmd.concat(["bash", "-c", "nmcli -t -f NAME,TYPE connection show | grep ':802-11-wireless$' | cut -d: -f1 | while read name; do ssid=$(nmcli -g 802-11-wireless.ssid connection show \"$name\"); echo \"$ssid:$name\"; done"])
|
|
running: false
|
|
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
const saved = []
|
|
const mapping = {}
|
|
const lines = text.trim().split('\n')
|
|
|
|
for (const line of lines) {
|
|
const parts = line.trim().split(':')
|
|
if (parts.length >= 2) {
|
|
const ssid = parts[0]
|
|
const connectionName = parts[1]
|
|
if (ssid && ssid.length > 0 && connectionName && connectionName.length > 0) {
|
|
saved.push({
|
|
"ssid": ssid,
|
|
"saved": true
|
|
})
|
|
mapping[ssid] = connectionName
|
|
}
|
|
}
|
|
}
|
|
|
|
root.savedConnections = saved
|
|
root.savedWifiNetworks = saved
|
|
root.ssidToConnectionName = mapping
|
|
|
|
const updated = [...root.wifiNetworks]
|
|
for (const network of updated) {
|
|
network.saved = saved.some(s => s.ssid === network.ssid)
|
|
}
|
|
root.wifiNetworks = updated
|
|
}
|
|
}
|
|
}
|
|
|
|
function connectToWifi(ssid, password = "", username = "") {
|
|
if (root.isConnecting) {
|
|
return
|
|
}
|
|
|
|
root.isConnecting = true
|
|
root.connectingSSID = ssid
|
|
root.connectionError = ""
|
|
root.connectionStatus = "connecting"
|
|
|
|
if (!password && root.ssidToConnectionName[ssid]) {
|
|
const connectionName = root.ssidToConnectionName[ssid]
|
|
wifiConnector.command = lowPriorityCmd.concat(["nmcli", "connection", "up", connectionName])
|
|
} else if (password) {
|
|
wifiConnector.command = lowPriorityCmd.concat(["nmcli", "dev", "wifi", "connect", ssid, "password", password])
|
|
} else {
|
|
wifiConnector.command = lowPriorityCmd.concat(["nmcli", "dev", "wifi", "connect", ssid])
|
|
}
|
|
wifiConnector.running = true
|
|
}
|
|
|
|
Process {
|
|
id: wifiConnector
|
|
running: false
|
|
|
|
property bool connectionSucceeded: false
|
|
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
if (text.includes("successfully")) {
|
|
wifiConnector.connectionSucceeded = true
|
|
ToastService.showInfo(`Connected to ${root.connectingSSID}`)
|
|
root.connectionError = ""
|
|
root.connectionStatus = "connected"
|
|
|
|
if (root.userPreference === "wifi" || root.userPreference === "auto") {
|
|
setConnectionPriority("wifi")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
stderr: StdioCollector {
|
|
onStreamFinished: {
|
|
root.connectionError = text
|
|
root.lastConnectionError = text
|
|
if (!wifiConnector.connectionSucceeded && text.trim() !== "") {
|
|
if (text.includes("password") || text.includes("authentication")) {
|
|
root.connectionStatus = "invalid_password"
|
|
root.passwordDialogShouldReopen = true
|
|
} else {
|
|
root.connectionStatus = "failed"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
onExited: exitCode => {
|
|
if (exitCode === 0 || wifiConnector.connectionSucceeded) {
|
|
if (!wifiConnector.connectionSucceeded) {
|
|
ToastService.showInfo(`Connected to ${root.connectingSSID}`)
|
|
root.connectionStatus = "connected"
|
|
}
|
|
} else {
|
|
if (root.connectionStatus === "") {
|
|
root.connectionStatus = "failed"
|
|
}
|
|
if (root.connectionStatus === "invalid_password") {
|
|
ToastService.showError(`Invalid password for ${root.connectingSSID}`)
|
|
} else {
|
|
ToastService.showError(`Failed to connect to ${root.connectingSSID}`)
|
|
}
|
|
}
|
|
|
|
wifiConnector.connectionSucceeded = false
|
|
root.isConnecting = false
|
|
root.connectingSSID = ""
|
|
refreshNetworkState()
|
|
}
|
|
}
|
|
|
|
function disconnectWifi() {
|
|
if (!root.wifiInterface) {
|
|
return
|
|
}
|
|
|
|
wifiDisconnector.command = lowPriorityCmd.concat(["nmcli", "dev", "disconnect", root.wifiInterface])
|
|
wifiDisconnector.running = true
|
|
}
|
|
|
|
Process {
|
|
id: wifiDisconnector
|
|
running: false
|
|
|
|
onExited: exitCode => {
|
|
if (exitCode === 0) {
|
|
ToastService.showInfo("Disconnected from WiFi")
|
|
root.currentWifiSSID = ""
|
|
root.connectionStatus = ""
|
|
}
|
|
refreshNetworkState()
|
|
}
|
|
}
|
|
|
|
function forgetWifiNetwork(ssid) {
|
|
root.forgetSSID = ssid
|
|
const connectionName = root.ssidToConnectionName[ssid] || ssid
|
|
networkForgetter.command = lowPriorityCmd.concat(["nmcli", "connection", "delete", connectionName])
|
|
networkForgetter.running = true
|
|
}
|
|
|
|
Process {
|
|
id: networkForgetter
|
|
running: false
|
|
|
|
onExited: exitCode => {
|
|
if (exitCode === 0) {
|
|
ToastService.showInfo(`Forgot network ${root.forgetSSID}`)
|
|
|
|
root.savedConnections = root.savedConnections.filter(s => s.ssid !== root.forgetSSID)
|
|
root.savedWifiNetworks = root.savedWifiNetworks.filter(s => s.ssid !== root.forgetSSID)
|
|
|
|
const updated = [...root.wifiNetworks]
|
|
for (const network of updated) {
|
|
if (network.ssid === root.forgetSSID) {
|
|
network.saved = false
|
|
if (network.connected) {
|
|
network.connected = false
|
|
root.currentWifiSSID = ""
|
|
}
|
|
}
|
|
}
|
|
root.wifiNetworks = updated
|
|
root.networksUpdated()
|
|
refreshNetworkState()
|
|
}
|
|
root.forgetSSID = ""
|
|
}
|
|
}
|
|
|
|
function toggleWifiRadio() {
|
|
if (root.wifiToggling) {
|
|
return
|
|
}
|
|
|
|
root.wifiToggling = true
|
|
const targetState = root.wifiEnabled ? "off" : "on"
|
|
wifiRadioToggler.targetState = targetState
|
|
wifiRadioToggler.command = lowPriorityCmd.concat(["nmcli", "radio", "wifi", targetState])
|
|
wifiRadioToggler.running = true
|
|
}
|
|
|
|
Process {
|
|
id: wifiRadioToggler
|
|
running: false
|
|
|
|
property string targetState: ""
|
|
|
|
onExited: exitCode => {
|
|
root.wifiToggling = false
|
|
if (exitCode === 0) {
|
|
ToastService.showInfo(targetState === "on" ? "WiFi enabled" : "WiFi disabled")
|
|
}
|
|
refreshNetworkState()
|
|
}
|
|
}
|
|
|
|
function setNetworkPreference(preference) {
|
|
root.userPreference = preference
|
|
root.changingPreference = true
|
|
root.targetPreference = preference
|
|
SettingsData.setNetworkPreference(preference)
|
|
|
|
if (preference === "wifi") {
|
|
setConnectionPriority("wifi")
|
|
} else if (preference === "ethernet") {
|
|
setConnectionPriority("ethernet")
|
|
}
|
|
}
|
|
|
|
function setConnectionPriority(type) {
|
|
if (type === "wifi") {
|
|
setRouteMetrics.command = lowPriorityCmd.concat(["bash", "-c", "nmcli -t -f NAME,TYPE connection show | grep 802-11-wireless | cut -d: -f1 | " + "xargs -I {} bash -c 'nmcli connection modify \"{}\" ipv4.route-metric 50 ipv6.route-metric 50'; " + "nmcli -t -f NAME,TYPE connection show | grep 802-3-ethernet | cut -d: -f1 | " + "xargs -I {} bash -c 'nmcli connection modify \"{}\" ipv4.route-metric 100 ipv6.route-metric 100'"])
|
|
} else if (type === "ethernet") {
|
|
setRouteMetrics.command = lowPriorityCmd.concat(["bash", "-c", "nmcli -t -f NAME,TYPE connection show | grep 802-3-ethernet | cut -d: -f1 | " + "xargs -I {} bash -c 'nmcli connection modify \"{}\" ipv4.route-metric 50 ipv6.route-metric 50'; " + "nmcli -t -f NAME,TYPE connection show | grep 802-11-wireless | cut -d: -f1 | " + "xargs -I {} bash -c 'nmcli connection modify \"{}\" ipv4.route-metric 100 ipv6.route-metric 100'"])
|
|
}
|
|
setRouteMetrics.running = true
|
|
}
|
|
|
|
Process {
|
|
id: setRouteMetrics
|
|
running: false
|
|
|
|
onExited: exitCode => {
|
|
console.log("Set route metrics process exited with code:", exitCode)
|
|
if (exitCode === 0) {
|
|
restartConnections.running = true
|
|
}
|
|
}
|
|
}
|
|
|
|
Process {
|
|
id: restartConnections
|
|
command: lowPriorityCmd.concat(["bash", "-c", "nmcli -t -f UUID,TYPE connection show --active | " + "grep -E '802-11-wireless|802-3-ethernet' | cut -d: -f1 | " + "xargs -I {} sh -c 'nmcli connection down {} && nmcli connection up {}'"])
|
|
running: false
|
|
|
|
onExited: {
|
|
root.changingPreference = false
|
|
root.targetPreference = ""
|
|
refreshNetworkState()
|
|
}
|
|
}
|
|
|
|
function startAutoScan() {
|
|
root.autoScan = true
|
|
root.autoRefreshEnabled = true
|
|
if (root.wifiEnabled) {
|
|
scanWifi()
|
|
}
|
|
}
|
|
|
|
function stopAutoScan() {
|
|
root.autoScan = false
|
|
root.autoRefreshEnabled = false
|
|
}
|
|
|
|
function fetchNetworkInfo(ssid) {
|
|
root.networkInfoSSID = ssid
|
|
root.networkInfoLoading = true
|
|
root.networkInfoDetails = "Loading network information..."
|
|
wifiInfoFetcher.running = true
|
|
}
|
|
|
|
Process {
|
|
id: wifiInfoFetcher
|
|
command: lowPriorityCmd.concat(["nmcli", "-t", "-f", "SSID,SIGNAL,SECURITY,FREQ,RATE,MODE,CHAN,WPA-FLAGS,RSN-FLAGS,ACTIVE,BSSID", "dev", "wifi", "list"])
|
|
running: false
|
|
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
let details = ""
|
|
if (text.trim()) {
|
|
const lines = text.trim().split('\n')
|
|
const bands = []
|
|
|
|
for (const line of lines) {
|
|
const parts = line.split(':')
|
|
if (parts.length >= 11 && parts[0] === root.networkInfoSSID) {
|
|
const signal = parts[1] || "0"
|
|
const security = parts[2] || "Open"
|
|
const freq = parts[3] || "Unknown"
|
|
const rate = parts[4] || "Unknown"
|
|
const channel = parts[6] || "Unknown"
|
|
const isActive = parts[9] === "yes"
|
|
let colonCount = 0
|
|
let bssidStart = -1
|
|
for (var i = 0; i < line.length; i++) {
|
|
if (line[i] === ':') {
|
|
colonCount++
|
|
if (colonCount === 10) {
|
|
bssidStart = i + 1
|
|
break
|
|
}
|
|
}
|
|
}
|
|
const bssid = bssidStart >= 0 ? line.substring(bssidStart).replace(/\\:/g, ":") : ""
|
|
|
|
let band = "Unknown"
|
|
const freqNum = parseInt(freq)
|
|
if (freqNum >= 2400 && freqNum <= 2500) {
|
|
band = "2.4 GHz"
|
|
} else if (freqNum >= 5000 && freqNum <= 6000) {
|
|
band = "5 GHz"
|
|
} else if (freqNum >= 6000) {
|
|
band = "6 GHz"
|
|
}
|
|
|
|
bands.push({
|
|
"band": band,
|
|
"freq": freq,
|
|
"channel": channel,
|
|
"signal": signal,
|
|
"rate": rate,
|
|
"security": security,
|
|
"isActive": isActive,
|
|
"bssid": bssid
|
|
})
|
|
}
|
|
}
|
|
|
|
if (bands.length > 0) {
|
|
bands.sort((a, b) => {
|
|
if (a.isActive && !b.isActive) {
|
|
return -1
|
|
}
|
|
if (!a.isActive && b.isActive) {
|
|
return 1
|
|
}
|
|
return parseInt(b.signal) - parseInt(a.signal)
|
|
})
|
|
|
|
for (var i = 0; i < bands.length; i++) {
|
|
const b = bands[i]
|
|
if (b.isActive) {
|
|
details += "● " + b.band + " (Connected) - " + b.signal + "%\\n"
|
|
} else {
|
|
details += " " + b.band + " - " + b.signal + "%\\n"
|
|
}
|
|
details += " Channel " + b.channel + " (" + b.freq + " MHz) • " + b.rate + " Mbit/s\\n"
|
|
details += " " + b.bssid
|
|
if (i < bands.length - 1) {
|
|
details += "\\n\\n"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (details === "") {
|
|
details = "Network information not found or network not available."
|
|
}
|
|
|
|
root.networkInfoDetails = details
|
|
root.networkInfoLoading = false
|
|
}
|
|
}
|
|
|
|
onExited: exitCode => {
|
|
root.networkInfoLoading = false
|
|
if (exitCode !== 0) {
|
|
root.networkInfoDetails = "Failed to fetch network information"
|
|
}
|
|
}
|
|
}
|
|
|
|
function enableWifiDevice() {
|
|
wifiDeviceEnabler.running = true
|
|
}
|
|
|
|
Process {
|
|
id: wifiDeviceEnabler
|
|
command: lowPriorityCmd.concat(["sh", "-c", "WIFI_DEV=$(nmcli -t -f DEVICE,TYPE device | grep wifi | cut -d: -f1 | head -1); if [ -n \"$WIFI_DEV\" ]; then nmcli device connect \"$WIFI_DEV\"; else echo \"No WiFi device found\"; exit 1; fi"])
|
|
running: false
|
|
|
|
onExited: exitCode => {
|
|
if (exitCode === 0) {
|
|
ToastService.showInfo("WiFi enabled")
|
|
} else {
|
|
ToastService.showError("Failed to enable WiFi")
|
|
}
|
|
refreshNetworkState()
|
|
}
|
|
}
|
|
|
|
function connectToWifiAndSetPreference(ssid, password) {
|
|
connectToWifi(ssid, password)
|
|
setNetworkPreference("wifi")
|
|
}
|
|
|
|
function toggleNetworkConnection(type) {
|
|
if (type === "ethernet") {
|
|
if (root.networkStatus === "ethernet") {
|
|
ethernetDisconnector.running = true
|
|
} else {
|
|
ethernetConnector.running = true
|
|
}
|
|
}
|
|
}
|
|
|
|
Process {
|
|
id: ethernetDisconnector
|
|
command: lowPriorityCmd.concat(["sh", "-c", "nmcli device disconnect $(nmcli -t -f DEVICE,TYPE device | grep ethernet | cut -d: -f1 | head -1)"])
|
|
running: false
|
|
|
|
onExited: function (exitCode) {
|
|
refreshNetworkState()
|
|
}
|
|
}
|
|
|
|
Process {
|
|
id: ethernetConnector
|
|
command: lowPriorityCmd.concat(["sh", "-c", "ETH_DEV=$(nmcli -t -f DEVICE,TYPE device | grep ethernet | cut -d: -f1 | head -1); if [ -n \"$ETH_DEV\" ]; then nmcli device connect \"$ETH_DEV\"; else echo \"No ethernet device found\"; exit 1; fi"])
|
|
running: false
|
|
|
|
onExited: function (exitCode) {
|
|
refreshNetworkState()
|
|
}
|
|
}
|
|
|
|
function getNetworkInfo(ssid) {
|
|
const network = root.wifiNetworks.find(n => n.ssid === ssid)
|
|
if (!network) {
|
|
return null
|
|
}
|
|
|
|
return {
|
|
"ssid": network.ssid,
|
|
"signal": network.signal,
|
|
"secured": network.secured,
|
|
"saved": network.saved,
|
|
"connected": network.connected,
|
|
"bssid": network.bssid
|
|
}
|
|
}
|
|
} |