nosignal-shell/modules/bar/components/StatusIcons.qml
Dylan Myers 90c051cfa1
internal: fix battery charging logic for tray and lock (#751)
* Update StatusIcons.qml --- Fix battery chargiing logic

idk what the difference is in the return value of UPower.onBattery and UPower.displayDevice.state, but the former always returns false after unplugging my laptop. Changing this to the more specific displayDevice.state === 2 fixes this

* Fetch.qml --- Fix battery charging boolean logic

* Use enum value for UPowerDeviceState instead of index

* Use enum value for UPowerDeviceState instead of index

* Update Fetch.qml --- invert battery conditional logic
2025-10-06 19:51:42 +11:00

259 lines
8.1 KiB
QML

pragma ComponentBehavior: Bound
import qs.components
import qs.services
import qs.utils
import qs.config
import Quickshell
import Quickshell.Bluetooth
import Quickshell.Services.UPower
import QtQuick
import QtQuick.Layouts
StyledRect {
id: root
property color colour: Colours.palette.m3secondary
readonly property alias items: iconColumn
color: Colours.tPalette.m3surfaceContainer
radius: Appearance.rounding.full
clip: true
implicitWidth: Config.bar.sizes.innerWidth
implicitHeight: iconColumn.implicitHeight + Appearance.padding.normal * 2 - (Config.bar.status.showLockStatus && !Hypr.capsLock && !Hypr.numLock ? iconColumn.spacing : 0)
ColumnLayout {
id: iconColumn
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.bottomMargin: Appearance.padding.normal
spacing: Appearance.spacing.smaller / 2
// Lock keys status
WrappedLoader {
name: "lockstatus"
active: Config.bar.status.showLockStatus
sourceComponent: ColumnLayout {
spacing: 0
Item {
implicitWidth: capslockIcon.implicitWidth
implicitHeight: Hypr.capsLock ? capslockIcon.implicitHeight : 0
MaterialIcon {
id: capslockIcon
anchors.centerIn: parent
scale: Hypr.capsLock ? 1 : 0.5
opacity: Hypr.capsLock ? 1 : 0
text: "keyboard_capslock_badge"
color: root.colour
Behavior on opacity {
Anim {}
}
Behavior on scale {
Anim {}
}
}
Behavior on implicitHeight {
Anim {}
}
}
Item {
Layout.topMargin: Hypr.capsLock && Hypr.numLock ? iconColumn.spacing : 0
implicitWidth: numlockIcon.implicitWidth
implicitHeight: Hypr.numLock ? numlockIcon.implicitHeight : 0
MaterialIcon {
id: numlockIcon
anchors.centerIn: parent
scale: Hypr.numLock ? 1 : 0.5
opacity: Hypr.numLock ? 1 : 0
text: "looks_one"
color: root.colour
Behavior on opacity {
Anim {}
}
Behavior on scale {
Anim {}
}
}
Behavior on implicitHeight {
Anim {}
}
}
}
}
// Audio icon
WrappedLoader {
name: "audio"
active: Config.bar.status.showAudio
sourceComponent: MaterialIcon {
animate: true
text: Icons.getVolumeIcon(Audio.volume, Audio.muted)
color: root.colour
}
}
// Microphone icon
WrappedLoader {
name: "audio"
active: Config.bar.status.showMicrophone
sourceComponent: MaterialIcon {
animate: true
text: Icons.getMicVolumeIcon(Audio.sourceVolume, Audio.sourceMuted)
color: root.colour
}
}
// Keyboard layout icon
WrappedLoader {
name: "kblayout"
active: Config.bar.status.showKbLayout
sourceComponent: StyledText {
animate: true
text: Hypr.kbLayout
color: root.colour
font.family: Appearance.font.family.mono
}
}
// Network icon
WrappedLoader {
name: "network"
active: Config.bar.status.showNetwork
sourceComponent: MaterialIcon {
animate: true
text: Network.active ? Icons.getNetworkIcon(Network.active.strength ?? 0) : "wifi_off"
color: root.colour
}
}
// Bluetooth section
WrappedLoader {
Layout.preferredHeight: implicitHeight
name: "bluetooth"
active: Config.bar.status.showBluetooth
sourceComponent: ColumnLayout {
spacing: Appearance.spacing.smaller / 2
// Bluetooth icon
MaterialIcon {
animate: true
text: {
if (!Bluetooth.defaultAdapter?.enabled)
return "bluetooth_disabled";
if (Bluetooth.devices.values.some(d => d.connected))
return "bluetooth_connected";
return "bluetooth";
}
color: root.colour
}
// Connected bluetooth devices
Repeater {
model: ScriptModel {
values: Bluetooth.devices.values.filter(d => d.state !== BluetoothDeviceState.Disconnected)
}
MaterialIcon {
id: device
required property BluetoothDevice modelData
animate: true
text: Icons.getBluetoothIcon(modelData?.icon)
color: root.colour
fill: 1
SequentialAnimation on opacity {
running: device.modelData?.state !== BluetoothDeviceState.Connected
alwaysRunToEnd: true
loops: Animation.Infinite
Anim {
from: 1
to: 0
duration: Appearance.anim.durations.large
easing.bezierCurve: Appearance.anim.curves.standardAccel
}
Anim {
from: 0
to: 1
duration: Appearance.anim.durations.large
easing.bezierCurve: Appearance.anim.curves.standardDecel
}
}
}
}
}
Behavior on Layout.preferredHeight {
Anim {}
}
}
// Battery icon
WrappedLoader {
name: "battery"
active: Config.bar.status.showBattery
sourceComponent: MaterialIcon {
animate: true
text: {
if (!UPower.displayDevice.isLaptopBattery) {
if (PowerProfiles.profile === PowerProfile.PowerSaver)
return "energy_savings_leaf";
if (PowerProfiles.profile === PowerProfile.Performance)
return "rocket_launch";
return "balance";
}
const perc = UPower.displayDevice.percentage;
const charging = UPower.displayDevice.state === UPowerDeviceState.Charging;
if (perc === 1)
return charging ? "battery_charging_full" : "battery_full";
let level = Math.floor(perc * 7);
if (charging && (level === 4 || level === 1))
level--;
return charging ? `battery_charging_${(level + 3) * 10}` : `battery_${level}_bar`;
}
color: !UPower.onBattery || UPower.displayDevice.percentage > 0.2 ? root.colour : Colours.palette.m3error
fill: 1
}
}
}
component WrappedLoader: Loader {
required property string name
Layout.alignment: Qt.AlignHCenter
asynchronous: true
visible: active
}
}