feat: improve lock resource widget

This commit is contained in:
2 * r + 2 * t 2026-06-01 21:10:33 +10:00
parent 58d2232c4a
commit 9665613ef1
3 changed files with 189 additions and 68 deletions

View file

@ -0,0 +1,47 @@
import QtQuick
import QtQuick.Shapes
import qs.components
import qs.services
Shape {
id: root
property color color: Colours.palette.m3surfaceContainer
property int waves: 4
property real amplitude: 3
readonly property real waveHeight: amplitude * 2
preferredRendererType: Shape.CurveRenderer
asynchronous: true
ShapePath {
strokeWidth: 0
strokeColor: "transparent"
fillColor: root.color
PathSvg {
path: {
const w = root.width;
const h = root.height;
const a = root.amplitude;
const n = Math.max(1, root.waves);
const wl = w / n;
const half = wl / 2;
let d = `M 0,${a} `;
for (let i = 0; i < n; ++i) {
const x = i * wl;
d += `Q ${x + half / 2},${-a} ${x + half},${a} `;
d += `Q ${x + half + half / 2},${3 * a} ${x + wl},${a} `;
}
d += `L ${w},${h} L 0,${h} Z`;
return d;
}
}
Behavior on fillColor {
CAnim {}
}
}
}

View file

@ -44,17 +44,8 @@ RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
spacing: Tokens.spacing.medium spacing: Tokens.spacing.medium
StyledRect { Resources {
Layout.fillWidth: true Layout.fillWidth: true
implicitHeight: resources.implicitHeight
topRightRadius: Tokens.rounding.extraLarge
radius: Tokens.rounding.medium
color: Colours.tPalette.m3surfaceContainer
Resources {
id: resources
}
} }
StyledRect { StyledRect {

View file

@ -1,22 +1,26 @@
pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import M3Shapes
import Caelestia.Config import Caelestia.Config
import Caelestia.Services import Caelestia.Services
import qs.components import qs.components
import qs.components.controls import qs.components.effects
import qs.components.widgets
import qs.services import qs.services
GridLayout { StyledRect {
id: root id: root
anchors.left: parent.left readonly property real fontScale: {
anchors.right: parent.right const diff = width / 391 - 1; // 391 is the width at 1080 height screen
anchors.margins: Tokens.padding.large return 1 + Math.pow(Math.abs(diff), 0.8) * Math.sign(diff);
}
rowSpacing: Tokens.spacing.largeIncreased implicitHeight: layout.implicitHeight + layout.anchors.margins * 2
columnSpacing: Tokens.spacing.largeIncreased radius: Tokens.rounding.extraLarge
rows: 2 color: Colours.tPalette.m3surfaceContainer
columns: 2
ServiceRef { ServiceRef {
service: Cpu service: Cpu
@ -30,71 +34,150 @@ GridLayout {
service: Storage service: Storage
} }
Resource { RowLayout {
Layout.topMargin: Tokens.padding.large id: layout
icon: "memory"
value: Cpu.percentage anchors.fill: parent
colour: Colours.palette.m3primary anchors.margins: Tokens.padding.large
spacing: Tokens.spacing.large
Resource {
id: cpu
icon: "memory"
value: Math.round(Cpu.percentage * 100) + "%"
fillValue: Cpu.percentage
colour: Colours.palette.m3primary
shapeColour: Colours.palette.m3primaryContainer
fillColour: Qt.alpha(Colours.palette.m3secondary, 0.3)
shape: MaterialShape.Pentagon
MaterialShape {
x: cpu.mShape.pointAtAngle(45).x - implicitSize / 2 + Tokens.padding.medium
y: cpu.mShape.pointAtAngle(45).y - implicitSize / 2
shape: Cpu.temperature > 90 ? MaterialShape.SoftBurst : MaterialShape.Circle
color: Cpu.temperature > 90 ? Colours.palette.m3errorContainer : Colours.palette.m3secondaryContainer
implicitSize: {
const size = Math.round(tempLabel.implicitHeight * 2);
return size % 2 === 0 ? size : size + 1; // Ensure even size so center works properly
}
Behavior on color {
CAnim {}
}
StyledText {
id: tempLabel
anchors.centerIn: parent
anchors.verticalCenterOffset: Math.round(fontInfo.pointSize * 0.04)
text: {
const temp = Cpu.temperature;
const useF = GlobalConfig.services.useFahrenheitPerformance;
return `${Math.ceil(useF ? temp * 1.8 + 32 : temp)}°${useF ? "F" : "C"}`;
}
color: Cpu.temperature > 90 ? Colours.palette.m3onErrorContainer : Colours.palette.m3secondary
font: Tokens.font.title.builders.medium.scale(cpu.width / 112).width(50).build()
}
}
}
Resource {
icon: "memory_alt"
value: Math.round(Memory.percentage * 100) + "%"
fillValue: Memory.percentage
colour: Colours.palette.m3tertiary
shapeColour: Colours.palette.m3onTertiary
fillColour: Qt.alpha(Colours.palette.m3tertiary, 0.3)
shape: MaterialShape.Slanted
}
Resource {
icon: "hard_disk"
value: Math.round(Storage.percentage * 100) + "%"
fillValue: Storage.percentage
colour: Colours.palette.m3secondary
shapeColour: Colours.palette.m3secondaryContainer
fillColour: Qt.alpha(Colours.palette.m3secondary, 0.4)
shape: MaterialShape.Gem
}
} }
Resource { component Resource: Item {
Layout.topMargin: Tokens.padding.large
icon: "thermostat"
value: Math.min(1, Cpu.temperature / 90)
colour: Colours.palette.m3secondary
}
Resource {
Layout.bottomMargin: Tokens.padding.large
icon: "memory_alt"
value: Memory.percentage
colour: Colours.palette.m3secondary
}
Resource {
Layout.bottomMargin: Tokens.padding.large
icon: "hard_disk"
value: Storage.percentage
colour: Colours.palette.m3tertiary
}
component Resource: StyledRect {
id: res id: res
required property string icon required property string icon
required property real value required property string value
required property color colour required property color colour
required property color shapeColour
property color fillColour
property real fillValue: -1
property alias shape: shape.shape
readonly property alias mShape: shape
Layout.fillWidth: true Layout.fillWidth: true
implicitHeight: width implicitHeight: width
color: Colours.layer(Colours.palette.m3surfaceContainerHigh, 2) Behavior on shapeColour {
radius: Tokens.rounding.extraLarge CAnim {}
CircularProgress {
id: circ
anchors.fill: parent
value: res.value
padding: Tokens.padding.extraExtraLarge
fgColour: res.colour
bgColour: Colours.layer(Colours.palette.m3surfaceContainerHighest, 3)
strokeWidth: width < 200 ? Tokens.padding.small : Tokens.padding.medium
} }
MaterialIcon { MaterialShape {
id: icon id: shape
anchors.centerIn: parent implicitSize: res.width
text: res.icon color: Qt.alpha(res.shapeColour, 1)
color: res.colour opacity: res.shapeColour.a
fontStyle: Tokens.font.icon.size((circ.arcRadius * 0.7) || 1).weight(Font.DemiBold).build() layer.enabled: true
} }
Behavior on value { Loader {
Anim { id: fillLoader
type: Anim.StandardLarge
anchors.fill: shape
active: res.fillValue >= 0
asynchronous: true
layer.enabled: active
layer.effect: Mask {
maskSource: shape
} }
sourceComponent: Item {
WavyTopRect {
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
implicitHeight: shape.implicitSize * res.fillValue
color: res.fillColour
}
}
}
ColumnLayout {
anchors.centerIn: parent
spacing: -Tokens.spacing.extraSmall
MaterialIcon {
Layout.alignment: Qt.AlignHCenter
text: res.icon
color: Colours.palette.m3secondary
fontStyle: Tokens.font.icon.builders.medium.scale(root.fontScale).build()
}
StyledText {
Layout.alignment: Qt.AlignHCenter
text: res.value
color: res.colour
font: Tokens.font.headline.builders.large.scale(root.fontScale).width(50).build()
}
}
Behavior on fillValue {
Anim {}
} }
} }
} }