From 9fefb534405980ccea9ea6048f02cf081033cb1e Mon Sep 17 00:00:00 2001 From: 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> Date: Sat, 25 Apr 2026 23:04:02 +1000 Subject: [PATCH] feat: improve dash perf network card --- modules/dashboard/Performance.qml | 204 +----------------- modules/dashboard/performance/NetworkCard.qml | 197 +++++++++++++++++ plugin/src/Caelestia/Config/tokens.hpp | 2 + 3 files changed, 200 insertions(+), 203 deletions(-) create mode 100644 modules/dashboard/performance/NetworkCard.qml diff --git a/modules/dashboard/Performance.qml b/modules/dashboard/Performance.qml index c6e75d19..b405ddc3 100644 --- a/modules/dashboard/Performance.qml +++ b/modules/dashboard/Performance.qml @@ -116,8 +116,7 @@ Item { NetworkCard { Layout.fillWidth: true - Layout.minimumWidth: 200 - Layout.preferredHeight: 220 + Layout.fillHeight: true visible: Config.dashboard.performance.showNetwork } @@ -252,205 +251,4 @@ Item { } } } - - component CardHeader: RowLayout { - property string icon - property string title - property color accentColor: Colours.palette.m3primary - - Layout.fillWidth: true - spacing: Tokens.spacing.small - - MaterialIcon { - text: parent.icon - fill: 1 - color: parent.accentColor - fontStyle: Tokens.font.icon.size(Tokens.spacing.large).build() - } - - StyledText { - Layout.fillWidth: true - text: parent.title - font: Tokens.font.body.medium - elide: Text.ElideRight - } - } - - component NetworkCard: StyledRect { - id: networkCard - - property color accentColor: Colours.palette.m3primary - - color: Colours.tPalette.m3surfaceContainer - radius: Tokens.rounding.extraLarge - clip: true - - Ref { - service: NetworkUsage - } - - ColumnLayout { - anchors.fill: parent - anchors.margins: Tokens.padding.large - spacing: Tokens.spacing.small - - CardHeader { - icon: "swap_vert" - title: qsTr("Network") - accentColor: networkCard.accentColor - } - - // Sparkline graph - Item { - Layout.fillWidth: true - Layout.fillHeight: true - - SparklineItem { - id: sparkline - - property real targetMax: 1024 - property real smoothMax: targetMax - - anchors.fill: parent - line1: NetworkUsage.uploadBuffer // qmllint disable missing-type - line1Color: Colours.palette.m3secondary - line1FillAlpha: 0.15 - line2: NetworkUsage.downloadBuffer // qmllint disable missing-type - line2Color: Colours.palette.m3tertiary - line2FillAlpha: 0.2 - maxValue: smoothMax - historyLength: NetworkUsage.historyLength - - Connections { - function onValuesChanged(): void { - sparkline.targetMax = Math.max(NetworkUsage.downloadBuffer.maximum, NetworkUsage.uploadBuffer.maximum, 1024); - slideAnim.restart(); - } - - target: NetworkUsage.downloadBuffer - } - - NumberAnimation { - id: slideAnim - - target: sparkline - property: "slideProgress" - from: 0 - to: 1 - duration: GlobalConfig.dashboard.resourceUpdateInterval - } - - Behavior on smoothMax { - Anim { - type: Anim.StandardLarge - } - } - } - - // "No data" placeholder - StyledText { - anchors.centerIn: parent - text: qsTr("Collecting data...") - font: Tokens.font.body.small - color: Colours.palette.m3onSurfaceVariant - visible: NetworkUsage.downloadBuffer.count < 2 - opacity: 0.6 - } - } - - // Download row - RowLayout { - Layout.fillWidth: true - spacing: Tokens.spacing.medium - - MaterialIcon { - text: "download" - color: Colours.palette.m3tertiary - fontStyle: Tokens.font.icon.medium - } - - StyledText { - text: qsTr("Download") - font: Tokens.font.body.small - color: Colours.palette.m3onSurfaceVariant - } - - Item { - Layout.fillWidth: true - } - - StyledText { - text: { - const fmt = NetworkUsage.formatBytes(NetworkUsage.downloadSpeed ?? 0); - return fmt ? `${fmt.value.toFixed(1)} ${fmt.unit}` : "0.0 B/s"; - } - font: Tokens.font.body.builders.medium.weight(Font.Medium).build() - color: Colours.palette.m3tertiary - } - } - - // Upload row - RowLayout { - Layout.fillWidth: true - spacing: Tokens.spacing.medium - - MaterialIcon { - text: "upload" - color: Colours.palette.m3secondary - fontStyle: Tokens.font.icon.medium - } - - StyledText { - text: qsTr("Upload") - font: Tokens.font.body.small - color: Colours.palette.m3onSurfaceVariant - } - - Item { - Layout.fillWidth: true - } - - StyledText { - text: { - const fmt = NetworkUsage.formatBytes(NetworkUsage.uploadSpeed ?? 0); - return fmt ? `${fmt.value.toFixed(1)} ${fmt.unit}` : "0.0 B/s"; - } - font: Tokens.font.body.builders.medium.weight(Font.Medium).build() - color: Colours.palette.m3secondary - } - } - - // Session totals - RowLayout { - Layout.fillWidth: true - spacing: Tokens.spacing.medium - - MaterialIcon { - text: "history" - color: Colours.palette.m3onSurfaceVariant - fontStyle: Tokens.font.icon.medium - } - - StyledText { - text: qsTr("Total") - font: Tokens.font.body.small - color: Colours.palette.m3onSurfaceVariant - } - - Item { - Layout.fillWidth: true - } - - StyledText { - text: { - const down = NetworkUsage.formatBytesTotal(NetworkUsage.downloadTotal ?? 0); - const up = NetworkUsage.formatBytesTotal(NetworkUsage.uploadTotal ?? 0); - return (down && up) ? `↓${down.value.toFixed(1)}${down.unit} ↑${up.value.toFixed(1)}${up.unit}` : "↓0.0B ↑0.0B"; - } - font: Tokens.font.body.small - color: Colours.palette.m3onSurfaceVariant - } - } - } - } } diff --git a/modules/dashboard/performance/NetworkCard.qml b/modules/dashboard/performance/NetworkCard.qml new file mode 100644 index 00000000..4eccebe7 --- /dev/null +++ b/modules/dashboard/performance/NetworkCard.qml @@ -0,0 +1,197 @@ +import QtQuick +import QtQuick.Layouts +import Caelestia.Config +import Caelestia.Internal +import qs.components +import qs.components.misc +import qs.services + +StyledRect { + id: root + + color: Colours.tPalette.m3surfaceContainer + radius: Tokens.rounding.extraLarge + + implicitWidth: Tokens.sizes.dashboard.perfNetworkCardWidth + implicitHeight: Tokens.sizes.dashboard.perfNetworkCardHeight + + Ref { + service: NetworkUsage + } + + ColumnLayout { + id: layout + + anchors.fill: parent + anchors.margins: Tokens.padding.large + anchors.bottomMargin: Tokens.padding.medium + spacing: 0 + + RowLayout { + spacing: Tokens.spacing.small + + MaterialIcon { + text: "swap_vert" + color: Colours.palette.m3primary + fontStyle: Tokens.font.icon.medium + } + + StyledText { + text: qsTr("Network") + font: Tokens.font.title.medium + } + } + + // Sparkline graph + Item { + Layout.topMargin: Tokens.spacing.medium + Layout.bottomMargin: Tokens.spacing.small + Layout.fillWidth: true + Layout.fillHeight: true + + SparklineItem { + id: sparkline + + property real targetMax: 1024 + property real smoothMax: targetMax + + anchors.fill: parent + line1: NetworkUsage.uploadBuffer // qmllint disable missing-type + line1Color: Colours.palette.m3secondary + line1FillAlpha: 0.15 + line2: NetworkUsage.downloadBuffer // qmllint disable missing-type + line2Color: Colours.palette.m3tertiary + line2FillAlpha: 0.2 + maxValue: smoothMax + historyLength: NetworkUsage.historyLength + + Connections { + function onValuesChanged(): void { + sparkline.targetMax = Math.max(NetworkUsage.downloadBuffer.maximum, NetworkUsage.uploadBuffer.maximum, 1024); + slideAnim.restart(); + } + + target: NetworkUsage.downloadBuffer + } + + NumberAnimation { + id: slideAnim + + target: sparkline + property: "slideProgress" + from: 0 + to: 1 + easing.type: Easing.Linear + duration: GlobalConfig.dashboard.resourceUpdateInterval + } + + Behavior on smoothMax { + Anim {} + } + } + + // "Collecting data" placeholder + StyledText { + anchors.centerIn: parent + text: qsTr("Collecting data...") + font: Tokens.font.body.small + color: Colours.palette.m3outline + visible: NetworkUsage.downloadBuffer.count < 2 + } + } + + // Download row + RowLayout { + Layout.fillWidth: true + spacing: Tokens.spacing.small + + MaterialIcon { + text: "download" + color: Colours.palette.m3tertiary + fontStyle: Tokens.font.icon.medium + } + + StyledText { + text: qsTr("Download") + font: Tokens.font.body.small + color: Colours.palette.m3onSurfaceVariant + } + + Item { + Layout.fillWidth: true + } + + StyledText { + text: { + const fmt = NetworkUsage.formatBytes(NetworkUsage.downloadSpeed ?? 0); + return fmt ? `${fmt.value.toFixed(1)} ${fmt.unit}` : "0.0 B/s"; + } + font: Tokens.font.body.builders.medium.weight(Font.Medium).build() + color: Colours.palette.m3tertiary + } + } + + // Upload row + RowLayout { + Layout.fillWidth: true + spacing: Tokens.spacing.small + + MaterialIcon { + text: "upload" + color: Colours.palette.m3secondary + fontStyle: Tokens.font.icon.medium + } + + StyledText { + text: qsTr("Upload") + font: Tokens.font.body.small + color: Colours.palette.m3onSurfaceVariant + } + + Item { + Layout.fillWidth: true + } + + StyledText { + text: { + const fmt = NetworkUsage.formatBytes(NetworkUsage.uploadSpeed ?? 0); + return fmt ? `${fmt.value.toFixed(1)} ${fmt.unit}` : "0.0 B/s"; + } + font: Tokens.font.body.builders.medium.weight(Font.Medium).build() + color: Colours.palette.m3secondary + } + } + + // Session totals + RowLayout { + Layout.fillWidth: true + spacing: Tokens.spacing.small + + MaterialIcon { + text: "history" + color: Colours.palette.m3onSurfaceVariant + fontStyle: Tokens.font.icon.medium + } + + StyledText { + text: qsTr("Total") + font: Tokens.font.body.small + color: Colours.palette.m3onSurfaceVariant + } + + Item { + Layout.fillWidth: true + } + + StyledText { + text: { + const down = NetworkUsage.formatBytesTotal(NetworkUsage.downloadTotal ?? 0); + const up = NetworkUsage.formatBytesTotal(NetworkUsage.uploadTotal ?? 0); + return (down && up) ? `↓${down.value.toFixed(1)}${down.unit} ↑${up.value.toFixed(1)}${up.unit}` : "↓0.0B ↑0.0B"; + } + font: Tokens.font.body.small + color: Colours.palette.m3onSurfaceVariant + } + } + } +} diff --git a/plugin/src/Caelestia/Config/tokens.hpp b/plugin/src/Caelestia/Config/tokens.hpp index 82f01915..119d7c80 100644 --- a/plugin/src/Caelestia/Config/tokens.hpp +++ b/plugin/src/Caelestia/Config/tokens.hpp @@ -192,6 +192,8 @@ class DashboardTokens : public ConfigObject { CONFIG_PROPERTY(int, perfHeroCardWidth, 400) CONFIG_PROPERTY(int, perfUsageShapeSize, 100) CONFIG_PROPERTY(int, perfStorageTextWidth, 160) + CONFIG_PROPERTY(int, perfNetworkCardWidth, 280) + CONFIG_PROPERTY(int, perfNetworkCardHeight, 220) public: explicit DashboardTokens(QObject* parent = nullptr)