nosignal-shell/modules/nexus/pages/NetworkPage.qml
28allday cf3c0d823d feat(nosignal): Nerd Font icon remap — nexus (Settings)
Convert caelestia's nexus Settings to Nerd Font icons (drop-in NsIcon).

- NsIcon hardened into a MaterialIcon drop-in: accepts fontStyle (sizes from
  it, keeps the NF Mono family), plus no-op fill/grade/animate for API parity.
- Glyphs map extended with caelestia core names: nexus static icons, nav/page
  icons (palette, wallpaper, dashboard, devices_other, extension, globe, info,
  monitor, shuffle, workspaces, ...), weather + app/device icons.
- Converted all MaterialIcon in modules/nexus/ to NsIcon; fixed icon aliases
  (NavRow/SliderRow .text -> .icon); reverted IconButton font: (it has font,
  not fontStyle, and renders its own icon).

Remaining core surfaces still Material Symbols (no breakage): launcher, osd,
lock, sidebar, utilities — to convert next with any further Glyphs entries.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 11:16:01 +01:00

235 lines
7.9 KiB
QML

pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import Caelestia.Config
import qs.components
import qs.components.controls
import qs.services
import qs.utils
import qs.modules.nexus.common
PageBase {
id: root
signal networkSelected(ap: Nmcli.AccessPoint)
title: qsTr("Network")
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
width: root.cappedWidth
spacing: Tokens.spacing.extraSmall / 2
Timer {
running: root.visible && Nmcli.wifiEnabled
repeat: true
triggeredOnStart: true
interval: GlobalConfig.nexus.networkRescanInterval
onTriggered: Nmcli.rescanWifi()
}
Timer {
id: wifiScanDelay
interval: 100
onTriggered: Nmcli.rescanWifi()
}
Connections {
function onWifiEnabledChanged(): void {
if (Nmcli.wifiEnabled)
wifiScanDelay.start();
}
target: Nmcli
}
ToggleRow {
Layout.fillWidth: true
first: true
text: qsTr("Wi-Fi")
font: Tokens.font.body.medium
horizontalPadding: Tokens.padding.largeIncreased
checked: Nmcli.wifiEnabled
onToggled: Nmcli.enableWifi(checked)
}
ItemList {
id: networkList
showList: Nmcli.wifiEnabled
placeholderIcon: Nmcli.wifiEnabled ? "wifi_find" : "signal_wifi_off"
placeholderText: Nmcli.wifiEnabled ? qsTr("No networks found") : qsTr("Wi-Fi disabled")
extraHeight: Nmcli.scanning ? Tokens.rounding.extraSmall : 0 // Inline so it isn't affected by anim
list.anchors.top: scanningIndicator.bottom
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;
return [...Nmcli.networks].sort((a, b) => rank(a) - rank(b) || b.strength - a.strength);
}
}
delegate: StateLayer {
id: network
required property Nmcli.AccessPoint modelData
property bool currentSelected
property real textOpacity: disabled ? 0.5 : 1
disabled: currentSelected || Nmcli.connectingSsid() === modelData.ssid
anchors.left: networkList.list.contentItem.left
anchors.right: networkList.list.contentItem.right
implicitHeight: networkLayout.implicitHeight + networkLayout.anchors.margins * 2
radius: Tokens.rounding.extraSmall
anchors.fill: undefined
onClicked: {
if (!modelData.active) {
NetworkConnection.handleConnect(modelData);
currentSelected = true;
root.networkSelected(modelData);
}
}
Behavior on textOpacity {
Anim {
type: Anim.DefaultEffects
}
}
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: root
}
RowLayout {
id: networkLayout
anchors.fill: parent
anchors.margins: Tokens.padding.large
anchors.leftMargin: Tokens.padding.extraLarge
anchors.rightMargin: Tokens.padding.extraLarge
spacing: Tokens.spacing.medium
NsIcon {
icon: Icons.getNetworkIcon(network.modelData.strength)
color: network.modelData.active ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant
fontStyle: Tokens.font.icon.medium
opacity: network.textOpacity
}
ColumnLayout {
Layout.fillWidth: true
spacing: 0
opacity: network.textOpacity
StyledText {
Layout.fillWidth: true
text: network.modelData.ssid
font: Tokens.font.body.small
elide: Text.ElideRight
}
StyledText {
Layout.fillWidth: true
text: qsTr("Security: %1%2").arg(network.modelData.security).arg(Nmcli.hasSavedProfile(network.modelData.ssid) ? qsTr(" • Saved") : "")
color: Colours.palette.m3outline
font: Tokens.font.label.small
elide: Text.ElideRight
}
}
AnimLoader {
sourceComp: Nmcli.connectingSsid() === network.modelData.ssid ? loadingComp : iconComp
Component {
id: iconComp
NsIcon {
icon: network.modelData.active ? "settings" : "lock"
color: network.modelData.active ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant
fontStyle: Tokens.font.icon.medium
opacity: network.textOpacity
}
}
Component {
id: loadingComp
LoadingIndicator {
implicitSize: Math.round(Tokens.font.icon.medium.pointSize * 1.3)
}
}
}
}
}
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
}
}
}
}
ConnectedRect {
Layout.fillWidth: true
implicitHeight: addNetworkLayout.implicitHeight + addNetworkLayout.anchors.margins * 2
last: true
StateLayer {}
RowLayout {
id: addNetworkLayout
anchors.fill: parent
anchors.margins: Tokens.padding.medium
anchors.leftMargin: Tokens.padding.largeIncreased
anchors.rightMargin: Tokens.padding.largeIncreased
spacing: Tokens.spacing.medium
NsIcon {
icon: "add"
fontStyle: Tokens.font.icon.medium
}
StyledText {
Layout.fillWidth: true
text: qsTr("Add network")
font: Tokens.font.body.small
elide: Text.ElideRight
}
}
}
}
}