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:
@@ -463,7 +463,8 @@
|
||||
"info": "Info",
|
||||
"device-address": "Device address",
|
||||
"paired": "Paired",
|
||||
"trusted": "Trusted"
|
||||
"trusted": "Trusted",
|
||||
"discoverable": "Discoverable"
|
||||
}
|
||||
},
|
||||
"calendar": {
|
||||
@@ -2553,7 +2554,23 @@
|
||||
"connected": "Connected to '{ssid}'",
|
||||
"disabled": "Disabled",
|
||||
"disconnected": "Disconnected from '{ssid}'",
|
||||
"enabled": "Enabled"
|
||||
"enabled": "Enabled",
|
||||
"incorrect-password": "Incorrect password",
|
||||
"network-not-found": "Network not found",
|
||||
"connection-timeout": "Connection timeout",
|
||||
"connection-failed": "Connection failed"
|
||||
},
|
||||
"bluetooth": {
|
||||
"enabled": "Enabled",
|
||||
"disabled": "Disabled",
|
||||
"pair-failed": "Failed to pair device",
|
||||
"connect-failed": "Failed to connect to device",
|
||||
"disconnect-failed": "Failed to disconnect from device",
|
||||
"forget-failed": "Failed to forget device",
|
||||
"state-change-failed": "Failed to change Bluetooth state",
|
||||
"discoverable-enabled": "Discoverable enabled",
|
||||
"discoverable-disabled": "Discoverable disabled",
|
||||
"discoverable-change-failed": "Failed to change discoverable state"
|
||||
}
|
||||
},
|
||||
"tooltips": {
|
||||
|
||||
@@ -62,6 +62,17 @@ SmartPanel {
|
||||
baseSize: Style.baseWidgetSize * 0.65
|
||||
}
|
||||
|
||||
// Discoverability toggle (advertising)
|
||||
NIconButton {
|
||||
enabled: BluetoothService.enabled
|
||||
icon: BluetoothService.discoverable ? "broadcast" : "broadcast-off"
|
||||
tooltipText: I18n.tr("bluetooth.panel.discoverable")
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
onClicked: {
|
||||
BluetoothService.setDiscoverable(!BluetoothService.discoverable);
|
||||
}
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
enabled: BluetoothService.enabled
|
||||
icon: BluetoothService.adapter && BluetoothService.adapter.discovering ? "stop" : "refresh"
|
||||
|
||||
@@ -10,6 +10,14 @@ import qs.Services.UI
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
// Translation fallback helper (prevents ##key## leaking to UI)
|
||||
function trOr(key, fallback) {
|
||||
var v = I18n.tr(key);
|
||||
if (!v) return fallback;
|
||||
if (v.indexOf("##") === 0 && v.lastIndexOf("##") === v.length - 2) return fallback;
|
||||
return v;
|
||||
}
|
||||
|
||||
property bool airplaneModeToggled: false
|
||||
property bool lastBluetoothBlocked: false
|
||||
readonly property BluetoothAdapter adapter: Bluetooth.defaultAdapter
|
||||
@@ -18,6 +26,8 @@ Singleton {
|
||||
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
|
||||
// Adapter discoverability (advertising) flag
|
||||
readonly property bool discoverable: (adapter && adapter.discoverable !== undefined) ? adapter.discoverable : false
|
||||
readonly property var devices: adapter ? adapter.devices : null
|
||||
readonly property var pairedDevices: {
|
||||
if (!adapter || !adapter.devices) {
|
||||
@@ -71,10 +81,10 @@ Singleton {
|
||||
if (bluetoothBlockedToggled) {
|
||||
checkWifiBlocked.running = true;
|
||||
} else if (adapter.state === BluetoothAdapterState.Enabled) {
|
||||
ToastService.showNotice(I18n.tr("bluetooth.panel.title"), I18n.tr("toast.bluetooth.enabled"), "bluetooth");
|
||||
ToastService.showNotice(I18n.tr("bluetooth.panel.title"), trOr("toast.bluetooth.enabled", "Enabled"), "bluetooth");
|
||||
discoveryTimer.running = true;
|
||||
} else if (adapter.state === BluetoothAdapterState.Disabled) {
|
||||
ToastService.showNotice(I18n.tr("bluetooth.panel.title"), I18n.tr("toast.bluetooth.disabled"), "bluetooth-off");
|
||||
ToastService.showNotice(I18n.tr("bluetooth.panel.title"), trOr("toast.bluetooth.disabled", "Disabled"), "bluetooth-off");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -280,12 +290,14 @@ Singleton {
|
||||
}
|
||||
} catch (e) {
|
||||
Logger.w("Bluetooth", "pairDevice failed", e);
|
||||
ToastService.showWarning(I18n.tr("bluetooth.panel.title"), I18n.tr("toast.bluetooth.pair-failed"));
|
||||
// Fallback to connect if pair not supported
|
||||
try {
|
||||
device.trusted = true;
|
||||
device.connect();
|
||||
} catch (e2) {
|
||||
Logger.w("Bluetooth", "pairDevice connect fallback failed", e2);
|
||||
ToastService.showWarning(I18n.tr("bluetooth.panel.title"), I18n.tr("toast.bluetooth.connect-failed"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -299,26 +311,38 @@ Singleton {
|
||||
if (!device) {
|
||||
return;
|
||||
}
|
||||
|
||||
device.trusted = true;
|
||||
device.connect();
|
||||
try {
|
||||
device.trusted = true;
|
||||
device.connect();
|
||||
} catch (e) {
|
||||
Logger.w("Bluetooth", "connectDeviceWithTrust failed", e);
|
||||
ToastService.showWarning(I18n.tr("bluetooth.panel.title"), I18n.tr("toast.bluetooth.connect-failed"));
|
||||
}
|
||||
}
|
||||
|
||||
function disconnectDevice(device) {
|
||||
if (!device) {
|
||||
return;
|
||||
}
|
||||
|
||||
device.disconnect();
|
||||
try {
|
||||
device.disconnect();
|
||||
} catch (e) {
|
||||
Logger.w("Bluetooth", "disconnectDevice failed", e);
|
||||
ToastService.showWarning(I18n.tr("bluetooth.panel.title"), I18n.tr("toast.bluetooth.disconnect-failed"));
|
||||
}
|
||||
}
|
||||
|
||||
function forgetDevice(device) {
|
||||
if (!device) {
|
||||
return;
|
||||
}
|
||||
|
||||
device.trusted = false;
|
||||
device.forget();
|
||||
try {
|
||||
device.trusted = false;
|
||||
device.forget();
|
||||
} catch (e) {
|
||||
Logger.w("Bluetooth", "forgetDevice failed", e);
|
||||
ToastService.showWarning(I18n.tr("bluetooth.panel.title"), I18n.tr("toast.bluetooth.forget-failed"));
|
||||
}
|
||||
}
|
||||
|
||||
function setBluetoothEnabled(state) {
|
||||
@@ -328,7 +352,32 @@ Singleton {
|
||||
}
|
||||
|
||||
Logger.i("Bluetooth", "SetBluetoothEnabled", state);
|
||||
adapter.enabled = state;
|
||||
try {
|
||||
adapter.enabled = state;
|
||||
} catch (e) {
|
||||
Logger.w("Bluetooth", "Enable/Disable failed", e);
|
||||
ToastService.showWarning(I18n.tr("bluetooth.panel.title"), I18n.tr("toast.bluetooth.state-change-failed"));
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle adapter discoverability (advertising visibility)
|
||||
function setDiscoverable(state) {
|
||||
if (!adapter) {
|
||||
Logger.w("Bluetooth", "setDiscoverable: No adapter available");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
adapter.discoverable = state;
|
||||
if (state) {
|
||||
ToastService.showNotice(I18n.tr("bluetooth.panel.title"), trOr("toast.bluetooth.discoverable-enabled", "Discoverable enabled"), "broadcast");
|
||||
} else {
|
||||
ToastService.showNotice(I18n.tr("bluetooth.panel.title"), trOr("toast.bluetooth.discoverable-disabled", "Discoverable disabled"), "broadcast-off");
|
||||
}
|
||||
Logger.i("Bluetooth", "Discoverable state set to:", state);
|
||||
} catch (e) {
|
||||
Logger.w("Bluetooth", "Failed to change discoverable state", e);
|
||||
ToastService.showWarning(I18n.tr("bluetooth.panel.title"), trOr("toast.bluetooth.discoverable-change-failed", "Failed to change discoverable state"));
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
@@ -339,7 +388,7 @@ Singleton {
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
var wifiBlocked = text && text.trim().indexOf("Soft blocked: yes") !== -1;
|
||||
Logger.d("Network", "Wi-Fi adapter was detected as blocked:", blocked);
|
||||
Logger.d("Network", "Wi-Fi adapter was detected as blocked:", wifiBlocked);
|
||||
|
||||
// Check if airplane mode has been toggled
|
||||
if (wifiBlocked && wifiBlocked === root.blocked) {
|
||||
@@ -351,13 +400,20 @@ Singleton {
|
||||
NetworkService.setWifiEnabled(true);
|
||||
ToastService.showNotice(I18n.tr("toast.airplane-mode.title"), I18n.tr("toast.airplane-mode.disabled"), "plane-off");
|
||||
} else if (adapter.enabled) {
|
||||
ToastService.showNotice(I18n.tr("bluetooth.panel.title"), I18n.tr("toast.bluetooth.enabled"), "bluetooth");
|
||||
ToastService.showNotice(I18n.tr("bluetooth.panel.title"), trOr("toast.bluetooth.enabled", "Enabled"), "bluetooth");
|
||||
discoveryTimer.running = true;
|
||||
} else {
|
||||
ToastService.showNotice(I18n.tr("bluetooth.panel.title"), I18n.tr("toast.bluetooth.disabled"), "bluetooth-off");
|
||||
ToastService.showNotice(I18n.tr("bluetooth.panel.title"), trOr("toast.bluetooth.disabled", "Disabled"), "bluetooth-off");
|
||||
}
|
||||
root.airplaneModeToggled = false;
|
||||
}
|
||||
}
|
||||
stderr: StdioCollector {
|
||||
onStreamFinished: {
|
||||
if (text && text.trim()) {
|
||||
Logger.w("Bluetooth", "rfkill (wifi) stderr:", text.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,6 +286,13 @@ Singleton {
|
||||
}
|
||||
}
|
||||
}
|
||||
stderr: StdioCollector {
|
||||
onStreamFinished: {
|
||||
if (text && text.trim()) {
|
||||
Logger.w("Network", "ethernetState nmcli stderr:", text.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Discover connected Wi‑Fi interface
|
||||
@@ -321,6 +328,18 @@ Singleton {
|
||||
}
|
||||
}
|
||||
}
|
||||
stderr: StdioCollector {
|
||||
onStreamFinished: {
|
||||
if (text && text.trim()) {
|
||||
Logger.w("Network", "nmcli device list stderr:", text.trim());
|
||||
}
|
||||
// Fail-safe to avoid spinner
|
||||
if (!root.activeWifiIf) {
|
||||
root.activeWifiDetailsTimestamp = Date.now();
|
||||
root.detailsLoading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch IPv4 and gateway for the interface
|
||||
@@ -365,6 +384,15 @@ Singleton {
|
||||
wifiIwLinkProcess.running = true;
|
||||
}
|
||||
}
|
||||
stderr: StdioCollector {
|
||||
onStreamFinished: {
|
||||
if (text && text.trim()) {
|
||||
Logger.w("Network", "nmcli device show stderr:", text.trim());
|
||||
}
|
||||
// Still proceed to finalize details to avoid UI waiting forever
|
||||
root.activeWifiDetailsTimestamp = Date.now();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Optional: query Wi‑Fi bitrate via iw if available
|
||||
@@ -426,6 +454,15 @@ Singleton {
|
||||
root.detailsLoading = false;
|
||||
}
|
||||
}
|
||||
stderr: StdioCollector {
|
||||
onStreamFinished: {
|
||||
if (text && text.trim()) {
|
||||
Logger.w("Network", "iw link stderr:", text.trim());
|
||||
}
|
||||
root.activeWifiDetailsTimestamp = Date.now();
|
||||
root.detailsLoading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only check the state of the actual interface
|
||||
@@ -444,6 +481,13 @@ Singleton {
|
||||
}
|
||||
}
|
||||
}
|
||||
stderr: StdioCollector {
|
||||
onStreamFinished: {
|
||||
if (text && text.trim()) {
|
||||
Logger.w("Network", "Wi-Fi state query stderr:", text.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process to enable/disable the Wi-Fi interface
|
||||
@@ -571,6 +615,19 @@ Singleton {
|
||||
scanProcess.running = true;
|
||||
}
|
||||
}
|
||||
stderr: StdioCollector {
|
||||
onStreamFinished: {
|
||||
if (text && text.trim()) {
|
||||
Logger.w("Network", "Profile check stderr:", text.trim());
|
||||
}
|
||||
// Fail safe
|
||||
if (root.scanning) {
|
||||
root.scanning = false;
|
||||
delayedScanTimer.interval = 5000;
|
||||
delayedScanTimer.restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
@@ -797,17 +854,20 @@ Singleton {
|
||||
if (text.trim()) {
|
||||
// Parse common errors
|
||||
if (text.indexOf("Secrets were required") !== -1 || text.indexOf("no secrets provided") !== -1) {
|
||||
root.lastError = "Incorrect password";
|
||||
root.lastError = I18n.tr("toast.wifi.incorrect-password");
|
||||
forget(connectProcess.ssid);
|
||||
} else if (text.indexOf("No network with SSID") !== -1) {
|
||||
root.lastError = "Network not found";
|
||||
root.lastError = I18n.tr("toast.wifi.network-not-found");
|
||||
} else if (text.indexOf("Timeout") !== -1) {
|
||||
root.lastError = "Connection timeout";
|
||||
root.lastError = I18n.tr("toast.wifi.connection-timeout");
|
||||
} else {
|
||||
root.lastError = text.split("\n")[0].trim();
|
||||
// Generic fallback
|
||||
root.lastError = I18n.tr("toast.wifi.connection-failed");
|
||||
}
|
||||
|
||||
Logger.w("Network", "Connect error: " + text);
|
||||
// Notify user about the failure
|
||||
ToastService.showWarning(I18n.tr("wifi.panel.title"), root.lastError || I18n.tr("toast.wifi.connection-failed"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user