Files
dms-gamebar/GameBarSystemWidget.qml
T
2026-09-21 16:50:56 +02:00

198 lines
6.8 KiB
QML

import QtQuick
import qs.Common
import qs.Services
import qs.Widgets
Item {
id: widget
readonly property var activeModules: ["system", "cpu", "memory", "network", "disk", "diskmounts"]
readonly property var rootMount: {
const mounts = DgopService.diskMounts || [];
return mounts.find(mount => mount.mount === "/") || mounts[0] || null;
}
readonly property real diskPercent: {
if (!rootMount || !rootMount.percent)
return 0;
return parseFloat(String(rootMount.percent).replace("%", "")) || 0;
}
function formatRate(bytesPerSecond) {
const value = bytesPerSecond || 0;
if (value < 1024)
return value.toFixed(0) + " B/s";
if (value < 1024 * 1024)
return (value / 1024).toFixed(0) + " K/s";
if (value < 1024 * 1024 * 1024)
return (value / (1024 * 1024)).toFixed(1) + " M/s";
return (value / (1024 * 1024 * 1024)).toFixed(1) + " G/s";
}
function formatGiB(megabytes) {
return ((megabytes || 0) / 1024).toFixed(1) + " GiB";
}
// Stats only get polled while this widget exists.
Component.onCompleted: DgopService.addRef(widget.activeModules)
Component.onDestruction: DgopService.removeRef(widget.activeModules)
component StatTile: Rectangle {
id: tile
property string icon: ""
property string label: ""
property string value: ""
property string detail: ""
property real fraction: 0
property color accent: Theme.primary
radius: Theme.cornerRadius
color: Theme.withAlpha(Theme.surfaceLight, Theme.popupTransparency)
border.color: Theme.outlineLight
border.width: Theme.layerOutlineWidth
DankIcon {
id: tileIcon
anchors.left: parent.left
anchors.leftMargin: Theme.spacingM
anchors.top: parent.top
anchors.topMargin: Theme.spacingM
name: tile.icon
size: Theme.iconSize - 6
color: tile.accent
}
StyledText {
anchors.left: tileIcon.right
anchors.leftMargin: Theme.spacingXS
anchors.verticalCenter: tileIcon.verticalCenter
text: tile.label
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
id: tileValue
anchors.right: parent.right
anchors.rightMargin: Theme.spacingM
anchors.verticalCenter: tileIcon.verticalCenter
text: tile.value
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
id: tileDetail
anchors.left: parent.left
anchors.leftMargin: Theme.spacingM
anchors.right: parent.right
anchors.rightMargin: Theme.spacingM
anchors.bottom: tileTrack.top
anchors.bottomMargin: Theme.spacingXS
text: tile.detail
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
elide: Text.ElideRight
}
Rectangle {
id: tileTrack
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.leftMargin: Theme.spacingM
anchors.rightMargin: Theme.spacingM
anchors.bottomMargin: Theme.spacingM
height: 5
radius: height / 2
color: Theme.withAlpha(Theme.outline, 0.4)
Rectangle {
width: parent.width * Math.max(0, Math.min(1, tile.fraction))
height: parent.height
radius: parent.radius
color: tile.accent
Behavior on width {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Easing.OutCubic
}
}
}
}
}
Grid {
anchors.fill: parent
columns: 2
rowSpacing: Theme.spacingS
columnSpacing: Theme.spacingS
readonly property real tileWidth: (width - columnSpacing) / 2
readonly property real tileHeight: (height - rowSpacing) / 2
StatTile {
width: parent.tileWidth
height: parent.tileHeight
icon: "memory"
label: "CPU"
value: Math.round(DgopService.cpuUsage || 0) + "%"
detail: DgopService.cpuTemperature > 0 ? DgopService.cpuTemperature.toFixed(0) + "°C" : (DgopService.cpuCores + " cores")
fraction: (DgopService.cpuUsage || 0) / 100
accent: DgopService.cpuUsage > 85 ? Theme.error : (DgopService.cpuUsage > 60 ? Theme.warning : Theme.primary)
}
StatTile {
width: parent.tileWidth
height: parent.tileHeight
icon: "developer_board"
label: "Memory"
value: Math.round(DgopService.memoryUsage || 0) + "%"
detail: widget.formatGiB(DgopService.usedMemoryMB) + " / " + widget.formatGiB(DgopService.totalMemoryMB)
fraction: (DgopService.memoryUsage || 0) / 100
accent: DgopService.memoryUsage > 85 ? Theme.error : (DgopService.memoryUsage > 60 ? Theme.warning : Theme.primary)
}
StatTile {
width: parent.tileWidth
height: parent.tileHeight
icon: "swap_vert"
label: "Network"
value: "↓ " + widget.formatRate(DgopService.networkRxRate)
detail: "↑ " + widget.formatRate(DgopService.networkTxRate)
// Scaled against 100 MiB/s so the bar stays readable on fast links.
fraction: Math.min(1, ((DgopService.networkRxRate || 0) + (DgopService.networkTxRate || 0)) / (100 * 1024 * 1024))
accent: Theme.primary
}
StatTile {
width: parent.tileWidth
height: parent.tileHeight
icon: "storage"
label: widget.rootMount ? widget.rootMount.mount : "Disk"
value: Math.round(widget.diskPercent) + "%"
detail: "R " + widget.formatRate(DgopService.diskReadRate) + " W " + widget.formatRate(DgopService.diskWriteRate)
fraction: widget.diskPercent / 100
accent: widget.diskPercent > 90 ? Theme.error : (widget.diskPercent > 75 ? Theme.warning : Theme.primary)
}
}
StyledText {
anchors.centerIn: parent
width: parent.width - Theme.spacingL * 2
text: "dgop is not available - install it to see system stats."
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
visible: !DgopService.dgopAvailable
}
}