diff --git a/quickshell/Modules/DankDash/DashMetrics.qml b/quickshell/Modules/DankDash/DashMetrics.qml index 583bc627a..d26325f89 100644 --- a/quickshell/Modules/DankDash/DashMetrics.qml +++ b/quickshell/Modules/DankDash/DashMetrics.qml @@ -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) diff --git a/quickshell/Modules/DankDash/DashRegistry.qml b/quickshell/Modules/DankDash/DashRegistry.qml index 5ab6d0f2d..2e17d5e37 100644 --- a/quickshell/Modules/DankDash/DashRegistry.qml +++ b/quickshell/Modules/DankDash/DashRegistry.qml @@ -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()] } ] diff --git a/quickshell/Modules/DankDash/Overview/BatteryCard.qml b/quickshell/Modules/DankDash/Overview/BatteryCard.qml index e28fc03a1..07fa1adae 100644 --- a/quickshell/Modules/DankDash/Overview/BatteryCard.qml +++ b/quickshell/Modules/DankDash/Overview/BatteryCard.qml @@ -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 } diff --git a/quickshell/Modules/DankDash/Overview/CpuCard.qml b/quickshell/Modules/DankDash/Overview/CpuCard.qml index bc0478c79..f9af6c264 100644 --- a/quickshell/Modules/DankDash/Overview/CpuCard.qml +++ b/quickshell/Modules/DankDash/Overview/CpuCard.qml @@ -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 } diff --git a/quickshell/Modules/DankDash/Overview/DashEditControls.qml b/quickshell/Modules/DankDash/Overview/DashEditControls.qml index 972116173..3fff1a12e 100644 --- a/quickshell/Modules/DankDash/Overview/DashEditControls.qml +++ b/quickshell/Modules/DankDash/Overview/DashEditControls.qml @@ -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 diff --git a/quickshell/Modules/DankDash/Overview/DiskCard.qml b/quickshell/Modules/DankDash/Overview/DiskCard.qml index a8c0a3c8d..d60094857 100644 --- a/quickshell/Modules/DankDash/Overview/DiskCard.qml +++ b/quickshell/Modules/DankDash/Overview/DiskCard.qml @@ -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 } diff --git a/quickshell/Modules/DankDash/Overview/MemoryCard.qml b/quickshell/Modules/DankDash/Overview/MemoryCard.qml index 2724ebd99..7912d0036 100644 --- a/quickshell/Modules/DankDash/Overview/MemoryCard.qml +++ b/quickshell/Modules/DankDash/Overview/MemoryCard.qml @@ -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 } diff --git a/quickshell/Modules/DankDash/Overview/MetricCard.qml b/quickshell/Modules/DankDash/Overview/MetricCard.qml index e03edfa72..88c800602 100644 --- a/quickshell/Modules/DankDash/Overview/MetricCard.qml +++ b/quickshell/Modules/DankDash/Overview/MetricCard.qml @@ -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 diff --git a/quickshell/Modules/DankDash/Overview/NetworkCard.qml b/quickshell/Modules/DankDash/Overview/NetworkCard.qml index 01f55839f..36e1ada00 100644 --- a/quickshell/Modules/DankDash/Overview/NetworkCard.qml +++ b/quickshell/Modules/DankDash/Overview/NetworkCard.qml @@ -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 } diff --git a/quickshell/Modules/DankDash/Weather/WeatherForecastChart.qml b/quickshell/Modules/DankDash/Weather/WeatherForecastChart.qml index eea290e44..e187ffdd0 100644 --- a/quickshell/Modules/DankDash/Weather/WeatherForecastChart.qml +++ b/quickshell/Modules/DankDash/Weather/WeatherForecastChart.qml @@ -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 diff --git a/quickshell/Modules/DankDash/Weather/WeatherForecastWidget.qml b/quickshell/Modules/DankDash/Weather/WeatherForecastWidget.qml index fb2aae195..d15652b96 100644 --- a/quickshell/Modules/DankDash/Weather/WeatherForecastWidget.qml +++ b/quickshell/Modules/DankDash/Weather/WeatherForecastWidget.qml @@ -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) diff --git a/quickshell/Services/DgopService.qml b/quickshell/Services/DgopService.qml index 524b9fa56..726f35064 100644 --- a/quickshell/Services/DgopService.qml +++ b/quickshell/Services/DgopService.qml @@ -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) {