feat: improve dash perf storage card
This commit is contained in:
parent
30878e3b51
commit
3ae676c040
5 changed files with 143 additions and 137 deletions
|
|
@ -19,14 +19,15 @@ Row {
|
||||||
property bool menuOnTop
|
property bool menuOnTop
|
||||||
property string fallbackIcon
|
property string fallbackIcon
|
||||||
property string fallbackText
|
property string fallbackText
|
||||||
|
property real minLeftWidth
|
||||||
|
|
||||||
property alias menuItems: menu.items
|
property alias menuItems: menu.items
|
||||||
property alias active: menu.active
|
property alias active: menu.active
|
||||||
property alias expanded: menu.expanded
|
property alias expanded: menu.expanded
|
||||||
property alias menu: menu
|
readonly property alias menu: menu
|
||||||
property alias iconLabel: iconLabel
|
readonly property alias iconLabel: iconLabel
|
||||||
property alias label: label
|
readonly property alias label: label
|
||||||
property alias stateLayer: stateLayer
|
readonly property alias stateLayer: stateLayer
|
||||||
|
|
||||||
property color colour: type == SplitButton.Filled ? Colours.palette.m3primary : Colours.palette.m3secondaryContainer
|
property color colour: type == SplitButton.Filled ? Colours.palette.m3primary : Colours.palette.m3secondaryContainer
|
||||||
property color textColour: type == SplitButton.Filled ? Colours.palette.m3onPrimary : Colours.palette.m3onSecondaryContainer
|
property color textColour: type == SplitButton.Filled ? Colours.palette.m3onPrimary : Colours.palette.m3onSecondaryContainer
|
||||||
|
|
@ -41,14 +42,14 @@ Row {
|
||||||
bottomRightRadius: Tokens.rounding.medium / 2
|
bottomRightRadius: Tokens.rounding.medium / 2
|
||||||
color: root.disabled ? root.disabledColour : root.colour
|
color: root.disabled ? root.disabledColour : root.colour
|
||||||
|
|
||||||
implicitWidth: textRow.implicitWidth + root.horizontalPadding * 2
|
implicitWidth: Math.max(root.minLeftWidth, textRow.implicitWidth + root.horizontalPadding * 2)
|
||||||
implicitHeight: expandBtn.implicitHeight
|
implicitHeight: expandBtn.implicitHeight
|
||||||
|
|
||||||
StateLayer {
|
StateLayer {
|
||||||
id: stateLayer
|
id: stateLayer
|
||||||
|
|
||||||
rect.topRightRadius: parent.topRightRadius
|
topRightRadius: parent.topRightRadius
|
||||||
rect.bottomRightRadius: parent.bottomRightRadius
|
bottomRightRadius: parent.bottomRightRadius
|
||||||
color: root.textColour
|
color: root.textColour
|
||||||
disabled: root.disabled
|
disabled: root.disabled
|
||||||
onClicked: root.active?.clicked()
|
onClicked: root.active?.clicked()
|
||||||
|
|
|
||||||
|
|
@ -125,10 +125,8 @@ Item {
|
||||||
visible: Config.dashboard.performance.showMemory
|
visible: Config.dashboard.performance.showMemory
|
||||||
}
|
}
|
||||||
|
|
||||||
StorageGaugeCard {
|
StorageCard {
|
||||||
Layout.minimumWidth: 250
|
Layout.fillHeight: true
|
||||||
Layout.preferredHeight: 220
|
|
||||||
Layout.fillWidth: !Config.dashboard.performance.showNetwork
|
|
||||||
visible: Config.dashboard.performance.showStorage
|
visible: Config.dashboard.performance.showStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -385,132 +383,6 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
component StorageGaugeCard: StyledRect {
|
|
||||||
id: storageGaugeCard
|
|
||||||
|
|
||||||
property int currentDiskIndex: 0
|
|
||||||
readonly property var currentDisk: SystemUsage.disks.length > 0 ? SystemUsage.disks[currentDiskIndex] : null
|
|
||||||
property int diskCount: 0
|
|
||||||
readonly property real arcStartAngle: 0.75 * Math.PI
|
|
||||||
readonly property real arcSweep: 1.5 * Math.PI
|
|
||||||
property real animatedPercentage: 0
|
|
||||||
property color accentColor: Colours.palette.m3secondary
|
|
||||||
|
|
||||||
color: Colours.tPalette.m3surfaceContainer
|
|
||||||
radius: Tokens.rounding.extraLarge
|
|
||||||
clip: true
|
|
||||||
Component.onCompleted: {
|
|
||||||
diskCount = SystemUsage.disks.length;
|
|
||||||
if (currentDisk)
|
|
||||||
animatedPercentage = currentDisk.perc;
|
|
||||||
}
|
|
||||||
onCurrentDiskChanged: {
|
|
||||||
if (currentDisk)
|
|
||||||
animatedPercentage = currentDisk.perc;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update diskCount and animatedPercentage when disks data changes
|
|
||||||
Connections {
|
|
||||||
function onDisksChanged() {
|
|
||||||
if (SystemUsage.disks.length !== storageGaugeCard.diskCount)
|
|
||||||
storageGaugeCard.diskCount = SystemUsage.disks.length;
|
|
||||||
|
|
||||||
// Update animated percentage when disk data refreshes
|
|
||||||
if (storageGaugeCard.currentDisk)
|
|
||||||
storageGaugeCard.animatedPercentage = storageGaugeCard.currentDisk.perc;
|
|
||||||
}
|
|
||||||
|
|
||||||
target: SystemUsage
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
onWheel: wheel => {
|
|
||||||
if (wheel.angleDelta.y > 0)
|
|
||||||
storageGaugeCard.currentDiskIndex = (storageGaugeCard.currentDiskIndex - 1 + storageGaugeCard.diskCount) % storageGaugeCard.diskCount;
|
|
||||||
else if (wheel.angleDelta.y < 0)
|
|
||||||
storageGaugeCard.currentDiskIndex = (storageGaugeCard.currentDiskIndex + 1) % storageGaugeCard.diskCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Tokens.padding.large
|
|
||||||
spacing: Tokens.spacing.medium
|
|
||||||
|
|
||||||
CardHeader {
|
|
||||||
icon: "hard_disk"
|
|
||||||
title: {
|
|
||||||
const base = qsTr("Storage");
|
|
||||||
if (!storageGaugeCard.currentDisk)
|
|
||||||
return base;
|
|
||||||
|
|
||||||
return `${base} - ${storageGaugeCard.currentDisk.mount}`;
|
|
||||||
}
|
|
||||||
accentColor: storageGaugeCard.accentColor
|
|
||||||
|
|
||||||
// Scroll hint icon
|
|
||||||
MaterialIcon {
|
|
||||||
text: "unfold_more"
|
|
||||||
color: Colours.palette.m3onSurfaceVariant
|
|
||||||
fontStyle: Tokens.font.icon.medium
|
|
||||||
visible: storageGaugeCard.diskCount > 1
|
|
||||||
opacity: 0.7
|
|
||||||
ToolTip.visible: hintHover.hovered
|
|
||||||
ToolTip.text: qsTr("Scroll to switch disks")
|
|
||||||
ToolTip.delay: 500
|
|
||||||
|
|
||||||
HoverHandler {
|
|
||||||
id: hintHover
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.fillHeight: true
|
|
||||||
|
|
||||||
ArcGauge {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: Math.min(parent.width, parent.height)
|
|
||||||
height: width
|
|
||||||
percentage: storageGaugeCard.animatedPercentage
|
|
||||||
accentColor: storageGaugeCard.accentColor
|
|
||||||
trackColor: Colours.layer(Colours.palette.m3surfaceContainerHigh, 2)
|
|
||||||
startAngle: storageGaugeCard.arcStartAngle
|
|
||||||
sweepAngle: storageGaugeCard.arcSweep
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
text: storageGaugeCard.currentDisk ? `${Math.round(storageGaugeCard.currentDisk.perc * 100)}%` : "—"
|
|
||||||
font: Tokens.font.body.builders.large.size(28).weight(Font.Medium).build()
|
|
||||||
color: storageGaugeCard.accentColor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
text: {
|
|
||||||
if (!storageGaugeCard.currentDisk)
|
|
||||||
return "—";
|
|
||||||
|
|
||||||
const usedFmt = SystemUsage.formatKib(storageGaugeCard.currentDisk.used);
|
|
||||||
const totalFmt = SystemUsage.formatKib(storageGaugeCard.currentDisk.total);
|
|
||||||
return `${usedFmt.value.toFixed(1)} / ${Math.floor(totalFmt.value)} ${totalFmt.unit}`;
|
|
||||||
}
|
|
||||||
font: Tokens.font.body.small
|
|
||||||
color: Colours.palette.m3onSurfaceVariant
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on animatedPercentage {
|
|
||||||
Anim {
|
|
||||||
type: Anim.StandardLarge
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
component NetworkCard: StyledRect {
|
component NetworkCard: StyledRect {
|
||||||
id: networkCard
|
id: networkCard
|
||||||
|
|
||||||
|
|
|
||||||
130
modules/dashboard/performance/StorageCard.qml
Normal file
130
modules/dashboard/performance/StorageCard.qml
Normal file
|
|
@ -0,0 +1,130 @@
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Caelestia.Config
|
||||||
|
import qs.components
|
||||||
|
import qs.components.controls
|
||||||
|
import qs.services
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property color accent: Colours.palette.m3secondary
|
||||||
|
readonly property real percentage: SystemUsage.primaryDisk?.perc ?? 0
|
||||||
|
|
||||||
|
color: Colours.tPalette.m3surfaceContainer
|
||||||
|
radius: Tokens.rounding.extraLarge
|
||||||
|
|
||||||
|
implicitWidth: layout.implicitWidth + layout.anchors.margins * 2
|
||||||
|
implicitHeight: layout.implicitHeight + Tokens.padding.large * 2
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: layout
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.margins: Tokens.padding.extraLarge
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: row
|
||||||
|
|
||||||
|
spacing: Tokens.spacing.large
|
||||||
|
|
||||||
|
CircularProgress {
|
||||||
|
fgColour: root.accent
|
||||||
|
value: root.percentage
|
||||||
|
implicitSize: usageColumn.implicitHeight + thickness + Tokens.padding.large * 2
|
||||||
|
startAngle: -225
|
||||||
|
sweepAngle: 270
|
||||||
|
|
||||||
|
Behavior on clampedVal {
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: usageColumn
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: "hard_drive"
|
||||||
|
color: root.accent
|
||||||
|
fontStyle: Tokens.font.icon.medium
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: Math.round(root.percentage * 100) + "%"
|
||||||
|
font: Tokens.font.title.builders.large.width(90).build()
|
||||||
|
color: root.accent
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: qsTr("Used")
|
||||||
|
font: Tokens.font.body.small
|
||||||
|
color: Colours.palette.m3onSurfaceVariant
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.minimumWidth: Tokens.sizes.dashboard.perfStorageTextWidth
|
||||||
|
spacing: Tokens.spacing.extraSmall
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: qsTr("Storage")
|
||||||
|
font: Tokens.font.title.medium
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: {
|
||||||
|
if (!SystemUsage.primaryDisk)
|
||||||
|
return qsTr("No disks detected");
|
||||||
|
|
||||||
|
const usedFmt = SystemUsage.formatKib(SystemUsage.primaryDisk.used);
|
||||||
|
const totalFmt = SystemUsage.formatKib(SystemUsage.primaryDisk.total);
|
||||||
|
return `${usedFmt.value.toFixed(1)} / ${Math.floor(totalFmt.value)} ${totalFmt.unit}`;
|
||||||
|
}
|
||||||
|
font: Tokens.font.body.large
|
||||||
|
color: root.accent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SplitButton {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
|
type: SplitButton.Tonal
|
||||||
|
disabled: !SystemUsage.disks.length
|
||||||
|
fallbackIcon: "storage"
|
||||||
|
fallbackText: qsTr("No disks")
|
||||||
|
menuOnTop: true
|
||||||
|
minLeftWidth: row.implicitWidth * 0.6
|
||||||
|
|
||||||
|
menuItems: disks.instances
|
||||||
|
active: menuItems.find(m => m.modelData === SystemUsage.primaryDisk) ?? menuItems[0] ?? null
|
||||||
|
menu.onItemSelected: item => SystemUsage.manualPrimaryDisk = (item as DiskItem).modelData
|
||||||
|
|
||||||
|
Variants {
|
||||||
|
id: disks
|
||||||
|
|
||||||
|
model: SystemUsage.disks
|
||||||
|
|
||||||
|
DiskItem {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component DiskItem: MenuItem {
|
||||||
|
required property var modelData
|
||||||
|
|
||||||
|
icon: modelData === SystemUsage.primaryDisk ? "check" : ""
|
||||||
|
text: modelData.mount
|
||||||
|
activeIcon: "storage"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -191,6 +191,7 @@ class DashboardTokens : public ConfigObject {
|
||||||
CONFIG_PROPERTY(int, mediaVisualiserSize, 80)
|
CONFIG_PROPERTY(int, mediaVisualiserSize, 80)
|
||||||
CONFIG_PROPERTY(int, perfHeroCardWidth, 400)
|
CONFIG_PROPERTY(int, perfHeroCardWidth, 400)
|
||||||
CONFIG_PROPERTY(int, perfUsageShapeSize, 100)
|
CONFIG_PROPERTY(int, perfUsageShapeSize, 100)
|
||||||
|
CONFIG_PROPERTY(int, perfStorageTextWidth, 160)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DashboardTokens(QObject* parent = nullptr)
|
explicit DashboardTokens(QObject* parent = nullptr)
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,8 @@ Singleton {
|
||||||
|
|
||||||
// Individual disks: Array of { mount, used, total, free, perc }
|
// Individual disks: Array of { mount, used, total, free, perc }
|
||||||
property var disks: []
|
property var disks: []
|
||||||
|
property var manualPrimaryDisk
|
||||||
|
readonly property var primaryDisk: manualPrimaryDisk ?? disks[0] ?? null
|
||||||
|
|
||||||
property real lastCpuIdle
|
property real lastCpuIdle
|
||||||
property real lastCpuTotal
|
property real lastCpuTotal
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue