dash: fix metric trends, edit bar focus rings, battery color option, forecast containers

fixes #3658
This commit is contained in:
bbedward
2026-10-02 18:23:50 -04:00
parent 1d789892f7
commit 850d7a6071
12 changed files with 86 additions and 67 deletions
@@ -147,7 +147,6 @@ Singleton {
readonly property real avatarSize: Theme.buttonHeightM
readonly property real avatarSizeHero: 72
readonly property int historyLength: 60
readonly property real tileTrendRatio: 0.45
readonly property real tileTrendFillAlpha: 0.1
readonly property real tileValueSizeCompact: Math.round((Theme.fontSizeXXLarge + Theme.fontSizeXLarge) / 2)
@@ -352,6 +352,15 @@ Singleton {
"value": "ring",
"text": I18n.tr("Ring", "noun, battery widget ring gauge style option")
}
]), choice("color", I18n.tr("Color"), "level", [
{
"value": "level",
"text": I18n.tr("Level", "battery settings: charge level indicator colors")
},
{
"value": "theme",
"text": I18n.tr("Theme", "battery settings: theme accent indicator colors")
}
]), toggle("health", I18n.tr("Show health"), false), toneOption()]
}
]
@@ -13,6 +13,7 @@ Card {
readonly property bool tall: height >= DashMetrics.gridRowUnit * 2
readonly property string levelText: Math.round(BatteryService.batteryLevel) + "%"
readonly property string meterStyle: options.style ?? "solid"
readonly property bool levelColors: options.color !== "theme"
readonly property string healthText: options.health === true && BatteryService.batteryHealth.endsWith("%") ? I18n.tr("Health") + " " + BatteryService.batteryHealth : ""
entryId: "battery"
@@ -30,7 +31,7 @@ Card {
anchors.verticalCenter: parent.verticalCenter
thickness: root.tall ? DashMetrics.batteryMeterThicknessHero : DashMetrics.batteryMeterThickness
meterStyle: root.meterStyle
levelColors: true
levelColors: root.levelColors
showNumber: false
}
@@ -81,7 +82,7 @@ Card {
anchors.horizontalCenter: parent.horizontalCenter
thickness: DashMetrics.batteryMeterThicknessCompact
meterStyle: root.meterStyle
levelColors: true
levelColors: root.levelColors
showNumber: false
}
@@ -13,8 +13,5 @@ MetricCard {
supportingText: DgopService.cpuModel
badgeText: options.temperature === true && DgopService.cpuTemperature > 0 ? Math.round(DgopService.cpuTemperature) + "°" : ""
showTrend: options.trend === true
trend: {
DgopService.cpuUsage;
return DgopService.cpuHistory.slice();
}
trend: DgopService.cpuHistory
}
@@ -16,6 +16,7 @@ Item {
property string pendingAction: ""
readonly property var actionButtons: [addButton, optionsButton, customButton, resetButton, clearButton, finishButton]
readonly property var focusTargets: actionButtons.filter(item => item.visible && item.enabled)
readonly property real focusPadding: Theme.focusRingOffset + Theme.focusRingWidth
signal addRequested(var anchor)
signal actionsRequested(var anchor)
@@ -37,10 +38,10 @@ Item {
return;
const point = target.mapToItem(viewport.contentItem, 0, 0);
if (vertical) {
viewport.contentY = Math.max(0, Math.min(point.y, Math.max(viewport.contentY, point.y + target.height - viewport.height)));
viewport.contentY = Math.max(0, Math.min(point.y - focusPadding, Math.max(viewport.contentY, point.y + target.height + focusPadding - viewport.height)));
return;
}
viewport.contentX = Math.max(0, Math.min(point.x, Math.max(viewport.contentX, point.x + target.width - viewport.width)));
viewport.contentX = Math.max(0, Math.min(point.x - focusPadding, Math.max(viewport.contentX, point.x + target.width + focusPadding - viewport.width)));
}
function cancelConfirmation() {
@@ -101,9 +102,10 @@ Item {
DankFlickable {
id: viewport
anchors.fill: parent
anchors.margins: -root.focusPadding
showScrollBar: false
contentWidth: root.vertical ? width : Math.max(width, actions.implicitWidth)
contentHeight: root.vertical ? actions.implicitHeight : height
contentWidth: root.vertical ? width : Math.max(width, actions.implicitWidth + root.focusPadding * 2)
contentHeight: root.vertical ? actions.implicitHeight + root.focusPadding * 2 : height
flickableDirection: root.vertical ? Flickable.VerticalFlick : Flickable.HorizontalFlick
wheelEnabled: root.vertical
clip: true
@@ -119,8 +121,8 @@ Item {
Grid {
id: actions
x: Math.max(0, (viewport.width - implicitWidth) / 2)
y: root.vertical ? 0 : Math.max(0, (viewport.height - implicitHeight) / 2)
x: Math.max(root.focusPadding, (viewport.width - implicitWidth) / 2)
y: root.vertical ? root.focusPadding : Math.max(root.focusPadding, (viewport.height - implicitHeight) / 2)
columns: root.vertical ? 1 : root.actionButtons.length
horizontalItemAlignment: Grid.AlignHCenter
verticalItemAlignment: Grid.AlignVCenter
@@ -26,12 +26,6 @@ MetricCard {
badgeIcon: "swap_vert"
trendMaximum: 0
showTrend: options.trend === true
trend: {
DgopService.diskReadRate;
return DgopService.diskHistory.read.slice();
}
secondaryTrend: {
DgopService.diskWriteRate;
return DgopService.diskHistory.write.slice();
}
trend: DgopService.diskHistory.read
secondaryTrend: DgopService.diskHistory.write
}
@@ -16,8 +16,5 @@ MetricCard {
badgeText: options.swap === true && DgopService.totalSwapKB > 0 ? Math.round(DgopService.usedSwapKB / DgopService.totalSwapKB * 100) + "%" : ""
badgeIcon: "swap_horiz"
showTrend: options.trend === true
trend: {
DgopService.memoryUsage;
return DgopService.memoryHistory.slice();
}
trend: DgopService.memoryHistory
}
@@ -86,17 +86,14 @@ Card {
anchors.left: root.wide ? valueText.right : parent.left
anchors.leftMargin: root.wide ? Theme.spacingM : -root.pad
anchors.right: parent.right
anchors.rightMargin: -root.pad
anchors.top: root.wide ? undefined : (narrowBadge.visible ? narrowBadge.bottom : header.bottom)
anchors.topMargin: Theme.spacingS
anchors.bottom: root.wide ? parent.bottom : valueText.top
anchors.bottomMargin: root.wide ? -root.pad : Theme.spacingXS
height: root.height * DashMetrics.tileTrendRatio
anchors.rightMargin: root.wide ? 0 : -root.pad
y: root.wide ? parent.height + root.pad - height : (narrowBadge.visible ? narrowBadge.y + narrowBadge.height : header.height) + Theme.spacingS
height: root.wide ? root.height * DashMetrics.tileTrendRatio : Math.max(0, valueText.y - Theme.spacingXS - y)
visible: root.trendVisible
values: root.trend
secondaryValues: root.secondaryTrend
maximum: root.trendMaximum
historyLength: DashMetrics.historyLength
insetBottom: root.wide ? root.pad : lineWidth
lineColor: root.accentColor
secondaryLineColor: root.tinted ? root.mutedColor : Theme.tertiary
lineWidth: Theme.outlineWidthFocused
@@ -15,12 +15,6 @@ MetricCard {
badgeIcon: "upload"
trendMaximum: 0
showTrend: options.trend === true
trend: {
DgopService.networkRxRate;
return DgopService.networkHistory.rx.slice();
}
secondaryTrend: {
DgopService.networkTxRate;
return DgopService.networkHistory.tx.slice();
}
trend: DgopService.networkHistory.rx
secondaryTrend: DgopService.networkHistory.tx
}
@@ -6,13 +6,9 @@ import qs.Services
import qs.Widgets
import qs.Modules.DankDash
Rectangle {
Item {
id: root
radius: Theme.cornerRadiusXL
color: DashMetrics.cardColor
border.width: Theme.layerOutlineWidth
border.color: Theme.outlineMedium
LayoutMirroring.enabled: false
LayoutMirroring.childrenInherit: true
@@ -6,7 +6,7 @@ import qs.Services
import qs.Widgets
import qs.Modules.DankDash
Column {
Rectangle {
id: root
property bool daily: false
@@ -19,7 +19,10 @@ Column {
readonly property int maxStart: Math.max(0, forecasts.length - visibleCount)
readonly property int start: Math.max(0, Math.min(maxStart, startIndex))
spacing: Theme.spacingS
radius: Theme.cornerRadiusXL
color: DashMetrics.cardColor
border.width: Theme.layerOutlineWidth
border.color: Theme.outlineMedium
function step(delta) {
const next = Math.max(0, Math.min(maxStart, start + delta));
@@ -30,24 +33,46 @@ Column {
}
Item {
width: parent.width
id: header
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: Theme.spacingM
height: Theme.buttonHeightS
StyledText {
Row {
id: title
anchors.left: parent.left
anchors.right: actions.left
anchors.rightMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
text: root.daily ? I18n.tr("Daily") : I18n.tr("Hourly")
font.pixelSize: Theme.fontSizeLarge
font.weight: Theme.fontWeightMedium
color: Theme.onSurface
elide: Text.ElideRight
spacing: Theme.spacingS
DankIcon {
anchors.verticalCenter: parent.verticalCenter
name: root.daily ? "calendar_month" : "schedule"
size: Theme.iconSize
color: Theme.onSurface
}
StyledText {
anchors.verticalCenter: parent.verticalCenter
width: Math.max(0, title.width - Theme.iconSize - title.spacing)
text: root.daily ? I18n.tr("Daily") : I18n.tr("Hourly")
font.pixelSize: Theme.fontSizeLarge
font.weight: Theme.fontWeightMedium
color: Theme.onSurface
elide: Text.ElideRight
}
}
Row {
id: actions
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingXS
DankActionButton {
@@ -76,8 +101,10 @@ Column {
}
Loader {
width: parent.width
height: Math.max(0, root.height - y)
anchors.left: parent.left
anchors.right: parent.right
anchors.top: header.bottom
anchors.bottom: parent.bottom
active: root.live
sourceComponent: root.chartMode ? chart : cards
}
@@ -98,6 +125,10 @@ Column {
Row {
id: cardRow
anchors.fill: parent
anchors.topMargin: Theme.spacingS
anchors.leftMargin: Theme.spacingM
anchors.rightMargin: Theme.spacingM
anchors.bottomMargin: Theme.spacingM
spacing: Theme.spacingS
Repeater {
model: root.forecasts.slice(root.start, root.start + root.visibleCount)
+13 -11
View File
@@ -395,7 +395,7 @@ Singleton {
cpuCores = cpu.count || 1;
cpuModel = cpu.model || "";
perCoreCpuUsage = cpu.coreUsage || [];
addToHistory(cpuHistory, cpuUsage);
cpuHistory = appendHistory(cpuHistory, cpuUsage);
if (cpu.cursor) {
cpuCursor = cpu.cursor;
@@ -425,7 +425,7 @@ Singleton {
totalSwapKB = mem.swaptotal || 0;
usedSwapKB = (mem.swaptotal || 0) - (mem.swapfree || 0);
addToHistory(memoryHistory, memoryUsage);
memoryHistory = appendHistory(memoryHistory, memoryUsage);
}
if (hasModule("network") && data.network && Array.isArray(data.network)) {
@@ -444,8 +444,10 @@ Singleton {
const txDiff = totalTx - lastNetworkStats.tx;
networkRxRate = Math.max(0, rxDiff / timeDiff);
networkTxRate = Math.max(0, txDiff / timeDiff);
addToHistory(networkHistory.rx, networkRxRate / 1024);
addToHistory(networkHistory.tx, networkTxRate / 1024);
networkHistory = {
rx: appendHistory(networkHistory.rx, networkRxRate / 1024),
tx: appendHistory(networkHistory.tx, networkTxRate / 1024)
};
}
lastNetworkStats = {
"time": sampleTime,
@@ -470,8 +472,10 @@ Singleton {
const writeDiff = totalWrite - lastDiskStats.write;
diskReadRate = Math.max(0, readDiff / timeDiff);
diskWriteRate = Math.max(0, writeDiff / timeDiff);
addToHistory(diskHistory.read, diskReadRate / (1024 * 1024));
addToHistory(diskHistory.write, diskWriteRate / (1024 * 1024));
diskHistory = {
read: appendHistory(diskHistory.read, diskReadRate / (1024 * 1024)),
write: appendHistory(diskHistory.write, diskWriteRate / (1024 * 1024))
};
}
lastDiskStats = {
"time": sampleTime,
@@ -570,11 +574,9 @@ Singleton {
statsUpdated();
}
function addToHistory(array, value) {
array.push(value);
if (array.length > historySize) {
array.splice(0, array.length - historySize);
}
function appendHistory(history, value) {
const next = history.concat([value]);
return next.length > historySize ? next.slice(next.length - historySize) : next;
}
function formatSystemMemory(memoryKB) {