controlcenter: wireless panel rewrite
This commit is contained in:
parent
ffe14748a2
commit
fc223237f0
10 changed files with 483 additions and 775 deletions
|
|
@ -36,7 +36,7 @@ ClippingRectangle {
|
|||
|
||||
Pane {
|
||||
index: 1
|
||||
sourceComponent: NetworkPane {
|
||||
sourceComponent: WirelessPane {
|
||||
session: root.session
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
36
modules/controlcenter/network/SimpleButton.qml
Normal file
36
modules/controlcenter/network/SimpleButton.qml
Normal file
|
|
@ -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
|
||||
}
|
||||
|
||||
46
modules/controlcenter/network/WirelessConnectionHelper.qml
Normal file
46
modules/controlcenter/network/WirelessConnectionHelper.qml
Normal file
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
pragma ComponentBehavior: Bound
|
||||
|
||||
import ".."
|
||||
import "."
|
||||
import qs.components
|
||||
import qs.components.controls
|
||||
import qs.components.effects
|
||||
|
|
@ -16,6 +17,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) {
|
||||
Network.updateWirelessDeviceDetails();
|
||||
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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 {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
299
modules/controlcenter/network/WirelessPasswordDialog.qml
Normal file
299
modules/controlcenter/network/WirelessPasswordDialog.qml
Normal file
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
82
modules/controlcenter/network/WirelessSettings.qml
Normal file
82
modules/controlcenter/network/WirelessSettings.qml
Normal file
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Add table
Reference in a new issue