Krolyxon
Commit 071f97f

Branches

Refs →

aurora.configquickshellauroraSysPage.qml

188 lines · 7.0 KB · QML

1import QtQuick
2import QtQuick.Layouts
3import Quickshell.Services.UPower
4
5Flickable {
6 id: flick
7 clip: true
8 contentWidth: width
9 contentHeight: col.implicitHeight
10 boundsBehavior: Flickable.StopAtBounds
11
12 readonly property var bat: UPower.displayDevice
13 readonly property bool hasBat: bat !== null && bat.isPresent
14 readonly property real batPct: hasBat ? (bat.percentage > 1 ? bat.percentage / 100 : bat.percentage) : 0
15 readonly property bool charging: hasBat && bat.state === UPowerDeviceState.Charging
16
17 property string armedGpu: ""
18 Timer { id: disarm; interval: 3000; onTriggered: flick.armedGpu = "" }
19
20 function gpuClick(m) {
21 if (Gpu.mode === m || Gpu.busy) return
22 if (armedGpu !== m) { armedGpu = m; disarm.restart(); return }
23 armedGpu = ""
24 Gpu.set(m)
25 }
26 function stateText() {
27 if (!hasBat) return ""
28 switch (bat.state) {
29 case UPowerDeviceState.Charging: return "charging"
30 case UPowerDeviceState.Discharging: return "discharging"
31 case UPowerDeviceState.FullyCharged: return "full"
32 default: return "idle"
33 }
34 }
35 // GiB -> "812G" / "1.8T"
36 function size(v) { return v >= 1000 ? (v / 1024).toFixed(1) + "T" : (v >= 100 ? Math.round(v) : v.toFixed(1)) + "G" }
37
38 // pick up drives plugged in since the last poll
39 onVisibleChanged: if (visible) SysStats.refreshDisks()
40
41 ColumnLayout {
42 id: col
43 width: flick.width
44 spacing: 8
45
46 SectionLabel { text: "cpu" }
47 RowLayout {
48 Layout.fillWidth: true
49 spacing: 10
50 Text {
51 text: Theme.iChip + " " + Math.round(SysStats.cpu * 100) + "%"
52 Layout.preferredWidth: 80
53 color: Theme.fg
54 font.family: Theme.font
55 font.pixelSize: Theme.fontSize + 2
56 font.bold: true
57 }
58 Spark { Layout.fillWidth: true; values: SysStats.history }
59 }
60
61 SectionLabel { text: "memory & storage"; Layout.topMargin: 6 }
62 StatBar {
63 label: "memory"
64 frac: SysStats.memTotal > 0 ? SysStats.memUsed / SysStats.memTotal : 0
65 valueText: flick.size(SysStats.memUsed) + " / " + flick.size(SysStats.memTotal)
66 }
67 Repeater {
68 model: SysStats.disks
69 delegate: StatBar {
70 required property var modelData
71 label: modelData.label
72 frac: modelData.used / modelData.size
73 fill: frac > 0.9 ? Theme.err : Theme.accent
74 valueText: flick.size(modelData.used) + " / " + flick.size(modelData.size)
75 }
76 }
77
78 ColumnLayout {
79 visible: flick.hasBat
80 Layout.fillWidth: true
81 Layout.topMargin: 6
82 spacing: 8
83 SectionLabel { text: "battery" }
84 StatBar {
85 label: "charge"
86 frac: flick.batPct
87 fill: flick.batPct <= 0.15 && !flick.charging ? Theme.err : Theme.accent
88 valueText: Math.round(flick.batPct * 100) + "% " + flick.stateText()
89 }
90 Text {
91 Layout.fillWidth: true
92 wrapMode: Text.Wrap
93 color: Theme.dim
94 font.family: Theme.font
95 font.pixelSize: Theme.fontSize - 1
96 lineHeight: 1.3
97 text: {
98 if (!flick.hasBat) return ""
99 var lines = []
100 var t = flick.charging ? flick.bat.timeToFull : flick.bat.timeToEmpty
101 lines.push((flick.charging ? "time to full " : "time left ") + Theme.fmtTime(t))
102 if (flick.bat.changeRate !== undefined)
103 lines.push("power draw " + Math.abs(flick.bat.changeRate).toFixed(1) + " W")
104 if (flick.bat.healthSupported)
105 lines.push("health " + Math.round(flick.bat.healthPercentage) + "%")
106 return lines.join("\n")
107 }
108 }
109 }
110
111 ColumnLayout {
112 visible: PowerProfiles.hasPerformanceProfile !== undefined
113 Layout.fillWidth: true
114 Layout.topMargin: 6
115 spacing: 8
116 SectionLabel { text: "power profile" }
117 RowLayout {
118 Layout.fillWidth: true
119 spacing: 6
120 IconBtn {
121 Layout.fillWidth: true
122 icon: Theme.iLeaf
123 label: "saver"
124 active: PowerProfiles.profile === PowerProfile.PowerSaver
125 onClicked: PowerProfiles.profile = PowerProfile.PowerSaver
126 }
127 IconBtn {
128 Layout.fillWidth: true
129 icon: Theme.iBalance
130 label: "balanced"
131 active: PowerProfiles.profile === PowerProfile.Balanced
132 onClicked: PowerProfiles.profile = PowerProfile.Balanced
133 }
134 IconBtn {
135 Layout.fillWidth: true
136 visible: PowerProfiles.hasPerformanceProfile
137 icon: Theme.iSpeed
138 label: "perf"
139 active: PowerProfiles.profile === PowerProfile.Performance
140 onClicked: PowerProfiles.profile = PowerProfile.Performance
141 }
142 }
143 }
144
145 ColumnLayout {
146 visible: Gpu.mode !== ""
147 Layout.fillWidth: true
148 Layout.topMargin: 6
149 spacing: 8
150 SectionLabel { text: "graphics · envycontrol" }
151 RowLayout {
152 Layout.fillWidth: true
153 spacing: 6
154 Repeater {
155 model: ["integrated", "hybrid", "nvidia"]
156 delegate: IconBtn {
157 required property string modelData
158 Layout.fillWidth: true
159 icon: Theme.iGpu
160 label: flick.armedGpu === modelData ? "sure?" : modelData
161 active: Gpu.mode === modelData
162 opacity: Gpu.busy ? 0.5 : 1
163 onClicked: flick.gpuClick(modelData)
164 }
165 }
166 }
167 Text {
168 visible: Gpu.pending !== "" || Gpu.message !== "" || Gpu.busy
169 Layout.fillWidth: true
170 wrapMode: Text.Wrap
171 color: Gpu.message !== "" ? Theme.err : Theme.accent
172 font.family: Theme.font
173 font.pixelSize: Theme.fontSize - 2
174 text: Gpu.busy ? "switching…" : (Gpu.message !== "" ? Gpu.message : "queued: " + Gpu.pending + " · reboot to apply")
175 }
176 }
177
178 Text {
179 Layout.topMargin: 10
180 Layout.alignment: Qt.AlignRight
181 text: "up " + Theme.fmtTime(SysStats.uptime)
182 color: Theme.dim
183 font.family: Theme.font
184 font.pixelSize: Theme.fontSize - 2
185 }
186 Item { Layout.preferredHeight: 6 }
187 }
188}