Moved network related files, added network sub pages
C++ / fmt (pull_request) Successful in 5s
C++ / build (pull_request) Successful in 2m10s
JS/TS / fmt (pull_request) Successful in 16s
JS/TS / lint (pull_request) Successful in 17s
Python / static (pull_request) Successful in 44s
C++ / clang-tidy (pull_request) Successful in 3m37s
Rust / build (pull_request) Successful in 1m3s
Rust / fmt (pull_request) Failing after 15m10s
Python / verify (pull_request) Failing after 16m16s
Rust / clippy (pull_request) Successful in 45s
C++ / fmt (pull_request) Successful in 5s
C++ / build (pull_request) Successful in 2m10s
JS/TS / fmt (pull_request) Successful in 16s
JS/TS / lint (pull_request) Successful in 17s
Python / static (pull_request) Successful in 44s
C++ / clang-tidy (pull_request) Successful in 3m37s
Rust / build (pull_request) Successful in 1m3s
Rust / fmt (pull_request) Failing after 15m10s
Python / verify (pull_request) Failing after 16m16s
Rust / clippy (pull_request) Successful in 45s
This commit is contained in:
@@ -12,6 +12,7 @@ import qs.Modules.Settings.Pages.Apps
|
|||||||
import qs.Modules.Settings.Pages.Panels
|
import qs.Modules.Settings.Pages.Panels
|
||||||
import qs.Modules.Settings.Pages.Panels.Bar
|
import qs.Modules.Settings.Pages.Panels.Bar
|
||||||
import qs.Modules.Settings.Pages.Services
|
import qs.Modules.Settings.Pages.Services
|
||||||
|
import qs.Modules.Settings.Pages.Network
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
@@ -50,6 +51,26 @@ QtObject {
|
|||||||
NetworkPage {
|
NetworkPage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
AllNetworks {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
SavedNetworks {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
AddNetwork {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
OldNetwork {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Component {
|
Component {
|
||||||
|
|||||||
@@ -0,0 +1,256 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import ZShell.Config
|
||||||
|
import ZShell.Internal
|
||||||
|
import ZShell.Blobs
|
||||||
|
import ZShell.Services
|
||||||
|
import ZShell.Components
|
||||||
|
import qs.Components
|
||||||
|
import qs.Modules.Settings.Common
|
||||||
|
|
||||||
|
PageBase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property bool connecting: false
|
||||||
|
property bool failed: false
|
||||||
|
|
||||||
|
// Security model: index 0 = none, 1 = WPA/WPA2/WPA3 personal.
|
||||||
|
readonly property bool secured: securitySelect.active !== noneItem
|
||||||
|
property bool success: false
|
||||||
|
|
||||||
|
function submit(): void {
|
||||||
|
const ssid = ssidField.text.trim();
|
||||||
|
if (ssid.length === 0) {
|
||||||
|
ssidField.isError = true;
|
||||||
|
ssidField.forceActiveFocus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (root.secured && passwordField.text.length < 8) {
|
||||||
|
passwordField.isError = true;
|
||||||
|
passwordField.forceActiveFocus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
root.failed = false;
|
||||||
|
root.connecting = true;
|
||||||
|
|
||||||
|
Nmcli.addHiddenNetwork(ssid, root.secured ? passwordField.text : "", root.secured ? "wpa" : "none", hiddenToggle.checked, result => {
|
||||||
|
root.connecting = false;
|
||||||
|
if (result && result.success) {
|
||||||
|
root.success = true;
|
||||||
|
root.nState.closeSubPage();
|
||||||
|
} else {
|
||||||
|
root.failed = true;
|
||||||
|
if (root.secured)
|
||||||
|
passwordField.isError = true;
|
||||||
|
// Clean up the half-created profile so a retry starts fresh.
|
||||||
|
Nmcli.forgetNetwork(ssid);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
isSubPage: true
|
||||||
|
title: Tr.tr("Add network")
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
spacing: Tokens.spacing.large
|
||||||
|
width: root.cappedWidth
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
function onSubPageClosed(): void {
|
||||||
|
if (root.success)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const ssid = ssidField.text.trim();
|
||||||
|
if (ssid)
|
||||||
|
Nmcli.forgetNetwork(ssid);
|
||||||
|
}
|
||||||
|
|
||||||
|
target: root.nState
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: Tokens.padding.extraSmall
|
||||||
|
color: Colours.palette.m3onSurfaceVariant
|
||||||
|
font: Tokens.font.body.small
|
||||||
|
text: Tr.tr("Enter the details below to manually connect to a network.")
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomTextField {
|
||||||
|
id: ssidField
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: Tokens.spacing.extraSmall
|
||||||
|
errorText: Tr.tr("Network name is required")
|
||||||
|
inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText
|
||||||
|
leadingIcon: "wifi"
|
||||||
|
// TRANSLATORS: SSID is a protocol term, leave it untranslated
|
||||||
|
placeholderText: Tr.tr("Network name (SSID)")
|
||||||
|
// TRANSLATORS: sample network name, translate the e.g. but the name is a placeholder
|
||||||
|
supportingText: Tr.tr("e.g. MyHiddenNetwork")
|
||||||
|
|
||||||
|
onAccepted: root.secured ? passwordField.forceActiveFocus() : root.submit()
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
id: hiddenToggle
|
||||||
|
|
||||||
|
checked: true
|
||||||
|
first: true
|
||||||
|
subtext: Tr.tr("Actively probe for a network that doesn't broadcast its name")
|
||||||
|
text: Tr.tr("Hidden network")
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectRow {
|
||||||
|
id: securitySelect
|
||||||
|
|
||||||
|
Layout.topMargin: Tokens.spacing.extraSmall / 2 - parent.spacing
|
||||||
|
fallbackIcon: "lock"
|
||||||
|
// TRANSLATORS: WPA/WPA2/WPA3 are protocol names, leave them untranslated
|
||||||
|
fallbackText: Tr.tr("WPA/WPA2/WPA3 Personal")
|
||||||
|
// label: Tr.tr("Security")
|
||||||
|
last: !root.secured
|
||||||
|
|
||||||
|
Behavior on bottomLeftRadius {
|
||||||
|
Anim {
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on bottomRightRadius {
|
||||||
|
Anim {
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
menuItems: [
|
||||||
|
MenuItem {
|
||||||
|
icon: "lock"
|
||||||
|
// TRANSLATORS: WPA/WPA2/WPA3 are protocol names, leave them untranslated
|
||||||
|
text: Tr.tr("WPA/WPA2/WPA3 Personal")
|
||||||
|
},
|
||||||
|
MenuItem {
|
||||||
|
id: noneItem
|
||||||
|
|
||||||
|
icon: "lock_open"
|
||||||
|
text: Tr.trCtx("None (open)", "wifi security type")
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.bottomMargin: root.secured ? 0 : -parent.spacing
|
||||||
|
Layout.fillWidth: true
|
||||||
|
implicitHeight: root.secured ? passwordField.implicitHeight : 0
|
||||||
|
opacity: root.secured ? 1 : 0
|
||||||
|
|
||||||
|
Behavior on Layout.bottomMargin {
|
||||||
|
Anim {
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on implicitHeight {
|
||||||
|
Anim {
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomTextField {
|
||||||
|
id: passwordField
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
echoMode: TextInput.Password
|
||||||
|
enabled: root.secured
|
||||||
|
errorText: root.failed ? Tr.tr("Connection failed — check the password") : Tr.tr("Password must be at least 8 characters")
|
||||||
|
leadingIcon: "key"
|
||||||
|
placeholderText: Tr.tr("Password")
|
||||||
|
// TRANSLATORS: WPA is a protocol name, leave it untranslated
|
||||||
|
supportingText: Tr.tr("WPA passwords are at least 8 characters")
|
||||||
|
|
||||||
|
onAccepted: root.submit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.alignment: Qt.AlignRight
|
||||||
|
Layout.topMargin: Tokens.spacing.extraSmall - parent.spacing
|
||||||
|
spacing: Tokens.spacing.small
|
||||||
|
|
||||||
|
TextButton {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
horizontalPadding: Tokens.padding.extraLarge
|
||||||
|
isRound: true
|
||||||
|
text: Tr.trCtx("Cancel", "button")
|
||||||
|
type: TextButton.Tonal
|
||||||
|
|
||||||
|
onClicked: root.nState.closeSubPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect button — swaps to a loading spinner while connecting,
|
||||||
|
// matching the Wi-Fi list connect animation.
|
||||||
|
ButtonBase {
|
||||||
|
id: connectBtn
|
||||||
|
|
||||||
|
implicitHeight: connectMetrics.height + Tokens.padding.medium * 2
|
||||||
|
implicitWidth: connectMetrics.width + Tokens.padding.extraLarge * 2
|
||||||
|
// inactiveColour: Colours.palette.m3primary
|
||||||
|
// inactiveOnColour: Colours.palette.m3onPrimary
|
||||||
|
isRound: true
|
||||||
|
shapeMorph: true
|
||||||
|
|
||||||
|
// stateLayer.disabled: root.connecting || ssidField.text.trim().length === 0
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
if (!root.connecting && ssidField.text.trim().length > 0)
|
||||||
|
root.submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
TextMetrics {
|
||||||
|
id: connectMetrics
|
||||||
|
|
||||||
|
font: connectBtn.font
|
||||||
|
text: Tr.tr("Connect")
|
||||||
|
}
|
||||||
|
|
||||||
|
Anim {
|
||||||
|
id: connectContent
|
||||||
|
|
||||||
|
// anchors.centerIn: parent
|
||||||
|
// inAnimType: Anim.SlowEffects
|
||||||
|
// outAnimType: Anim.SlowEffects
|
||||||
|
// sourceComp: root.connecting ? connectLoadingComp : connectTextComp
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: connectLoadingComp
|
||||||
|
|
||||||
|
LoadingIndicator {
|
||||||
|
color: connectBtn.onColour
|
||||||
|
implicitSize: Math.round(Tokens.font.body.medium.pointSize * 1.4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: connectTextComp
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
color: connectBtn.onColour
|
||||||
|
font: connectBtn.font
|
||||||
|
text: connectMetrics.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,345 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import ZShell.Config
|
||||||
|
import qs.Components
|
||||||
|
import qs.Helpers.Network
|
||||||
|
import qs.Services
|
||||||
|
import qs.Modules.Settings.Common
|
||||||
|
|
||||||
|
PageBase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
flickable.bottomMargin: Tokens.padding.extraExtraLarge * 2 // Extra scrolling space at the bottom
|
||||||
|
|
||||||
|
isSubPage: true
|
||||||
|
title: Tr.tr("All networks")
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
// spacing: Tokens.spacing.extraSmall / 2
|
||||||
|
width: root.cappedWidth
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 300 // GlobalConfig.nexus.networkRescanInterval
|
||||||
|
repeat: true
|
||||||
|
running: root.visible && Nmcli.wifiEnabled
|
||||||
|
triggeredOnStart: true
|
||||||
|
|
||||||
|
onTriggered: Nmcli.rescanWifi()
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectedRect {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
first: true
|
||||||
|
implicitHeight: headerLayout.implicitHeight + Tokens.padding.medium * 2
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: headerLayout
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: Tokens.padding.largeIncreased
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: Tokens.padding.large
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.verticalCenterOffset: 1
|
||||||
|
|
||||||
|
// spacing: Tokens.spacing.extraSmall / 2
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
font: Tokens.font.title.small
|
||||||
|
text: Tr.trCtx("Filters", "network filter heading")
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterButton {
|
||||||
|
id: savedFilter
|
||||||
|
|
||||||
|
function internalFilter(ap: Nmcli.AccessPoint): bool {
|
||||||
|
return Nmcli.hasSavedProfile(ap.ssid);
|
||||||
|
}
|
||||||
|
|
||||||
|
bottomLeftRadius: pressed ? pressedRadius : implicitHeight / 2
|
||||||
|
text: Tr.trCtx("Saved", "network filter")
|
||||||
|
topLeftRadius: pressed ? pressedRadius : implicitHeight / 2
|
||||||
|
|
||||||
|
Behavior on bottomLeftRadius {
|
||||||
|
Anim {
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on topLeftRadius {
|
||||||
|
Anim {
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterButton {
|
||||||
|
id: secureFilter
|
||||||
|
|
||||||
|
function internalFilter(ap: Nmcli.AccessPoint): bool {
|
||||||
|
return ap.security !== "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
text: Tr.trCtx("Secured", "network filter")
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterButton {
|
||||||
|
id: highFreqFilter
|
||||||
|
|
||||||
|
function internalFilter(ap: Nmcli.AccessPoint): bool {
|
||||||
|
return ap.frequency >= 4900 && ap.frequency <= 5900;
|
||||||
|
}
|
||||||
|
|
||||||
|
text: Tr.trCtx("5 GHz", "network filter")
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterButton {
|
||||||
|
id: lowFreqFilter
|
||||||
|
|
||||||
|
function internalFilter(ap: Nmcli.AccessPoint): bool {
|
||||||
|
return ap.frequency >= 2400 && ap.frequency <= 2500;
|
||||||
|
}
|
||||||
|
|
||||||
|
bottomRightRadius: pressed ? pressedRadius : implicitHeight / 2
|
||||||
|
text: Tr.trCtx("2.4 GHz", "network filter")
|
||||||
|
topRightRadius: pressed ? pressedRadius : implicitHeight / 2
|
||||||
|
|
||||||
|
Behavior on bottomRightRadius {
|
||||||
|
Anim {
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on topRightRadius {
|
||||||
|
Anim {
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkList {
|
||||||
|
id: networkList
|
||||||
|
|
||||||
|
function networkFilter(ap: Nmcli.AccessPoint): bool {
|
||||||
|
return savedFilter.filter(ap) && secureFilter.filter(ap) && highFreqFilter.filter(ap) && lowFreqFilter.filter(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
enableFilter: true
|
||||||
|
last: true
|
||||||
|
// nState: root.nState
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component FilterButton: IconTextButton {
|
||||||
|
id: filter
|
||||||
|
|
||||||
|
property int filterState // 0 = default, 1 = on, 2 = negate
|
||||||
|
|
||||||
|
function filter(ap: Nmcli.AccessPoint): bool {
|
||||||
|
if (filterState === 0)
|
||||||
|
return true;
|
||||||
|
if (filterState === 1)
|
||||||
|
return internalFilter(ap);
|
||||||
|
return !internalFilter(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
function internalFilter(ap: Nmcli.AccessPoint): bool {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultRadius: filterState > 0 ? implicitHeight / 2 : Tokens.rounding.small
|
||||||
|
icon: ["check_indeterminate_small", "check", "close"][filterState]
|
||||||
|
// inactiveColour: [Colours.palette.m3secondaryContainer, Colours.palette.m3secondary, Colours.palette.m3tertiary][filterState]
|
||||||
|
// inactiveOnColour: [Colours.palette.m3onSecondaryContainer, Colours.palette.m3onSecondary, Colours.palette.m3onTertiary][filterState]
|
||||||
|
pressedRadius: Tokens.rounding.extraSmall
|
||||||
|
|
||||||
|
// spacing: Tokens.spacing.extraSmall
|
||||||
|
|
||||||
|
onClicked: filterState = (filterState + 1) % 3
|
||||||
|
}
|
||||||
|
component NetworkList: ItemList {
|
||||||
|
id: netList
|
||||||
|
|
||||||
|
property bool enableFilter
|
||||||
|
property int limit: 0 // 0 = show all
|
||||||
|
|
||||||
|
// required property NexusState nState
|
||||||
|
|
||||||
|
signal networkSelected(ap: Nmcli.AccessPoint)
|
||||||
|
|
||||||
|
function networkFilter(ap: Nmcli.AccessPoint): bool {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
extraHeight: Nmcli.scanning ? Tokens.rounding.extraSmall : 0 // Inline so it isn't affected by anim
|
||||||
|
list.anchors.top: scanningIndicator.bottom
|
||||||
|
placeholderIcon: Nmcli.wifiEnabled ? "wifi_find" : "signal_wifi_off"
|
||||||
|
placeholderText: Nmcli.wifiEnabled ? Tr.tr("No networks found") : Tr.tr("Wi-Fi disabled")
|
||||||
|
showList: Nmcli.wifiEnabled
|
||||||
|
|
||||||
|
delegate: StateLayer {
|
||||||
|
id: network
|
||||||
|
|
||||||
|
property bool currentSelected
|
||||||
|
required property int index
|
||||||
|
required property var modelData
|
||||||
|
property real textOpacity: disabled ? 0.5 : 1
|
||||||
|
|
||||||
|
anchors.fill: undefined
|
||||||
|
anchors.left: netList.list.contentItem.left
|
||||||
|
anchors.right: netList.list.contentItem.right
|
||||||
|
bottomLeftRadius: netList?.last && index === netList.list.count - 1 ? Tokens.rounding.extraLarge : radius
|
||||||
|
bottomRightRadius: netList?.last && index === netList.list.count - 1 ? Tokens.rounding.extraLarge : radius
|
||||||
|
// disabled: currentSelected || Nmcli.connectingSsid() === modelData.ssid
|
||||||
|
implicitHeight: networkLayout.implicitHeight + networkLayout.anchors.margins * 2
|
||||||
|
radius: Tokens.rounding.extraSmall
|
||||||
|
|
||||||
|
Behavior on textOpacity {
|
||||||
|
Anim {
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
if (!modelData.active) {
|
||||||
|
NetworkConnection.handleConnect(modelData);
|
||||||
|
currentSelected = true;
|
||||||
|
netList.networkSelected(modelData);
|
||||||
|
} else {
|
||||||
|
// Active network: open its detail/settings sub-page.
|
||||||
|
netList.nState.selectedNetworkSsid = modelData.ssid;
|
||||||
|
netList.nState.networkDetailsFromSaved = false;
|
||||||
|
netList.nState.openSubPage(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
function onActiveChanged(): void {
|
||||||
|
if (network.modelData.active)
|
||||||
|
network.currentSelected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
target: network.modelData
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
function onNetworkSelected(ap: Nmcli.AccessPoint): void {
|
||||||
|
if (ap !== network.modelData)
|
||||||
|
network.currentSelected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
target: netList
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: networkLayout
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: Tokens.padding.extraLarge
|
||||||
|
anchors.margins: Tokens.padding.large
|
||||||
|
anchors.rightMargin: Tokens.padding.extraLarge
|
||||||
|
|
||||||
|
// spacing: Tokens.spacing.extraSmall
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
color: network.modelData.active ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant
|
||||||
|
font.pointSize: Tokens.font.size.normal
|
||||||
|
opacity: network.textOpacity
|
||||||
|
text: Icons.getNetworkIcon(network.modelData.strength)
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
opacity: network.textOpacity
|
||||||
|
|
||||||
|
// spacing: 0
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font: Tokens.font.body.small
|
||||||
|
text: network.modelData.ssid
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: Colours.palette.m3outline
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font: Tokens.font.label.small
|
||||||
|
text: {
|
||||||
|
const net = network.modelData;
|
||||||
|
let status = "";
|
||||||
|
if (net.active)
|
||||||
|
status = Tr.trCtx("Connected", "network connected");
|
||||||
|
else if (Nmcli.hasSavedProfile(net.ssid))
|
||||||
|
status = Tr.trCtx("Saved", "network saved");
|
||||||
|
if (status)
|
||||||
|
// TRANSLATORS: %1 = security type, %2 = connection status
|
||||||
|
return Tr.trCtx("Security: %1 • %2", "network security and status").arg(net.security).arg(status);
|
||||||
|
return Tr.trCtx("Security: %1", "network security").arg(net.security);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Anim {
|
||||||
|
// // sourceComp: Nmcli.connectingSsid() === network.modelData.ssid ? loadingComp : iconComp
|
||||||
|
//
|
||||||
|
// Component {
|
||||||
|
// id: iconComp
|
||||||
|
//
|
||||||
|
// MaterialIcon {
|
||||||
|
// color: network.modelData.active ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant
|
||||||
|
// fontStyle: Tokens.font.icon.medium
|
||||||
|
// opacity: network.textOpacity
|
||||||
|
// text: network.modelData.active ? "settings" : "lock"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Component {
|
||||||
|
// id: loadingComp
|
||||||
|
//
|
||||||
|
// LoadingIndicator {
|
||||||
|
// implicitSize: Math.round(Tokens.font.icon.medium.pointSize * 1.3)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// model: ScriptModel {
|
||||||
|
// values: {
|
||||||
|
// const connecting = Nmcli.connectingSsid();
|
||||||
|
// // Lower rank sorts higher in the list
|
||||||
|
// const rank = n => n.active ? 0 : n.ssid === connecting ? 1 : Nmcli.hasSavedProfile(n.ssid) ? 2 : 3;
|
||||||
|
// const sorted = [...Nmcli.networks].sort((a, b) => rank(a) - rank(b) || b.strength - a.strength);
|
||||||
|
// if (netList.limit > 0 && sorted.length > netList.limit)
|
||||||
|
// sorted.length = netList.limit;
|
||||||
|
// return netList.enableFilter ? sorted.filter(netList.networkFilter) : sorted;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// StyledProgressBar {
|
||||||
|
// id: scanningIndicator
|
||||||
|
//
|
||||||
|
// anchors.left: parent.left
|
||||||
|
// anchors.margins: 1
|
||||||
|
// anchors.right: parent.right
|
||||||
|
// implicitHeight: Nmcli.scanning ? Tokens.rounding.extraSmall : 0
|
||||||
|
// indeterminate: true
|
||||||
|
//
|
||||||
|
// Behavior on implicitHeight {
|
||||||
|
// Anim {
|
||||||
|
// type: Anim.DefaultEffects
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import ZShell.Config
|
||||||
|
import qs.Modules.Settings.Common
|
||||||
|
import qs.Modules.Bar.Popouts.Network
|
||||||
|
import qs.Components
|
||||||
|
import qs.Helpers.Network
|
||||||
|
import qs.Services
|
||||||
|
|
||||||
|
PageBase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
title: qsTr("Begin page")
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
spacing: Tokens.spacing.extraSmall / 2
|
||||||
|
width: root.cappedWidth
|
||||||
|
|
||||||
|
NavRow {
|
||||||
|
first: true
|
||||||
|
icon: "dock_to_bottom"
|
||||||
|
// settingAnchor: "panels-bar"
|
||||||
|
text: qsTr("Show all networks")
|
||||||
|
|
||||||
|
onClicked: root.sState.openSubPage(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
NavRow {
|
||||||
|
icon: "dock_to_bottom"
|
||||||
|
text: qsTr("Saved networks")
|
||||||
|
|
||||||
|
onClicked: root.sState.openSubPage(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
NavRow {
|
||||||
|
icon: "dock_to_bottom"
|
||||||
|
text: qsTr("Add network")
|
||||||
|
|
||||||
|
onClicked: root.sState.openSubPage(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
NavRow {
|
||||||
|
icon: "dock_to_bottom"
|
||||||
|
last: true
|
||||||
|
text: qsTr("Old Network Page")
|
||||||
|
|
||||||
|
onClicked: root.sState.openSubPage(4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-1
@@ -13,7 +13,8 @@ import qs.Services
|
|||||||
PageBase {
|
PageBase {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
title: qsTr("Network")
|
isSubPage: true
|
||||||
|
title: qsTr("Old network page")
|
||||||
|
|
||||||
Component.onCompleted: Network.active = true
|
Component.onCompleted: Network.active = true
|
||||||
Component.onDestruction: Network.active = false
|
Component.onDestruction: Network.active = false
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import ZShell.Config
|
||||||
|
import ZShell.Internal
|
||||||
|
import ZShell.Blobs
|
||||||
|
import ZShell.Services
|
||||||
|
import ZShell.Components
|
||||||
|
import qs.Components
|
||||||
|
import qs.Modules.Settings.Common
|
||||||
|
|
||||||
|
PageBase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
isSubPage: true
|
||||||
|
title: Tr.tr("Saved networks")
|
||||||
|
|
||||||
|
Component.onCompleted: Nmcli.loadSavedConnections(() => {})
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
spacing: Tokens.spacing.extraSmall / 2
|
||||||
|
width: root.cappedWidth
|
||||||
|
|
||||||
|
ItemList {
|
||||||
|
id: savedList
|
||||||
|
|
||||||
|
first: true
|
||||||
|
last: true
|
||||||
|
placeholderIcon: "wifi_find"
|
||||||
|
placeholderText: Tr.tr("No saved networks")
|
||||||
|
showList: true
|
||||||
|
|
||||||
|
delegate: StateLayer {
|
||||||
|
id: saved
|
||||||
|
|
||||||
|
readonly property var ap: Nmcli.findNetwork(modelData)
|
||||||
|
required property int index
|
||||||
|
readonly property bool isActive: !!Nmcli.active && Nmcli.active.ssid === modelData
|
||||||
|
required property var modelData
|
||||||
|
|
||||||
|
anchors.fill: undefined
|
||||||
|
anchors.left: savedList.list.contentItem.left
|
||||||
|
anchors.right: savedList.list.contentItem.right
|
||||||
|
bottomLeftRadius: index === savedList?.list.count - 1 ? Tokens.rounding.extraLarge : radius
|
||||||
|
bottomRightRadius: index === savedList?.list.count - 1 ? Tokens.rounding.extraLarge : radius
|
||||||
|
implicitHeight: savedLayout.implicitHeight + savedLayout.anchors.margins * 2
|
||||||
|
radius: Tokens.rounding.extraSmall
|
||||||
|
topLeftRadius: index === 0 ? Tokens.rounding.extraLarge : radius
|
||||||
|
topRightRadius: index === 0 ? Tokens.rounding.extraLarge : radius
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
root.nState.selectedNetworkSsid = saved.modelData;
|
||||||
|
root.nState.networkDetailsFromSaved = true;
|
||||||
|
root.nState.openSubPage(3); // Shared network detail/edit sub-page
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: savedLayout
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: Tokens.padding.extraLarge
|
||||||
|
anchors.margins: Tokens.padding.large
|
||||||
|
anchors.rightMargin: Tokens.padding.extraLarge
|
||||||
|
spacing: Tokens.spacing.medium
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
color: saved.isActive ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant
|
||||||
|
font.pointSize: Tokens.font.size.normal
|
||||||
|
text: saved.ap ? Icons.getNetworkIcon(saved.ap.strength, !["", "none"].includes(Nmcli.savedSecurityFor(saved.modelData))) : "signal_wifi_off"
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font: Tokens.font.body.small
|
||||||
|
text: saved.modelData
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: saved.isActive ? Colours.palette.m3primary : Colours.palette.m3outline
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font: Tokens.font.label.small
|
||||||
|
text: {
|
||||||
|
let security;
|
||||||
|
if (saved.ap)
|
||||||
|
security = saved.ap.security || Tr.trCtx("Open", "wifi security type");
|
||||||
|
else
|
||||||
|
security = Nmcli.securityLabel(Nmcli.savedSecurityFor(saved.modelData)) || Tr.trCtx("Unknown", "unknown wifi security");
|
||||||
|
if (saved.isActive)
|
||||||
|
// TRANSLATORS: %1 = security type
|
||||||
|
return Tr.trCtx("Connected • %1", "network connected with security").arg(security);
|
||||||
|
return security;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
color: Colours.palette.m3onSurfaceVariant
|
||||||
|
font.pointSize: Tokens.font.size.normal
|
||||||
|
text: "chevron_right"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
model: ScriptModel {
|
||||||
|
values: [...Nmcli.savedConnectionSsids].sort((a, b) => a.localeCompare(b))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1834
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user