diff --git a/Assets/settings-default.json b/Assets/settings-default.json index 4fe07b90f..fc5db6525 100644 --- a/Assets/settings-default.json +++ b/Assets/settings-default.json @@ -335,11 +335,13 @@ }, "network": { "wifiEnabled": true, + "airplaneModeEnabled": false, "bluetoothRssiPollingEnabled": false, "bluetoothRssiPollIntervalMs": 60000, "wifiDetailsViewMode": "grid", "bluetoothDetailsViewMode": "grid", - "bluetoothHideUnnamedDevices": false + "bluetoothHideUnnamedDevices": false, + "disableDiscoverability": false }, "sessionMenu": { "enableCountdown": true, diff --git a/Commons/IconsTabler.qml b/Commons/IconsTabler.qml index 0ebe03a58..f0a9226ad 100644 --- a/Commons/IconsTabler.qml +++ b/Commons/IconsTabler.qml @@ -118,7 +118,7 @@ Singleton { "settings-launcher": "rocket", "settings-audio": "device-speaker", "settings-display": "device-desktop", - "settings-network": "affiliate", + "settings-network": "circles-relation", "settings-brightness": "brightness-up", "settings-location": "world-pin", "settings-color-scheme": "palette", diff --git a/Commons/Settings.qml b/Commons/Settings.qml index 63e790244..f474f3f6d 100644 --- a/Commons/Settings.qml +++ b/Commons/Settings.qml @@ -540,11 +540,13 @@ Singleton { // network property JsonObject network: JsonObject { property bool wifiEnabled: true + property bool airplaneModeEnabled: false property bool bluetoothRssiPollingEnabled: false // Opt-in Bluetooth RSSI polling (uses bluetoothctl) property int bluetoothRssiPollIntervalMs: 60000 // Polling interval in milliseconds for RSSI queries property string wifiDetailsViewMode: "grid" // "grid" or "list" property string bluetoothDetailsViewMode: "grid" // "grid" or "list" property bool bluetoothHideUnnamedDevices: false + property bool disableDiscoverability: false } // session menu diff --git a/Modules/Bar/Widgets/Network.qml b/Modules/Bar/Widgets/Network.qml index 70f2d7483..72f252479 100644 --- a/Modules/Bar/Widgets/Network.qml +++ b/Modules/Bar/Widgets/Network.qml @@ -51,7 +51,7 @@ Item { "icon": Settings.data.network.wifiEnabled ? "wifi-off" : "wifi" }, { - "label": I18n.tr("tooltips.manage-wifi") + " " + I18n.tr("tooltips.open-settings"), + "label": I18n.tr("common.wifi") + " " + I18n.tr("tooltips.open-settings"), "action": "wifi-settings", "icon": "settings" }, @@ -161,7 +161,7 @@ Item { } catch (e) { // noop } - return I18n.tr("tooltips.manage-wifi"); + return I18n.tr("common.wifi"); } } } diff --git a/Modules/Panels/ControlCenter/Widgets/Network.qml b/Modules/Panels/ControlCenter/Widgets/Network.qml index 88d54568d..c8d8e8b9d 100644 --- a/Modules/Panels/ControlCenter/Widgets/Network.qml +++ b/Modules/Panels/ControlCenter/Widgets/Network.qml @@ -46,7 +46,7 @@ NIconButtonHot { } catch (e) { // noop } - return I18n.tr("tooltips.manage-wifi"); + return I18n.tr("common.wifi"); } onClicked: { var panel = PanelService.getPanel("networkPanel", screen); diff --git a/Modules/Panels/Network/NetworkPanel.qml b/Modules/Panels/Network/NetworkPanel.qml index 744eb3cba..758497171 100644 --- a/Modules/Panels/Network/NetworkPanel.qml +++ b/Modules/Panels/Network/NetworkPanel.qml @@ -140,13 +140,13 @@ SmartPanel { panelViewMode = "wifi"; } } - onEntered: TooltipService.show(parent, panelViewMode === "wifi" ? I18n.tr("control-center.wifi.label-ethernet") : I18n.tr("wifi.panel.title")) + onEntered: TooltipService.show(parent, panelViewMode === "wifi" ? I18n.tr("control-center.wifi.label-ethernet") : I18n.tr("common.wifi")) onExited: TooltipService.hide() } } NText { - text: panelViewMode === "wifi" ? I18n.tr("wifi.panel.title") : I18n.tr("control-center.wifi.label-ethernet") + text: panelViewMode === "wifi" ? I18n.tr("common.wifi") : I18n.tr("control-center.wifi.label-ethernet") pointSize: Style.fontSizeL font.weight: Style.fontWeightBold color: Color.mOnSurface @@ -198,7 +198,7 @@ SmartPanel { } NTabButton { - text: I18n.tr("tooltips.manage-wifi") + text: I18n.tr("common.wifi") tabIndex: 0 checked: modeTabBar.currentIndex === 0 } diff --git a/Modules/Panels/Network/WiFiNetworksList.qml b/Modules/Panels/Network/WiFiNetworksList.qml index 89c695b12..998d4ed70 100644 --- a/Modules/Panels/Network/WiFiNetworksList.qml +++ b/Modules/Panels/Network/WiFiNetworksList.qml @@ -402,7 +402,7 @@ NBox { const value = NetworkService.activeWifiIf || ""; if (value.length > 0) { Quickshell.execDetached(["wl-copy", value]); - ToastService.showNotice(I18n.tr("wifi.panel.title"), I18n.tr("toast.bluetooth.address-copied"), "wifi"); + ToastService.showNotice(I18n.tr("common.wifi"), I18n.tr("toast.bluetooth.address-copied"), "wifi"); } } } @@ -545,7 +545,7 @@ NBox { const value = NetworkService.activeWifiDetails.ipv4 || ""; if (value.length > 0) { Quickshell.execDetached(["wl-copy", value]); - ToastService.showNotice(I18n.tr("wifi.panel.title"), I18n.tr("toast.bluetooth.address-copied"), "wifi"); + ToastService.showNotice(I18n.tr("common.wifi"), I18n.tr("toast.bluetooth.address-copied"), "wifi"); } } } diff --git a/Modules/Panels/Settings/Tabs/Connections/BluetoothSubTab.qml b/Modules/Panels/Settings/Tabs/Connections/BluetoothSubTab.qml index abfd47183..e98a90f3b 100644 --- a/Modules/Panels/Settings/Tabs/Connections/BluetoothSubTab.qml +++ b/Modules/Panels/Settings/Tabs/Connections/BluetoothSubTab.qml @@ -104,15 +104,15 @@ Item { function _updateScanningState() { if (effectivelyVisible && BluetoothService.enabled && !showOnlyLists) { - Logger.d("Bluetooth Prefs", "Panel/Tab Active"); + Logger.d("BluetoothPrefs", "Panel/tab active"); if (!isScanningActive) { BluetoothService.setScanActive(true); } - if (!isDiscoverable) { + if (!Settings.data.network.disableDiscoverability && !isDiscoverable) { BluetoothService.setDiscoverable(true); } } else { - Logger.d("Bluetooth Prefs", "Panel/Tab Inactive"); + Logger.d("BluetoothPrefs", "Panel/tab inactive"); if (isScanningActive) { BluetoothService.setScanActive(false); } @@ -131,7 +131,7 @@ Item { if (isDiscoverable) { BluetoothService.setDiscoverable(false); } - Logger.d("Bluetooth Prefs", "Panel Closed"); + Logger.d("BluetoothPrefs", "Panel closed"); } ColumnLayout { @@ -161,11 +161,8 @@ Item { color: BluetoothService.enabled ? Color.mPrimary : Color.mOnSurfaceVariant } - NText { - text: I18n.tr("common.bluetooth") - pointSize: Style.fontSizeL - font.weight: Style.fontWeightBold - color: Color.mOnSurface + NLabel { + label: I18n.tr("common.bluetooth") } Item { @@ -186,9 +183,7 @@ Item { } NText { - text: I18n.tr("panels.connections.bluetooth-discoverable", { - hostName: HostService.hostName - }) + text: I18n.tr("panels.connections.bluetooth-discoverable", {hostName: HostService.hostName}) visible: (BluetoothService.enabled && isDiscoverable) richTextEnabled: true wrapMode: Text.WordWrap @@ -320,19 +315,31 @@ Item { } NToggle { - label: I18n.tr("tooltips.hide-unnamed-devices") - description: "Hide devices that appear only as Bluetooth addresses." - checked: Settings.data && Settings.data.network && Settings.data.network.bluetoothHideUnnamedDevices + label: I18n.tr("panels.connections.hide-unnamed-devices-label") // former i18n key: tooltips.hide-unnamed-devices + description: I18n.tr("panels.connections.hide-unnamed-devices-description") // "Hide devices that appear only as Bluetooth addresses." + checked: Settings.data.network.bluetoothHideUnnamedDevices onToggled: checked => Settings.data.network.bluetoothHideUnnamedDevices = checked Layout.alignment: Qt.AlignVCenter visible: !btprefs.showOnlyLists && BluetoothService.enabled } + NToggle { + label: I18n.tr("panels.connections.disable-discoverability-label") // "Disable device visibility" + description: I18n.tr("panels.connections.disable-discoverability-description") // "Hide your device from nearby Bluetooth devices." + checked: Settings.data.network.disableDiscoverability + onToggled: checked => { + Settings.data.network.disableDiscoverability = checked; + BluetoothService.setDiscoverable(!checked); + } + Layout.alignment: Qt.AlignVCenter + visible: !btprefs.showOnlyLists && BluetoothService.enabled + } + // RSSI Polling NToggle { label: I18n.tr("panels.connections.bluetooth-rssi-polling-label") description: I18n.tr("panels.connections.bluetooth-rssi-polling-description") - checked: Settings.data && Settings.data.network && Settings.data.network.bluetoothRssiPollingEnabled + checked: Settings.data.network.bluetoothRssiPollingEnabled onToggled: checked => Settings.data.network.bluetoothRssiPollingEnabled = checked Layout.alignment: Qt.AlignVCenter visible: !btprefs.showOnlyLists && BluetoothService.enabled @@ -343,12 +350,12 @@ Item { from: 10000 to: 120000 stepSize: 1000 - value: Settings.data && Settings.data.network && Settings.data.network.bluetoothRssiPollIntervalMs + value: Settings.data.network.bluetoothRssiPollIntervalMs defaultValue: Settings.getDefaultValue("network.bluetoothRssiPollIntervalMs") onValueChanged: Settings.data.network.bluetoothRssiPollIntervalMs = value suffix: " ms" Layout.alignment: Qt.AlignVCenter - visible: (!btprefs.showOnlyLists && BluetoothService.enabled) && Settings.data && Settings.data.network && Settings.data.network.bluetoothRssiPollingEnabled + visible: (!btprefs.showOnlyLists && BluetoothService.enabled) && Settings.data.network.bluetoothRssiPollingEnabled } } diff --git a/Modules/Panels/Settings/Tabs/Connections/EthernetSubTab.qml b/Modules/Panels/Settings/Tabs/Connections/EthernetSubTab.qml deleted file mode 100644 index 1e083f415..000000000 --- a/Modules/Panels/Settings/Tabs/Connections/EthernetSubTab.qml +++ /dev/null @@ -1,25 +0,0 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import qs.Commons -import qs.Services.Networking -import qs.Widgets - -Item { - id: root - Layout.fillWidth: true - // TBD: Implement Ethernet settings - implicitHeight: placeholder.implicitHeight - - NBox { - id: placeholder - anchors.fill: parent - implicitHeight: 100 - - NText { - anchors.centerIn: parent - text: "Ethernet Settings - Coming Soon" - color: Color.mOnSurfaceVariant - } - } -} diff --git a/Modules/Panels/Settings/Tabs/Connections/WifiSubTab.qml b/Modules/Panels/Settings/Tabs/Connections/WifiSubTab.qml index 5213fd023..c7418979f 100644 --- a/Modules/Panels/Settings/Tabs/Connections/WifiSubTab.qml +++ b/Modules/Panels/Settings/Tabs/Connections/WifiSubTab.qml @@ -25,6 +25,43 @@ Item { anchors.right: parent.right spacing: Style.marginL + // Airplane Mode Toggle + NBox { + Layout.fillWidth: true + Layout.preferredHeight: masterControlColAirplane.implicitHeight + + ColumnLayout { + id: masterControlColAirplane + anchors.fill: parent + spacing: Style.marginM + + RowLayout { + Layout.fillWidth: true + spacing: Style.marginM + + NIcon { + icon: Settings.data.network.airplaneModeEnabled ? "plane" : "plane-off" + pointSize: Style.fontSizeXXL + color: Settings.data.network.airplaneModeEnabled ? Color.mPrimary : Color.mOnSurfaceVariant + } + + NLabel { + label: I18n.tr("toast.airplane-mode.title") + } + + Item { + Layout.fillWidth: true + } + + NToggle { + checked: Settings.data.network.airplaneModeEnabled + onToggled: checked => NetworkService.setAirplaneMode(checked) + Layout.alignment: Qt.AlignVCenter + } + } + } + } + // Wi-Fi Master Control NBox { Layout.fillWidth: true @@ -45,11 +82,11 @@ Item { color: Settings.data.network.wifiEnabled ? Color.mPrimary : Color.mOnSurfaceVariant } - NText { - text: I18n.tr("tooltips.manage-wifi") - pointSize: Style.fontSizeL - font.weight: Style.fontWeightBold - color: Color.mOnSurface + NLabel { + label: I18n.tr("common.wifi") + } + + Item { Layout.fillWidth: true } @@ -57,10 +94,10 @@ Item { checked: Settings.data.network.wifiEnabled onToggled: checked => NetworkService.setWifiEnabled(checked) Layout.alignment: Qt.AlignVCenter - enabled: !NetworkService.wifiBlocked + enabled: ProgramCheckerService.nmcliAvailable } } } } } -} +} \ No newline at end of file diff --git a/Modules/Panels/Settings/Tabs/ConnectionsTab.qml b/Modules/Panels/Settings/Tabs/ConnectionsTab.qml index 41f4e4408..893b97c62 100644 --- a/Modules/Panels/Settings/Tabs/ConnectionsTab.qml +++ b/Modules/Panels/Settings/Tabs/ConnectionsTab.qml @@ -18,7 +18,7 @@ ColumnLayout { currentIndex: tabView.currentIndex NTabButton { - text: I18n.tr("tooltips.manage-wifi") + text: I18n.tr("common.wifi") // visible: NetworkService.wifiAvailable enabled: NetworkService.wifiAvailable // Remove when work finished, only use visibility tabIndex: 0 @@ -31,13 +31,6 @@ ColumnLayout { tabIndex: 1 checked: subTabBar.currentIndex === 1 } - NTabButton { - text: I18n.tr("panels.connections.ethernet") - // visible: NetworkService.ethernetAvailable - enabled: NetworkService.ethernetAvailable // Remove when work finished, only use visibility - tabIndex: 2 - checked: subTabBar.currentIndex === 2 - } } Item { @@ -51,6 +44,5 @@ ColumnLayout { currentIndex: subTabBar.currentIndex WifiSubTab {} BluetoothSubTab {} - EthernetSubTab {} } } diff --git a/Services/Networking/BluetoothService.qml b/Services/Networking/BluetoothService.qml index af026be6b..fbc79c1a5 100644 --- a/Services/Networking/BluetoothService.qml +++ b/Services/Networking/BluetoothService.qml @@ -17,16 +17,20 @@ Singleton { readonly property BluetoothAdapter adapter: Bluetooth.defaultAdapter + // Airplane mode status + property bool airplaneModeToggled: false + property bool wifiBlocked: false + property bool btBlocked: false + // Power/blocked/availability state readonly property bool bluetoothAvailable: !!adapter - readonly property bool enabled: adapter ? adapter.enabled : root.ctlPowered - readonly property bool blocked: adapter?.state === BluetoothAdapterState.Blocked + readonly property bool enabled: adapter?.enabled ?? root.ctlPowered property bool ctlPowered: false property bool ctlDiscovering: false property bool ctlDiscoverable: false - // Adapter discoverability (advertising) flag (driven by bluetoothctl) - readonly property bool discoverable: root.ctlDiscoverable + // Adapter discoverability (advertising) flag + readonly property bool discoverable: adapter?.discoverable ?? root.ctlDiscoverable readonly property var devices: adapter ? adapter.devices : null readonly property var connectedDevices: { if (!adapter || !adapter.devices) { @@ -94,7 +98,7 @@ Singleton { } // Exposed scanning flag for UI button state; reflects adapter discovery when available - readonly property bool scanningActive: (adapter && adapter.discovering) || root.ctlDiscovering + readonly property bool scanningActive: adapter?.discovering ?? root.ctlDiscovering function init() { Logger.i("Bluetooth", "Service started"); @@ -107,13 +111,58 @@ Singleton { target: adapter function onStateChanged() { if (!adapter || adapter.state === BluetoothAdapter.Enabling || adapter.state === BluetoothAdapter.Disabling) { - return; + return; + } + checkAirplaneMode.running = true; } + } - if (adapter.state === BluetoothAdapter.Enabled) { - ToastService.showNotice(I18n.tr("common.bluetooth"), I18n.tr("common.enabled"), "bluetooth"); - } else if (adapter.state === BluetoothAdapter.Disabled && !root.blocked) { - ToastService.showNotice(I18n.tr("common.bluetooth"), I18n.tr("common.disabled"), "bluetooth-off"); + Process { + id: checkAirplaneMode + running: false + command: ["rfkill", "list"] + stdout: StdioCollector { + onStreamFinished: { + var output = this.text || ""; + var wifiBlocked = /^\d+:.*Wireless LAN[^\n]*\n\s*Soft blocked:\s*yes/im.test(output) + var btBlocked = /^\d+:.*Bluetooth[^\n]*\n\s*Soft blocked:\s*yes/im.test(output) + + // Track if actual state changed + var actualAirplaneModeActive = wifiBlocked && btBlocked; + var previousAirplaneModeActive = root.wifiBlocked && root.btBlocked; + + // Check if airplane mode has been toggled + if (actualAirplaneModeActive && !previousAirplaneModeActive) { + root.airplaneModeToggled = true; + NetworkService.setWifiEnabled(false); + Settings.data.network.airplaneModeEnabled = true; + ToastService.showNotice(I18n.tr("toast.airplane-mode.title"), I18n.tr("common.enabled"), "plane"); + Logger.i("AirplaneMode", "Wi-Fi & Bluetooth adapter blocked") + } else if (!actualAirplaneModeActive && previousAirplaneModeActive) { + root.airplaneModeToggled = true; + NetworkService.setWifiEnabled(true); + Settings.data.network.airplaneModeEnabled = false; + ToastService.showNotice(I18n.tr("toast.airplane-mode.title"), I18n.tr("common.disabled"), "plane-off"); + Logger.i("AirplaneMode", "Wi-Fi & Bluetooth adapter unblocked") + } else if (adapter.enabled) { + ToastService.showNotice(I18n.tr("common.bluetooth"), I18n.tr("common.enabled"), "bluetooth"); + Logger.d("Bluetooth", "Adapter enabled"); + } else { + ToastService.showNotice(I18n.tr("common.bluetooth"), I18n.tr("common.disabled"), "bluetooth-off"); + Logger.d("Bluetooth", "Adapter disabled"); + } + root.airplaneModeToggled = false; + + // Update current blocked states (always reflect actual rfkill state) + root.wifiBlocked = wifiBlocked; + root.btBlocked = btBlocked; + } + } + stderr: StdioCollector { + onStreamFinished: { + if (text && text.trim()) { + Logger.w("AirplaneMode", "rfkill stderr:", text.trim()); + } } } } diff --git a/Services/Networking/NetworkService.qml b/Services/Networking/NetworkService.qml index dddec52c8..d0fed7f73 100644 --- a/Services/Networking/NetworkService.qml +++ b/Services/Networking/NetworkService.qml @@ -70,81 +70,22 @@ Singleton { } } - property bool bluetoothBlocked: false - property bool wifiBlocked: false - Connections { target: Settings.data.network function onWifiEnabledChanged() { if (Settings.data.network.wifiEnabled) { - ToastService.showNotice(I18n.tr("wifi.panel.title"), I18n.tr("common.enabled"), "wifi"); + ToastService.showNotice(I18n.tr("common.wifi"), I18n.tr("common.enabled"), "wifi"); // Perform a scan to update the UI delayedScanTimer.interval = 3000; delayedScanTimer.restart(); } else { - ToastService.showNotice(I18n.tr("wifi.panel.title"), I18n.tr("common.disabled"), "wifi-off"); + ToastService.showNotice(I18n.tr("common.wifi"), I18n.tr("common.disabled"), "wifi-off"); // Clear networks so the widget icon changes root.networks = ({}); } } } - // Poll rfkill status periodically to detect hardware switches - Timer { - id: rfkillPollTimer - interval: 2000 - repeat: true - running: true - onTriggered: checkWifiBlocked.running = true - } - - // Handle Airplane Mode detection via rfkill - Process { - id: checkWifiBlocked - running: false - command: ["rfkill", "list", "wifi"] - stdout: StdioCollector { - onStreamFinished: { - var wifiBlocked = text && text.trim().indexOf("Soft blocked: yes") !== -1; - checkBluetoothBlocked.wifiBlockedState = wifiBlocked; - checkBluetoothBlocked.running = true; - } - } - } - - Process { - id: checkBluetoothBlocked - running: false - command: ["rfkill", "list", "bluetooth"] - property bool wifiBlockedState: false // To pass state from checkWifiBlocked - - stdout: StdioCollector { - onStreamFinished: { - var wifiBlocked = checkBluetoothBlocked.wifiBlockedState; - var btBlocked = text && text.trim().indexOf("Soft blocked: yes") !== -1; - - var currentAirplaneMode = wifiBlocked && btBlocked; - var previousAirplaneMode = root.wifiBlocked && root.bluetoothBlocked; - - if (currentAirplaneMode && !previousAirplaneMode) { - ToastService.showNotice(I18n.tr("toast.airplane-mode.title"), I18n.tr("common.enabled"), "plane"); - } else if (!currentAirplaneMode && previousAirplaneMode) { - ToastService.showNotice(I18n.tr("toast.airplane-mode.title"), I18n.tr("common.disabled"), "plane-off"); - } else { - if (wifiBlocked !== root.wifiBlocked) { - if (wifiBlocked) { - ToastService.showNotice(I18n.tr("wifi.panel.title"), I18n.tr("common.disabled"), "wifi-off"); - } else { - ToastService.showNotice(I18n.tr("wifi.panel.title"), I18n.tr("common.enabled"), "wifi"); - } - } - } - root.wifiBlocked = wifiBlocked; - root.bluetoothBlocked = btBlocked; - } - } - } - // Handle system resume to refresh state and connectivity Connections { target: Time @@ -310,10 +251,23 @@ Singleton { if (!ProgramCheckerService.nmcliAvailable) { return; } + Logger.i("Wi-Fi", "SetWifiEnabled", enabled); Settings.data.network.wifiEnabled = enabled; wifiStateEnableProcess.running = true; } + function setAirplaneMode(enabled) { + if (enabled) { + Quickshell.execDetached(["rfkill", "block", "wifi"]); + Quickshell.execDetached(["rfkill", "block", "bluetooth"]); + Settings.data.network.airplaneModeEnabled = true; + } else { + Quickshell.execDetached(["rfkill", "unblock", "wifi"]); + Quickshell.execDetached(["rfkill", "unblock", "bluetooth"]); + Settings.data.network.airplaneModeEnabled = false; + } + } + function scan() { if (!ProgramCheckerService.nmcliAvailable || !Settings.data.network.wifiEnabled) { return; @@ -974,7 +928,6 @@ Singleton { stdout: StdioCollector { onStreamFinished: { - Logger.i("Network", "Wi-Fi state change command executed"); // Re-check the state to ensure it's in sync syncWifiState(); } @@ -1316,7 +1269,7 @@ Singleton { root.connecting = false; root.connectingTo = ""; Logger.i("Network", "Connected to network: '" + connectProcess.ssid + "'"); - ToastService.showNotice(I18n.tr("wifi.panel.title"), I18n.tr("toast.wifi.connected", { + ToastService.showNotice(I18n.tr("common.wifi"), I18n.tr("toast.wifi.connected", { "ssid": connectProcess.ssid }), "wifi"); @@ -1347,7 +1300,7 @@ Singleton { 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")); + ToastService.showWarning(I18n.tr("common.wifi"), root.lastError || I18n.tr("toast.wifi.connection-failed")); } } } @@ -1362,7 +1315,7 @@ Singleton { stdout: StdioCollector { onStreamFinished: { Logger.i("Network", "Disconnected from network: '" + disconnectProcess.ssid + "'"); - ToastService.showNotice(I18n.tr("wifi.panel.title"), I18n.tr("toast.wifi.disconnected", { + ToastService.showNotice(I18n.tr("common.wifi"), I18n.tr("toast.wifi.disconnected", { "ssid": disconnectProcess.ssid }), "wifi-off");