feat: auto rescan networks in network settings

Also add anims
And sort active network first
And add indicator for scanning
This commit is contained in:
2 * r + 2 * t 2026-06-06 01:31:08 +10:00
parent f109f5f2d7
commit db3093b5d1
2 changed files with 121 additions and 50 deletions

View file

@ -2,7 +2,7 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Caelestia.Components
import Quickshell
import Caelestia.Config
import qs.components
import qs.components.controls
@ -21,85 +21,155 @@ PageBase {
width: root.cappedWidth
spacing: Tokens.spacing.extraSmall / 2
Timer {
running: root.visible
repeat: true
triggeredOnStart: true
interval: GlobalConfig.nexus.networkRescanInterval
onTriggered: Nmcli.rescanWifi()
}
ToggleRow {
Layout.fillWidth: true
first: true
text: qsTr("Wi-Fi")
font: Tokens.font.title.medium
checked: Network.wifiEnabled
onToggled: Network.enableWifi(checked)
checked: Nmcli.wifiEnabled
onToggled: Nmcli.enableWifi(checked)
horizontalPadding: Tokens.padding.largeIncreased
verticalPadding: Tokens.padding.medium
verticalPadding: Tokens.padding.large
}
StyledRect {
Layout.fillWidth: true
implicitHeight: networkList.implicitHeight + networkList.anchors.margins * 2
implicitHeight: networkList.contentHeight + (Nmcli.scanning ? Tokens.rounding.extraSmall : 0) // Inline so it isn't affected by anim
radius: Tokens.rounding.extraSmall
color: Colours.tPalette.m3surfaceContainer
clip: true
ColumnLayout {
Behavior on implicitHeight {
Anim {}
}
ListView {
id: networkList
anchors.fill: parent
anchors.left: parent.left
anchors.right: parent.right
anchors.top: scanningIndicator.bottom
anchors.bottom: parent.bottom
spacing: 0
interactive: false
Repeater {
model: Network.networks
model: ScriptModel {
values: [...Nmcli.networks].sort((a, b) => {
if (a.active)
return -1;
if (b.active)
return 1;
return b.strength - a.strength;
})
}
StateLayer {
id: network
add: Transition {
Anim {
property: "opacity"
from: 0
to: 1
type: Anim.DefaultEffects
}
}
required property Network.AccessPoint modelData
remove: Transition {
Anim {
property: "opacity"
to: 0
type: Anim.DefaultEffects
}
}
Layout.fillWidth: true
implicitHeight: networkLayout.implicitHeight + networkLayout.anchors.margins * 2
radius: Tokens.rounding.extraSmall
anchors.fill: undefined
move: Transition {
Anim {
property: "y"
}
}
RowLayout {
id: networkLayout
displaced: Transition {
Anim {
property: "y"
}
}
anchors.fill: parent
anchors.margins: Tokens.padding.medium
anchors.leftMargin: Tokens.padding.largeIncreased
anchors.rightMargin: Tokens.padding.largeIncreased
spacing: Tokens.spacing.medium
delegate: StateLayer {
id: network
MaterialIcon {
text: Icons.getNetworkIcon(network.modelData.strength)
color: network.modelData.active ? Colours.palette.m3primary : Colours.tPalette.m3onSurfaceVariant
font: Tokens.font.icon.medium
}
required property Nmcli.AccessPoint modelData
ColumnLayout {
anchors.left: networkList.contentItem.left
anchors.right: networkList.contentItem.right
implicitHeight: networkLayout.implicitHeight + networkLayout.anchors.margins * 2
radius: Tokens.rounding.extraSmall
anchors.fill: undefined
RowLayout {
id: networkLayout
anchors.fill: parent
anchors.margins: Tokens.padding.medium
anchors.leftMargin: Tokens.padding.largeIncreased
anchors.rightMargin: Tokens.padding.largeIncreased
spacing: Tokens.spacing.medium
MaterialIcon {
text: Icons.getNetworkIcon(network.modelData.strength)
color: network.modelData.active ? Colours.palette.m3primary : Colours.tPalette.m3onSurfaceVariant
font: Tokens.font.icon.medium
}
ColumnLayout {
Layout.fillWidth: true
spacing: 0
StyledText {
Layout.fillWidth: true
spacing: 0
StyledText {
Layout.fillWidth: true
text: network.modelData.ssid
font: Tokens.font.body.small
elide: Text.ElideRight
}
StyledText {
Layout.fillWidth: true
text: qsTr("Security: %1").arg(network.modelData.security)
color: Colours.tPalette.m3outline
font: Tokens.font.label.small
elide: Text.ElideRight
}
text: network.modelData.ssid
font: Tokens.font.body.small
elide: Text.ElideRight
}
MaterialIcon {
visible: network.modelData.isSecure
text: network.modelData.active ? "settings" : "lock"
color: network.modelData.active ? Colours.palette.m3primary : Colours.tPalette.m3onSurfaceVariant
font: Tokens.font.icon.medium
StyledText {
Layout.fillWidth: true
text: qsTr("Security: %1").arg(network.modelData.security)
color: Colours.tPalette.m3outline
font: Tokens.font.label.small
elide: Text.ElideRight
}
}
MaterialIcon {
visible: network.modelData.isSecure
text: network.modelData.active ? "settings" : "lock"
color: network.modelData.active ? Colours.palette.m3primary : Colours.tPalette.m3onSurfaceVariant
font: Tokens.font.icon.medium
}
}
}
}
StyledProgressBar {
id: scanningIndicator
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 1
implicitHeight: Nmcli.scanning ? Tokens.rounding.extraSmall : 0
indeterminate: true
Behavior on implicitHeight {
Anim {
type: Anim.DefaultEffects
}
}
}

View file

@ -9,6 +9,7 @@ class NexusConfig : public ConfigObject {
QML_ANONYMOUS
CONFIG_PROPERTY(int, wallpapersPerRow, 4)
CONFIG_GLOBAL_PROPERTY(int, networkRescanInterval, 15000)
public:
explicit NexusConfig(QObject* parent = nullptr)