212 lines
5.7 KiB
QML
212 lines
5.7 KiB
QML
pragma ComponentBehavior: Bound
|
|
|
|
import QtQuick
|
|
import QtQuick.Layouts
|
|
|
|
import Quickshell
|
|
import Quickshell.Services.UPower
|
|
|
|
Item {
|
|
id: root
|
|
|
|
readonly property var battery: UPower.displayDevice
|
|
readonly property bool charging: !UPower.onBattery
|
|
|
|
implicitHeight: label.implicitHeight
|
|
implicitWidth: label.implicitWidth
|
|
|
|
function fmtTime(seconds: real): string {
|
|
if (!seconds || seconds <= 0)
|
|
return "\u2014";
|
|
const h = Math.floor(seconds / 3600);
|
|
const m = Math.floor((seconds % 3600) / 60);
|
|
return h > 0 ? `${h}h ${m}m` : `${m}m`;
|
|
}
|
|
|
|
function batteryGlyph(): string {
|
|
if (!root.battery)
|
|
return "\u{F0091}";
|
|
const percent = Math.round(root.battery.percentage * 100);
|
|
if (root.charging)
|
|
return "\u{F0084}";
|
|
if (percent > 80)
|
|
return "\u{F0079}";
|
|
if (percent > 60)
|
|
return "\u{F0080}";
|
|
if (percent > 40)
|
|
return "\u{F007F}";
|
|
if (percent > 20)
|
|
return "\u{F007E}";
|
|
return "\u{F007A}";
|
|
}
|
|
|
|
function stateText(s: int): string {
|
|
switch (s) {
|
|
case UPowerDeviceState.Charging:
|
|
return "Charging";
|
|
case UPowerDeviceState.Discharging:
|
|
return "Discharging";
|
|
case UPowerDeviceState.Empty:
|
|
return "Empty";
|
|
case UPowerDeviceState.FullyCharged:
|
|
return "Fully charged";
|
|
case UPowerDeviceState.PendingCharge:
|
|
return "Pending charge";
|
|
case UPowerDeviceState.PendingDischarge:
|
|
return "Pending discharge";
|
|
default:
|
|
return "Unknown";
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
id: mousearea
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
|
|
Text {
|
|
id: label
|
|
anchors.centerIn: parent
|
|
font.family: "JetBrainsMono Nerd Font"
|
|
color: "#cdd6f4"
|
|
text: {
|
|
if (!root.battery)
|
|
return "No Battery";
|
|
return root.batteryGlyph() + " " + Math.round(root.battery.percentage * 100) + "%";
|
|
}
|
|
}
|
|
}
|
|
|
|
PopupWindow {
|
|
id: popup
|
|
|
|
visible: mousearea.containsMouse && root.battery
|
|
|
|
anchor {
|
|
item: label
|
|
edges: Edges.Bottom
|
|
rect {
|
|
y: 30
|
|
}
|
|
}
|
|
|
|
color: "transparent"
|
|
implicitWidth: 270
|
|
implicitHeight: card.height
|
|
|
|
Rectangle {
|
|
id: card
|
|
|
|
width: 270
|
|
height: col.implicitHeight + 24
|
|
radius: 16
|
|
color: "#f21e1e2e"
|
|
border.color: "#45475a"
|
|
border.width: 1
|
|
|
|
ColumnLayout {
|
|
id: col
|
|
|
|
anchors {
|
|
left: parent.left
|
|
right: parent.right
|
|
top: parent.top
|
|
margins: 12
|
|
}
|
|
|
|
spacing: 8
|
|
|
|
RowLayout {
|
|
Layout.fillWidth: true
|
|
spacing: 12
|
|
|
|
Text {
|
|
font.family: "JetBrainsMono Nerd Font"
|
|
font.pixelSize: 30
|
|
color: root.charging ? "#a6e3a1" : "#89b4fa"
|
|
text: root.batteryGlyph()
|
|
}
|
|
|
|
ColumnLayout {
|
|
Layout.fillWidth: true
|
|
spacing: 0
|
|
|
|
Text {
|
|
color: "#cdd6f4"
|
|
font.pixelSize: 22
|
|
font.bold: true
|
|
text: root.battery ? Math.round(root.battery.percentage * 100) + "%" : "\u2014"
|
|
}
|
|
|
|
Text {
|
|
color: root.charging ? "#a6e3a1" : "#a6adc8"
|
|
font.pixelSize: 12
|
|
text: root.battery ? root.stateText(root.battery.state) : ""
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
Layout.fillWidth: true
|
|
implicitHeight: 1
|
|
color: "#313244"
|
|
}
|
|
|
|
InfoRow {
|
|
label: "Power draw"
|
|
value: root.battery ? Math.abs(root.battery.changeRate).toFixed(1) + " W" : "\u2014"
|
|
}
|
|
|
|
InfoRow {
|
|
visible: root.charging
|
|
label: "Time to full"
|
|
value: root.battery ? root.fmtTime(root.battery.timeToFull) : "\u2014"
|
|
}
|
|
|
|
InfoRow {
|
|
visible: !root.charging
|
|
label: "Time to empty"
|
|
value: root.battery ? root.fmtTime(root.battery.timeToEmpty) : "\u2014"
|
|
}
|
|
|
|
InfoRow {
|
|
label: "Energy"
|
|
value: root.battery ? root.battery.energy.toFixed(1) + " / " + root.battery.energyCapacity.toFixed(1) + " Wh" : "\u2014"
|
|
}
|
|
|
|
InfoRow {
|
|
visible: root.battery && root.battery.healthSupported
|
|
label: "Health"
|
|
value: root.battery ? Math.round(root.battery.healthPercentage) + "%" : "\u2014"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
component InfoRow: RowLayout {
|
|
id: infoRow
|
|
|
|
property string label: ""
|
|
property string value: ""
|
|
|
|
Layout.fillWidth: true
|
|
spacing: 8
|
|
|
|
Text {
|
|
color: "#a6adc8"
|
|
font.pixelSize: 12
|
|
text: infoRow.label
|
|
}
|
|
|
|
Item {
|
|
Layout.fillWidth: true
|
|
}
|
|
|
|
Text {
|
|
color: "#cdd6f4"
|
|
font.pixelSize: 12
|
|
text: infoRow.value
|
|
}
|
|
}
|
|
}
|