1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-10 23:42:51 -05:00
Files
DankMaterialShell/Services/NetworkService.qml
2025-08-13 14:06:12 -04:00

971 lines
33 KiB
QML

pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import Quickshell.Io
import qs.Common
Singleton {
id: root
// Core network state
property int refCount: 0
property string networkStatus: "disconnected" // "ethernet", "wifi", "disconnected"
property string primaryConnection: "" // Active connection UUID
// Ethernet properties
property string ethernetIP: ""
property string ethernetInterface: ""
property bool ethernetConnected: false
property string ethernetConnectionUuid: ""
// WiFi properties
property string wifiIP: ""
property string wifiInterface: ""
property bool wifiConnected: false
property bool wifiEnabled: true
property string wifiConnectionUuid: ""
// WiFi details
property string currentWifiSSID: ""
property int wifiSignalStrength: 0
property var wifiNetworks: []
property var savedConnections: []
// Connection management
property string userPreference: "auto" // "auto", "wifi", "ethernet"
property bool isConnecting: false
property string connectingSSID: ""
property string connectionError: ""
// Scanning
property bool isScanning: false
property bool autoScan: false
// Legacy compatibility properties
property bool wifiAvailable: true
property bool wifiToggling: false
property bool changingPreference: false
property string targetPreference: ""
property string wifiSignalStrengthStr: "excellent"
property var savedWifiNetworks: []
property string connectionStatus: ""
property string lastConnectionError: ""
property bool passwordDialogShouldReopen: false
property bool autoRefreshEnabled: false
property string wifiPassword: ""
property string forgetSSID: ""
// Network info properties
property string networkInfoSSID: ""
property string networkInfoDetails: ""
property bool networkInfoLoading: false
signal networksUpdated
signal connectionChanged
Component.onCompleted: {
root.userPreference = SettingsData.networkPreference
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
refreshNetworkState()
}
Process {
id: nmStateMonitor
command: ["gdbus", "monitor", "--system", "--dest", "org.freedesktop.NetworkManager"]
running: false
stdout: SplitParser {
splitMarker: "\n"
onRead: line => {
if (line.includes("StateChanged") ||
line.includes("PrimaryConnectionChanged") ||
line.includes("WirelessEnabled") ||
line.includes("ActiveConnection")) {
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
}
function refreshNetworkState() {
updatePrimaryConnection()
updateDeviceStates()
updateActiveConnections()
updateWifiState()
if (root.refCount > 0 && root.wifiEnabled) {
scanWifiNetworks()
}
}
function updatePrimaryConnection() {
primaryConnectionQuery.running = true
}
Process {
id: primaryConnectionQuery
command: ["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 ?
["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: ["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 [device, type] = line.split(':')
if (type === "ethernet") {
ethernetInterface = device
break
}
}
if (ethernetInterface) {
root.ethernetInterface = ethernetInterface
getEthernetDevicePath.command = ["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 = ["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 ?
["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: ["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 [device, type] = line.split(':')
if (type === "wifi") {
wifiInterface = device
break
}
}
if (wifiInterface) {
root.wifiInterface = wifiInterface
getWifiDevicePath.command = ["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] !== '/') {
checkWifiState.command = ["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
}
}
}
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
} else {
root.wifiIP = ""
root.currentWifiSSID = ""
root.wifiSignalStrength = 0
}
}
}
}
Process {
id: getWifiIP
command: root.wifiInterface ?
["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: getCurrentWifiInfo
command: root.wifiInterface ?
["nmcli", "-t", "-f", "ACTIVE,SSID,SIGNAL", "dev", "wifi", "list", "ifname", root.wifiInterface] : []
running: false
stdout: SplitParser {
splitMarker: "\n"
onRead: line => {
if (line.startsWith("yes:")) {
const parts = line.substring(4).split(":")
if (parts.length >= 2) {
root.currentWifiSSID = parts[0]
root.wifiSignalStrength = parseInt(parts[1]) || 0
if (root.wifiSignalStrength >= 75) {
root.wifiSignalStrengthStr = "excellent"
} else if (root.wifiSignalStrength >= 50) {
root.wifiSignalStrengthStr = "good"
} else if (root.wifiSignalStrength >= 25) {
root.wifiSignalStrengthStr = "fair"
} else {
root.wifiSignalStrengthStr = "poor"
}
}
}
}
}
}
function updateActiveConnections() {
getActiveConnections.running = true
}
Process {
id: getActiveConnections
command: ["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, type, device, state] = parts
if (type === "802-3-ethernet" && state === "activated") {
root.ethernetConnectionUuid = uuid
} else if (type === "802-11-wireless" && state === "activated") {
root.wifiConnectionUuid = uuid
}
}
}
}
}
}
function updateWifiState() {
checkWifiEnabled.running = true
}
Process {
id: checkWifiEnabled
command: ["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 ?
["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: ["nmcli", "-t", "-f", "SSID,SIGNAL,SECURITY,BSSID", "dev", "wifi", "list", "ifname", root.wifiInterface]
running: false
stdout: StdioCollector {
onStreamFinished: {
let networks = []
const lines = text.trim().split('\n')
const seen = new Set()
for (const line of lines) {
const parts = line.split(':')
if (parts.length >= 4 && parts[0]) {
const ssid = parts[0]
if (!seen.has(ssid)) {
seen.add(ssid)
const signal = parseInt(parts[1]) || 0
let signalQuality = "poor"
if (signal >= 75) signalQuality = "excellent"
else if (signal >= 50) signalQuality = "good"
else if (signal >= 25) signalQuality = "fair"
networks.push({
ssid: ssid,
signal: signal,
signalStrength: signalQuality,
secured: parts[2] !== "",
bssid: parts[3],
connected: ssid === root.currentWifiSSID,
saved: false // Will be updated by saved connections check
})
}
}
}
networks.sort((a, b) => b.signal - a.signal)
root.wifiNetworks = networks
root.isScanning = false
root.networksUpdated()
}
}
}
Process {
id: getSavedConnections
command: ["nmcli", "-t", "-f", "NAME,TYPE", "connection", "show"]
running: false
stdout: StdioCollector {
onStreamFinished: {
let saved = []
const lines = text.trim().split('\n')
for (const line of lines) {
const parts = line.split(':')
if (parts.length >= 2 && parts[1] === "802-11-wireless") {
saved.push({
ssid: parts[0],
saved: true
})
}
}
root.savedConnections = saved
root.savedWifiNetworks = saved
let updated = [...root.wifiNetworks]
for (let network of updated) {
network.saved = saved.some(s => s.ssid === network.ssid)
}
root.wifiNetworks = updated
}
}
}
function connectToWifi(ssid, password = "") {
if (root.isConnecting) return
root.isConnecting = true
root.connectingSSID = ssid
root.connectionError = ""
root.connectionStatus = "connecting"
if (password) {
wifiConnector.command = ["nmcli", "dev", "wifi", "connect", ssid, "password", password]
} else {
wifiConnector.command = ["nmcli", "dev", "wifi", "connect", ssid]
}
wifiConnector.running = true
}
function connectToWifiWithPassword(ssid, password) {
connectToWifi(ssid, password)
}
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) {
// Command succeeded but we didn't see "successfully" - still mark as success
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 = ["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
networkForgetter.command = ["nmcli", "connection", "delete", ssid]
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)
let updated = [...root.wifiNetworks]
for (let 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 = ["nmcli", "radio", "wifi", targetState]
wifiRadioToggler.running = true
}
Process {
id: wifiRadioToggler
running: false
property string targetState: ""
onExited: (exitCode) => {
root.wifiToggling = false
if (exitCode === 0) {
// Don't manually toggle wifiEnabled - let DBus monitoring handle it
ToastService.showInfo(targetState === "on" ? "WiFi enabled" : "WiFi disabled")
}
refreshNetworkState()
}
}
// ===== Network Preference Management =====
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")
}
// "auto" uses default NetworkManager behavior
}
function setConnectionPriority(type) {
if (type === "wifi") {
setRouteMetrics.command = ["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 = ["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: ["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
}
// ===== Network Info =====
function fetchNetworkInfo(ssid) {
root.networkInfoSSID = ssid
root.networkInfoLoading = true
root.networkInfoDetails = "Loading network information..."
wifiInfoFetcher.running = true
}
Process {
id: wifiInfoFetcher
command: ["nmcli", "-t", "-f", "SSID,SIGNAL,SECURITY,FREQ,RATE,MODE,CHAN,WPA-FLAGS,RSN-FLAGS", "dev", "wifi", "list"]
running: false
stdout: StdioCollector {
onStreamFinished: {
let details = ""
if (text.trim()) {
let lines = text.trim().split('\n')
for (let line of lines) {
let parts = line.split(':')
if (parts.length >= 9 && parts[0] === root.networkInfoSSID) {
let ssid = parts[0] || "Unknown"
let signal = parts[1] || "0"
let security = parts[2] || "Open"
let freq = parts[3] || "Unknown"
let rate = parts[4] || "Unknown"
let mode = parts[5] || "Unknown"
let channel = parts[6] || "Unknown"
let wpaFlags = parts[7] || ""
let rsnFlags = parts[8] || ""
let band = "Unknown"
let 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"
}
details = "Network Name: " + ssid + "\\n"
details += "Signal Strength: " + signal + "%\\n"
details += "Security: " + (security === "" ? "Open" : security) + "\\n"
details += "Frequency: " + freq + " MHz\\n"
details += "Band: " + band + "\\n"
details += "Channel: " + channel + "\\n"
details += "Mode: " + mode + "\\n"
details += "Max Rate: " + rate + " Mbit/s\\n"
if (wpaFlags !== "") {
details += "WPA Flags: " + wpaFlags + "\\n"
}
if (rsnFlags !== "") {
details += "RSN Flags: " + rsnFlags + "\\n"
}
break
}
}
}
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 refreshNetworkStatus() {
refreshNetworkState()
}
function delayedRefreshNetworkStatus() {
refreshNetworkState()
}
function updateCurrentWifiInfo() {
getCurrentWifiInfo.running = true
}
function enableWifiDevice() {
wifiDeviceEnabler.running = true
}
Process {
id: wifiDeviceEnabler
command: ["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) {
connectToWifiWithPassword(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: ["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: ["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 getSignalQuality(strength) {
if (strength >= 75) return "excellent"
if (strength >= 50) return "good"
if (strength >= 25) return "fair"
return "poor"
}
function getNetworkInfo(ssid) {
const network = root.wifiNetworks.find(n => n.ssid === ssid)
if (!network) return null
return {
ssid: network.ssid,
signal: network.signal,
signalQuality: getSignalQuality(network.signal),
secured: network.secured,
saved: network.saved,
connected: network.connected,
bssid: network.bssid
}
}
}