1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-06 05:25:41 -05:00

dgop: use dgop for uptime

This commit is contained in:
bbedward
2025-11-28 10:41:59 -05:00
parent d3030c3ec6
commit 94a1aebe2b
8 changed files with 355 additions and 403 deletions

View File

@@ -22,7 +22,6 @@ FloatingWindow {
return; return;
} }
visible = true; visible = true;
UserInfoService.getUptime();
} }
function hide() { function hide() {

View File

@@ -8,16 +8,18 @@ Rectangle {
property bool editMode: false property bool editMode: false
signal powerButtonClicked() signal powerButtonClicked
signal lockRequested() signal lockRequested
signal editModeToggled() signal editModeToggled
signal settingsButtonClicked() signal settingsButtonClicked
Component.onCompleted: DgopService.addRef("system")
Component.onDestruction: DgopService.removeRef("system")
implicitHeight: 70 implicitHeight: 70
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
Theme.outline.b, 0.08)
border.width: 0 border.width: 0
Row { Row {
@@ -34,12 +36,12 @@ Rectangle {
height: 60 height: 60
imageSource: { imageSource: {
if (PortalService.profileImage === "") if (PortalService.profileImage === "")
return "" return "";
if (PortalService.profileImage.startsWith("/")) if (PortalService.profileImage.startsWith("/"))
return "file://" + PortalService.profileImage return "file://" + PortalService.profileImage;
return PortalService.profileImage return PortalService.profileImage;
} }
fallbackIcon: "person" fallbackIcon: "person"
} }
@@ -49,14 +51,13 @@ Rectangle {
spacing: 2 spacing: 2
Typography { Typography {
text: UserInfoService.fullName text: UserInfoService.fullName || UserInfoService.username || "User"
|| UserInfoService.username || "User"
style: Typography.Style.Subtitle style: Typography.Style.Subtitle
color: Theme.surfaceText color: Theme.surfaceText
} }
Typography { Typography {
text: (UserInfoService.uptime || "Unknown") text: DgopService.uptime || "Unknown"
style: Typography.Style.Caption style: Typography.Style.Caption
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
} }
@@ -77,7 +78,7 @@ Rectangle {
iconColor: Theme.surfaceText iconColor: Theme.surfaceText
backgroundColor: "transparent" backgroundColor: "transparent"
onClicked: { onClicked: {
root.lockRequested() root.lockRequested();
} }
} }
@@ -97,8 +98,8 @@ Rectangle {
iconColor: Theme.surfaceText iconColor: Theme.surfaceText
backgroundColor: "transparent" backgroundColor: "transparent"
onClicked: { onClicked: {
root.settingsButtonClicked() root.settingsButtonClicked();
settingsModal.show() settingsModal.show();
} }
} }

View File

@@ -84,11 +84,8 @@ DankPopout {
if (shouldBeVisible) { if (shouldBeVisible) {
collapseAll(); collapseAll();
Qt.callLater(() => { Qt.callLater(() => {
if (NetworkService.activeService) { if (NetworkService.activeService)
NetworkService.activeService.autoRefreshEnabled = NetworkService.wifiEnabled; NetworkService.activeService.autoRefreshEnabled = NetworkService.wifiEnabled;
}
if (UserInfoService)
UserInfoService.getUptime();
}); });
} else { } else {
Qt.callLater(() => { Qt.callLater(() => {

View File

@@ -1,5 +1,4 @@
import QtQuick import QtQuick
import QtQuick.Effects
import qs.Common import qs.Common
import qs.Services import qs.Services
import qs.Widgets import qs.Widgets
@@ -7,6 +6,9 @@ import qs.Widgets
Card { Card {
id: root id: root
Component.onCompleted: DgopService.addRef("system")
Component.onDestruction: DgopService.removeRef("system")
Row { Row {
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: Theme.spacingM anchors.leftMargin: Theme.spacingM
@@ -21,12 +23,12 @@ Card {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
imageSource: { imageSource: {
if (PortalService.profileImage === "") if (PortalService.profileImage === "")
return "" return "";
if (PortalService.profileImage.startsWith("/")) if (PortalService.profileImage.startsWith("/"))
return "file://" + PortalService.profileImage return "file://" + PortalService.profileImage;
return PortalService.profileImage return PortalService.profileImage;
} }
fallbackIcon: "person" fallbackIcon: "person"
} }
@@ -56,12 +58,16 @@ Card {
StyledText { StyledText {
text: { text: {
if (CompositorService.isNiri) return "on niri" if (CompositorService.isNiri)
if (CompositorService.isHyprland) return "on Hyprland" return "on niri";
if (CompositorService.isHyprland)
return "on Hyprland";
// technically they might not be on mangowc, but its what we support in the docs // technically they might not be on mangowc, but its what we support in the docs
if (CompositorService.isDwl) return "on MangoWC" if (CompositorService.isDwl)
if (CompositorService.isSway) return "on Sway" return "on MangoWC";
return "" if (CompositorService.isSway)
return "on Sway";
return "";
} }
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.8) color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.8)
@@ -82,27 +88,10 @@ Card {
} }
StyledText { StyledText {
id: uptimeText text: DgopService.shortUptime || "up"
property real availableWidth: parent.parent.parent.parent.width - avatarContainer.width - Theme.spacingM * 3 - 16 - Theme.spacingS
property real longTextWidth: {
const fontSize = Math.round(Theme.fontSizeSmall || 12)
const testMetrics = Qt.createQmlObject('import QtQuick; TextMetrics { font.pixelSize: ' + fontSize + ' }', uptimeText)
testMetrics.text = UserInfoService.uptime || "up 1 hour, 23 minutes"
const result = testMetrics.width
testMetrics.destroy()
return result
}
// Just using truncated is always true initially idk
property bool shouldUseShort: longTextWidth > availableWidth
text: shouldUseShort ? UserInfoService.shortUptime : UserInfoService.uptime || "up 1h 23m"
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7) color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
elide: Text.ElideRight
width: availableWidth
wrapMode: Text.NoWrap
} }
} }
} }

View File

@@ -38,7 +38,7 @@ Item {
} }
WeatherService.addRef(); WeatherService.addRef();
UserInfoService.refreshUserInfo(); UserInfoService.getUserInfo();
if (CompositorService.isHyprland) { if (CompositorService.isHyprland) {
updateHyprlandLayout(); updateHyprlandLayout();

View File

@@ -1,5 +1,4 @@
import QtQuick import QtQuick
import QtQuick.Controls
import qs.Common import qs.Common
import qs.Services import qs.Services
import qs.Widgets import qs.Widgets
@@ -69,7 +68,7 @@ DankFlickable {
} }
StyledText { StyledText {
text: `${UserInfoService.uptime} Boot: ${DgopService.bootTime}` text: `${DgopService.uptime} Boot: ${DgopService.bootTime}`
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
font.family: SettingsData.monoFontFamily font.family: SettingsData.monoFontFamily
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
@@ -83,9 +82,7 @@ DankFlickable {
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6) color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
} }
} }
} }
Rectangle { Rectangle {
@@ -134,7 +131,6 @@ DankFlickable {
color: Theme.primary color: Theme.primary
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
StyledText { StyledText {
@@ -181,9 +177,7 @@ DankFlickable {
elide: Text.ElideRight elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
} }
} }
} }
Rectangle { Rectangle {
@@ -275,7 +269,6 @@ DankFlickable {
color: Theme.secondary color: Theme.secondary
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
StyledText { StyledText {
@@ -365,22 +358,16 @@ DankFlickable {
elide: Text.ElideRight elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
} }
} }
Behavior on color { Behavior on color {
ColorAnimation { ColorAnimation {
duration: Theme.shortDuration duration: Theme.shortDuration
} }
} }
} }
} }
} }
} }
Rectangle { Rectangle {
@@ -418,7 +405,6 @@ DankFlickable {
color: Theme.surfaceText color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
Column { Column {
@@ -495,7 +481,6 @@ DankFlickable {
elide: Text.ElideRight elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
} }
} }
Repeater { Repeater {
@@ -596,19 +581,11 @@ DankFlickable {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
} }
} }
} }
} }
} }
} }
} }
} }
} }

View File

@@ -1,5 +1,4 @@
pragma Singleton pragma Singleton
pragma ComponentBehavior: Bound pragma ComponentBehavior: Bound
import QtQuick import QtQuick
@@ -72,504 +71,547 @@ Singleton {
property string bootTime: "" property string bootTime: ""
property string motherboard: "" property string motherboard: ""
property string biosVersion: "" property string biosVersion: ""
property string uptime: ""
property string shortUptime: ""
property int historySize: 60 property int historySize: 60
property var cpuHistory: [] property var cpuHistory: []
property var memoryHistory: [] property var memoryHistory: []
property var networkHistory: ({ property var networkHistory: ({
"rx": [], "rx": [],
"tx": [] "tx": []
}) })
property var diskHistory: ({ property var diskHistory: ({
"read": [], "read": [],
"write": [] "write": []
}) })
function addRef(modules = null) { function addRef(modules = null) {
refCount++ refCount++;
let modulesChanged = false let modulesChanged = false;
if (modules) { if (modules) {
const modulesToAdd = Array.isArray(modules) ? modules : [modules] const modulesToAdd = Array.isArray(modules) ? modules : [modules];
for (const module of modulesToAdd) { for (const module of modulesToAdd) {
// Increment reference count for this module // Increment reference count for this module
const currentCount = moduleRefCounts[module] || 0 const currentCount = moduleRefCounts[module] || 0;
moduleRefCounts[module] = currentCount + 1 moduleRefCounts[module] = currentCount + 1;
console.log("Adding ref for module:", module, "count:", moduleRefCounts[module]) console.log("Adding ref for module:", module, "count:", moduleRefCounts[module]);
// Add to enabled modules if not already there // Add to enabled modules if not already there
if (enabledModules.indexOf(module) === -1) { if (enabledModules.indexOf(module) === -1) {
enabledModules.push(module) enabledModules.push(module);
modulesChanged = true modulesChanged = true;
} }
} }
} }
if (modulesChanged || refCount === 1) { if (modulesChanged || refCount === 1) {
enabledModules = enabledModules.slice() // Force property change enabledModules = enabledModules.slice(); // Force property change
moduleRefCounts = Object.assign({}, moduleRefCounts) // Force property change moduleRefCounts = Object.assign({}, moduleRefCounts); // Force property change
updateAllStats() updateAllStats();
} else if (gpuPciIds.length > 0 && refCount > 0) { } else if (gpuPciIds.length > 0 && refCount > 0) {
// If we have GPU PCI IDs and active modules, make sure to update // If we have GPU PCI IDs and active modules, make sure to update
// This handles the case where PCI IDs were loaded after modules were added // This handles the case where PCI IDs were loaded after modules were added
updateAllStats() updateAllStats();
} }
} }
function removeRef(modules = null) { function removeRef(modules = null) {
refCount = Math.max(0, refCount - 1) refCount = Math.max(0, refCount - 1);
let modulesChanged = false let modulesChanged = false;
if (modules) { if (modules) {
const modulesToRemove = Array.isArray(modules) ? modules : [modules] const modulesToRemove = Array.isArray(modules) ? modules : [modules];
for (const module of modulesToRemove) { for (const module of modulesToRemove) {
const currentCount = moduleRefCounts[module] || 0 const currentCount = moduleRefCounts[module] || 0;
if (currentCount > 1) { if (currentCount > 1) {
// Decrement reference count // Decrement reference count
moduleRefCounts[module] = currentCount - 1 moduleRefCounts[module] = currentCount - 1;
console.log("Removing ref for module:", module, "count:", moduleRefCounts[module]) console.log("Removing ref for module:", module, "count:", moduleRefCounts[module]);
} else if (currentCount === 1) { } else if (currentCount === 1) {
// Remove completely when count reaches 0 // Remove completely when count reaches 0
delete moduleRefCounts[module] delete moduleRefCounts[module];
const index = enabledModules.indexOf(module) const index = enabledModules.indexOf(module);
if (index > -1) { if (index > -1) {
enabledModules.splice(index, 1) enabledModules.splice(index, 1);
modulesChanged = true modulesChanged = true;
console.log("Disabling module:", module, "(no more refs)") console.log("Disabling module:", module, "(no more refs)");
} }
} }
} }
} }
if (modulesChanged) { if (modulesChanged) {
enabledModules = enabledModules.slice() // Force property change enabledModules = enabledModules.slice(); // Force property change
moduleRefCounts = Object.assign({}, moduleRefCounts) // Force property change moduleRefCounts = Object.assign({}, moduleRefCounts); // Force property change
// Clear cursor data when CPU or process modules are no longer active // Clear cursor data when CPU or process modules are no longer active
if (!enabledModules.includes("cpu")) { if (!enabledModules.includes("cpu")) {
cpuCursor = "" cpuCursor = "";
cpuSampleCount = 0 cpuSampleCount = 0;
} }
if (!enabledModules.includes("processes")) { if (!enabledModules.includes("processes")) {
procCursor = "" procCursor = "";
processSampleCount = 0 processSampleCount = 0;
} }
} }
} }
function setGpuPciIds(pciIds) { function setGpuPciIds(pciIds) {
gpuPciIds = Array.isArray(pciIds) ? pciIds : [] gpuPciIds = Array.isArray(pciIds) ? pciIds : [];
} }
function addGpuPciId(pciId) { function addGpuPciId(pciId) {
const currentCount = gpuPciIdRefCounts[pciId] || 0 const currentCount = gpuPciIdRefCounts[pciId] || 0;
gpuPciIdRefCounts[pciId] = currentCount + 1 gpuPciIdRefCounts[pciId] = currentCount + 1;
// Add to gpuPciIds array if not already there // Add to gpuPciIds array if not already there
if (!gpuPciIds.includes(pciId)) { if (!gpuPciIds.includes(pciId)) {
gpuPciIds = gpuPciIds.concat([pciId]) gpuPciIds = gpuPciIds.concat([pciId]);
} }
console.log("Adding GPU PCI ID ref:", pciId, "count:", gpuPciIdRefCounts[pciId]) console.log("Adding GPU PCI ID ref:", pciId, "count:", gpuPciIdRefCounts[pciId]);
// Force property change notification // Force property change notification
gpuPciIdRefCounts = Object.assign({}, gpuPciIdRefCounts) gpuPciIdRefCounts = Object.assign({}, gpuPciIdRefCounts);
} }
function removeGpuPciId(pciId) { function removeGpuPciId(pciId) {
const currentCount = gpuPciIdRefCounts[pciId] || 0 const currentCount = gpuPciIdRefCounts[pciId] || 0;
if (currentCount > 1) { if (currentCount > 1) {
// Decrement reference count // Decrement reference count
gpuPciIdRefCounts[pciId] = currentCount - 1 gpuPciIdRefCounts[pciId] = currentCount - 1;
console.log("Removing GPU PCI ID ref:", pciId, "count:", gpuPciIdRefCounts[pciId]) console.log("Removing GPU PCI ID ref:", pciId, "count:", gpuPciIdRefCounts[pciId]);
} else if (currentCount === 1) { } else if (currentCount === 1) {
// Remove completely when count reaches 0 // Remove completely when count reaches 0
delete gpuPciIdRefCounts[pciId] delete gpuPciIdRefCounts[pciId];
const index = gpuPciIds.indexOf(pciId) const index = gpuPciIds.indexOf(pciId);
if (index > -1) { if (index > -1) {
gpuPciIds = gpuPciIds.slice() gpuPciIds = gpuPciIds.slice();
gpuPciIds.splice(index, 1) gpuPciIds.splice(index, 1);
} }
// Clear temperature data for this GPU when no longer monitored // Clear temperature data for this GPU when no longer monitored
if (availableGpus && availableGpus.length > 0) { if (availableGpus && availableGpus.length > 0) {
const updatedGpus = availableGpus.slice() const updatedGpus = availableGpus.slice();
for (var i = 0; i < updatedGpus.length; i++) { for (var i = 0; i < updatedGpus.length; i++) {
if (updatedGpus[i].pciId === pciId) { if (updatedGpus[i].pciId === pciId) {
updatedGpus[i] = Object.assign({}, updatedGpus[i], { updatedGpus[i] = Object.assign({}, updatedGpus[i], {
"temperature": 0 "temperature": 0
}) });
} }
} }
availableGpus = updatedGpus availableGpus = updatedGpus;
} }
console.log("Removing GPU PCI ID completely:", pciId) console.log("Removing GPU PCI ID completely:", pciId);
} }
// Force property change notification // Force property change notification
gpuPciIdRefCounts = Object.assign({}, gpuPciIdRefCounts) gpuPciIdRefCounts = Object.assign({}, gpuPciIdRefCounts);
} }
function setProcessOptions(limit = 20, sort = "cpu", disableCpu = false) { function setProcessOptions(limit = 20, sort = "cpu", disableCpu = false) {
processLimit = limit processLimit = limit;
processSort = sort processSort = sort;
noCpu = disableCpu noCpu = disableCpu;
} }
function updateAllStats() { function updateAllStats() {
if (dgopAvailable && refCount > 0 && enabledModules.length > 0) { if (dgopAvailable && refCount > 0 && enabledModules.length > 0) {
isUpdating = true isUpdating = true;
dgopProcess.running = true dgopProcess.running = true;
} else { } else {
isUpdating = false isUpdating = false;
} }
} }
function initializeGpuMetadata() { function initializeGpuMetadata() {
if (!dgopAvailable) if (!dgopAvailable)
return return;
gpuInitProcess.running = true gpuInitProcess.running = true;
} }
function initializeSystemMetadata() { function initializeSystemMetadata() {
if (!dgopAvailable) if (!dgopAvailable)
return return;
systemInitProcess.running = true systemInitProcess.running = true;
} }
function buildDgopCommand() { function buildDgopCommand() {
const cmd = ["dgop", "meta", "--json"] const cmd = ["dgop", "meta", "--json"];
if (enabledModules.length === 0) { if (enabledModules.length === 0) {
// Don't run if no modules are needed // Don't run if no modules are needed
return [] return [];
} }
// Replace 'gpu' with 'gpu-temp' when we have PCI IDs to monitor // Replace 'gpu' with 'gpu-temp' when we have PCI IDs to monitor
const finalModules = [] const finalModules = [];
for (const module of enabledModules) { for (const module of enabledModules) {
if (module === "gpu" && gpuPciIds.length > 0) { if (module === "gpu" && gpuPciIds.length > 0) {
finalModules.push("gpu-temp") finalModules.push("gpu-temp");
} else if (module !== "gpu") { } else if (module !== "gpu") {
finalModules.push(module) finalModules.push(module);
} }
} }
// Add gpu-temp module automatically when we have PCI IDs to monitor // Add gpu-temp module automatically when we have PCI IDs to monitor
if (gpuPciIds.length > 0 && finalModules.indexOf("gpu-temp") === -1) { if (gpuPciIds.length > 0 && finalModules.indexOf("gpu-temp") === -1) {
finalModules.push("gpu-temp") finalModules.push("gpu-temp");
} }
if (enabledModules.indexOf("all") !== -1) { if (enabledModules.indexOf("all") !== -1) {
cmd.push("--modules", "all") cmd.push("--modules", "all");
} else if (finalModules.length > 0) { } else if (finalModules.length > 0) {
const moduleList = finalModules.join(",") const moduleList = finalModules.join(",");
cmd.push("--modules", moduleList) cmd.push("--modules", moduleList);
} else { } else {
return [] return [];
} }
// Add cursor data if available for accurate CPU percentages // Add cursor data if available for accurate CPU percentages
if ((enabledModules.includes("cpu") || enabledModules.includes("all")) && cpuCursor) { if ((enabledModules.includes("cpu") || enabledModules.includes("all")) && cpuCursor) {
cmd.push("--cpu-cursor", cpuCursor) cmd.push("--cpu-cursor", cpuCursor);
} }
if ((enabledModules.includes("processes") || enabledModules.includes("all")) && procCursor) { if ((enabledModules.includes("processes") || enabledModules.includes("all")) && procCursor) {
cmd.push("--proc-cursor", procCursor) cmd.push("--proc-cursor", procCursor);
} }
if (gpuPciIds.length > 0) { if (gpuPciIds.length > 0) {
cmd.push("--gpu-pci-ids", gpuPciIds.join(",")) cmd.push("--gpu-pci-ids", gpuPciIds.join(","));
} }
if (enabledModules.indexOf("processes") !== -1 || enabledModules.indexOf("all") !== -1) { if (enabledModules.indexOf("processes") !== -1 || enabledModules.indexOf("all") !== -1) {
cmd.push("--limit", "100") // Get more data for client sorting cmd.push("--limit", "100"); // Get more data for client sorting
cmd.push("--sort", "cpu") // Always get CPU sorted data cmd.push("--sort", "cpu"); // Always get CPU sorted data
if (noCpu) { if (noCpu) {
cmd.push("--no-cpu") cmd.push("--no-cpu");
} }
} }
return cmd return cmd;
} }
function parseData(data) { function parseData(data) {
if (data.cpu) { if (data.cpu) {
const cpu = data.cpu const cpu = data.cpu;
cpuSampleCount++ cpuSampleCount++;
cpuUsage = cpu.usage || 0 cpuUsage = cpu.usage || 0;
cpuFrequency = cpu.frequency || 0 cpuFrequency = cpu.frequency || 0;
cpuTemperature = cpu.temperature || 0 cpuTemperature = cpu.temperature || 0;
cpuCores = cpu.count || 1 cpuCores = cpu.count || 1;
cpuModel = cpu.model || "" cpuModel = cpu.model || "";
perCoreCpuUsage = cpu.coreUsage || [] perCoreCpuUsage = cpu.coreUsage || [];
addToHistory(cpuHistory, cpuUsage) addToHistory(cpuHistory, cpuUsage);
if (cpu.cursor) { if (cpu.cursor) {
cpuCursor = cpu.cursor cpuCursor = cpu.cursor;
} }
} }
if (data.memory) { if (data.memory) {
const mem = data.memory const mem = data.memory;
const totalKB = mem.total || 0 const totalKB = mem.total || 0;
const availableKB = mem.available || 0 const availableKB = mem.available || 0;
const freeKB = mem.free || 0 const freeKB = mem.free || 0;
totalMemoryMB = totalKB / 1024 totalMemoryMB = totalKB / 1024;
availableMemoryMB = availableKB / 1024 availableMemoryMB = availableKB / 1024;
freeMemoryMB = freeKB / 1024 freeMemoryMB = freeKB / 1024;
usedMemoryMB = totalMemoryMB - availableMemoryMB usedMemoryMB = totalMemoryMB - availableMemoryMB;
memoryUsage = totalKB > 0 ? ((totalKB - availableKB) / totalKB) * 100 : 0 memoryUsage = totalKB > 0 ? ((totalKB - availableKB) / totalKB) * 100 : 0;
totalMemoryKB = totalKB totalMemoryKB = totalKB;
usedMemoryKB = totalKB - availableKB usedMemoryKB = totalKB - availableKB;
totalSwapKB = mem.swaptotal || 0 totalSwapKB = mem.swaptotal || 0;
usedSwapKB = (mem.swaptotal || 0) - (mem.swapfree || 0) usedSwapKB = (mem.swaptotal || 0) - (mem.swapfree || 0);
addToHistory(memoryHistory, memoryUsage) addToHistory(memoryHistory, memoryUsage);
} }
if (data.network && Array.isArray(data.network)) { if (data.network && Array.isArray(data.network)) {
networkInterfaces = data.network networkInterfaces = data.network;
let totalRx = 0 let totalRx = 0;
let totalTx = 0 let totalTx = 0;
for (const iface of data.network) { for (const iface of data.network) {
totalRx += iface.rx || 0 totalRx += iface.rx || 0;
totalTx += iface.tx || 0 totalTx += iface.tx || 0;
} }
if (lastNetworkStats) { if (lastNetworkStats) {
const timeDiff = updateInterval / 1000 const timeDiff = updateInterval / 1000;
const rxDiff = totalRx - lastNetworkStats.rx const rxDiff = totalRx - lastNetworkStats.rx;
const txDiff = totalTx - lastNetworkStats.tx const txDiff = totalTx - lastNetworkStats.tx;
networkRxRate = Math.max(0, rxDiff / timeDiff) networkRxRate = Math.max(0, rxDiff / timeDiff);
networkTxRate = Math.max(0, txDiff / timeDiff) networkTxRate = Math.max(0, txDiff / timeDiff);
addToHistory(networkHistory.rx, networkRxRate / 1024) addToHistory(networkHistory.rx, networkRxRate / 1024);
addToHistory(networkHistory.tx, networkTxRate / 1024) addToHistory(networkHistory.tx, networkTxRate / 1024);
} }
lastNetworkStats = { lastNetworkStats = {
"rx": totalRx, "rx": totalRx,
"tx": totalTx "tx": totalTx
} };
} }
if (data.disk && Array.isArray(data.disk)) { if (data.disk && Array.isArray(data.disk)) {
diskDevices = data.disk diskDevices = data.disk;
let totalRead = 0 let totalRead = 0;
let totalWrite = 0 let totalWrite = 0;
for (const disk of data.disk) { for (const disk of data.disk) {
totalRead += (disk.read || 0) * 512 totalRead += (disk.read || 0) * 512;
totalWrite += (disk.write || 0) * 512 totalWrite += (disk.write || 0) * 512;
} }
if (lastDiskStats) { if (lastDiskStats) {
const timeDiff = updateInterval / 1000 const timeDiff = updateInterval / 1000;
const readDiff = totalRead - lastDiskStats.read const readDiff = totalRead - lastDiskStats.read;
const writeDiff = totalWrite - lastDiskStats.write const writeDiff = totalWrite - lastDiskStats.write;
diskReadRate = Math.max(0, readDiff / timeDiff) diskReadRate = Math.max(0, readDiff / timeDiff);
diskWriteRate = Math.max(0, writeDiff / timeDiff) diskWriteRate = Math.max(0, writeDiff / timeDiff);
addToHistory(diskHistory.read, diskReadRate / (1024 * 1024)) addToHistory(diskHistory.read, diskReadRate / (1024 * 1024));
addToHistory(diskHistory.write, diskWriteRate / (1024 * 1024)) addToHistory(diskHistory.write, diskWriteRate / (1024 * 1024));
} }
lastDiskStats = { lastDiskStats = {
"read": totalRead, "read": totalRead,
"write": totalWrite "write": totalWrite
} };
} }
if (data.diskmounts) { if (data.diskmounts) {
diskMounts = data.diskmounts || [] diskMounts = data.diskmounts || [];
} }
if (data.processes && Array.isArray(data.processes)) { if (data.processes && Array.isArray(data.processes)) {
const newProcesses = [] const newProcesses = [];
processSampleCount++ processSampleCount++;
for (const proc of data.processes) { for (const proc of data.processes) {
const cpuUsage = processSampleCount >= 2 ? (proc.cpu || 0) : 0 const cpuUsage = processSampleCount >= 2 ? (proc.cpu || 0) : 0;
newProcesses.push({ newProcesses.push({
"pid": proc.pid || 0, "pid": proc.pid || 0,
"ppid": proc.ppid || 0, "ppid": proc.ppid || 0,
"cpu": cpuUsage, "cpu": cpuUsage,
"memoryPercent": proc.memoryPercent || proc.pssPercent || 0, "memoryPercent": proc.memoryPercent || proc.pssPercent || 0,
"memoryKB": proc.memoryKB || proc.pssKB || 0, "memoryKB": proc.memoryKB || proc.pssKB || 0,
"command": proc.command || "", "command": proc.command || "",
"fullCommand": proc.fullCommand || "", "fullCommand": proc.fullCommand || "",
"displayName": (proc.command && proc.command.length > 15) ? proc.command.substring(0, 15) + "..." : (proc.command || "") "displayName": (proc.command && proc.command.length > 15) ? proc.command.substring(0, 15) + "..." : (proc.command || "")
}) });
} }
allProcesses = newProcesses allProcesses = newProcesses;
applySorting() applySorting();
if (data.cursor) { if (data.cursor) {
procCursor = data.cursor procCursor = data.cursor;
} }
} }
const gpuData = (data.gpu && data.gpu.gpus) || data.gpus const gpuData = (data.gpu && data.gpu.gpus) || data.gpus;
if (gpuData && Array.isArray(gpuData)) { if (gpuData && Array.isArray(gpuData)) {
// Check if this is temperature update data (has PCI IDs being monitored) // Check if this is temperature update data (has PCI IDs being monitored)
if (gpuPciIds.length > 0 && availableGpus && availableGpus.length > 0) { if (gpuPciIds.length > 0 && availableGpus && availableGpus.length > 0) {
// This is temperature data - merge with existing GPU metadata // This is temperature data - merge with existing GPU metadata
const updatedGpus = availableGpus.slice() const updatedGpus = availableGpus.slice();
for (var i = 0; i < updatedGpus.length; i++) { for (var i = 0; i < updatedGpus.length; i++) {
const existingGpu = updatedGpus[i] const existingGpu = updatedGpus[i];
const tempGpu = gpuData.find(g => g.pciId === existingGpu.pciId) const tempGpu = gpuData.find(g => g.pciId === existingGpu.pciId);
// Only update temperature if this GPU's PCI ID is being monitored // Only update temperature if this GPU's PCI ID is being monitored
if (tempGpu && gpuPciIds.includes(existingGpu.pciId)) { if (tempGpu && gpuPciIds.includes(existingGpu.pciId)) {
updatedGpus[i] = Object.assign({}, existingGpu, { updatedGpus[i] = Object.assign({}, existingGpu, {
"temperature": tempGpu.temperature || 0 "temperature": tempGpu.temperature || 0
}) });
} }
} }
availableGpus = updatedGpus availableGpus = updatedGpus;
} else { } else {
// This is initial GPU metadata - set the full list // This is initial GPU metadata - set the full list
const gpuList = [] const gpuList = [];
for (const gpu of gpuData) { for (const gpu of gpuData) {
let displayName = gpu.displayName || gpu.name || "Unknown GPU" let displayName = gpu.displayName || gpu.name || "Unknown GPU";
let fullName = gpu.fullName || gpu.name || "Unknown GPU" let fullName = gpu.fullName || gpu.name || "Unknown GPU";
gpuList.push({ gpuList.push({
"driver": gpu.driver || "", "driver": gpu.driver || "",
"vendor": gpu.vendor || "", "vendor": gpu.vendor || "",
"displayName": displayName, "displayName": displayName,
"fullName": fullName, "fullName": fullName,
"pciId": gpu.pciId || "", "pciId": gpu.pciId || "",
"temperature": gpu.temperature || 0 "temperature": gpu.temperature || 0
}) });
} }
availableGpus = gpuList availableGpus = gpuList;
} }
} }
if (data.system) { if (data.system) {
const sys = data.system const sys = data.system;
loadAverage = sys.loadavg || "" loadAverage = sys.loadavg || "";
processCount = sys.processes || 0 processCount = sys.processes || 0;
threadCount = sys.threads || 0 threadCount = sys.threads || 0;
bootTime = sys.boottime || "" bootTime = sys.boottime || "";
updateUptime();
} }
const hwData = data.hardware || (data.hostname || data.kernel || data.distro || data.arch) ? data : null const hwData = data.hardware || (data.hostname || data.kernel || data.distro || data.arch) ? data : null;
if (hwData) { if (hwData) {
hostname = hwData.hostname || "" hostname = hwData.hostname || "";
kernelVersion = hwData.kernel || "" kernelVersion = hwData.kernel || "";
distribution = hwData.distro || "" distribution = hwData.distro || "";
architecture = hwData.arch || "" architecture = hwData.arch || "";
motherboard = (hwData.bios && hwData.bios.motherboard) || "" motherboard = (hwData.bios && hwData.bios.motherboard) || "";
biosVersion = (hwData.bios && hwData.bios.version) || "" biosVersion = (hwData.bios && hwData.bios.version) || "";
} }
isUpdating = false isUpdating = false;
} }
function addToHistory(array, value) { function addToHistory(array, value) {
array.push(value) array.push(value);
if (array.length > historySize) { if (array.length > historySize) {
array.shift() array.shift();
} }
} }
function getProcessIcon(command) { function getProcessIcon(command) {
const cmd = command.toLowerCase() const cmd = command.toLowerCase();
if (cmd.includes("firefox") || cmd.includes("chrome") || cmd.includes("browser") || cmd.includes("chromium")) { if (cmd.includes("firefox") || cmd.includes("chrome") || cmd.includes("browser") || cmd.includes("chromium")) {
return "web" return "web";
} }
if (cmd.includes("code") || cmd.includes("editor") || cmd.includes("vim")) { if (cmd.includes("code") || cmd.includes("editor") || cmd.includes("vim")) {
return "code" return "code";
} }
if (cmd.includes("terminal") || cmd.includes("bash") || cmd.includes("zsh")) { if (cmd.includes("terminal") || cmd.includes("bash") || cmd.includes("zsh")) {
return "terminal" return "terminal";
} }
if (cmd.includes("music") || cmd.includes("audio") || cmd.includes("spotify")) { if (cmd.includes("music") || cmd.includes("audio") || cmd.includes("spotify")) {
return "music_note" return "music_note";
} }
if (cmd.includes("video") || cmd.includes("vlc") || cmd.includes("mpv")) { if (cmd.includes("video") || cmd.includes("vlc") || cmd.includes("mpv")) {
return "play_circle" return "play_circle";
} }
if (cmd.includes("systemd") || cmd.includes("elogind") || cmd.includes("kernel") || cmd.includes("kthread") || cmd.includes("kworker")) { if (cmd.includes("systemd") || cmd.includes("elogind") || cmd.includes("kernel") || cmd.includes("kthread") || cmd.includes("kworker")) {
return "settings" return "settings";
} }
return "memory" return "memory";
} }
function formatCpuUsage(cpu) { function formatCpuUsage(cpu) {
return (cpu || 0).toFixed(1) + "%" return (cpu || 0).toFixed(1) + "%";
} }
function formatMemoryUsage(memoryKB) { function formatMemoryUsage(memoryKB) {
const mem = memoryKB || 0 const mem = memoryKB || 0;
if (mem < 1024) { if (mem < 1024) {
return mem.toFixed(0) + " KB" return mem.toFixed(0) + " KB";
} else if (mem < 1024 * 1024) { } else if (mem < 1024 * 1024) {
return (mem / 1024).toFixed(1) + " MB" return (mem / 1024).toFixed(1) + " MB";
} else { } else {
return (mem / (1024 * 1024)).toFixed(1) + " GB" return (mem / (1024 * 1024)).toFixed(1) + " GB";
} }
} }
function formatSystemMemory(memoryKB) { function formatSystemMemory(memoryKB) {
const mem = memoryKB || 0 const mem = memoryKB || 0;
if (mem === 0) { if (mem === 0) {
return "--" return "--";
} }
if (mem < 1024 * 1024) { if (mem < 1024 * 1024) {
return (mem / 1024).toFixed(0) + " MB" return (mem / 1024).toFixed(0) + " MB";
} else { } else {
return (mem / (1024 * 1024)).toFixed(1) + " GB" return (mem / (1024 * 1024)).toFixed(1) + " GB";
} }
} }
function killProcess(pid) { function killProcess(pid) {
if (pid > 0) { if (pid > 0) {
Quickshell.execDetached("kill", [pid.toString()]) Quickshell.execDetached("kill", [pid.toString()]);
} }
} }
function updateUptime() {
if (!bootTime) {
uptime = "";
shortUptime = "";
return;
}
const bootDate = new Date(bootTime.replace(" ", "T"));
if (isNaN(bootDate.getTime())) {
uptime = "";
shortUptime = "";
return;
}
const now = new Date();
const seconds = Math.floor((now - bootDate) / 1000);
const days = Math.floor(seconds / 86400);
const hours = Math.floor((seconds % 86400) / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const parts = [];
if (days > 0)
parts.push(`${days} day${days === 1 ? "" : "s"}`);
if (hours > 0)
parts.push(`${hours} hour${hours === 1 ? "" : "s"}`);
if (minutes > 0)
parts.push(`${minutes} minute${minutes === 1 ? "" : "s"}`);
uptime = parts.length > 0 ? `up ${parts.join(", ")}` : `up ${seconds} seconds`;
var shortStr = "up";
if (days > 0)
shortStr += ` ${days}d`;
if (hours > 0)
shortStr += ` ${hours}h`;
if (minutes > 0)
shortStr += ` ${minutes}m`;
shortUptime = shortStr;
}
function setSortBy(newSortBy) { function setSortBy(newSortBy) {
if (newSortBy !== currentSort) { if (newSortBy !== currentSort) {
currentSort = newSortBy currentSort = newSortBy;
applySorting() applySorting();
} }
} }
function applySorting() { function applySorting() {
if (!allProcesses || allProcesses.length === 0) { if (!allProcesses || allProcesses.length === 0) {
return return;
} }
const sorted = allProcesses.slice() const sorted = allProcesses.slice();
sorted.sort((a, b) => { sorted.sort((a, b) => {
let valueA, valueB let valueA, valueB;
switch (currentSort) { switch (currentSort) {
case "cpu": case "cpu":
valueA = a.cpu || 0 valueA = a.cpu || 0;
valueB = b.cpu || 0 valueB = b.cpu || 0;
return valueB - valueA return valueB - valueA;
case "memory": case "memory":
valueA = a.memoryKB || 0 valueA = a.memoryKB || 0;
valueB = b.memoryKB || 0 valueB = b.memoryKB || 0;
return valueB - valueA return valueB - valueA;
case "name": case "name":
valueA = (a.command || "").toLowerCase() valueA = (a.command || "").toLowerCase();
valueB = (b.command || "").toLowerCase() valueB = (b.command || "").toLowerCase();
return valueA.localeCompare(valueB) return valueA.localeCompare(valueB);
case "pid": case "pid":
valueA = a.pid || 0 valueA = a.pid || 0;
valueB = b.pid || 0 valueB = b.pid || 0;
return valueA - valueB return valueA - valueB;
default: default:
return 0 return 0;
} }
}) });
processes = sorted.slice(0, processLimit) processes = sorted.slice(0, processLimit);
} }
Timer { Timer {
@@ -585,26 +627,26 @@ Singleton {
id: dgopProcess id: dgopProcess
command: root.buildDgopCommand() command: root.buildDgopCommand()
running: false running: false
onCommandChanged: { onCommandChanged:
//console.log("DgopService command:", JSON.stringify(command)) //console.log("DgopService command:", JSON.stringify(command))
} {}
onExited: exitCode => { onExited: exitCode => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("Dgop process failed with exit code:", exitCode) console.warn("Dgop process failed with exit code:", exitCode);
isUpdating = false isUpdating = false;
} }
} }
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: { onStreamFinished: {
if (text.trim()) { if (text.trim()) {
try { try {
const data = JSON.parse(text.trim()) const data = JSON.parse(text.trim());
parseData(data) parseData(data);
} catch (e) { } catch (e) {
console.warn("Failed to parse dgop JSON:", e) console.warn("Failed to parse dgop JSON:", e);
console.warn("Raw text was:", text.substring(0, 200)) console.warn("Raw text was:", text.substring(0, 200));
isUpdating = false isUpdating = false;
} }
} }
} }
@@ -617,17 +659,17 @@ Singleton {
running: false running: false
onExited: exitCode => { onExited: exitCode => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("GPU init process failed with exit code:", exitCode) console.warn("GPU init process failed with exit code:", exitCode);
} }
} }
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: { onStreamFinished: {
if (text.trim()) { if (text.trim()) {
try { try {
const data = JSON.parse(text.trim()) const data = JSON.parse(text.trim());
parseData(data) parseData(data);
} catch (e) { } catch (e) {
console.warn("Failed to parse GPU init JSON:", e) console.warn("Failed to parse GPU init JSON:", e);
} }
} }
} }
@@ -640,17 +682,17 @@ Singleton {
running: false running: false
onExited: exitCode => { onExited: exitCode => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("System init process failed with exit code:", exitCode) console.warn("System init process failed with exit code:", exitCode);
} }
} }
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: { onStreamFinished: {
if (text.trim()) { if (text.trim()) {
try { try {
const data = JSON.parse(text.trim()) const data = JSON.parse(text.trim());
parseData(data) parseData(data);
} catch (e) { } catch (e) {
console.warn("Failed to parse system init JSON:", e) console.warn("Failed to parse system init JSON:", e);
} }
} }
} }
@@ -662,20 +704,20 @@ Singleton {
command: ["which", "dgop"] command: ["which", "dgop"]
running: false running: false
onExited: exitCode => { onExited: exitCode => {
dgopAvailable = (exitCode === 0) dgopAvailable = (exitCode === 0);
if (dgopAvailable) { if (dgopAvailable) {
initializeGpuMetadata() initializeGpuMetadata();
initializeSystemMetadata() initializeSystemMetadata();
if (SessionData.enabledGpuPciIds && SessionData.enabledGpuPciIds.length > 0) { if (SessionData.enabledGpuPciIds && SessionData.enabledGpuPciIds.length > 0) {
for (const pciId of SessionData.enabledGpuPciIds) { for (const pciId of SessionData.enabledGpuPciIds) {
addGpuPciId(pciId) addGpuPciId(pciId);
} }
if (refCount > 0 && enabledModules.length > 0) { if (refCount > 0 && enabledModules.length > 0) {
updateAllStats() updateAllStats();
} }
} }
} else { } else {
console.warn("dgop is not installed or not in PATH") console.warn("dgop is not installed or not in PATH");
} }
} }
} }
@@ -686,33 +728,33 @@ Singleton {
running: false running: false
onExited: exitCode => { onExited: exitCode => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("Failed to read /etc/os-release") console.warn("Failed to read /etc/os-release");
} }
} }
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: { onStreamFinished: {
if (text.trim()) { if (text.trim()) {
try { try {
const lines = text.trim().split('\n') const lines = text.trim().split('\n');
let prettyName = "" let prettyName = "";
let name = "" let name = "";
for (const line of lines) { for (const line of lines) {
const trimmedLine = line.trim() const trimmedLine = line.trim();
if (trimmedLine.startsWith('PRETTY_NAME=')) { if (trimmedLine.startsWith('PRETTY_NAME=')) {
prettyName = trimmedLine.substring(12).replace(/^["']|["']$/g, '') prettyName = trimmedLine.substring(12).replace(/^["']|["']$/g, '');
} else if (trimmedLine.startsWith('NAME=')) { } else if (trimmedLine.startsWith('NAME=')) {
name = trimmedLine.substring(5).replace(/^["']|["']$/g, '') name = trimmedLine.substring(5).replace(/^["']|["']$/g, '');
} }
} }
// Prefer PRETTY_NAME, fallback to NAME // Prefer PRETTY_NAME, fallback to NAME
const distroName = prettyName || name || "Linux" const distroName = prettyName || name || "Linux";
distribution = distroName distribution = distroName;
console.info("Detected distribution:", distroName) console.info("Detected distribution:", distroName);
} catch (e) { } catch (e) {
console.warn("Failed to parse /etc/os-release:", e) console.warn("Failed to parse /etc/os-release:", e);
distribution = "Linux" distribution = "Linux";
} }
} }
} }
@@ -720,7 +762,7 @@ Singleton {
} }
Component.onCompleted: { Component.onCompleted: {
dgopCheckProcess.running = true dgopCheckProcess.running = true;
osReleaseProcess.running = true osReleaseProcess.running = true;
} }
} }

View File

@@ -1,5 +1,4 @@
pragma Singleton pragma Singleton
pragma ComponentBehavior: Bound pragma ComponentBehavior: Bound
import QtQuick import QtQuick
@@ -12,77 +11,25 @@ Singleton {
property string username: "" property string username: ""
property string fullName: "" property string fullName: ""
property string profilePicture: "" property string profilePicture: ""
property string uptime: ""
property string shortUptime: ""
property string hostname: "" property string hostname: ""
property bool profileAvailable: false property bool profileAvailable: false
function getUserInfo() { function getUserInfo() {
Proc.runCommand("userInfo", ["bash", "-c", "echo \"$USER|$(getent passwd $USER | cut -d: -f5 | cut -d, -f1)|$(hostname)\""], (output, exitCode) => { Proc.runCommand("userInfo", ["sh", "-c", "echo \"$USER|$(getent passwd $USER | cut -d: -f5 | cut -d, -f1)|$(hostname)\""], (output, exitCode) => {
if (exitCode !== 0) { if (exitCode !== 0) {
root.username = "User" root.username = "User";
root.fullName = "User" root.fullName = "User";
root.hostname = "System" root.hostname = "System";
return return;
} }
const parts = output.trim().split("|") const parts = output.trim().split("|");
if (parts.length >= 3) { if (parts.length >= 3) {
root.username = parts[0] || "" root.username = parts[0] || "";
root.fullName = parts[1] || parts[0] || "" root.fullName = parts[1] || parts[0] || "";
root.hostname = parts[2] || "" root.hostname = parts[2] || "";
} }
}, 0) }, 0);
} }
function getUptime() { Component.onCompleted: getUserInfo()
Proc.runCommand("uptime", ["cat", "/proc/uptime"], (output, exitCode) => {
if (exitCode !== 0) {
root.uptime = "Unknown"
return
}
const seconds = parseInt(output.split(" ")[0])
const days = Math.floor(seconds / 86400)
const hours = Math.floor((seconds % 86400) / 3600)
const minutes = Math.floor((seconds % 3600) / 60)
const parts = []
if (days > 0) {
parts.push(`${days} day${days === 1 ? "" : "s"}`)
}
if (hours > 0) {
parts.push(`${hours} hour${hours === 1 ? "" : "s"}`)
}
if (minutes > 0) {
parts.push(`${minutes} minute${minutes === 1 ? "" : "s"}`)
}
if (parts.length > 0) {
root.uptime = `up ${parts.join(", ")}`
} else {
root.uptime = `up ${seconds} seconds`
}
let shortUptime = "up"
if (days > 0) {
shortUptime += ` ${days}d`
}
if (hours > 0) {
shortUptime += ` ${hours}h`
}
if (minutes > 0) {
shortUptime += ` ${minutes}m`
}
root.shortUptime = shortUptime
}, 0)
}
function refreshUserInfo() {
getUserInfo()
getUptime()
}
Component.onCompleted: {
getUserInfo()
getUptime()
}
} }