summaryrefslogtreecommitdiff
path: root/modules/controlcenter
diff options
context:
space:
mode:
authorATMDA <atdma2600@gmail.com>2025-11-12 21:58:14 -0500
committerATMDA <atdma2600@gmail.com>2025-11-12 21:58:14 -0500
commitfc223237f0938c7904360d8c2674368bffa53373 (patch)
treec00be67fbdfcfbff0c17183ecea766213cb19076 /modules/controlcenter
parentnotifs/toasts: reverted all changes to notifications to c0ea060f (diff)
downloadcaelestia-shell-fc223237f0938c7904360d8c2674368bffa53373.tar.gz
caelestia-shell-fc223237f0938c7904360d8c2674368bffa53373.tar.bz2
caelestia-shell-fc223237f0938c7904360d8c2674368bffa53373.zip
controlcenter: wireless panel rewrite
Diffstat (limited to 'modules/controlcenter')
-rw-r--r--modules/controlcenter/Panes.qml2
-rw-r--r--modules/controlcenter/network/PasswordDialog.qml514
-rw-r--r--modules/controlcenter/network/Settings.qml166
-rw-r--r--modules/controlcenter/network/SimpleButton.qml36
-rw-r--r--modules/controlcenter/network/WirelessConnectionHelper.qml46
-rw-r--r--modules/controlcenter/network/WirelessDetails.qml (renamed from modules/controlcenter/network/Details.qml)69
-rw-r--r--modules/controlcenter/network/WirelessList.qml (renamed from modules/controlcenter/network/NetworkList.qml)35
-rw-r--r--modules/controlcenter/network/WirelessPane.qml (renamed from modules/controlcenter/network/NetworkPane.qml)9
-rw-r--r--modules/controlcenter/network/WirelessPasswordDialog.qml299
-rw-r--r--modules/controlcenter/network/WirelessSettings.qml82
10 files changed, 483 insertions, 775 deletions
diff --git a/modules/controlcenter/Panes.qml b/modules/controlcenter/Panes.qml
index 94bea9a..11e60d3 100644
--- a/modules/controlcenter/Panes.qml
+++ b/modules/controlcenter/Panes.qml
@@ -36,7 +36,7 @@ ClippingRectangle {
Pane {
index: 1
- sourceComponent: NetworkPane {
+ sourceComponent: WirelessPane {
session: root.session
}
}
diff --git a/modules/controlcenter/network/PasswordDialog.qml b/modules/controlcenter/network/PasswordDialog.qml
deleted file mode 100644
index 7aa698b..0000000
--- a/modules/controlcenter/network/PasswordDialog.qml
+++ /dev/null
@@ -1,514 +0,0 @@
-pragma ComponentBehavior: Bound
-
-import ".."
-import qs.components
-import qs.components.controls
-import qs.components.effects
-import qs.components.containers
-import qs.services
-import qs.config
-import QtQuick
-import QtQuick.Layouts
-
-Item {
- id: root
-
- required property Session session
- readonly property var network: {
- // Try pendingNetwork first, then fall back to active network selection
- if (session.network.pendingNetwork) {
- return session.network.pendingNetwork;
- }
- // Fallback to active network if available
- if (session.network.active) {
- return session.network.active;
- }
- return null;
- }
-
- visible: session.network.showPasswordDialog
- enabled: visible
- focus: visible
-
- // Ensure network is set when dialog opens
- Component.onCompleted: {
- if (visible && !session.network.pendingNetwork && session.network.active) {
- session.network.pendingNetwork = session.network.active;
- }
- }
-
- Connections {
- target: root
- function onVisibleChanged(): void {
- if (visible && !session.network.pendingNetwork && session.network.active) {
- session.network.pendingNetwork = session.network.active;
- }
- }
- }
-
- Keys.onEscapePressed: {
- root.session.network.showPasswordDialog = false;
- passwordField.text = "";
- }
-
- Rectangle {
- anchors.fill: parent
- color: Qt.rgba(0, 0, 0, 0.5)
- opacity: root.visible ? 1 : 0
-
- Behavior on opacity {
- NumberAnimation {
- duration: 200
- }
- }
-
- MouseArea {
- anchors.fill: parent
- onClicked: {
- root.session.network.showPasswordDialog = false;
- passwordField.text = "";
- }
- }
- }
-
- StyledRect {
- id: dialog
-
- anchors.centerIn: parent
-
- implicitWidth: 400
- implicitHeight: content.implicitHeight + Appearance.padding.large * 2
-
- radius: Appearance.rounding.normal
- color: Colours.tPalette.m3surface
- opacity: root.visible ? 1 : 0
- scale: root.visible ? 1 : 0.9
-
- Behavior on opacity {
- NumberAnimation {
- duration: 200
- }
- }
-
- Behavior on scale {
- NumberAnimation {
- duration: 200
- }
- }
-
- Keys.onEscapePressed: {
- root.session.network.showPasswordDialog = false;
- passwordField.text = "";
- }
-
- ColumnLayout {
- id: content
-
- anchors.left: parent.left
- anchors.right: parent.right
- anchors.verticalCenter: parent.verticalCenter
- anchors.margins: Appearance.padding.large
-
- spacing: Appearance.spacing.normal
-
- MaterialIcon {
- Layout.alignment: Qt.AlignHCenter
- text: "lock"
- font.pointSize: Appearance.font.size.extraLarge * 2
- }
-
- StyledText {
- Layout.alignment: Qt.AlignHCenter
- text: qsTr("Enter password")
- font.pointSize: Appearance.font.size.large
- font.weight: 500
- }
-
- StyledText {
- Layout.alignment: Qt.AlignHCenter
- text: root.network ? qsTr("Network: %1").arg(root.network.ssid) : ""
- color: Colours.palette.m3outline
- font.pointSize: Appearance.font.size.small
- }
-
- StyledText {
- id: statusText
-
- Layout.alignment: Qt.AlignHCenter
- Layout.topMargin: Appearance.spacing.small
- visible: Network.connectionStatus.length > 0 || connectButton.connecting
- text: {
- if (Network.connectionStatus.length > 0) {
- return Network.connectionStatus;
- } else if (connectButton.connecting) {
- return qsTr("Connecting...");
- }
- return "";
- }
- color: {
- const status = Network.connectionStatus;
- if (status.includes("Error") || status.includes("error") || status.includes("failed")) {
- return Colours.palette.m3error;
- } else if (status.includes("successful") || status.includes("Connected") || status.includes("success")) {
- return Colours.palette.m3primary;
- }
- return Colours.palette.m3onSurfaceVariant;
- }
- font.pointSize: Appearance.font.size.small
- font.weight: (Network.connectionStatus.includes("Error") || Network.connectionStatus.includes("error")) ? 500 : 400
- wrapMode: Text.WordWrap
- Layout.maximumWidth: parent.width - Appearance.padding.large * 2
- }
-
- Item {
- Layout.topMargin: Appearance.spacing.large
- Layout.fillWidth: true
- implicitHeight: passwordField.implicitHeight + Appearance.padding.normal * 2
-
- StyledRect {
- anchors.fill: parent
- radius: Appearance.rounding.normal
- color: Colours.tPalette.m3surfaceContainer
- border.width: passwordField.activeFocus ? 2 : 1
- border.color: passwordField.activeFocus ? Colours.palette.m3primary : Colours.palette.m3outline
-
- Behavior on border.color {
- CAnim {}
- }
- }
-
- StyledTextField {
- id: passwordField
-
- anchors.left: parent.left
- anchors.right: parent.right
- anchors.verticalCenter: parent.verticalCenter
- anchors.margins: Appearance.padding.normal
-
- echoMode: TextField.Password
- placeholderText: qsTr("Password")
-
- Component.onCompleted: {
- if (root.visible) {
- forceActiveFocus();
- }
- }
-
- Connections {
- target: root
- function onVisibleChanged(): void {
- if (root.visible) {
- passwordField.forceActiveFocus();
- passwordField.text = "";
- Network.connectionStatus = "";
- }
- }
- }
-
- Connections {
- target: Network
- function onConnectionStatusChanged(): void {
- // Status updated, ensure it's visible
- }
- }
-
- Keys.onReturnPressed: {
- if (connectButton.enabled) {
- connectButton.clicked();
- }
- }
- Keys.onEnterPressed: {
- if (connectButton.enabled) {
- connectButton.clicked();
- }
- }
- }
- }
-
- RowLayout {
- Layout.topMargin: Appearance.spacing.normal
- Layout.fillWidth: true
- spacing: Appearance.spacing.normal
-
- Button {
- id: cancelButton
-
- Layout.fillWidth: true
- color: Colours.palette.m3secondaryContainer
- onColor: Colours.palette.m3onSecondaryContainer
- text: qsTr("Cancel")
-
- function onClicked(): void {
- root.session.network.showPasswordDialog = false;
- passwordField.text = "";
- }
- }
-
- Button {
- id: connectButton
-
- Layout.fillWidth: true
- color: Colours.palette.m3primary
- onColor: Colours.palette.m3onPrimary
- text: qsTr("Connect")
- enabled: passwordField.text.length > 0
-
- property bool connecting: false
-
- function onClicked(): void {
- Network.connectionStatus = "";
-
- // Get password first
- const password = passwordField.text;
-
- // Try multiple ways to get the network
- let networkToUse = null;
-
- // Try 1: root.network (computed property)
- if (root.network) {
- networkToUse = root.network;
- }
-
- // Try 2: pendingNetwork
- if (!networkToUse && root.session.network.pendingNetwork) {
- networkToUse = root.session.network.pendingNetwork;
- }
-
- // Try 3: active network
- if (!networkToUse && root.session.network.active) {
- networkToUse = root.session.network.active;
- root.session.network.pendingNetwork = networkToUse;
- }
-
- // Check all conditions
- const hasNetwork = !!networkToUse;
- const hasPassword = password && password.length > 0;
- const notConnecting = !connecting;
-
- if (hasNetwork && hasPassword && notConnecting) {
- // Set status immediately
- Network.connectionStatus = qsTr("Preparing to connect...");
-
- // Keep dialog open and track connection
- connecting = true;
- connectButton.enabled = false;
- connectButton.text = qsTr("Connecting...");
-
- // Force immediate UI update
- statusText.visible = true;
-
- // Store target SSID for later comparison
- const ssidToConnect = networkToUse.ssid || "";
- const bssidToConnect = networkToUse.bssid || "";
-
- // Store the SSID we're connecting to so we can compare later
- // even if root.network changes
- content.connectingToSsid = ssidToConnect;
-
- // Execute connection immediately
- Network.connectToNetwork(
- ssidToConnect,
- password,
- bssidToConnect,
- () => {
- // Callback if connection fails - keep dialog open
- connecting = false;
- connectButton.enabled = true;
- connectButton.text = qsTr("Connect");
- content.connectingToSsid = ""; // Clear on failure
- }
- );
-
- // Start connection check timer immediately
- connectionCheckTimer.checkCount = 0;
- connectionCheckTimer.start();
-
- // Also check immediately after a short delay to catch quick connections
- Qt.callLater(() => {
- if (root.visible) {
- closeDialogIfConnected();
- }
- });
- } else {
- // Show error in status
- Network.connectionStatus = qsTr("Error: Cannot connect - missing network or password");
- }
- }
- }
- }
-
- // Store the SSID we're connecting to when connection starts
- property string connectingToSsid: ""
-
- property string targetSsid: {
- // Track the SSID we're trying to connect to
- // Prefer explicitly stored connectingToSsid, then computed values
- if (connectingToSsid && connectingToSsid.length > 0) {
- return connectingToSsid;
- }
- if (root.network && root.network.ssid) {
- return root.network.ssid;
- }
- if (root.session.network.pendingNetwork && root.session.network.pendingNetwork.ssid) {
- return root.session.network.pendingNetwork.ssid;
- }
- return "";
- }
-
- function closeDialogIfConnected(): bool {
- // Check if we're connected to the network we're trying to connect to
- const ssid = targetSsid;
-
- if (!ssid || ssid.length === 0) {
- return false;
- }
-
- if (!Network.active) {
- return false;
- }
-
- const activeSsid = Network.active.ssid || "";
-
- if (activeSsid === ssid) {
- // Connection succeeded - close dialog
- connectionCheckTimer.stop();
- aggressiveCheckTimer.stop();
- connectionCheckTimer.checkCount = 0;
- connectButton.connecting = false;
- Network.connectionStatus = "";
- root.session.network.showPasswordDialog = false;
- passwordField.text = "";
- content.connectingToSsid = ""; // Clear stored SSID
- return true;
- }
- return false;
- }
-
- Timer {
- id: connectionCheckTimer
- interval: 1000 // Check every 1 second for faster response
- repeat: true
- triggeredOnStart: false
- property int checkCount: 0
-
- onTriggered: {
- checkCount++;
-
- // Try to close dialog if connected
- const closed = content.closeDialogIfConnected();
- if (closed) {
- return;
- }
-
- if (connectButton.connecting) {
- // Still connecting, check again
- // Limit to 20 checks (20 seconds total)
- if (checkCount >= 20) {
- connectionCheckTimer.stop();
- connectionCheckTimer.checkCount = 0;
- connectButton.connecting = false;
- connectButton.enabled = true;
- connectButton.text = qsTr("Connect");
- }
- } else {
- // Not connecting anymore, stop timer
- connectionCheckTimer.stop();
- connectionCheckTimer.checkCount = 0;
- }
- }
- }
-
- Connections {
- target: Network
- function onActiveChanged(): void {
- // Check immediately when active network changes
- if (root.visible) {
- // Check immediately - if connected, close right away
- if (content.closeDialogIfConnected()) {
- return;
- }
-
- // Also check after a delay in case the active network isn't fully updated yet
- Qt.callLater(() => {
- if (root.visible) {
- content.closeDialogIfConnected();
- }
- });
- }
- }
- }
-
- // Also check when dialog becomes visible
- Connections {
- target: root
- function onVisibleChanged(): void {
- if (root.visible) {
- // Check immediately when dialog opens
- Qt.callLater(() => {
- if (root.visible) {
- closeDialogIfConnected();
- }
- });
- }
- }
- }
-
- // Aggressive polling timer - checks every 500ms when dialog is visible and connecting
- // This ensures we catch the connection even if signals are missed
- Timer {
- id: aggressiveCheckTimer
- interval: 500
- repeat: true
- running: root.visible && connectButton.connecting
- triggeredOnStart: true
-
- onTriggered: {
- if (root.visible && connectButton.connecting) {
- if (content.closeDialogIfConnected()) {
- stop();
- }
- } else {
- stop();
- }
- }
- }
- }
- }
-
- component Button: StyledRect {
- property color onColor: Colours.palette.m3onSurface
- property alias disabled: stateLayer.disabled
- property alias text: label.text
- property alias enabled: stateLayer.enabled
-
- function onClicked(): void {
- }
-
- radius: Appearance.rounding.small
- implicitHeight: label.implicitHeight + Appearance.padding.small * 2
- opacity: enabled ? 1 : 0.5
-
- StateLayer {
- id: stateLayer
-
- enabled: parent.enabled
- color: parent.onColor
-
- function onClicked(): void {
- if (enabled) {
- parent.onClicked();
- }
- }
- }
-
- StyledText {
- id: label
-
- anchors.centerIn: parent
- animate: true
- color: parent.onColor
- font.pointSize: Appearance.font.size.normal
- }
- }
-}
-
diff --git a/modules/controlcenter/network/Settings.qml b/modules/controlcenter/network/Settings.qml
deleted file mode 100644
index 0794e6a..0000000
--- a/modules/controlcenter/network/Settings.qml
+++ /dev/null
@@ -1,166 +0,0 @@
-pragma ComponentBehavior: Bound
-
-import ".."
-import qs.components
-import qs.components.controls
-import qs.components.effects
-import qs.services
-import qs.config
-import QtQuick
-import QtQuick.Layouts
-
-ColumnLayout {
- id: root
-
- required property Session session
-
- spacing: Appearance.spacing.normal
-
- MaterialIcon {
- Layout.alignment: Qt.AlignHCenter
- text: "wifi"
- font.pointSize: Appearance.font.size.extraLarge * 3
- font.bold: true
- }
-
- StyledText {
- Layout.alignment: Qt.AlignHCenter
- text: qsTr("Network settings")
- font.pointSize: Appearance.font.size.large
- font.bold: true
- }
-
- StyledText {
- Layout.topMargin: Appearance.spacing.large
- text: qsTr("WiFi status")
- font.pointSize: Appearance.font.size.larger
- font.weight: 500
- }
-
- StyledText {
- text: qsTr("General WiFi settings")
- color: Colours.palette.m3outline
- }
-
- StyledRect {
- Layout.fillWidth: true
- implicitHeight: wifiStatus.implicitHeight + Appearance.padding.large * 2
-
- radius: Appearance.rounding.normal
- color: Colours.tPalette.m3surfaceContainer
-
- ColumnLayout {
- id: wifiStatus
-
- anchors.left: parent.left
- anchors.right: parent.right
- anchors.verticalCenter: parent.verticalCenter
- anchors.margins: Appearance.padding.large
-
- spacing: Appearance.spacing.larger
-
- Toggle {
- label: qsTr("WiFi enabled")
- checked: Network.wifiEnabled
- toggle.onToggled: {
- Network.enableWifi(checked);
- }
- }
- }
- }
-
- StyledText {
- Layout.topMargin: Appearance.spacing.large
- text: qsTr("Network information")
- font.pointSize: Appearance.font.size.larger
- font.weight: 500
- }
-
- StyledText {
- text: qsTr("Current network connection")
- color: Colours.palette.m3outline
- }
-
- StyledRect {
- Layout.fillWidth: true
- implicitHeight: networkInfo.implicitHeight + Appearance.padding.large * 2
-
- radius: Appearance.rounding.normal
- color: Colours.tPalette.m3surfaceContainer
-
- ColumnLayout {
- id: networkInfo
-
- anchors.left: parent.left
- anchors.right: parent.right
- anchors.verticalCenter: parent.verticalCenter
- anchors.margins: Appearance.padding.large
-
- spacing: Appearance.spacing.small / 2
-
- StyledText {
- text: qsTr("Connected network")
- }
-
- StyledText {
- text: Network.active ? Network.active.ssid : qsTr("Not connected")
- color: Colours.palette.m3outline
- font.pointSize: Appearance.font.size.small
- }
-
- StyledText {
- Layout.topMargin: Appearance.spacing.normal
- text: qsTr("Signal strength")
- }
-
- StyledText {
- text: Network.active ? qsTr("%1%").arg(Network.active.strength) : qsTr("N/A")
- color: Colours.palette.m3outline
- font.pointSize: Appearance.font.size.small
- }
-
- StyledText {
- Layout.topMargin: Appearance.spacing.normal
- text: qsTr("Security")
- }
-
- StyledText {
- text: Network.active ? (Network.active.isSecure ? qsTr("Secured") : qsTr("Open")) : qsTr("N/A")
- color: Colours.palette.m3outline
- font.pointSize: Appearance.font.size.small
- }
-
- StyledText {
- Layout.topMargin: Appearance.spacing.normal
- text: qsTr("Frequency")
- }
-
- StyledText {
- text: Network.active ? qsTr("%1 MHz").arg(Network.active.frequency) : qsTr("N/A")
- color: Colours.palette.m3outline
- font.pointSize: Appearance.font.size.small
- }
- }
- }
-
- component Toggle: RowLayout {
- required property string label
- property alias checked: toggle.checked
- property alias toggle: toggle
-
- Layout.fillWidth: true
- spacing: Appearance.spacing.normal
-
- StyledText {
- Layout.fillWidth: true
- text: parent.label
- }
-
- StyledSwitch {
- id: toggle
-
- cLayer: 2
- }
- }
-}
-
diff --git a/modules/controlcenter/network/SimpleButton.qml b/modules/controlcenter/network/SimpleButton.qml
new file mode 100644
index 0000000..49ab2f4
--- /dev/null
+++ b/modules/controlcenter/network/SimpleButton.qml
@@ -0,0 +1,36 @@
+import qs.components
+import qs.components.effects
+import qs.config
+import QtQuick
+
+StyledRect {
+ id: root
+
+ property color onColor: Colours.palette.m3onSurface
+ property alias disabled: stateLayer.disabled
+ property alias text: label.text
+ property alias enabled: stateLayer.enabled
+
+ implicitWidth: label.implicitWidth + Appearance.padding.normal * 2
+ implicitHeight: label.implicitHeight + Appearance.padding.normal * 2
+ radius: Appearance.rounding.normal
+
+ StateLayer {
+ id: stateLayer
+ color: parent.onColor
+ function onClicked(): void {
+ if (parent.enabled !== false) {
+ parent.clicked();
+ }
+ }
+ }
+
+ StyledText {
+ id: label
+ anchors.centerIn: parent
+ color: parent.onColor
+ }
+
+ signal clicked
+}
+
diff --git a/modules/controlcenter/network/WirelessConnectionHelper.qml b/modules/controlcenter/network/WirelessConnectionHelper.qml
new file mode 100644
index 0000000..d63b359
--- /dev/null
+++ b/modules/controlcenter/network/WirelessConnectionHelper.qml
@@ -0,0 +1,46 @@
+pragma ComponentBehavior: Bound
+
+import ".."
+import qs.services
+import QtQuick
+
+QtObject {
+ id: root
+
+ required property Session session
+
+ function connectToNetwork(network: var): void {
+ if (!network) {
+ return;
+ }
+
+ // If already connected to a different network, disconnect first
+ if (Network.active && Network.active.ssid !== network.ssid) {
+ Network.disconnectFromNetwork();
+ Qt.callLater(() => {
+ performConnect(network);
+ });
+ } else {
+ performConnect(network);
+ }
+ }
+
+ function performConnect(network: var): void {
+ if (network.isSecure) {
+ // Try connecting without password first (in case it's saved)
+ Network.connectToNetworkWithPasswordCheck(
+ network.ssid,
+ network.isSecure,
+ () => {
+ // Callback: connection failed, show password dialog
+ root.session.network.showPasswordDialog = true;
+ root.session.network.pendingNetwork = network;
+ },
+ network.bssid
+ );
+ } else {
+ Network.connectToNetwork(network.ssid, "", network.bssid, null);
+ }
+ }
+}
+
diff --git a/modules/controlcenter/network/Details.qml b/modules/controlcenter/network/WirelessDetails.qml
index 5e636a2..e858fbc 100644
--- a/modules/controlcenter/network/Details.qml
+++ b/modules/controlcenter/network/WirelessDetails.qml
@@ -1,6 +1,7 @@
pragma ComponentBehavior: Bound
import ".."
+import "."
import qs.components
import qs.components.controls
import qs.components.effects
@@ -15,6 +16,10 @@ Item {
required property Session session
readonly property var network: session.network.active
+
+ readonly property var connectionHelper: WirelessConnectionHelper {
+ session: root.session
+ }
Component.onCompleted: {
if (network && network.active) {
@@ -70,41 +75,14 @@ Item {
checked: root.network?.active ?? false
toggle.onToggled: {
if (checked) {
- // If already connected to a different network, disconnect first
- if (Network.active && Network.active.ssid !== root.network.ssid) {
- Network.disconnectFromNetwork();
- // Wait a moment before connecting to new network
- Qt.callLater(() => {
- connectToNetwork();
- });
- } else {
- connectToNetwork();
- }
+ root.connectionHelper.connectToNetwork(root.network);
} else {
Network.disconnectFromNetwork();
}
}
-
- function connectToNetwork(): void {
- if (root.network.isSecure) {
- // Try connecting without password first (in case it's saved)
- Network.connectToNetworkWithPasswordCheck(
- root.network.ssid,
- root.network.isSecure,
- () => {
- // Callback: connection failed, show password dialog
- root.session.network.showPasswordDialog = true;
- root.session.network.pendingNetwork = root.network;
- },
- root.network.bssid
- );
- } else {
- Network.connectToNetwork(root.network.ssid, "", root.network.bssid, null);
- }
- }
}
- Button {
+ SimpleButton {
Layout.fillWidth: true
Layout.topMargin: Appearance.spacing.normal
visible: root.network && root.network.ssid && Network.savedConnections.includes(root.network.ssid)
@@ -176,38 +154,5 @@ Item {
}
}
-
- component Button: StyledRect {
- property color onColor: Colours.palette.m3onSurface
- property alias disabled: stateLayer.disabled
- property alias text: label.text
- property alias enabled: stateLayer.enabled
-
- Layout.fillWidth: true
- implicitHeight: label.implicitHeight + Appearance.padding.normal * 2
- radius: Appearance.rounding.normal
-
- StateLayer {
- id: stateLayer
- color: parent.onColor
- function onClicked(): void {
- if (parent.enabled !== false) {
- parent.clicked();
- }
- }
- }
-
- StyledText {
- id: label
- anchors.centerIn: parent
- color: parent.onColor
- }
-
- signal clicked
- }
-
}
-
-
-
diff --git a/modules/controlcenter/network/NetworkList.qml b/modules/controlcenter/network/WirelessList.qml
index 6c4158c..1a4ba00 100644
--- a/modules/controlcenter/network/NetworkList.qml
+++ b/modules/controlcenter/network/WirelessList.qml
@@ -1,6 +1,7 @@
pragma ComponentBehavior: Bound
import ".."
+import "."
import qs.components
import qs.components.controls
import qs.components.containers
@@ -14,6 +15,10 @@ ColumnLayout {
required property Session session
+ readonly property var connectionHelper: WirelessConnectionHelper {
+ session: root.session
+ }
+
spacing: Appearance.spacing.small
RowLayout {
@@ -180,34 +185,7 @@ ColumnLayout {
if (modelData.active) {
Network.disconnectFromNetwork();
} else {
- // If already connected to a different network, disconnect first
- if (Network.active && Network.active.ssid !== modelData.ssid) {
- Network.disconnectFromNetwork();
- // Wait a moment before connecting to new network
- Qt.callLater(() => {
- connectToNetwork();
- });
- } else {
- connectToNetwork();
- }
- }
- }
-
- function connectToNetwork(): void {
- if (modelData.isSecure) {
- // Try connecting without password first (in case it's saved)
- Network.connectToNetworkWithPasswordCheck(
- modelData.ssid,
- modelData.isSecure,
- () => {
- // Callback: connection failed, show password dialog
- root.session.network.showPasswordDialog = true;
- root.session.network.pendingNetwork = modelData;
- },
- modelData.bssid
- );
- } else {
- Network.connectToNetwork(modelData.ssid, "", modelData.bssid, null);
+ root.connectionHelper.connectToNetwork(modelData);
}
}
}
@@ -226,3 +204,4 @@ ColumnLayout {
}
}
}
+
diff --git a/modules/controlcenter/network/NetworkPane.qml b/modules/controlcenter/network/WirelessPane.qml
index fe18274..a23b6e8 100644
--- a/modules/controlcenter/network/NetworkPane.qml
+++ b/modules/controlcenter/network/WirelessPane.qml
@@ -23,7 +23,7 @@ RowLayout {
Layout.minimumWidth: 420
Layout.fillHeight: true
- NetworkList {
+ WirelessList {
anchors.fill: parent
anchors.margins: Appearance.padding.large + Appearance.padding.normal
anchors.leftMargin: Appearance.padding.large
@@ -121,7 +121,7 @@ RowLayout {
flickableDirection: Flickable.VerticalFlick
contentHeight: settingsInner.height
- Settings {
+ WirelessSettings {
id: settingsInner
anchors.left: parent.left
@@ -134,13 +134,13 @@ RowLayout {
Component {
id: details
- Details {
+ WirelessDetails {
session: root.session
}
}
}
- PasswordDialog {
+ WirelessPasswordDialog {
anchors.fill: parent
session: root.session
z: 1000
@@ -152,3 +152,4 @@ RowLayout {
easing.type: Easing.BezierSpline
}
}
+
diff --git a/modules/controlcenter/network/WirelessPasswordDialog.qml b/modules/controlcenter/network/WirelessPasswordDialog.qml
new file mode 100644
index 0000000..778fb4f
--- /dev/null
+++ b/modules/controlcenter/network/WirelessPasswordDialog.qml
@@ -0,0 +1,299 @@
+pragma ComponentBehavior: Bound
+
+import ".."
+import "."
+import qs.components
+import qs.components.controls
+import qs.components.effects
+import qs.components.containers
+import qs.services
+import qs.config
+import QtQuick
+import QtQuick.Layouts
+
+Item {
+ id: root
+
+ required property Session session
+
+ readonly property var network: {
+ // Prefer pendingNetwork, then active network
+ if (session.network.pendingNetwork) {
+ return session.network.pendingNetwork;
+ }
+ if (session.network.active) {
+ return session.network.active;
+ }
+ return null;
+ }
+
+ visible: session.network.showPasswordDialog
+ enabled: visible
+ focus: visible
+
+ Keys.onEscapePressed: {
+ closeDialog();
+ }
+
+ Rectangle {
+ anchors.fill: parent
+ color: Qt.rgba(0, 0, 0, 0.5)
+ opacity: root.visible ? 1 : 0
+
+ Behavior on opacity {
+ NumberAnimation { duration: 200 }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: closeDialog();
+ }
+ }
+
+ StyledRect {
+ id: dialog
+
+ anchors.centerIn: parent
+
+ implicitWidth: 400
+ implicitHeight: content.implicitHeight + Appearance.padding.large * 2
+
+ radius: Appearance.rounding.normal
+ color: Colours.tPalette.m3surface
+ opacity: root.visible ? 1 : 0
+ scale: root.visible ? 1 : 0.9
+
+ Behavior on opacity {
+ NumberAnimation { duration: 200 }
+ }
+
+ Behavior on scale {
+ NumberAnimation { duration: 200 }
+ }
+
+ Keys.onEscapePressed: closeDialog();
+
+ ColumnLayout {
+ id: content
+
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.margins: Appearance.padding.large
+
+ spacing: Appearance.spacing.normal
+
+ MaterialIcon {
+ Layout.alignment: Qt.AlignHCenter
+ text: "lock"
+ font.pointSize: Appearance.font.size.extraLarge * 2
+ }
+
+ StyledText {
+ Layout.alignment: Qt.AlignHCenter
+ text: qsTr("Enter password")
+ font.pointSize: Appearance.font.size.large
+ font.weight: 500
+ }
+
+ StyledText {
+ Layout.alignment: Qt.AlignHCenter
+ text: root.network ? qsTr("Network: %1").arg(root.network.ssid) : ""
+ color: Colours.palette.m3outline
+ font.pointSize: Appearance.font.size.small
+ }
+
+ StyledText {
+ id: statusText
+
+ Layout.alignment: Qt.AlignHCenter
+ Layout.topMargin: Appearance.spacing.small
+ visible: Network.connectionStatus.length > 0 || connectButton.connecting
+ text: {
+ if (Network.connectionStatus.length > 0) {
+ return Network.connectionStatus;
+ } else if (connectButton.connecting) {
+ return qsTr("Connecting...");
+ }
+ return "";
+ }
+ color: {
+ const status = Network.connectionStatus;
+ if (status.includes("Error") || status.includes("error") || status.includes("failed")) {
+ return Colours.palette.m3error;
+ } else if (status.includes("successful") || status.includes("Connected") || status.includes("success")) {
+ return Colours.palette.m3primary;
+ }
+ return Colours.palette.m3onSurfaceVariant;
+ }
+ font.pointSize: Appearance.font.size.small
+ font.weight: (Network.connectionStatus.includes("Error") || Network.connectionStatus.includes("error")) ? 500 : 400
+ wrapMode: Text.WordWrap
+ Layout.maximumWidth: parent.width - Appearance.padding.large * 2
+ }
+
+ Item {
+ Layout.topMargin: Appearance.spacing.large
+ Layout.fillWidth: true
+ implicitHeight: passwordField.implicitHeight + Appearance.padding.normal * 2
+
+ StyledRect {
+ anchors.fill: parent
+ radius: Appearance.rounding.normal
+ color: Colours.tPalette.m3surfaceContainer
+ border.width: passwordField.activeFocus ? 2 : 1
+ border.color: passwordField.activeFocus ? Colours.palette.m3primary : Colours.palette.m3outline
+
+ Behavior on border.color {
+ CAnim {}
+ }
+ }
+
+ StyledTextField {
+ id: passwordField
+
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.margins: Appearance.padding.normal
+
+ echoMode: TextField.Password
+ placeholderText: qsTr("Password")
+
+ Connections {
+ target: root
+ function onVisibleChanged(): void {
+ if (root.visible) {
+ passwordField.forceActiveFocus();
+ passwordField.text = "";
+ Network.clearConnectionStatus();
+ }
+ }
+ }
+
+ Keys.onReturnPressed: {
+ if (connectButton.enabled) {
+ connectButton.clicked();
+ }
+ }
+ Keys.onEnterPressed: {
+ if (connectButton.enabled) {
+ connectButton.clicked();
+ }
+ }
+ }
+ }
+
+ RowLayout {
+ Layout.topMargin: Appearance.spacing.normal
+ Layout.fillWidth: true
+ spacing: Appearance.spacing.normal
+
+ SimpleButton {
+ id: cancelButton
+
+ Layout.fillWidth: true
+ color: Colours.palette.m3secondaryContainer
+ onColor: Colours.palette.m3onSecondaryContainer
+ text: qsTr("Cancel")
+
+ onClicked: closeDialog();
+ }
+
+ SimpleButton {
+ id: connectButton
+
+ Layout.fillWidth: true
+ color: Colours.palette.m3primary
+ onColor: Colours.palette.m3onPrimary
+ text: qsTr("Connect")
+ enabled: passwordField.text.length > 0 && !connecting
+
+ property bool connecting: false
+
+ onClicked: {
+ if (!root.network || connecting) {
+ return;
+ }
+
+ const password = passwordField.text;
+ if (!password || password.length === 0) {
+ return;
+ }
+
+ // Set connecting state
+ connecting = true;
+ enabled = false;
+ text = qsTr("Connecting...");
+ Network.clearConnectionStatus();
+
+ // Connect to network
+ Network.connectToNetwork(
+ root.network.ssid,
+ password,
+ root.network.bssid || "",
+ null
+ );
+
+ // Start monitoring connection
+ connectionMonitor.start();
+ }
+ }
+ }
+ }
+ }
+
+ Timer {
+ id: connectionMonitor
+ interval: 1000
+ repeat: true
+ triggeredOnStart: false
+
+ onTriggered: {
+ // Check if we're connected to the target network
+ if (root.network && Network.active && Network.active.ssid === root.network.ssid) {
+ // Successfully connected
+ stop();
+ connectButton.connecting = false;
+ connectButton.text = qsTr("Connect");
+ closeDialog();
+ } else if (connectButton.connecting) {
+ // Still connecting, check status
+ const status = Network.connectionStatus;
+ if (status.includes("Error") || status.includes("error") || status.includes("failed")) {
+ // Connection failed
+ stop();
+ connectButton.connecting = false;
+ connectButton.enabled = true;
+ connectButton.text = qsTr("Connect");
+ }
+ } else {
+ // Not connecting anymore
+ stop();
+ }
+ }
+ }
+
+ Connections {
+ target: Network
+ function onActiveChanged() {
+ if (root.visible && root.network && Network.active && Network.active.ssid === root.network.ssid) {
+ // Connected successfully
+ connectionMonitor.stop();
+ connectButton.connecting = false;
+ connectButton.text = qsTr("Connect");
+ closeDialog();
+ }
+ }
+ }
+
+ function closeDialog(): void {
+ session.network.showPasswordDialog = false;
+ passwordField.text = "";
+ connectButton.connecting = false;
+ connectButton.text = qsTr("Connect");
+ connectionMonitor.stop();
+ Network.clearConnectionStatus();
+ }
+}
+
diff --git a/modules/controlcenter/network/WirelessSettings.qml b/modules/controlcenter/network/WirelessSettings.qml
new file mode 100644
index 0000000..7890099
--- /dev/null
+++ b/modules/controlcenter/network/WirelessSettings.qml
@@ -0,0 +1,82 @@
+pragma ComponentBehavior: Bound
+
+import ".."
+import qs.components
+import qs.components.controls
+import qs.components.effects
+import qs.services
+import qs.config
+import QtQuick
+import QtQuick.Layouts
+
+ColumnLayout {
+ id: root
+
+ required property Session session
+
+ spacing: Appearance.spacing.normal
+
+ MaterialIcon {
+ Layout.alignment: Qt.AlignHCenter
+ text: "wifi"
+ font.pointSize: Appearance.font.size.extraLarge * 3
+ font.bold: true
+ }
+
+ StyledText {
+ Layout.alignment: Qt.AlignHCenter
+ text: qsTr("Network settings")
+ font.pointSize: Appearance.font.size.large
+ font.bold: true
+ }
+
+ SectionHeader {
+ Layout.topMargin: Appearance.spacing.large
+ title: qsTr("WiFi status")
+ description: qsTr("General WiFi settings")
+ }
+
+ SectionContainer {
+ ToggleRow {
+ label: qsTr("WiFi enabled")
+ checked: Network.wifiEnabled
+ toggle.onToggled: {
+ Network.enableWifi(checked);
+ }
+ }
+ }
+
+ SectionHeader {
+ Layout.topMargin: Appearance.spacing.large
+ title: qsTr("Network information")
+ description: qsTr("Current network connection")
+ }
+
+ SectionContainer {
+ contentSpacing: Appearance.spacing.small / 2
+
+ PropertyRow {
+ label: qsTr("Connected network")
+ value: Network.active ? Network.active.ssid : qsTr("Not connected")
+ }
+
+ PropertyRow {
+ showTopMargin: true
+ label: qsTr("Signal strength")
+ value: Network.active ? qsTr("%1%").arg(Network.active.strength) : qsTr("N/A")
+ }
+
+ PropertyRow {
+ showTopMargin: true
+ label: qsTr("Security")
+ value: Network.active ? (Network.active.isSecure ? qsTr("Secured") : qsTr("Open")) : qsTr("N/A")
+ }
+
+ PropertyRow {
+ showTopMargin: true
+ label: qsTr("Frequency")
+ value: Network.active ? qsTr("%1 MHz").arg(Network.active.frequency) : qsTr("N/A")
+ }
+ }
+}
+