Merge branch 'main' into module/wifi
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 17s
Python / lint-format (pull_request) Successful in 27s
Python / test (pull_request) Successful in 50s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m39s

This commit is contained in:
2026-06-24 18:58:36 +02:00
202 changed files with 11455 additions and 4203 deletions
@@ -19,7 +19,7 @@ Item {
required property var wrapper
implicitHeight: vol.implicitHeight + Appearance.padding.small * 2
implicitWidth: 400 + Appearance.padding.small * 2
implicitWidth: 500 + Appearance.padding.small * 2
CustomRect {
anchors.left: parent.left
@@ -52,56 +52,16 @@ Item {
CustomRect {
Layout.fillWidth: true
Layout.preferredHeight: 50 + Appearance.spacing.smaller * 2
Layout.preferredHeight: 65 + Appearance.spacing.smaller * 2
Layout.topMargin: root.topMargin
color: DynamicColors.tPalette.m3surfaceContainer
radius: root.rounding
Item {
id: sinkIcon
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.leftMargin: Appearance.padding.normal
anchors.top: parent.top
implicitWidth: childrenRect.width
CustomRect {
anchors.centerIn: parent
color: Audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
implicitHeight: 40
implicitWidth: 40
radius: Appearance.rounding.full
MaterialIcon {
anchors.alignWhenCentered: false
anchors.centerIn: parent
animate: true
color: Audio.muted ? DynamicColors.palette.m3onError : DynamicColors.palette.m3onPrimary
font.pointSize: 22
text: Audio.muted ? "volume_off" : "volume_up"
}
StateLayer {
color: Audio.muted ? DynamicColors.palette.m3onError : DynamicColors.palette.m3onPrimary
onClicked: {
const audio = Audio.sink?.audio;
if (audio)
audio.muted = !audio.muted;
}
}
}
}
ColumnLayout {
anchors.bottom: parent.bottom
anchors.bottomMargin: Appearance.padding.smallest
anchors.left: sinkIcon.right
anchors.leftMargin: Appearance.spacing.normal
anchors.right: parent.right
anchors.rightMargin: Appearance.padding.large
anchors.top: parent.top
anchors.bottomMargin: Appearance.padding.smaller
anchors.fill: parent
anchors.leftMargin: Appearance.padding.larger
anchors.rightMargin: Appearance.padding.larger
anchors.topMargin: Appearance.padding.smaller
RowLayout {
@@ -111,34 +71,53 @@ Item {
CustomText {
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.fillWidth: true
text: "Output Volume"
text: "Output volume"
}
CustomText {
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
color: Qt.alpha(DynamicColors.palette.m3onSurface, 0.7)
font.bold: true
text: qsTr("%1").arg(Audio.muted ? qsTr("Muted") : `${Math.round(Audio.volume * 100)}%`)
}
}
CustomMouseArea {
Layout.bottomMargin: 5
Layout.fillHeight: true
Layout.fillWidth: true
RowLayout {
spacing: Appearance.spacing.large
CustomSlider {
anchors.left: parent.left
anchors.right: parent.right
color: Audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
implicitHeight: parent.height
value: Audio.volume
CustomMouseArea {
Layout.bottomMargin: Appearance.padding.normal
Layout.fillWidth: true
Layout.preferredHeight: Appearance.padding.larger * 3
Behavior on value {
Anim {
CustomSlider {
anchors.left: parent.left
anchors.right: parent.right
bgColor: Audio.muted ? Qt.alpha(DynamicColors.palette.m3errorContainer, 0.5) : DynamicColors.palette.m3secondaryContainer
fgColor: Audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
implicitHeight: parent.height
insetColor: Audio.muted ? (inset.attached ? DynamicColors.palette.m3onErrorContainer : DynamicColors.palette.m3onError) : (inset.attached ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onPrimary)
insetIcon: Audio.muted || Audio.volume < 0.001 ? "volume_off" : "volume_up"
value: Audio.volume
Behavior on value {
Anim {
}
}
}
onMoved: Audio.setVolume(value)
onInteraction: value => Audio.setVolume(value)
}
}
CustomSwitch {
Layout.bottomMargin: Appearance.padding.normal
checked: !Audio.muted
onToggled: {
const audio = Audio.sink?.audio;
if (audio)
audio.muted = !audio.muted;
}
}
}
}
@@ -146,7 +125,7 @@ Item {
CustomClippingRect {
Layout.fillWidth: true
Layout.preferredHeight: 50 + Appearance.spacing.smaller * 2
Layout.preferredHeight: 65 + Appearance.spacing.smaller * 2
Layout.topMargin: root.topMargin
color: DynamicColors.tPalette.m3surfaceContainer
radius: root.rounding
@@ -173,51 +152,11 @@ Item {
}
}
Item {
id: sourceIcon
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.leftMargin: Appearance.padding.normal
anchors.top: parent.top
implicitWidth: childrenRect.width
CustomRect {
anchors.centerIn: parent
color: Audio.sourceMuted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
implicitHeight: 40
implicitWidth: 40
radius: Appearance.rounding.full
MaterialIcon {
anchors.alignWhenCentered: false
anchors.centerIn: parent
animate: true
color: Audio.sourceMuted ? DynamicColors.palette.m3onError : DynamicColors.palette.m3onPrimary
font.pointSize: 22
text: Audio.sourceMuted ? "mic_off" : "mic"
}
StateLayer {
color: Audio.sourceMuted ? DynamicColors.palette.m3onError : DynamicColors.palette.m3onPrimary
onClicked: {
const audio = Audio.source?.audio;
if (audio)
audio.muted = !audio.muted;
}
}
}
}
ColumnLayout {
anchors.bottom: parent.bottom
anchors.bottomMargin: Appearance.padding.smallest
anchors.left: sourceIcon.right
anchors.leftMargin: Appearance.spacing.normal
anchors.right: parent.right
anchors.rightMargin: Appearance.padding.large
anchors.top: parent.top
anchors.bottomMargin: Appearance.padding.smaller
anchors.fill: parent
anchors.leftMargin: Appearance.padding.larger
anchors.rightMargin: Appearance.padding.larger
anchors.topMargin: Appearance.padding.smaller
RowLayout {
@@ -227,34 +166,53 @@ Item {
CustomText {
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.fillWidth: true
text: "Input Volume"
text: "Input volume"
}
CustomText {
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
color: Qt.alpha(DynamicColors.palette.m3onSurface, 0.7)
font.bold: true
text: qsTr("%1").arg(Audio.sourceMuted ? qsTr("Muted") : `${Math.round(Audio.sourceVolume * 100)}%`)
}
}
CustomMouseArea {
Layout.bottomMargin: 5
Layout.fillHeight: true
Layout.fillWidth: true
RowLayout {
spacing: Appearance.spacing.large
CustomSlider {
anchors.left: parent.left
anchors.right: parent.right
color: Audio.sourceMuted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
implicitHeight: parent.height
value: Audio.sourceVolume
CustomMouseArea {
Layout.bottomMargin: Appearance.padding.normal
Layout.fillWidth: true
Layout.preferredHeight: Appearance.padding.larger * 3
Behavior on value {
Anim {
CustomSlider {
anchors.left: parent.left
anchors.right: parent.right
bgColor: Audio.sourceMuted ? Qt.alpha(DynamicColors.palette.m3errorContainer, 0.5) : DynamicColors.palette.m3secondaryContainer
fgColor: Audio.sourceMuted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
implicitHeight: parent.height
insetColor: Audio.sourceMuted ? (inset.attached ? DynamicColors.palette.m3onErrorContainer : DynamicColors.palette.m3onError) : (inset.attached ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onPrimary)
insetIcon: Audio.sourceMuted || Audio.sourceVolume < 0.001 ? "mic_off" : "mic"
value: Audio.sourceVolume
Behavior on value {
Anim {
}
}
}
onMoved: Audio.setSourceVolume(value)
onInteraction: value => Audio.setSourceVolume(value)
}
}
CustomSwitch {
Layout.bottomMargin: Appearance.padding.normal
checked: !Audio.sourceMuted
onToggled: {
const audio = Audio.source?.audio;
if (audio)
audio.muted = !audio.muted;
}
}
}
}
@@ -280,7 +238,7 @@ Item {
required property var modelData
Layout.fillWidth: true
Layout.preferredHeight: 50 + Appearance.spacing.smaller * 2
Layout.preferredHeight: 65 + Appearance.spacing.smaller * 2
Layout.topMargin: root.topMargin
color: DynamicColors.tPalette.m3surfaceContainer
radius: root.rounding
@@ -307,43 +265,6 @@ Item {
}
}
Item {
id: appBoxIcon
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.leftMargin: Appearance.padding.normal
anchors.top: parent.top
implicitWidth: childrenRect.width
CustomRect {
anchors.centerIn: parent
color: appBox.modelData.audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
implicitHeight: 40
implicitWidth: 40
radius: Appearance.rounding.full
MaterialIcon {
id: icon
anchors.centerIn: parent
animate: true
color: appBox.modelData.audio.muted ? DynamicColors.palette.m3onError : DynamicColors.palette.m3onPrimary
font.pointSize: 22
text: appBox.modelData.audio.muted ? "volume_off" : "volume_up"
}
StateLayer {
color: appBox.modelData.audio.muted ? DynamicColors.palette.m3onError : DynamicColors.palette.m3onPrimary
radius: Appearance.rounding.full
onClicked: {
appBox.modelData.audio.muted = !appBox.modelData.audio.muted;
}
}
}
}
TextMetrics {
id: metrics
@@ -353,13 +274,10 @@ Item {
}
ColumnLayout {
anchors.bottom: parent.bottom
anchors.bottomMargin: Appearance.padding.smallest
anchors.left: appBoxIcon.right
anchors.leftMargin: Appearance.spacing.normal
anchors.right: parent.right
anchors.rightMargin: Appearance.padding.large
anchors.top: parent.top
anchors.bottomMargin: Appearance.padding.smaller
anchors.fill: parent
anchors.leftMargin: Appearance.padding.larger
anchors.rightMargin: Appearance.padding.larger
anchors.topMargin: Appearance.padding.smaller
RowLayout {
@@ -375,25 +293,45 @@ Item {
CustomText {
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
color: Qt.alpha(DynamicColors.palette.m3onSurface, 0.7)
font.bold: true
text: qsTr("%1").arg(appBox.modelData.audio.muted ? qsTr("Muted") : `${Math.round(appBox.modelData.audio.volume * 100)}%`)
}
}
CustomMouseArea {
Layout.bottomMargin: 5
Layout.fillHeight: true
Layout.fillWidth: true
RowLayout {
spacing: Appearance.spacing.large
CustomSlider {
anchors.left: parent.left
anchors.right: parent.right
color: appBox.modelData.audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
implicitHeight: parent.height
value: appBox.modelData.audio.volume
CustomMouseArea {
Layout.bottomMargin: Appearance.padding.normal
Layout.fillWidth: true
Layout.preferredHeight: Appearance.padding.larger * 3
onMoved: {
Audio.setStreamVolume(appBox.modelData, value);
CustomSlider {
anchors.left: parent.left
anchors.right: parent.right
bgColor: appBox.modelData.audio.muted ? Qt.alpha(DynamicColors.palette.m3errorContainer, 0.5) : DynamicColors.palette.m3secondaryContainer
fgColor: appBox.modelData.audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
implicitHeight: parent.height
insetColor: appBox.modelData.audio.muted ? (inset.attached ? DynamicColors.palette.m3onErrorContainer : DynamicColors.palette.m3onError) : (inset.attached ? DynamicColors.palette.m3onSecondaryContainer : DynamicColors.palette.m3onPrimary)
insetIcon: appBox.modelData.audio.muted || appBox.modelData.audio.volume < 0.001 ? "volume_off" : "volume_up"
value: appBox.modelData.audio.volume
Behavior on value {
Anim {
}
}
onInteraction: value => Audio.setStreamVolume(appBox.modelData, value)
}
}
CustomSwitch {
Layout.bottomMargin: Appearance.padding.normal
checked: !appBox.modelData.audio.muted
onToggled: {
appBox.modelData.audio.muted = !appBox.modelData.audio.muted;
}
}
}
+11 -9
View File
@@ -13,6 +13,8 @@ StackView {
id: root
property int biggestWidth: 0
readonly property int itemHeight: 30
readonly property int panelRadius: ((itemHeight / 2) + Appearance.padding.small) * Appearance.rounding.scale
required property PopoutState popouts
property int rootWidth: 0
required property QsMenuHandle trayItem
@@ -100,10 +102,13 @@ StackView {
asynchronous: true
sourceComponent: Item {
implicitHeight: 30
implicitHeight: root.itemHeight
StateLayer {
function onClicked(): void {
enabled: item.modelData.enabled
radius: item.radius
onClicked: {
const entry = item.modelData;
if (entry.hasChildren) {
root.rootWidth = root.biggestWidth;
@@ -117,9 +122,6 @@ StackView {
root.popouts.hasCurrent = false;
}
}
disabled: !item.modelData.enabled
radius: item.radius
}
Loader {
@@ -217,13 +219,13 @@ StackView {
radius: Appearance.rounding.full
StateLayer {
function onClicked(): void {
color: DynamicColors.palette.m3onSecondaryContainer
radius: parent.radius
onClicked: {
root.pop();
root.biggestWidth = root.rootWidth;
}
color: DynamicColors.palette.m3onSecondaryContainer
radius: parent.radius
}
}
+105 -61
View File
@@ -3,16 +3,97 @@ pragma ComponentBehavior: Bound
import QtQuick
import Quickshell.Services.UPower
import qs.Config
import qs.Helpers
import qs.Components
import qs.Modules
Item {
Column {
id: root
required property var wrapper
readonly property int panelRadius: ((profiles.height / 2) + Appearance.padding.small) * Appearance.rounding.scale
implicitHeight: profiles.implicitHeight
implicitWidth: profiles.implicitWidth
spacing: Appearance.spacing.normal
Loader {
active: Battery.isLaptop
CustomText {
text: qsTr("Remaining: %1%").arg(Math.round(UPower.displayDevice.percentage * 100))
}
}
CustomText {
function formatSeconds(s: int, fallback: string): string {
const day = Math.floor(s / 86400);
const hr = Math.floor(s / 3600) % 60;
const min = Math.floor(s / 60) % 60;
let comps = [];
if (day > 0)
comps.push(`${day} days`);
if (hr > 0)
comps.push(`${hr} hours`);
if (min > 0)
comps.push(`${min} mins`);
return comps.join(", ") || fallback;
}
anchors.left: parent.left
anchors.leftMargin: Appearance.padding.normal
text: Battery.isLaptop ? qsTr("Time %1: %2").arg(Battery.onBattery ? "remaining" : "until charged").arg(Battery.onBattery ? formatSeconds(Battery.timeToEmpty, "Calculating...") : formatSeconds(Battery.timeToFull, "Fully charged!")) : qsTr("Power profile: %1").arg(PowerProfile.toString(PowerProfiles.profile))
}
Loader {
active: PowerProfiles.degradationReason !== PerformanceDegradationReason.None
anchors.horizontalCenter: parent.horizontalCenter
asynchronous: true
height: active ? ((item as Item)?.implicitHeight ?? 0) : 0
sourceComponent: CustomRect {
color: DynamicColors.palette.m3error
implicitHeight: child.implicitHeight + Appearance.padding.large
implicitWidth: child.implicitWidth + Appearance.padding.larger * 2
radius: Appearance.rounding.large
Column {
id: child
anchors.centerIn: parent
Row {
anchors.horizontalCenter: parent.horizontalCenter
spacing: Appearance.spacing.small
MaterialIcon {
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: -font.pointSize / 10
color: DynamicColors.palette.m3onError
text: "warning"
}
CustomText {
anchors.verticalCenter: parent.verticalCenter
color: DynamicColors.palette.m3onError
font.family: Appearance.font.family.mono
text: qsTr("Performance Degraded")
}
MaterialIcon {
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: -font.pointSize / 10
color: DynamicColors.palette.m3onError
text: "warning"
}
}
CustomText {
anchors.horizontalCenter: parent.horizontalCenter
color: DynamicColors.palette.m3onError
text: qsTr("Reason: %1").arg(PerformanceDegradationReason.toString(PowerProfiles.degradationReason))
}
}
}
}
CustomRect {
id: profiles
@@ -28,10 +109,9 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter
color: DynamicColors.tPalette.m3surfaceContainer
implicitHeight: Math.max(saver.implicitHeight, balance.implicitHeight, perf.implicitHeight) + 5 * 2 + saverLabel.contentHeight
implicitWidth: saver.implicitHeight + balance.implicitHeight + perf.implicitHeight + 8 * 2 + saverLabel.contentWidth
// color: "transparent"
radius: (20 - Appearance.padding.small) * Appearance.rounding.scale
implicitHeight: indicator.height + Appearance.padding.extraSmall * 2
implicitWidth: saver.implicitHeight + balance.implicitHeight + perf.implicitHeight + Appearance.padding.larger * 2 + Appearance.spacing.small * 8
radius: Appearance.rounding.full
CustomRect {
id: indicator
@@ -64,10 +144,7 @@ Item {
}
]
transitions: Transition {
AnchorAnimation {
duration: MaterialEasing.expressiveEffectsTime
easing.bezierCurve: MaterialEasing.expressiveEffects
easing.type: Easing.BezierSpline
AnchorAnim {
}
}
}
@@ -76,62 +153,28 @@ Item {
id: saver
anchors.left: parent.left
anchors.leftMargin: 25
anchors.top: parent.top
anchors.topMargin: 8
icon: "nest_eco_leaf"
anchors.leftMargin: Appearance.padding.extraSmall
anchors.verticalCenter: parent.verticalCenter
icon: "energy_savings_leaf"
profile: PowerProfile.PowerSaver
text: "Power Saver"
}
CustomText {
id: saverLabel
anchors.horizontalCenter: saver.horizontalCenter
anchors.top: saver.bottom
font.bold: true
text: saver.text
}
Profile {
id: balance
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 8
icon: "power_settings_new"
anchors.centerIn: parent
icon: "balance"
profile: PowerProfile.Balanced
text: "Balanced"
}
CustomText {
id: balanceLabel
anchors.horizontalCenter: balance.horizontalCenter
anchors.top: balance.bottom
font.bold: true
text: balance.text
}
Profile {
id: perf
anchors.right: parent.right
anchors.rightMargin: 25
anchors.top: parent.top
anchors.topMargin: 8
anchors.rightMargin: Appearance.padding.extraSmall
anchors.verticalCenter: parent.verticalCenter
icon: "bolt"
profile: PowerProfile.Performance
text: "Performance"
}
CustomText {
id: perfLabel
anchors.horizontalCenter: perf.horizontalCenter
anchors.top: perf.bottom
font.bold: true
text: perf.text
}
}
@@ -147,18 +190,17 @@ Item {
component Profile: Item {
required property string icon
required property int profile
required property string text
implicitHeight: icon.implicitHeight + 5 * 2
implicitWidth: icon.implicitHeight + 5 * 2
implicitHeight: icon.implicitHeight + Appearance.padding.small
implicitWidth: icon.implicitHeight + Appearance.padding.small
StateLayer {
function onClicked(): void {
PowerProfiles.profile = parent.profile;
}
color: profiles.current === parent.icon ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface
radius: Appearance.rounding.full
onClicked: {
PowerProfiles.profile = parent.profile;
}
}
MaterialIcon {
@@ -168,10 +210,12 @@ Item {
color: profiles.current === text ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface
fill: profiles.current === text ? 1 : 0
font.pointSize: Appearance.font.size.large * 2
grade: DynamicColors.light ? 0 : (text === "balance" ? -25 : 0)
text: parent.icon
Behavior on fill {
Anim {
type: Anim.DefaultEffects
}
}
}
+3 -2
View File
@@ -45,14 +45,15 @@ Item {
CustomRect {
anchors.fill: parent
anchors.margins: 3
color: root.current ? DynamicColors.palette.m3primary : "transparent"
color: Config.general.color.scheduleDark && root.current ? DynamicColors.palette.m3primary : "transparent"
radius: Appearance.rounding.full
StateLayer {
acceptedButtons: Qt.LeftButton | Qt.RightButton
anchors.fill: parent
color: Config.general.color.scheduleDark && root.current ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface
onClicked: {
onClicked: mouse => {
if (mouse.button === Qt.LeftButton) {
root.item.activate();
console.log(icon.source + "\n" + root.item.id);
+27 -3
View File
@@ -2,12 +2,10 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Services.SystemTray
import qs.Components
import qs.Config
import qs.Modules.SysTray.Widgets
import qs.Modules.SysTray.Popouts
import qs.Modules
RowLayout {
@@ -17,11 +15,37 @@ RowLayout {
required property RowLayout loader
required property Wrapper popouts
function closestRowChild(row, x) {
let child = row.childAt(x, row.height / 2);
if (child)
return child;
let closest = null;
let closestDistance = Infinity;
for (let i = 0; i < row.children.length; ++i) {
let c = row.children[i];
if (!c.visible || c.width <= 0)
continue;
let centerX = c.x + c.width / 2;
let dist = Math.abs(x - centerX);
if (dist < closestDistance) {
closestDistance = dist;
closest = c;
}
}
return closest;
}
function getHoveredSubItem(localX, localY) {
let modPos = mapToItem(sysTrayMod, localX, localY);
if (sysTrayMod.contains(Qt.point(modPos.x, modPos.y))) {
let modRowPos = sysTrayMod.mapToItem(sysModRow, modPos.x, modPos.y);
let child = sysModRow.childAt(modRowPos.x, modRowPos.y);
let child = closestRowChild(sysModRow, modRowPos.x);
if (child) {
if (child.objectName === "audioWidget" && Config.barConfig.popouts.audio)
return {
+2
View File
@@ -14,6 +14,8 @@ RowLayout {
property color textColor: DynamicColors.palette.m3onSurface
MaterialIcon {
id: mic
Layout.alignment: Qt.AlignVCenter
animate: true
color: (Audio.sourceMuted ?? false) ? DynamicColors.palette.m3error : root.textColor
+10 -14
View File
@@ -102,20 +102,16 @@ Item {
active: !Battery.isLaptop
anchors.centerIn: parent
sourceComponent: RowLayout {
id: upowerIcon
MaterialIcon {
Layout.alignment: Qt.AlignVCenter
animate: true
fill: 1
text: {
if (PowerProfiles.profile === PowerProfile.PowerSaver)
return "nest_eco_leaf";
if (PowerProfiles.profile === PowerProfile.Performance)
return "bolt";
return "power_settings_new";
}
sourceComponent: MaterialIcon {
Layout.alignment: Qt.AlignVCenter
animate: true
fill: 1
text: {
if (PowerProfiles.profile === PowerProfile.PowerSaver)
return "energy_savings_leaf";
if (PowerProfiles.profile === PowerProfile.Performance)
return "bolt";
return "balance";
}
}
}