mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
Here we go again
This commit is contained in:
@@ -39,6 +39,42 @@ Singleton {
|
||||
property bool ignoreScanResults: false
|
||||
property bool scanPending: false
|
||||
|
||||
// Supported Wi-Fi security types
|
||||
property var supportedSecurityTypes: [
|
||||
{
|
||||
key: "open",
|
||||
name: "None"
|
||||
},
|
||||
{
|
||||
key: "wep",
|
||||
name: "WEP"
|
||||
},
|
||||
{
|
||||
key: "wpa-psk",
|
||||
name: "WPA"
|
||||
},
|
||||
{
|
||||
key: "wpa2-psk",
|
||||
name: "WPA2/WPA3"
|
||||
},
|
||||
{
|
||||
key: "sae",
|
||||
name: "WPA3"
|
||||
},
|
||||
{
|
||||
key: "wpa-eap",
|
||||
name: "WPA Enterprise"
|
||||
},
|
||||
{
|
||||
key: "wpa2-eap",
|
||||
name: "WPA2 Enterprise"
|
||||
},
|
||||
{
|
||||
key: "wpa3-eap",
|
||||
name: "WPA3 Enterprise"
|
||||
}
|
||||
]
|
||||
|
||||
// Active Wi‑Fi connection details (for info panel)
|
||||
property var activeWifiDetails: ({})
|
||||
property string activeWifiIf: ""
|
||||
@@ -145,16 +181,23 @@ Singleton {
|
||||
Process {
|
||||
id: capabilityDetectProcess
|
||||
running: false
|
||||
command: ["nmcli", "-t", "-f", "TYPE", "device"]
|
||||
command: ["nmcli", "-t", "-f", "DEVICE,TYPE", "device"]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
var lines = text.trim().split("\n");
|
||||
var wifi = false;
|
||||
var eth = false;
|
||||
var wifiDev = "";
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var type = lines[i].trim();
|
||||
var parts = lines[i].split(":");
|
||||
if (parts.length < 2)
|
||||
continue;
|
||||
var dev = parts[0].trim();
|
||||
var type = parts[1].trim();
|
||||
if (type === "wifi") {
|
||||
wifi = true;
|
||||
if (!wifiDev)
|
||||
wifiDev = dev;
|
||||
} else if (type === "ethernet") {
|
||||
eth = true;
|
||||
}
|
||||
@@ -162,6 +205,10 @@ Singleton {
|
||||
root._wifiAvailable = wifi;
|
||||
root._ethernetAvailable = eth;
|
||||
Logger.d("Network", "Detected capabilities - WiFi:", wifi, "Ethernet:", eth);
|
||||
|
||||
if (wifi && wifiDev) {
|
||||
// Additional initialization if needed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -182,8 +229,9 @@ Singleton {
|
||||
}
|
||||
|
||||
// Use cached details if they are fresh
|
||||
if (activeWifiIf && activeWifiDetails && (now - activeWifiDetailsTimestamp) < activeWifiDetailsTtlMs)
|
||||
if (activeWifiIf && activeWifiDetails && (now - activeWifiDetailsTimestamp) < activeWifiDetailsTtlMs) {
|
||||
return;
|
||||
}
|
||||
|
||||
detailsLoading = true;
|
||||
wifiDeviceListProcess.running = true;
|
||||
@@ -224,8 +272,9 @@ Singleton {
|
||||
return;
|
||||
}
|
||||
// If we have fresh details for the same iface, skip
|
||||
if (activeEthernetIf && activeEthernetDetails && (now - activeEthernetDetailsTimestamp) < activeEthernetDetailsTtlMs)
|
||||
if (activeEthernetIf && activeEthernetDetails && (now - activeEthernetDetailsTimestamp) < activeEthernetDetailsTtlMs) {
|
||||
return;
|
||||
}
|
||||
|
||||
ethernetDetailsLoading = true;
|
||||
ethernetDeviceListProcess.running = true;
|
||||
@@ -293,7 +342,7 @@ Singleton {
|
||||
refreshActiveEthernetDetails();
|
||||
}
|
||||
|
||||
function connect(ssid, password = "") {
|
||||
function connect(ssid, password = "", isHidden = false) {
|
||||
if (!ProgramCheckerService.nmcliAvailable || connecting) {
|
||||
return;
|
||||
}
|
||||
@@ -306,15 +355,31 @@ Singleton {
|
||||
connectProcess.mode = "saved";
|
||||
connectProcess.ssid = ssid;
|
||||
connectProcess.password = "";
|
||||
connectProcess.isHidden = false;
|
||||
} else {
|
||||
connectProcess.mode = "new";
|
||||
connectProcess.ssid = ssid;
|
||||
connectProcess.password = password;
|
||||
connectProcess.isHidden = isHidden;
|
||||
}
|
||||
|
||||
connectProcess.running = true;
|
||||
}
|
||||
|
||||
function connectManual(ssid, password, securityKey) {
|
||||
if (!ProgramCheckerService.nmcliAvailable || connecting) {
|
||||
return;
|
||||
}
|
||||
connecting = true;
|
||||
connectingTo = ssid;
|
||||
lastError = "";
|
||||
|
||||
manualConnectProcess.ssid = ssid;
|
||||
manualConnectProcess.password = password;
|
||||
manualConnectProcess.securityKey = securityKey;
|
||||
manualConnectProcess.running = true;
|
||||
}
|
||||
|
||||
function disconnect(ssid) {
|
||||
if (!ProgramCheckerService.nmcliAvailable) {
|
||||
return;
|
||||
@@ -416,6 +481,55 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
function parseIpDetails(text) {
|
||||
const details = {
|
||||
ipv4: "",
|
||||
gateway4: "",
|
||||
ipv6: "",
|
||||
gateway6: "",
|
||||
dns4: [],
|
||||
dns6: [],
|
||||
dns: "",
|
||||
connectionName: ""
|
||||
};
|
||||
const lines = text.split("\n");
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i].trim();
|
||||
if (!line) {
|
||||
continue;
|
||||
}
|
||||
const idx = line.indexOf(":");
|
||||
if (idx === -1) {
|
||||
continue;
|
||||
}
|
||||
const key = line.substring(0, idx);
|
||||
const val = line.substring(idx + 1);
|
||||
if (key === "GENERAL.CONNECTION") {
|
||||
details.connectionName = val;
|
||||
} else if (key.indexOf("IP4.ADDRESS") === 0) {
|
||||
details.ipv4 = val.split("/")[0];
|
||||
} else if (key === "IP4.GATEWAY") {
|
||||
details.gateway4 = val;
|
||||
} else if (key.indexOf("IP6.ADDRESS") === 0) {
|
||||
details.ipv6 = val.split("/")[0];
|
||||
} else if (key === "IP6.GATEWAY") {
|
||||
details.gateway6 = val;
|
||||
} else if (key.indexOf("IP4.DNS") === 0) {
|
||||
if (val && details.dns4.indexOf(val) === -1) {
|
||||
details.dns4.push(val);
|
||||
}
|
||||
} else if (key.indexOf("IP6.DNS") === 0) {
|
||||
if (val && details.dns6.indexOf(val) === -1) {
|
||||
details.dns6.push(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
details.dns4 = details.dns4.join(", ");
|
||||
details.dns6 = details.dns6.join(", ");
|
||||
details.dns = [].concat(details.dns4 ? [details.dns4] : [], details.dns6 ? [details.dns6] : []).join(", ");
|
||||
return details;
|
||||
}
|
||||
|
||||
// Processes
|
||||
Process {
|
||||
id: ethernetStateProcess
|
||||
@@ -430,7 +544,7 @@ Singleton {
|
||||
var ethList = [];
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var parts = lines[i].split(":");
|
||||
if (parts.length >= 3 && parts[1] === "ethernet") {
|
||||
if (parts.length >= 3 && parts[1] === "ethernet" && parts[2] !== "unmanaged") {
|
||||
var ifname = parts[0];
|
||||
var state = parts[2];
|
||||
var isConn = state === "connected";
|
||||
@@ -447,8 +561,9 @@ Singleton {
|
||||
}
|
||||
// Sort interfaces: connected first, then by name
|
||||
ethList.sort(function (a, b) {
|
||||
if (a.connected !== b.connected)
|
||||
if (a.connected !== b.connected) {
|
||||
return a.connected ? -1 : 1;
|
||||
}
|
||||
return a.ifname.localeCompare(b.ifname);
|
||||
});
|
||||
root.ethernetInterfaces = ethList;
|
||||
@@ -497,6 +612,9 @@ Singleton {
|
||||
const dev = parts[0];
|
||||
const type = parts[1];
|
||||
const state = parts[2];
|
||||
if (state === "unmanaged") {
|
||||
continue;
|
||||
}
|
||||
if (type === "ethernet" && state === "connected") {
|
||||
ifname = dev;
|
||||
}
|
||||
@@ -510,8 +628,9 @@ Singleton {
|
||||
}
|
||||
}
|
||||
ethList.sort(function (a, b) {
|
||||
if (a.connected !== b.connected)
|
||||
if (a.connected !== b.connected) {
|
||||
return a.connected ? -1 : 1;
|
||||
}
|
||||
return a.ifname.localeCompare(b.ifname);
|
||||
});
|
||||
root.ethernetInterfaces = ethList;
|
||||
@@ -551,42 +670,20 @@ Singleton {
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const details = root.activeEthernetDetails || ({});
|
||||
let connName = "";
|
||||
let ipv4 = "";
|
||||
let gw4 = "";
|
||||
let dnsServers = [];
|
||||
const lines = text.split("\n");
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i].trim();
|
||||
if (!line) {
|
||||
continue;
|
||||
}
|
||||
const idx = line.indexOf(":");
|
||||
if (idx === -1) {
|
||||
continue;
|
||||
}
|
||||
const key = line.substring(0, idx);
|
||||
const val = line.substring(idx + 1);
|
||||
if (key === "GENERAL.CONNECTION") {
|
||||
connName = val;
|
||||
} else if (key.indexOf("IP4.ADDRESS") === 0) {
|
||||
ipv4 = val.split("/")[0];
|
||||
} else if (key === "IP4.GATEWAY") {
|
||||
gw4 = val;
|
||||
} else if (key.indexOf("IP4.DNS") === 0) {
|
||||
if (val && dnsServers.indexOf(val) === -1) {
|
||||
dnsServers.push(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
const parsed = root.parseIpDetails(text);
|
||||
|
||||
details.ifname = ethernetDeviceShowProcess.ifname;
|
||||
details.connectionName = connName;
|
||||
details.connectionName = parsed.connectionName;
|
||||
// No speed from nmcli: keep empty so ethtool fallback below fills it
|
||||
details.speed = details.speed && details.speed.length > 0 ? details.speed : "";
|
||||
details.ipv4 = ipv4;
|
||||
details.gateway4 = gw4;
|
||||
details.dnsServers = dnsServers;
|
||||
details.dns = dnsServers.join(", ");
|
||||
details.ipv4 = parsed.ipv4;
|
||||
details.gateway4 = parsed.gateway4;
|
||||
details.ipv6 = parsed.ipv6;
|
||||
details.gateway6 = parsed.gateway6;
|
||||
details.dns4 = parsed.dns4;
|
||||
details.dns6 = parsed.dns6;
|
||||
details.dns = parsed.dns;
|
||||
|
||||
root.activeEthernetDetails = details;
|
||||
// If speed missing, try sysfs first, then fallback to ethtool
|
||||
if (!details.speed || details.speed.length === 0) {
|
||||
@@ -696,6 +793,9 @@ Singleton {
|
||||
const dev = parts[0];
|
||||
const type = parts[1];
|
||||
const state = parts[2];
|
||||
if (state === "unmanaged") {
|
||||
continue;
|
||||
}
|
||||
if (type === "wifi" && state === "connected") {
|
||||
ifname = dev;
|
||||
break;
|
||||
@@ -727,45 +827,25 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch IPv4 and gateway for the interface
|
||||
// Fetch IP info for the interface
|
||||
Process {
|
||||
id: wifiDeviceShowProcess
|
||||
property string ifname: ""
|
||||
running: false
|
||||
command: ["nmcli", "-t", "-f", "IP4.ADDRESS,IP4.GATEWAY,IP4.DNS", "device", "show", ifname]
|
||||
command: ["nmcli", "-t", "-f", "IP4.ADDRESS,IP4.GATEWAY,IP4.DNS,IP6.ADDRESS,IP6.GATEWAY,IP6.DNS", "device", "show", ifname]
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const details = root.activeWifiDetails || ({});
|
||||
let ipv4 = "";
|
||||
let gw4 = "";
|
||||
let dnsServers = [];
|
||||
const lines = text.split("\n");
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i].trim();
|
||||
if (!line) {
|
||||
continue;
|
||||
}
|
||||
const idx = line.indexOf(":");
|
||||
if (idx === -1) {
|
||||
continue;
|
||||
}
|
||||
const key = line.substring(0, idx);
|
||||
const val = line.substring(idx + 1);
|
||||
if (key.indexOf("IP4.ADDRESS") === 0) {
|
||||
ipv4 = val.split("/")[0];
|
||||
} else if (key === "IP4.GATEWAY") {
|
||||
gw4 = val;
|
||||
} else if (key.indexOf("IP4.DNS") === 0) {
|
||||
if (val && dnsServers.indexOf(val) === -1) {
|
||||
dnsServers.push(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
details.ipv4 = ipv4;
|
||||
details.gateway4 = gw4;
|
||||
details.dnsServers = dnsServers;
|
||||
details.dns = dnsServers.join(", ");
|
||||
const parsed = root.parseIpDetails(text);
|
||||
|
||||
details.ipv4 = parsed.ipv4;
|
||||
details.gateway4 = parsed.gateway4;
|
||||
details.ipv6 = parsed.ipv6;
|
||||
details.gateway6 = parsed.gateway6;
|
||||
details.dns4 = parsed.dns4;
|
||||
details.dns6 = parsed.dns6;
|
||||
details.dns = parsed.dns;
|
||||
root.activeWifiDetails = details;
|
||||
|
||||
// Try to get link rate (best effort)
|
||||
@@ -784,18 +864,20 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
// Optional: query Wi‑Fi bitrate via iw if available
|
||||
// Optional: query Wi‑Fi bitrate and link info via iw if available
|
||||
Process {
|
||||
id: wifiIwLinkProcess
|
||||
property string ifname: ""
|
||||
running: false
|
||||
command: ["sh", "-c", "iw dev '" + ifname + "' link 2>/dev/null || true"]
|
||||
command: ["sh", "-c", "iw dev '" + ifname + "' link 2>/dev/null; iw dev '" + ifname + "' info 2>/dev/null || true"]
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const details = root.activeWifiDetails || ({});
|
||||
let rate = "";
|
||||
let freq = "";
|
||||
let iwChannel = "";
|
||||
let iwWidth = "";
|
||||
const lines = text.split("\n");
|
||||
for (var k = 0; k < lines.length; k++) {
|
||||
var line2 = lines[k].trim();
|
||||
@@ -804,12 +886,23 @@ Singleton {
|
||||
rate = line2.substring(11).trim();
|
||||
} else if (low.indexOf("freq:") === 0) {
|
||||
freq = line2.substring(5).trim();
|
||||
} else if (low.indexOf("channel") === 0) {
|
||||
// Parse "channel 9 (2452 MHz), width: 20 MHz, center1: 2452 MHz"
|
||||
var chanMatch = line2.match(/channel\s+(\d+)/i);
|
||||
if (chanMatch) {
|
||||
iwChannel = chanMatch[1];
|
||||
}
|
||||
var widthMatchInfo = line2.match(/width:\s+(\d+)\s+MHz/i);
|
||||
if (widthMatchInfo) {
|
||||
iwWidth = widthMatchInfo[1] + " MHz";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Determine band from frequency
|
||||
// Determine band and channel from frequency
|
||||
// https://en.wikipedia.org/wiki/List_of_WLAN_channels
|
||||
let band = "";
|
||||
let channel = iwChannel;
|
||||
if (freq) {
|
||||
const f = +freq;
|
||||
if (f) {
|
||||
@@ -817,14 +910,27 @@ Singleton {
|
||||
// https://en.wikipedia.org/wiki/List_of_WLAN_channels#6_GHz_(802.11ax_and_802.11be)
|
||||
case (f >= 5925 && f < 7125):
|
||||
band = "6 GHz";
|
||||
if (!channel) {
|
||||
channel = Math.round((f - 5940) / 5).toString();
|
||||
}
|
||||
break;
|
||||
// https://en.wikipedia.org/wiki/List_of_WLAN_channels#5_GHz_(802.11a/h/n/ac/ax/be)
|
||||
case (f >= 5150 && f < 5925):
|
||||
band = "5 GHz";
|
||||
if (!channel) {
|
||||
channel = Math.round((f - 5000) / 5).toString();
|
||||
}
|
||||
break;
|
||||
// https://en.wikipedia.org/wiki/List_of_WLAN_channels#2.4_GHz_(802.11b/g/n/ax/be)
|
||||
case (f >= 2400 && f < 2500):
|
||||
band = "2.4 GHz";
|
||||
if (!channel) {
|
||||
if (f === 2484) {
|
||||
channel = "14";
|
||||
} else {
|
||||
channel = Math.round((f - 2407) / 5).toString();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
band = `${f} MHz`;
|
||||
@@ -834,7 +940,16 @@ Singleton {
|
||||
|
||||
// Shorten verbose bitrate strings like: "360.0 MBit/s VHT-MCS 8 40MHz short GI"
|
||||
let rateShort = "";
|
||||
let width = iwWidth;
|
||||
if (rate) {
|
||||
// Extract width from bitrate if not already found in info (fallback)
|
||||
if (!width) {
|
||||
var widthMatchBitrate = rate.match(/(\d+)MHz/i);
|
||||
if (widthMatchBitrate) {
|
||||
width = widthMatchBitrate[1] + " MHz";
|
||||
}
|
||||
}
|
||||
|
||||
var parts = rate.trim().split(" ");
|
||||
// compact consecutive spaces
|
||||
var compact = [];
|
||||
@@ -866,9 +981,20 @@ Singleton {
|
||||
rateShort = compact.slice(0, 2).join(" ");
|
||||
}
|
||||
}
|
||||
|
||||
// Enhance band string with channel and width: "Band / Ch Channel (Width)"
|
||||
let enhancedBand = band;
|
||||
if (channel && width) {
|
||||
enhancedBand = `${band} / Ch ${channel} (${width})`;
|
||||
} else if (channel) {
|
||||
enhancedBand = `${band} / Ch ${channel}`;
|
||||
}
|
||||
|
||||
details.rate = rate;
|
||||
details.rateShort = rateShort;
|
||||
details.band = band;
|
||||
details.band = enhancedBand;
|
||||
details.channel = channel;
|
||||
details.width = width;
|
||||
root.activeWifiDetails = details;
|
||||
root.activeWifiDetailsTimestamp = Date.now();
|
||||
root.detailsLoading = false;
|
||||
@@ -1210,6 +1336,7 @@ Singleton {
|
||||
property string mode: "new"
|
||||
property string ssid: ""
|
||||
property string password: ""
|
||||
property bool isHidden: false
|
||||
running: false
|
||||
|
||||
command: {
|
||||
@@ -1217,9 +1344,15 @@ Singleton {
|
||||
return ["nmcli", "connection", "up", "id", ssid];
|
||||
} else {
|
||||
var cmd = ["nmcli", "device", "wifi", "connect", ssid];
|
||||
if (isHidden) {
|
||||
cmd.push("hidden", "yes");
|
||||
}
|
||||
if (password) {
|
||||
cmd.push("password", password);
|
||||
}
|
||||
if (root.activeWifiIf) {
|
||||
cmd.push("ifname", root.activeWifiIf);
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
}
|
||||
@@ -1296,6 +1429,89 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: manualConnectProcess
|
||||
property string ssid: ""
|
||||
property string password: ""
|
||||
property string securityKey: ""
|
||||
running: false
|
||||
|
||||
command: {
|
||||
var script = `
|
||||
SSID="$1"
|
||||
PWD="$2"
|
||||
SEC="$3"
|
||||
|
||||
# Remove existing profile to avoid conflict
|
||||
nmcli connection delete id "$SSID" 2>/dev/null || true
|
||||
|
||||
# Create profile based on security key
|
||||
if [ "$SEC" = "wpa-psk" ] || [ "$SEC" = "wpa2-psk" ]; then
|
||||
nmcli connection add type wifi con-name "$SSID" ssid "$SSID" -- wifi-sec.key-mgmt wpa-psk wifi-sec.psk "$PWD" 802-11-wireless.hidden yes
|
||||
elif [ "$SEC" = "sae" ]; then
|
||||
nmcli connection add type wifi con-name "$SSID" ssid "$SSID" -- wifi-sec.key-mgmt sae wifi-sec.psk "$PWD" 802-11-wireless.hidden yes
|
||||
elif [ "$SEC" = "wep" ]; then
|
||||
nmcli connection add type wifi con-name "$SSID" ssid "$SSID" -- wifi-sec.key-mgmt none wifi-sec.wep-key0 "$PWD" 802-11-wireless.hidden yes
|
||||
elif [[ "$SEC" == *-eap ]]; then
|
||||
# Enterprise not fully supported in Stage 1
|
||||
echo "Enterprise networks not supported yet"
|
||||
exit 1
|
||||
else
|
||||
nmcli connection add type wifi con-name "$SSID" ssid "$SSID" -- 802-11-wireless.hidden yes
|
||||
fi
|
||||
|
||||
# Bring up the connection
|
||||
nmcli connection up id "$SSID"
|
||||
`;
|
||||
|
||||
return ["sh", "-c", script, "--", ssid, password, securityKey];
|
||||
}
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const output = text.trim();
|
||||
if (output.indexOf("successfully activated") === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Success - update cache
|
||||
let known = cacheAdapter.knownNetworks;
|
||||
known[manualConnectProcess.ssid] = {
|
||||
"profileName": manualConnectProcess.ssid,
|
||||
"lastConnected": Date.now()
|
||||
};
|
||||
cacheAdapter.knownNetworks = known;
|
||||
cacheAdapter.lastConnected = manualConnectProcess.ssid;
|
||||
saveCache();
|
||||
|
||||
root.updateNetworkStatus(manualConnectProcess.ssid, true);
|
||||
root.refreshActiveWifiDetails();
|
||||
|
||||
root.connecting = false;
|
||||
root.connectingTo = "";
|
||||
Logger.i("Network", "Manually connected to hidden network: '" + manualConnectProcess.ssid + "'");
|
||||
ToastService.showNotice(I18n.tr("common.wifi"), I18n.tr("toast.wifi.connected", {
|
||||
"ssid": manualConnectProcess.ssid
|
||||
}), "wifi");
|
||||
|
||||
delayedScanTimer.interval = 5000;
|
||||
delayedScanTimer.restart();
|
||||
}
|
||||
}
|
||||
|
||||
stderr: StdioCollector {
|
||||
onStreamFinished: {
|
||||
root.connecting = false;
|
||||
root.connectingTo = "";
|
||||
if (text.trim()) {
|
||||
root.lastError = I18n.tr("toast.wifi.connection-failed");
|
||||
Logger.w("Network", "Manual connect error: " + text);
|
||||
ToastService.showWarning(I18n.tr("common.wifi"), root.lastError);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: disconnectProcess
|
||||
property string ssid: ""
|
||||
|
||||
Reference in New Issue
Block a user