feat: dashboard performance panel
This commit is contained in:
parent
b6a34cbc47
commit
ea573554d4
4 changed files with 323 additions and 7 deletions
|
|
@ -21,5 +21,6 @@ Singleton {
|
||||||
readonly property int weatherWidth: 250
|
readonly property int weatherWidth: 250
|
||||||
readonly property int mediaCoverArtSize: 150
|
readonly property int mediaCoverArtSize: 150
|
||||||
readonly property int mediaVisualiserSize: 80
|
readonly property int mediaVisualiserSize: 80
|
||||||
|
readonly property int resourceSize: 200
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,18 +54,21 @@ Item {
|
||||||
radius: Appearance.rounding.normal
|
radius: Appearance.rounding.normal
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
Dash {
|
Dash {}
|
||||||
clip: true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ClippingWrapperRectangle {
|
ClippingWrapperRectangle {
|
||||||
radius: Appearance.rounding.normal
|
radius: Appearance.rounding.normal
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
Media {
|
Media {}
|
||||||
clip: true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClippingWrapperRectangle {
|
||||||
|
radius: Appearance.rounding.normal
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
Performance {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
230
modules/dashboard/Performance.qml
Normal file
230
modules/dashboard/Performance.qml
Normal file
|
|
@ -0,0 +1,230 @@
|
||||||
|
import "root:/widgets"
|
||||||
|
import "root:/services"
|
||||||
|
import "root:/config"
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
spacing: Appearance.spacing.large * 3
|
||||||
|
padding: Appearance.padding.large
|
||||||
|
leftPadding: padding * 2
|
||||||
|
rightPadding: padding * 3
|
||||||
|
|
||||||
|
Resource {
|
||||||
|
value1: Math.min(1, SystemUsage.gpuTemp / 90)
|
||||||
|
value2: SystemUsage.gpuPerc
|
||||||
|
|
||||||
|
label1: `${Math.ceil(SystemUsage.gpuTemp)}°C`
|
||||||
|
label2: `${Math.round(SystemUsage.gpuPerc * 100)}%`
|
||||||
|
|
||||||
|
sublabel1: "GPU temp"
|
||||||
|
sublabel2: "Usage"
|
||||||
|
}
|
||||||
|
|
||||||
|
Resource {
|
||||||
|
primary: true
|
||||||
|
|
||||||
|
value1: Math.min(1, SystemUsage.cpuTemp / 90)
|
||||||
|
value2: SystemUsage.cpuPerc
|
||||||
|
|
||||||
|
label1: `${Math.ceil(SystemUsage.cpuTemp)}°C`
|
||||||
|
label2: `${Math.round(SystemUsage.cpuPerc * 100)}%`
|
||||||
|
|
||||||
|
sublabel1: "CPU temp"
|
||||||
|
sublabel2: "Usage"
|
||||||
|
}
|
||||||
|
|
||||||
|
Resource {
|
||||||
|
value1: SystemUsage.memPerc
|
||||||
|
value2: SystemUsage.storagePerc
|
||||||
|
|
||||||
|
label1: {
|
||||||
|
const fmt = SystemUsage.formatKib(SystemUsage.memUsed);
|
||||||
|
return `${+fmt.value.toFixed(1)}${fmt.unit}`;
|
||||||
|
}
|
||||||
|
label2: {
|
||||||
|
const fmt = SystemUsage.formatKib(SystemUsage.storageUsed);
|
||||||
|
return `${Math.floor(fmt.value)}${fmt.unit}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
sublabel1: "Memory"
|
||||||
|
sublabel2: "Storage"
|
||||||
|
}
|
||||||
|
|
||||||
|
component Resource: Item {
|
||||||
|
id: res
|
||||||
|
|
||||||
|
required property real value1
|
||||||
|
required property real value2
|
||||||
|
required property string sublabel1
|
||||||
|
required property string sublabel2
|
||||||
|
required property string label1
|
||||||
|
required property string label2
|
||||||
|
|
||||||
|
property bool primary
|
||||||
|
readonly property real primaryMult: primary ? 1.2 : 1
|
||||||
|
|
||||||
|
readonly property real thickness: DashboardConfig.sizes.resourceProgessThickness * primaryMult
|
||||||
|
|
||||||
|
property color fg1: Colours.palette.m3primary
|
||||||
|
property color fg2: Colours.palette.m3secondary
|
||||||
|
property color bg1: Colours.palette.m3primaryContainer
|
||||||
|
property color bg2: Colours.palette.m3secondaryContainer
|
||||||
|
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
implicitWidth: DashboardConfig.sizes.resourceSize * primaryMult
|
||||||
|
implicitHeight: DashboardConfig.sizes.resourceSize * primaryMult
|
||||||
|
|
||||||
|
onValue1Changed: canvas.requestPaint()
|
||||||
|
onValue2Changed: canvas.requestPaint()
|
||||||
|
onFg1Changed: canvas.requestPaint()
|
||||||
|
onFg2Changed: canvas.requestPaint()
|
||||||
|
onBg1Changed: canvas.requestPaint()
|
||||||
|
onBg2Changed: canvas.requestPaint()
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
text: res.label1
|
||||||
|
font.pointSize: Appearance.font.size.extraLarge * res.primaryMult
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
text: res.sublabel1
|
||||||
|
color: Colours.palette.m3onSurfaceVariant
|
||||||
|
font.pointSize: Appearance.font.size.smaller * res.primaryMult
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.horizontalCenter: parent.right
|
||||||
|
anchors.top: parent.verticalCenter
|
||||||
|
anchors.horizontalCenterOffset: -res.thickness / 2
|
||||||
|
anchors.topMargin: res.thickness / 2 + Appearance.spacing.small
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
text: res.label2
|
||||||
|
font.pointSize: Appearance.font.size.smaller * res.primaryMult
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
text: res.sublabel2
|
||||||
|
color: Colours.palette.m3onSurfaceVariant
|
||||||
|
font.pointSize: Appearance.font.size.small * res.primaryMult
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Canvas {
|
||||||
|
id: canvas
|
||||||
|
|
||||||
|
readonly property real centerX: width / 2
|
||||||
|
readonly property real centerY: height / 2
|
||||||
|
|
||||||
|
readonly property real arc1Start: degToRad(45)
|
||||||
|
readonly property real arc1End: degToRad(220)
|
||||||
|
readonly property real arc2Start: degToRad(230)
|
||||||
|
readonly property real arc2End: degToRad(360)
|
||||||
|
|
||||||
|
function degToRad(deg: int): real {
|
||||||
|
return deg * Math.PI / 180;
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
onPaint: {
|
||||||
|
const ctx = getContext("2d");
|
||||||
|
ctx.reset();
|
||||||
|
|
||||||
|
ctx.lineWidth = res.thickness;
|
||||||
|
ctx.lineCap = "round";
|
||||||
|
|
||||||
|
const radius = (Math.min(width, height) - ctx.lineWidth) / 2;
|
||||||
|
const cx = centerX;
|
||||||
|
const cy = centerY;
|
||||||
|
const a1s = arc1Start;
|
||||||
|
const a1e = arc1End;
|
||||||
|
const a2s = arc2Start;
|
||||||
|
const a2e = arc2End;
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(cx, cy, radius, a1s, a1e, false);
|
||||||
|
ctx.strokeStyle = res.bg1;
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(cx, cy, radius, a1s, (a1e - a1s) * res.value1 + a1s, false);
|
||||||
|
ctx.strokeStyle = res.fg1;
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(cx, cy, radius, a2s, a2e, false);
|
||||||
|
ctx.strokeStyle = res.bg2;
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(cx, cy, radius, a2s, (a2e - a2s) * res.value2 + a2s, false);
|
||||||
|
ctx.strokeStyle = res.fg2;
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on value1 {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Appearance.anim.durations.normal
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.standard
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on value2 {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Appearance.anim.durations.normal
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.standard
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on fg1 {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Appearance.anim.durations.normal
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.standard
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on fg2 {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Appearance.anim.durations.normal
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.standard
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on bg1 {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Appearance.anim.durations.normal
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.standard
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on bg2 {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Appearance.anim.durations.normal
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.anim.curves.standard
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,9 @@ Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property real cpuPerc
|
property real cpuPerc
|
||||||
|
property real cpuTemp
|
||||||
|
property real gpuPerc
|
||||||
|
property real gpuTemp
|
||||||
property int memUsed
|
property int memUsed
|
||||||
property int memTotal
|
property int memTotal
|
||||||
readonly property real memPerc: memTotal > 0 ? memUsed / memTotal : 0
|
readonly property real memPerc: memTotal > 0 ? memUsed / memTotal : 0
|
||||||
|
|
@ -18,14 +21,41 @@ Singleton {
|
||||||
property int lastCpuIdle
|
property int lastCpuIdle
|
||||||
property int lastCpuTotal
|
property int lastCpuTotal
|
||||||
|
|
||||||
|
function formatKib(kib: int): var {
|
||||||
|
const mib = 1024;
|
||||||
|
const gib = 1024 ** 2;
|
||||||
|
const tib = 1024 ** 3;
|
||||||
|
|
||||||
|
if (kib >= tib)
|
||||||
|
return {
|
||||||
|
value: kib / tib,
|
||||||
|
unit: "TiB"
|
||||||
|
};
|
||||||
|
if (kib >= gib)
|
||||||
|
return {
|
||||||
|
value: kib / gib,
|
||||||
|
unit: "GiB"
|
||||||
|
};
|
||||||
|
if (kib >= mib)
|
||||||
|
return {
|
||||||
|
value: kib / mib,
|
||||||
|
unit: "MiB"
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
value: kib,
|
||||||
|
unit: "KiB"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
running: true
|
running: true
|
||||||
interval: 1000
|
interval: 3000
|
||||||
repeat: true
|
repeat: true
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
stat.reload();
|
stat.reload();
|
||||||
meminfo.reload();
|
meminfo.reload();
|
||||||
storage.running = true;
|
storage.running = true;
|
||||||
|
cpuTemp.running = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,4 +111,56 @@ Singleton {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: cpuTemp
|
||||||
|
|
||||||
|
running: true
|
||||||
|
command: ["fish", "-c", "cat /sys/class/thermal/thermal_zone*/temp | string join ' '"]
|
||||||
|
stdout: SplitParser {
|
||||||
|
onRead: data => {
|
||||||
|
const temps = data.trim().split(" ");
|
||||||
|
const sum = temps.reduce((acc, d) => acc + parseInt(d, 10), 0);
|
||||||
|
root.cpuTemp = sum / temps.length / 1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: gpuUsage
|
||||||
|
|
||||||
|
running: true
|
||||||
|
command: ["sh", "-c", "cat /sys/class/drm/card*/device/gpu_busy_percent"]
|
||||||
|
stdout: SplitParser {
|
||||||
|
splitMarker: ""
|
||||||
|
onRead: data => root.gpuPerc = data.trim().split("\n").reduce((acc, d) => acc + parseInt(d, 10), 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: gpuTemp
|
||||||
|
|
||||||
|
running: true
|
||||||
|
command: ["sh", "-c", "sensors | jq -nRc '[inputs]'"]
|
||||||
|
stdout: SplitParser {
|
||||||
|
readonly property var tempTest: new RegExp("^temp[0-9]+:")
|
||||||
|
|
||||||
|
onRead: data => {
|
||||||
|
let eligible = false;
|
||||||
|
let sum = 0;
|
||||||
|
let count = 0;
|
||||||
|
for (const line of JSON.parse(data)) {
|
||||||
|
if (line === "Adapter: PCI Adapter")
|
||||||
|
eligible = true;
|
||||||
|
else if (line === "")
|
||||||
|
eligible = false;
|
||||||
|
else if (eligible && (line.startsWith("GPU core:") || tempTest.test(line))) {
|
||||||
|
sum += parseFloat(line).split(" ")[1];
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
root.gpuTemp = count > 0 ? sum / count : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue