mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
Improved network and Bluetooth panel with additional info and options to manage devices.
This commit is contained in:
@@ -52,7 +52,8 @@ NBox {
|
||||
readonly property bool isBusy: BluetoothService.isDeviceBusy(modelData)
|
||||
readonly property bool isExpanded: root.expandedDeviceKey === BluetoothService.deviceKey(modelData)
|
||||
|
||||
function getContentColor(defaultColor = Color.mOnSurface) {
|
||||
function getContentColor(defaultColor) {
|
||||
if (defaultColor === undefined) defaultColor = Color.mOnSurface;
|
||||
if (modelData.pairing || modelData.state === BluetoothDeviceState.Connecting)
|
||||
return Color.mPrimary;
|
||||
if (modelData.blocked)
|
||||
|
||||
@@ -58,7 +58,7 @@ SmartPanel {
|
||||
NToggle {
|
||||
id: bluetoothSwitch
|
||||
checked: BluetoothService.enabled
|
||||
onToggled: checked => BluetoothService.setBluetoothEnabled(checked)
|
||||
onToggled: function(checked) { BluetoothService.setBluetoothEnabled(checked); }
|
||||
baseSize: Style.baseWidgetSize * 0.65
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ SmartPanel {
|
||||
property var items: {
|
||||
if (!BluetoothService.adapter || !Bluetooth.devices)
|
||||
return [];
|
||||
var filtered = Bluetooth.devices.values.filter(dev => dev && !dev.blocked && dev.connected);
|
||||
var filtered = Bluetooth.devices.values.filter(function(dev) { return dev && !dev.blocked && dev.connected; });
|
||||
filtered = BluetoothService.dedupeDevices(filtered);
|
||||
return BluetoothService.sortDevices(filtered);
|
||||
}
|
||||
@@ -166,7 +166,7 @@ SmartPanel {
|
||||
property var items: {
|
||||
if (!BluetoothService.adapter || !Bluetooth.devices)
|
||||
return [];
|
||||
var filtered = Bluetooth.devices.values.filter(dev => dev && !dev.blocked && !dev.connected && (dev.paired || dev.trusted));
|
||||
var filtered = Bluetooth.devices.values.filter(function(dev) { return dev && !dev.blocked && !dev.connected && (dev.paired || dev.trusted); });
|
||||
filtered = BluetoothService.dedupeDevices(filtered);
|
||||
return BluetoothService.sortDevices(filtered);
|
||||
}
|
||||
@@ -181,7 +181,7 @@ SmartPanel {
|
||||
property var items: {
|
||||
if (!BluetoothService.adapter || !Bluetooth.devices)
|
||||
return [];
|
||||
var filtered = Bluetooth.devices.values.filter(dev => dev && !dev.blocked && !dev.paired && !dev.trusted);
|
||||
var filtered = Bluetooth.devices.values.filter(function(dev) { return dev && !dev.blocked && !dev.paired && !dev.trusted; });
|
||||
filtered = BluetoothService.dedupeDevices(filtered);
|
||||
return BluetoothService.sortDevices(filtered);
|
||||
}
|
||||
@@ -199,9 +199,9 @@ SmartPanel {
|
||||
return false;
|
||||
}
|
||||
|
||||
var availableCount = Bluetooth.devices.values.filter(dev => {
|
||||
return dev && !dev.paired && !dev.pairing && !dev.blocked && (dev.signalStrength === undefined || dev.signalStrength > 0);
|
||||
}).length;
|
||||
var availableCount = Bluetooth.devices.values.filter(function(dev) {
|
||||
return dev && !dev.paired && !dev.pairing && !dev.blocked && (dev.signalStrength === undefined || dev.signalStrength > 0);
|
||||
}).length;
|
||||
return (availableCount === 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -215,7 +215,7 @@ NBox {
|
||||
NIconButton {
|
||||
visible: modelData.connected && NetworkService.disconnectingFrom !== modelData.ssid
|
||||
icon: "info-circle"
|
||||
tooltipText: I18n.tr("wifi.panel.info")
|
||||
tooltipText: root.trOr("wifi.panel.info", "Info")
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
onClicked: {
|
||||
if (root.infoSsid === modelData.ssid) {
|
||||
@@ -276,6 +276,7 @@ NBox {
|
||||
border.width: Style.borderS
|
||||
border.color: Color.mOutline
|
||||
height: infoColumn.implicitHeight + Style.marginS * 2
|
||||
clip: true
|
||||
|
||||
ColumnLayout {
|
||||
id: infoColumn
|
||||
@@ -283,12 +284,6 @@ NBox {
|
||||
anchors.margins: Style.marginS
|
||||
spacing: Style.marginXS
|
||||
|
||||
RowLayout {
|
||||
spacing: Style.marginS
|
||||
NIcon { icon: NetworkService.signalIcon(modelData.signal, modelData.connected); pointSize: Style.fontSizeM; color: Color.mOnSurface }
|
||||
NText { text: "Signal: " + modelData.signal + "%"; pointSize: Style.fontSizeXS; color: Color.mOnSurface }
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: Style.marginS
|
||||
NIcon { icon: "lock"; pointSize: Style.fontSizeM; color: Color.mOnSurface }
|
||||
@@ -306,17 +301,56 @@ NBox {
|
||||
spacing: Style.marginS
|
||||
NIcon { icon: "activity"; pointSize: Style.fontSizeM; color: Color.mOnSurface }
|
||||
NText { text: root.trOr("wifi.panel.link-speed", "Link speed") + ": "; pointSize: Style.fontSizeXS; color: Color.mOnSurfaceVariant }
|
||||
NText { text: (NetworkService.activeWifiDetails.rate || "-"); pointSize: Style.fontSizeXS; color: Color.mOnSurface }
|
||||
NText {
|
||||
text: (NetworkService.activeWifiDetails.rateShort && NetworkService.activeWifiDetails.rateShort.length > 0)
|
||||
? NetworkService.activeWifiDetails.rateShort
|
||||
: ((NetworkService.activeWifiDetails.rate && NetworkService.activeWifiDetails.rate.length > 0)
|
||||
? NetworkService.activeWifiDetails.rate
|
||||
: "-");
|
||||
pointSize: Style.fontSizeXS
|
||||
color: Color.mOnSurface
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: Style.marginS
|
||||
NIcon { icon: "router"; pointSize: Style.fontSizeM; color: Color.mOnSurface }
|
||||
NText { text: "IPv4: "; pointSize: Style.fontSizeXS; color: Color.mOnSurfaceVariant }
|
||||
NText { text: (NetworkService.activeWifiDetails.ipv4 || "-"); pointSize: Style.fontSizeXS; color: Color.mOnSurface }
|
||||
NText { text: "•"; pointSize: Style.fontSizeXS; color: Color.mOnSurfaceVariant }
|
||||
NText {
|
||||
text: (NetworkService.activeWifiDetails.ipv4 || "-")
|
||||
pointSize: Style.fontSizeXS
|
||||
color: Color.mOnSurface
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: Style.marginS
|
||||
NIcon { icon: "router"; pointSize: Style.fontSizeM; color: Color.mOnSurface }
|
||||
NText { text: root.trOr("wifi.panel.gateway", "Gateway") + ": "; pointSize: Style.fontSizeXS; color: Color.mOnSurfaceVariant }
|
||||
NText { text: (NetworkService.activeWifiDetails.gateway4 || "-"); pointSize: Style.fontSizeXS; color: Color.mOnSurface }
|
||||
NText {
|
||||
text: (NetworkService.activeWifiDetails.gateway4 || "-")
|
||||
pointSize: Style.fontSizeXS
|
||||
color: Color.mOnSurface
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: Style.marginS
|
||||
NIcon { icon: "server"; pointSize: Style.fontSizeM; color: Color.mOnSurface }
|
||||
NText { text: root.trOr("wifi.panel.dns", "DNS") + ": "; pointSize: Style.fontSizeXS; color: Color.mOnSurfaceVariant }
|
||||
NText {
|
||||
text: (NetworkService.activeWifiDetails.dns || "-")
|
||||
pointSize: Style.fontSizeXS
|
||||
color: Color.mOnSurface
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,15 +22,15 @@ SmartPanel {
|
||||
if (!Settings.data.network.wifiEnabled)
|
||||
return [];
|
||||
|
||||
const nets = Object.values(NetworkService.networks);
|
||||
const known = nets.filter(n => n.connected || n.existing || n.cached);
|
||||
var nets = Object.values(NetworkService.networks);
|
||||
var known = nets.filter(function(n) { return n.connected || n.existing || n.cached; });
|
||||
|
||||
// Sort: connected first, then by signal strength
|
||||
known.sort((a, b) => {
|
||||
if (a.connected !== b.connected)
|
||||
return b.connected - a.connected;
|
||||
return b.signal - a.signal;
|
||||
});
|
||||
known.sort(function(a, b) {
|
||||
if (a.connected !== b.connected)
|
||||
return (b.connected ? 1 : 0) - (a.connected ? 1 : 0);
|
||||
return b.signal - a.signal;
|
||||
});
|
||||
|
||||
return known;
|
||||
}
|
||||
@@ -39,11 +39,11 @@ SmartPanel {
|
||||
if (!Settings.data.network.wifiEnabled)
|
||||
return [];
|
||||
|
||||
const nets = Object.values(NetworkService.networks);
|
||||
const available = nets.filter(n => !n.connected && !n.existing && !n.cached);
|
||||
var nets = Object.values(NetworkService.networks);
|
||||
var available = nets.filter(function(n) { return !n.connected && !n.existing && !n.cached; });
|
||||
|
||||
// Sort by signal strength
|
||||
available.sort((a, b) => b.signal - a.signal);
|
||||
available.sort(function(a, b) { return b.signal - a.signal; });
|
||||
|
||||
return available;
|
||||
}
|
||||
@@ -51,6 +51,8 @@ SmartPanel {
|
||||
onOpened: {
|
||||
hasHadNetworks = false;
|
||||
NetworkService.scan();
|
||||
// Preload active Wi‑Fi details so Info shows instantly
|
||||
NetworkService.refreshActiveWifiDetails();
|
||||
}
|
||||
|
||||
onKnownNetworksChanged: {
|
||||
|
||||
@@ -13,34 +13,34 @@ Singleton {
|
||||
property bool airplaneModeToggled: false
|
||||
property bool lastBluetoothBlocked: false
|
||||
readonly property BluetoothAdapter adapter: Bluetooth.defaultAdapter
|
||||
readonly property int state: adapter?.state ?? 0
|
||||
readonly property int state: (adapter && adapter.state !== undefined) ? adapter.state : 0
|
||||
readonly property bool available: (adapter !== null)
|
||||
readonly property bool enabled: adapter?.enabled ?? false
|
||||
readonly property bool blocked: (adapter?.state === BluetoothAdapterState.Blocked)
|
||||
readonly property bool discovering: (adapter && adapter.discovering) ?? false
|
||||
readonly property bool enabled: (adapter && adapter.enabled !== undefined) ? adapter.enabled : false
|
||||
readonly property bool blocked: (adapter && adapter.state === BluetoothAdapterState.Blocked)
|
||||
readonly property bool discovering: (adapter && adapter.discovering) ? adapter.discovering : false
|
||||
readonly property var devices: adapter ? adapter.devices : null
|
||||
readonly property var pairedDevices: {
|
||||
if (!adapter || !adapter.devices) {
|
||||
return [];
|
||||
}
|
||||
return adapter.devices.values.filter(dev => {
|
||||
return dev && (dev.paired || dev.trusted);
|
||||
});
|
||||
return adapter.devices.values.filter(function(dev) {
|
||||
return dev && (dev.paired || dev.trusted);
|
||||
});
|
||||
}
|
||||
readonly property var connectedDevices: {
|
||||
if (!adapter || !adapter.devices) {
|
||||
return [];
|
||||
}
|
||||
return adapter.devices.values.filter(dev => dev && dev.connected);
|
||||
return adapter.devices.values.filter(function(dev) { return dev && dev.connected; });
|
||||
}
|
||||
|
||||
readonly property var allDevicesWithBattery: {
|
||||
if (!adapter || !adapter.devices) {
|
||||
return [];
|
||||
}
|
||||
return adapter.devices.values.filter(dev => {
|
||||
return dev && dev.batteryAvailable && dev.battery > 0;
|
||||
});
|
||||
return adapter.devices.values.filter(function(dev) {
|
||||
return dev && dev.batteryAvailable && dev.battery > 0;
|
||||
});
|
||||
}
|
||||
|
||||
function init() {
|
||||
@@ -80,22 +80,22 @@ Singleton {
|
||||
}
|
||||
|
||||
function sortDevices(devices) {
|
||||
return devices.sort((a, b) => {
|
||||
var aName = a.name || a.deviceName || "";
|
||||
var bName = b.name || b.deviceName || "";
|
||||
return devices.sort(function(a, b) {
|
||||
var aName = a.name || a.deviceName || "";
|
||||
var bName = b.name || b.deviceName || "";
|
||||
|
||||
var aHasRealName = aName.includes(" ") && aName.length > 3;
|
||||
var bHasRealName = bName.includes(" ") && bName.length > 3;
|
||||
var aHasRealName = aName.indexOf(" ") !== -1 && aName.length > 3;
|
||||
var bHasRealName = bName.indexOf(" ") !== -1 && bName.length > 3;
|
||||
|
||||
if (aHasRealName && !bHasRealName)
|
||||
return -1;
|
||||
if (!aHasRealName && bHasRealName)
|
||||
return 1;
|
||||
if (aHasRealName && !bHasRealName)
|
||||
return -1;
|
||||
if (!aHasRealName && bHasRealName)
|
||||
return 1;
|
||||
|
||||
var aSignal = (a.signalStrength !== undefined && a.signalStrength > 0) ? a.signalStrength : 0;
|
||||
var bSignal = (b.signalStrength !== undefined && b.signalStrength > 0) ? b.signalStrength : 0;
|
||||
return bSignal - aSignal;
|
||||
});
|
||||
var aSignal = (a.signalStrength !== undefined && a.signalStrength > 0) ? a.signalStrength : 0;
|
||||
var bSignal = (b.signalStrength !== undefined && b.signalStrength > 0) ? b.signalStrength : 0;
|
||||
return bSignal - aSignal;
|
||||
});
|
||||
}
|
||||
|
||||
function getDeviceIcon(device) {
|
||||
@@ -105,37 +105,37 @@ Singleton {
|
||||
|
||||
var name = (device.name || device.deviceName || "").toLowerCase();
|
||||
var icon = (device.icon || "").toLowerCase();
|
||||
if (icon.includes("controller") || icon.includes("gamepad") || name.includes("controller") || name.includes("gamepad")) {
|
||||
if (icon.indexOf("controller") !== -1 || icon.indexOf("gamepad") !== -1 || name.indexOf("controller") !== -1 || name.indexOf("gamepad") !== -1) {
|
||||
return "bt-device-gamepad";
|
||||
}
|
||||
if (icon.includes("microphone") || name.includes("microphone")) {
|
||||
if (icon.indexOf("microphone") !== -1 || name.indexOf("microphone") !== -1) {
|
||||
return "bt-device-microphone";
|
||||
}
|
||||
if (name.includes("pod") || name.includes("bud") || name.includes("minor")) {
|
||||
if (name.indexOf("pod") !== -1 || name.indexOf("bud") !== -1 || name.indexOf("minor") !== -1) {
|
||||
return "bt-device-earbuds";
|
||||
}
|
||||
if (icon.includes("headset") || name.includes("arctis") || name.includes("headset") || name.includes("major")) {
|
||||
if (icon.indexOf("headset") !== -1 || name.indexOf("arctis") !== -1 || name.indexOf("headset") !== -1 || name.indexOf("major") !== -1) {
|
||||
return "bt-device-headset";
|
||||
}
|
||||
if (icon.includes("headphone") || name.includes("headphone")) {
|
||||
if (icon.indexOf("headphone") !== -1 || name.indexOf("headphone") !== -1) {
|
||||
return "bt-device-headphones";
|
||||
}
|
||||
if (icon.includes("mouse") || name.includes("mouse")) {
|
||||
if (icon.indexOf("mouse") !== -1 || name.indexOf("mouse") !== -1) {
|
||||
return "bt-device-mouse";
|
||||
}
|
||||
if (icon.includes("keyboard") || name.includes("keyboard")) {
|
||||
if (icon.indexOf("keyboard") !== -1 || name.indexOf("keyboard") !== -1) {
|
||||
return "bt-device-keyboard";
|
||||
}
|
||||
if (icon.includes("watch") || name.includes("watch")) {
|
||||
if (icon.indexOf("watch") !== -1 || name.indexOf("watch") !== -1) {
|
||||
return "bt-device-watch";
|
||||
}
|
||||
if (icon.includes("speaker") || name.includes("speaker") || name.includes("audio") || name.includes("sound")) {
|
||||
if (icon.indexOf("speaker") !== -1 || name.indexOf("speaker") !== -1 || name.indexOf("audio") !== -1 || name.indexOf("sound") !== -1) {
|
||||
return "bt-device-speaker";
|
||||
}
|
||||
if (icon.includes("display") || name.includes("tv")) {
|
||||
if (icon.indexOf("display") !== -1 || name.indexOf("tv") !== -1) {
|
||||
return "bt-device-tv";
|
||||
}
|
||||
if (icon.includes("phone") || name.includes("phone") || name.includes("iphone") || name.includes("android") || name.includes("samsung")) {
|
||||
if (icon.indexOf("phone") !== -1 || name.indexOf("phone") !== -1 || name.indexOf("iphone") !== -1 || name.indexOf("android") !== -1 || name.indexOf("samsung") !== -1) {
|
||||
return "bt-device-phone";
|
||||
}
|
||||
return "bt-device-generic";
|
||||
@@ -196,7 +196,7 @@ Singleton {
|
||||
}
|
||||
|
||||
function getBattery(device) {
|
||||
return `Battery: ${Math.round(device.battery * 100)}%`;
|
||||
return "Battery: " + Math.round(device.battery * 100) + "%";
|
||||
}
|
||||
|
||||
function getSignalIcon(device) {
|
||||
@@ -338,7 +338,7 @@ Singleton {
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const wifiBlocked = text && text.trim().includes("Soft blocked: yes");
|
||||
var wifiBlocked = text && text.trim().indexOf("Soft blocked: yes") !== -1;
|
||||
Logger.d("Network", "Wi-Fi adapter was detected as blocked:", blocked);
|
||||
|
||||
// Check if airplane mode has been toggled
|
||||
|
||||
@@ -78,6 +78,8 @@ Singleton {
|
||||
Logger.i("Network", "Service started");
|
||||
syncWifiState();
|
||||
scan();
|
||||
// Preload details at startup if already connected
|
||||
refreshActiveWifiDetails();
|
||||
}
|
||||
|
||||
// Save cache with debounce
|
||||
@@ -163,7 +165,8 @@ Singleton {
|
||||
Logger.d("Network", "Wi-Fi scan in progress...");
|
||||
}
|
||||
|
||||
function connect(ssid, password = "") {
|
||||
function connect(ssid, password) {
|
||||
if (password === undefined) password = "";
|
||||
if (connecting)
|
||||
return;
|
||||
connecting = true;
|
||||
@@ -171,7 +174,7 @@ Singleton {
|
||||
lastError = "";
|
||||
|
||||
// Check if we have a saved connection
|
||||
if (networks[ssid]?.existing || cachedNetworks[ssid]) {
|
||||
if ((networks[ssid] && networks[ssid].existing) || cachedNetworks[ssid]) {
|
||||
connectProcess.mode = "saved";
|
||||
connectProcess.ssid = ssid;
|
||||
connectProcess.password = "";
|
||||
@@ -243,7 +246,8 @@ Singleton {
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
function signalIcon(signal, isConnected = false) {
|
||||
function signalIcon(signal, isConnected) {
|
||||
if (isConnected === undefined) isConnected = false;
|
||||
if (isConnected && !root.internetConnectivity)
|
||||
return "world-off";
|
||||
if (signal >= 80)
|
||||
@@ -267,10 +271,15 @@ Singleton {
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const connected = text.split("\n").some(line => {
|
||||
const parts = line.split(":");
|
||||
return parts[1] === "ethernet" && parts[2] === "connected";
|
||||
});
|
||||
var connected = false;
|
||||
var lines = text.split("\n");
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var parts = lines[i].split(":");
|
||||
if (parts.length >= 3 && parts[1] === "ethernet" && parts[2] === "connected") {
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (root.ethernetConnected !== connected) {
|
||||
root.ethernetConnected = connected;
|
||||
Logger.d("Network", "Ethernet connected:", root.ethernetConnected);
|
||||
@@ -335,11 +344,11 @@ Singleton {
|
||||
if (idx === -1) continue;
|
||||
const key = line.substring(0, idx);
|
||||
const val = line.substring(idx + 1);
|
||||
if (key.startsWith("IP4.ADDRESS")) {
|
||||
if (key.indexOf("IP4.ADDRESS") === 0) {
|
||||
ipv4 = val.split("/")[0];
|
||||
} else if (key === "IP4.GATEWAY") {
|
||||
gw4 = val;
|
||||
} else if (key.startsWith("IP4.DNS")) {
|
||||
} else if (key.indexOf("IP4.DNS") === 0) {
|
||||
if (val && dnsServers.indexOf(val) === -1) {
|
||||
dnsServers.push(val);
|
||||
}
|
||||
@@ -370,10 +379,11 @@ Singleton {
|
||||
const details = root.activeWifiDetails || ({});
|
||||
let rate = "";
|
||||
const lines = text.split("\n");
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i].trim();
|
||||
if (line.toLowerCase().startsWith("tx bitrate:")) {
|
||||
rate = line.substring(11).trim();
|
||||
for (var k = 0; k < lines.length; k++) {
|
||||
var line2 = lines[k].trim();
|
||||
var low = line2.toLowerCase();
|
||||
if (low.indexOf("tx bitrate:") === 0) {
|
||||
rate = line2.substring(11).trim();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -515,7 +525,7 @@ Singleton {
|
||||
id: pingCheckProcess
|
||||
command: ["sh", "-c", "ping -c1 -W2 ping.archlinux.org >/dev/null 2>&1 || " + "ping -c1 -W2 1.1.1.1 >/dev/null 2>&1 || " + "curl -fsI --max-time 5 https://cloudflare.com/cdn-cgi/trace >/dev/null 2>&1"]
|
||||
|
||||
onExited: (exitCode, exitStatus) => {
|
||||
onExited: function(exitCode, exitStatus) {
|
||||
if (exitCode === 0) {
|
||||
connectivityCheckProcess.failedChecks = 0;
|
||||
} else {
|
||||
@@ -549,10 +559,13 @@ Singleton {
|
||||
return;
|
||||
}
|
||||
|
||||
const profiles = {};
|
||||
const lines = text.split("\n").filter(l => l.trim());
|
||||
for (const line of lines) {
|
||||
profiles[line.trim()] = true;
|
||||
var profiles = {};
|
||||
var lines = text.split("\n");
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var l = lines[i];
|
||||
if (l && l.trim()) {
|
||||
profiles[l.trim()] = true;
|
||||
}
|
||||
}
|
||||
scanProcess.existingProfiles = profiles;
|
||||
scanProcess.running = true;
|
||||
@@ -657,8 +670,8 @@ Singleton {
|
||||
// Logging
|
||||
const oldSSIDs = Object.keys(root.networks);
|
||||
const newSSIDs = Object.keys(networksMap);
|
||||
const newNetworks = newSSIDs.filter(ssid => !oldSSIDs.includes(ssid));
|
||||
const lostNetworks = oldSSIDs.filter(ssid => !newSSIDs.includes(ssid));
|
||||
const newNetworks = newSSIDs.filter(function(ssid) { return oldSSIDs.indexOf(ssid) === -1; });
|
||||
const lostNetworks = oldSSIDs.filter(function(ssid) { return newSSIDs.indexOf(ssid) === -1; });
|
||||
|
||||
if (newNetworks.length > 0 || lostNetworks.length > 0) {
|
||||
if (newNetworks.length > 0) {
|
||||
@@ -674,6 +687,22 @@ Singleton {
|
||||
root.networks = networksMap;
|
||||
root.scanning = false;
|
||||
|
||||
// Preload active Wi‑Fi details so Info panel shows instantly when opened
|
||||
// This is lightweight and guarded by detailsLoading + TTL.
|
||||
var hasConnected = false;
|
||||
for (var ssid in networksMap) {
|
||||
if (networksMap.hasOwnProperty(ssid)) {
|
||||
var net = networksMap[ssid];
|
||||
if (net && net.connected) {
|
||||
hasConnected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasConnected) {
|
||||
root.refreshActiveWifiDetails();
|
||||
}
|
||||
|
||||
// Check if we need to start a new scan
|
||||
if (root.scanPending) {
|
||||
root.scanPending = false;
|
||||
@@ -707,7 +736,7 @@ Singleton {
|
||||
if (mode === "saved") {
|
||||
return ["nmcli", "connection", "up", "id", ssid];
|
||||
} else {
|
||||
const cmd = ["nmcli", "device", "wifi", "connect", ssid];
|
||||
var cmd = ["nmcli", "device", "wifi", "connect", ssid];
|
||||
if (password) {
|
||||
cmd.push("password", password);
|
||||
}
|
||||
@@ -725,7 +754,7 @@ Singleton {
|
||||
// on success. Empty output or other messages indicate failure.
|
||||
const output = text.trim();
|
||||
|
||||
if (!output || (!output.includes("successfully activated") && !output.includes("Connection successfully"))) {
|
||||
if (!output || (output.indexOf("successfully activated") === -1 && output.indexOf("Connection successfully") === -1)) {
|
||||
// No success message - likely an error occurred
|
||||
// Don't update anything, let stderr handler deal with it
|
||||
return;
|
||||
@@ -744,9 +773,12 @@ Singleton {
|
||||
// Immediately update the UI before scanning
|
||||
root.updateNetworkStatus(connectProcess.ssid, true);
|
||||
|
||||
// Preload details immediately so Info panel has data instantly
|
||||
root.refreshActiveWifiDetails();
|
||||
|
||||
root.connecting = false;
|
||||
root.connectingTo = "";
|
||||
Logger.i("Network", `Connected to network: '${connectProcess.ssid}'`);
|
||||
Logger.i("Network", "Connected to network: '" + connectProcess.ssid + "'");
|
||||
ToastService.showNotice(I18n.tr("wifi.panel.title"), I18n.tr("toast.wifi.connected", {
|
||||
"ssid": connectProcess.ssid
|
||||
}), "wifi");
|
||||
@@ -764,12 +796,12 @@ Singleton {
|
||||
|
||||
if (text.trim()) {
|
||||
// Parse common errors
|
||||
if (text.includes("Secrets were required") || text.includes("no secrets provided")) {
|
||||
if (text.indexOf("Secrets were required") !== -1 || text.indexOf("no secrets provided") !== -1) {
|
||||
root.lastError = "Incorrect password";
|
||||
forget(connectProcess.ssid);
|
||||
} else if (text.includes("No network with SSID")) {
|
||||
} else if (text.indexOf("No network with SSID") !== -1) {
|
||||
root.lastError = "Network not found";
|
||||
} else if (text.includes("Timeout")) {
|
||||
} else if (text.indexOf("Timeout") !== -1) {
|
||||
root.lastError = "Connection timeout";
|
||||
} else {
|
||||
root.lastError = text.split("\n")[0].trim();
|
||||
@@ -789,7 +821,7 @@ Singleton {
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
Logger.i("Network", `Disconnected from network: '${disconnectProcess.ssid}'`);
|
||||
Logger.i("Network", "Disconnected from network: '" + disconnectProcess.ssid + "'");
|
||||
ToastService.showNotice(I18n.tr("wifi.panel.title"), I18n.tr("toast.wifi.disconnected", {
|
||||
"ssid": disconnectProcess.ssid
|
||||
}), "wifi-off");
|
||||
@@ -823,38 +855,36 @@ Singleton {
|
||||
running: false
|
||||
|
||||
// Try multiple common profile name patterns
|
||||
command: ["sh", "-c", `
|
||||
ssid="$1"
|
||||
deleted=false
|
||||
|
||||
# Try exact SSID match first
|
||||
if nmcli connection delete id "$ssid" 2>/dev/null; then
|
||||
echo "Deleted profile: $ssid"
|
||||
deleted=true
|
||||
fi
|
||||
|
||||
# Try "Auto <SSID>" pattern
|
||||
if nmcli connection delete id "Auto $ssid" 2>/dev/null; then
|
||||
echo "Deleted profile: Auto $ssid"
|
||||
deleted=true
|
||||
fi
|
||||
|
||||
# Try "<SSID> 1", "<SSID> 2", etc. patterns
|
||||
for i in 1 2 3; do
|
||||
if nmcli connection delete id "$ssid $i" 2>/dev/null; then
|
||||
echo "Deleted profile: $ssid $i"
|
||||
deleted=true
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$deleted" = "false" ]; then
|
||||
echo "No profiles found for SSID: $ssid"
|
||||
fi
|
||||
`, "--", ssid]
|
||||
command: {
|
||||
var script = "";
|
||||
script += "ssid=\"$1\"\n";
|
||||
script += "deleted=false\n\n";
|
||||
script += "# Try exact SSID match first\n";
|
||||
script += "if nmcli connection delete id \"$ssid\" 2>/dev/null; then\n";
|
||||
script += " echo \"Deleted profile: $ssid\"\n";
|
||||
script += " deleted=true\n";
|
||||
script += "fi\n\n";
|
||||
script += "# Try \"Auto $ssid\" pattern\n";
|
||||
script += "if nmcli connection delete id \"Auto $ssid\" 2>/dev/null; then\n";
|
||||
script += " echo \"Deleted profile: Auto $ssid\"\n";
|
||||
script += " deleted=true\n";
|
||||
script += "fi\n\n";
|
||||
script += "# Try \"$ssid 1\", \"$ssid 2\", etc. patterns\n";
|
||||
script += "for i in 1 2 3; do\n";
|
||||
script += " if nmcli connection delete id \"$ssid $i\" 2>/dev/null; then\n";
|
||||
script += " echo \"Deleted profile: $ssid $i\"\n";
|
||||
script += " deleted=true\n";
|
||||
script += " fi\n";
|
||||
script += "done\n\n";
|
||||
script += "if [ \"$deleted\" = \"false\" ]; then\n";
|
||||
script += " echo \"No profiles found for SSID: $ssid\"\n";
|
||||
script += "fi\n";
|
||||
return ["sh", "-c", script, "--", ssid];
|
||||
}
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
Logger.i("Network", `Forget network: "${forgetProcess.ssid}"`);
|
||||
Logger.i("Network", "Forget network: \"" + forgetProcess.ssid + "\"");
|
||||
Logger.d("Network", text.trim().replace(/[\r\n]/g, " "));
|
||||
|
||||
// Update both cached and existing status immediately
|
||||
@@ -878,7 +908,7 @@ Singleton {
|
||||
stderr: StdioCollector {
|
||||
onStreamFinished: {
|
||||
root.forgettingNetwork = "";
|
||||
if (text.trim() && !text.includes("No profiles found")) {
|
||||
if (text.trim() && text.indexOf("No profiles found") === -1) {
|
||||
Logger.w("Network", "Forget error: " + text);
|
||||
}
|
||||
// Still Trigger a scan even on error
|
||||
|
||||
Reference in New Issue
Block a user