diff --git a/Helpers/NetworkUsage.qml b/Helpers/NetworkUsage.qml index 51957da..f206d2c 100644 --- a/Helpers/NetworkUsage.qml +++ b/Helpers/NetworkUsage.qml @@ -39,6 +39,21 @@ Singleton { readonly property real uploadSpeed: _uploadSpeed readonly property real uploadTotal: _uploadTotal +function resetSampling(): void { + netDevFile.reload(); + + const content = netDevFile.text(); + if (!content) + return; + + const data = root.parseNetDev(content); + const now = Date.now(); + + root._prevRxBytes = data.rx; + root._prevTxBytes = data.tx; + root._prevTimestamp = now; +} + function formatBytes(bytes: real): var { // Handle negative or invalid values if (bytes < 0 || isNaN(bytes) || !isFinite(bytes)) { @@ -156,10 +171,15 @@ Singleton { Timer { interval: Config.dashboard.resourceUpdateInterval repeat: true - running: root.refCount > 0 + running: true triggeredOnStart: true onTriggered: { + if (root.refCount <= 0) { + root.resetSampling(); + return; + } + netDevFile.reload(); const content = netDevFile.text(); if (!content) diff --git a/Modules/Resources/Cards/NetworkCard.qml b/Modules/Resources/Cards/NetworkCard.qml index 7f3f052..b3bbebc 100644 --- a/Modules/Resources/Cards/NetworkCard.qml +++ b/Modules/Resources/Cards/NetworkCard.qml @@ -1,6 +1,7 @@ import QtQuick import QtQuick.Layouts import ZShell.Internal +import qs.Modules.Resources import qs.Helpers import qs.Components import qs.Config @@ -8,6 +9,8 @@ import qs.Config CustomRect { id: root + required property Wrapper wrapper + color: DynamicColors.tPalette.m3surfaceContainer implicitHeight: 220 implicitWidth: 300 @@ -47,6 +50,7 @@ CustomRect { SparklineItem { id: sparkline + property bool initialized: false property real smoothMax: targetMax property real targetMax: 1024 @@ -59,12 +63,23 @@ CustomRect { line2Color: DynamicColors.palette.m3tertiary line2FillAlpha: 0.2 maxValue: smoothMax + slideProgress: 1 Behavior on smoothMax { + enabled: sparkline.initialized + Anim { } } + Component.onCompleted: { + sparkline.targetMax = Math.max(NetworkUsage.downloadBuffer.maximum, NetworkUsage.uploadBuffer.maximum, 1024); + + sparkline.smoothMax = Qt.binding(() => sparkline.targetMax); + + sparkline.initialized = true; + } + Connections { function onValuesChanged(): void { sparkline.targetMax = Math.max(NetworkUsage.downloadBuffer.maximum, NetworkUsage.uploadBuffer.maximum, 1024); diff --git a/Modules/Resources/Content.qml b/Modules/Resources/Content.qml index c9f8df8..f18867f 100644 --- a/Modules/Resources/Content.qml +++ b/Modules/Resources/Content.qml @@ -9,6 +9,8 @@ import qs.Config Item { id: root + required property Wrapper wrapper + implicitHeight: content.implicitHeight + Appearance.padding.normal * 2 implicitWidth: content.implicitWidth @@ -98,6 +100,7 @@ Item { active: Config.dashboard.performance.showNetwork sourceComponent: NetworkCard { + wrapper: root.wrapper } } } diff --git a/Modules/Resources/Wrapper.qml b/Modules/Resources/Wrapper.qml index af73e35..7c196e6 100644 --- a/Modules/Resources/Wrapper.qml +++ b/Modules/Resources/Wrapper.qml @@ -34,6 +34,7 @@ Item { anchors.centerIn: parent sourceComponent: Content { + wrapper: root } } } diff --git a/Plugins/ZShell/Internal/sparklineitem.cpp b/Plugins/ZShell/Internal/sparklineitem.cpp index d61592f..830926f 100644 --- a/Plugins/ZShell/Internal/sparklineitem.cpp +++ b/Plugins/ZShell/Internal/sparklineitem.cpp @@ -1,5 +1,6 @@ #include "sparklineitem.hpp" +#include #include #include #include @@ -33,19 +34,45 @@ void SparklineItem::drawLine(QPainter* painter, CircularBuffer* buffer, const QC const qreal w = width(); const qreal h = height(); const int len = buffer->count(); + if (len < 2 || m_maxValue <= 0.0) + return; + const qreal stepX = w / static_cast(m_historyLength - 1); const qreal startX = w - (len - 1) * stepX - stepX * m_slideProgress + stepX; - // Build line path - QPainterPath linePath; - linePath.moveTo(startX, h - (buffer->at(0) / m_maxValue) * h); - for (int i = 1; i < len; ++i) { + const qreal strokePad = qCeil(m_lineWidth / 2); + const qreal curvePad = 3.0; + const qreal topPad = strokePad + curvePad; + const qreal bottomPad = strokePad; + const qreal plotTop = topPad; + const qreal plotBottom = h - bottomPad; + const qreal fillBottom = h; + const qreal plotH = qMax(1.0, plotBottom - plotTop); + + QVector points; + points.reserve(len); + + for (int i = 0; i < len; ++i) { const qreal x = startX + i * stepX; - const qreal y = h - (buffer->at(i) / m_maxValue) * h; - linePath.lineTo(x, y); + const qreal value = qBound(0.0, buffer->at(i), m_maxValue); + const qreal y = plotTop + (1.0 - (value / m_maxValue)) * plotH; + points.append(QPointF(x, y)); + } + + QPainterPath linePath; + linePath.moveTo(points[0]); + + for (int i = 0; i < points.size() - 1; ++i) { + const QPointF& p0 = points[i]; + const QPointF& p1 = points[i + 1]; + + const qreal ctrlX = (p0.x() + p1.x()) * 0.5; + const QPointF c1(ctrlX, p0.y()); + const QPointF c2(ctrlX, p1.y()); + + linePath.cubicTo(c1, c2, p1); } - // Stroke the line QPen pen(color, m_lineWidth); pen.setCapStyle(Qt::RoundCap); pen.setJoinStyle(Qt::RoundJoin); @@ -53,10 +80,9 @@ void SparklineItem::drawLine(QPainter* painter, CircularBuffer* buffer, const QC painter->setBrush(Qt::NoBrush); painter->drawPath(linePath); - // Fill under the line QPainterPath fillPath = linePath; - fillPath.lineTo(startX + (len - 1) * stepX, h); - fillPath.lineTo(startX, h); + fillPath.lineTo(startX + (len - 1) * stepX, fillBottom); + fillPath.lineTo(startX, fillBottom); fillPath.closeSubpath(); QColor fillColor = color;