import QtQuick import Quickshell import Quickshell.Widgets import Quickshell.Services.UPower Item { id: root height: parent.height width: batteryIcon.width + 8 anchors.verticalCenter: parent.verticalCenter property var batteryDevice: Array.from(UPower.devices.values).find(dev => dev.isLaptopBattery) WrapperMouseArea { id: widgetMouseArea anchors.fill: parent hoverEnabled: true Item { anchors.fill: parent MaterialDesignIcon { id: batteryIcon implicitSize: 14 anchors.centerIn: parent icon: { if (!root.batteryDevice?.ready) return "battery-unknown"; if (root.batteryDevice.state == UPowerDeviceState.FullyCharged) return "power-plug-battery"; const perdec = 10 * Math.max(1, Math.ceil(root.batteryDevice.percentage * 10)); if (root.batteryDevice.state == UPowerDeviceState.Charging) return `battery-charging-${perdec}`; if (perdec == 100) return "battery"; return `battery-${perdec}`; } color: { if (!root.batteryDevice?.ready) return "#555"; if (root.batteryDevice.state != UPowerDeviceState.FullyCharged && root.batteryDevice.state != UPowerDeviceState.Charging && root.batteryDevice.timeToEmpty < 20 * 60) return "#f2201f"; if (root.batteryDevice.state != UPowerDeviceState.FullyCharged && root.batteryDevice.state != UPowerDeviceState.Charging && root.batteryDevice.timeToEmpty < 40 * 60) return "#f28a21"; if (root.batteryDevice.state != UPowerDeviceState.FullyCharged) return "#fff"; return "#555"; } } } } PopupWindow { id: tooltip property bool nextVisible: widgetMouseArea.containsMouse || tooltipMouseArea.containsMouse anchor { item: widgetMouseArea edges: Edges.Bottom | Edges.Left } visible: false onNextVisibleChanged: hangTimer.restart() Timer { id: hangTimer interval: 100 onTriggered: tooltip.visible = tooltip.nextVisible } implicitWidth: widgetTooltipText.contentWidth + 16 implicitHeight: widgetTooltipText.contentHeight + 16 color: "black" WrapperMouseArea { id: tooltipMouseArea hoverEnabled: true enabled: true anchors.centerIn: parent Text { id: widgetTooltipText font.pointSize: 10 font.family: "Fira Sans" color: "white" text: { const stateStr = UPowerDeviceState.toString(root.batteryDevice.state); var outStr = stateStr; if (root.batteryDevice.state != UPowerDeviceState.FullyCharged) outStr += ` ${Math.round(root.batteryDevice.percentage * 100)}%`; function formatTime(t) { var res = ""; for (const unit of [{ "s": "h", "v": 3600 }, { "s": "m", "v": 60 }, { "s": "s", "v": 1 }]) { if (t < unit.v) continue; res += Math.floor(t / unit.v) + unit.s; t %= unit.v; } return res; } if (root.batteryDevice.timeToEmpty != 0) { const tStr = formatTime(Math.floor(root.batteryDevice.timeToEmpty / 60) * 60); if (tStr) outStr += " " + tStr; } else if (root.batteryDevice.timeToFull != 0) { const tStr = formatTime(Math.ceil(root.batteryDevice.timeToFull / 60) * 60); if (tStr) outStr += " " + tStr; } return outStr; } } } } }