applets/batterymonitor: port to `PC3.ItemDelegate` and improve a11y

1. Add arrow key navigation support
2. Imrpove a11y description for battery items, so messages like "Your
   battery is unhealthy" can be read by a screen reader.
wilder-5.26
Fushan Wen 4 years ago
parent a38fbf4884
commit f8f77c178f
  1. 268
      applets/batterymonitor/package/contents/ui/BatteryItem.qml
  2. 80
      applets/batterymonitor/package/contents/ui/BrightnessItem.qml
  3. 209
      applets/batterymonitor/package/contents/ui/PopupDialog.qml
  4. 7
      applets/batterymonitor/package/contents/ui/PowerManagementItem.qml
  5. 298
      applets/batterymonitor/package/contents/ui/PowerProfileItem.qml
  6. 1
      applets/batterymonitor/package/contents/ui/main.qml

@ -16,7 +16,7 @@ import org.kde.plasma.workspace.components 2.0
import "logic.js" as Logic
RowLayout {
PlasmaComponents3.ItemDelegate {
id: root
// We'd love to use `required` properties, especially since the model provides role names for them;
@ -54,148 +54,168 @@ RowLayout {
property PlasmaComponents3.Slider matchHeightOfSlider: PlasmaComponents3.Slider {}
readonly property real extraMargin: Math.max(0, Math.floor((matchHeightOfSlider.height - chargeBar.height) / 2))
spacing: PlasmaCore.Units.gridUnit
background.visible: highlighted
highlighted: activeFocus
text: battery["Pretty Name"]
BatteryIcon {
id: batteryIcon
Accessible.description: `${isPowerSupplyLabel.text} ${percentLabel.text}; ${details.Accessible.description}`
Layout.alignment: Qt.AlignTop
Layout.preferredWidth: PlasmaCore.Units.iconSizes.medium
Layout.preferredHeight: PlasmaCore.Units.iconSizes.medium
contentItem: RowLayout {
spacing: PlasmaCore.Units.gridUnit
batteryType: root.battery.Type
percent: root.battery.Percent
hasBattery: root.isPresent
pluggedIn: root.battery.State === "Charging" && root.battery["Is Power Supply"]
}
ColumnLayout {
Layout.fillWidth: true
Layout.alignment: root.isPresent ? Qt.AlignTop : Qt.AlignVCenter
spacing: 0
RowLayout {
spacing: PlasmaCore.Units.smallSpacing
PlasmaComponents3.Label {
Layout.fillWidth: true
elide: Text.ElideRight
text: root.battery["Pretty Name"]
}
BatteryIcon {
id: batteryIcon
PlasmaComponents3.Label {
text: Logic.stringForBatteryState(root.battery)
visible: root.battery["Is Power Supply"]
enabled: false
}
Layout.alignment: Qt.AlignTop
Layout.preferredWidth: PlasmaCore.Units.iconSizes.medium
Layout.preferredHeight: PlasmaCore.Units.iconSizes.medium
PlasmaComponents3.Label {
horizontalAlignment: Text.AlignRight
visible: root.isPresent
text: i18nc("Placeholder is battery percentage", "%1%", root.battery.Percent)
}
batteryType: root.battery.Type
percent: root.battery.Percent
hasBattery: root.isPresent
pluggedIn: root.battery.State === "Charging" && root.battery["Is Power Supply"]
}
PlasmaComponents3.ProgressBar {
id: chargeBar
Layout.fillWidth: true
Layout.topMargin: root.extraMargin
Layout.bottomMargin: root.extraMargin
from: 0
to: 100
visible: root.isPresent
value: Number(root.battery.Percent)
}
// This gridLayout basically emulates an at-most-two-rows table with a
// single wide fillWidth/columnSpan header. Not really worth it trying
// to refactor it into some more clever fancy model-delegate stuff.
GridLayout {
id: details
ColumnLayout {
Layout.fillWidth: true
Layout.topMargin: PlasmaCore.Units.smallSpacing
Layout.alignment: root.isPresent ? Qt.AlignTop : Qt.AlignVCenter
spacing: 0
RowLayout {
spacing: PlasmaCore.Units.smallSpacing
PlasmaComponents3.Label {
Layout.fillWidth: true
elide: Text.ElideRight
text: root.text
}
PlasmaComponents3.Label {
id: isPowerSupplyLabel
text: Logic.stringForBatteryState(root.battery)
visible: root.battery["Is Power Supply"]
enabled: false
}
PlasmaComponents3.Label {
id: percentLabel
horizontalAlignment: Text.AlignRight
visible: root.isPresent
text: i18nc("Placeholder is battery percentage", "%1%", root.battery.Percent)
}
}
columns: 2
columnSpacing: PlasmaCore.Units.smallSpacing
rowSpacing: 0
PlasmaComponents3.ProgressBar {
id: chargeBar
component LeftLabel : PlasmaComponents3.Label {
// fillWidth is true, so using internal alignment
horizontalAlignment: Text.AlignLeft
Layout.fillWidth: true
font: PlasmaCore.Theme.smallestFont
wrapMode: Text.WordWrap
enabled: false
}
component RightLabel : PlasmaComponents3.Label {
// fillWidth is false, so using external (grid-cell-internal) alignment
Layout.alignment: Qt.AlignRight
Layout.fillWidth: false
font: PlasmaCore.Theme.smallestFont
enabled: false
}
Layout.topMargin: root.extraMargin
Layout.bottomMargin: root.extraMargin
PlasmaComponents3.Label {
Layout.fillWidth: true
Layout.columnSpan: 2
text: root.isBroken && typeof root.battery.Capacity !== "undefined"
? i18n("This battery's health is at only %1% and it should be replaced. Contact the manufacturer.", root.battery.Capacity)
: ""
font: PlasmaCore.Theme.smallestFont
color: PlasmaCore.Theme.neutralTextColor
visible: root.isBroken
wrapMode: Text.WordWrap
from: 0
to: 100
visible: root.isPresent
value: Number(root.battery.Percent)
}
readonly property bool remainingTimeRowVisible: root.battery !== null
&& root.remainingTime > 0
&& root.battery["Is Power Supply"]
&& ["Discharging", "Charging"].includes(root.battery.State)
LeftLabel {
text: root.battery.State === "Charging"
? i18n("Time To Full:")
: i18n("Remaining Time:")
visible: details.remainingTimeRowVisible
}
// This gridLayout basically emulates an at-most-two-rows table with a
// single wide fillWidth/columnSpan header. Not really worth it trying
// to refactor it into some more clever fancy model-delegate stuff.
GridLayout {
id: details
RightLabel {
text: KCoreAddons.Format.formatDuration(root.remainingTime, KCoreAddons.FormatTypes.HideSeconds)
visible: details.remainingTimeRowVisible
Layout.fillWidth: true
Layout.topMargin: PlasmaCore.Units.smallSpacing
columns: 2
columnSpacing: PlasmaCore.Units.smallSpacing
rowSpacing: 0
Accessible.description: {
let description = [];
for (let i = 0; i < children.length; i++) {
if (children[i].visible && children[i].hasOwnProperty("text")) {
description.push(children[i].text);
}
}
return description.join(" ");
}
component LeftLabel : PlasmaComponents3.Label {
// fillWidth is true, so using internal alignment
horizontalAlignment: Text.AlignLeft
Layout.fillWidth: true
font: PlasmaCore.Theme.smallestFont
wrapMode: Text.WordWrap
enabled: false
}
component RightLabel : PlasmaComponents3.Label {
// fillWidth is false, so using external (grid-cell-internal) alignment
Layout.alignment: Qt.AlignRight
Layout.fillWidth: false
font: PlasmaCore.Theme.smallestFont
enabled: false
}
PlasmaComponents3.Label {
Layout.fillWidth: true
Layout.columnSpan: 2
text: root.isBroken && typeof root.battery.Capacity !== "undefined"
? i18n("This battery's health is at only %1% and it should be replaced. Contact the manufacturer.", root.battery.Capacity)
: ""
font: PlasmaCore.Theme.smallestFont
color: PlasmaCore.Theme.neutralTextColor
visible: root.isBroken
wrapMode: Text.WordWrap
}
readonly property bool remainingTimeRowVisible: root.battery !== null
&& root.remainingTime > 0
&& root.battery["Is Power Supply"]
&& ["Discharging", "Charging"].includes(root.battery.State)
LeftLabel {
text: root.battery.State === "Charging"
? i18n("Time To Full:")
: i18n("Remaining Time:")
visible: details.remainingTimeRowVisible
}
RightLabel {
text: KCoreAddons.Format.formatDuration(root.remainingTime, KCoreAddons.FormatTypes.HideSeconds)
visible: details.remainingTimeRowVisible
}
readonly property bool healthRowVisible: root.battery !== null
&& root.battery["Is Power Supply"]
&& root.battery.Capacity !== ""
&& typeof root.battery.Capacity === "number"
&& !root.isBroken
LeftLabel {
text: i18n("Battery Health:")
visible: details.healthRowVisible
}
RightLabel {
text: details.healthRowVisible
? i18nc("Placeholder is battery health percentage", "%1%", root.battery.Capacity)
: ""
visible: details.healthRowVisible
}
}
readonly property bool healthRowVisible: root.battery !== null
&& root.battery["Is Power Supply"]
&& root.battery.Capacity !== ""
&& typeof root.battery.Capacity === "number"
&& !root.isBroken
LeftLabel {
text: i18n("Battery Health:")
visible: details.healthRowVisible
}
InhibitionHint {
Layout.fillWidth: true
Layout.topMargin: PlasmaCore.Units.smallSpacing
RightLabel {
text: details.healthRowVisible
? i18nc("Placeholder is battery health percentage", "%1%", root.battery.Capacity)
: ""
visible: details.healthRowVisible
readonly property var chargeStopThreshold: pmSource.data["Battery"] ? pmSource.data["Battery"]["Charge Stop Threshold"] : undefined
readonly property bool pluggedIn: pmSource.data["AC Adapter"] !== undefined && pmSource.data["AC Adapter"]["Plugged in"]
visible: pluggedIn && root.isPowerSupply && typeof chargeStopThreshold === "number" && chargeStopThreshold > 0 && chargeStopThreshold < 100
iconSource: "kt-speed-limits" // FIXME good icon
text: i18n("Battery is configured to charge up to approximately %1%.", chargeStopThreshold || 0)
}
}
InhibitionHint {
Layout.fillWidth: true
Layout.topMargin: PlasmaCore.Units.smallSpacing
readonly property var chargeStopThreshold: pmSource.data["Battery"] ? pmSource.data["Battery"]["Charge Stop Threshold"] : undefined
readonly property bool pluggedIn: pmSource.data["AC Adapter"] !== undefined && pmSource.data["AC Adapter"]["Plugged in"]
visible: pluggedIn && root.isPowerSupply && typeof chargeStopThreshold === "number" && chargeStopThreshold > 0 && chargeStopThreshold < 100
iconSource: "kt-speed-limits" // FIXME good icon
text: i18n("Battery is configured to charge up to approximately %1%.", chargeStopThreshold || 0)
}
}
}

@ -11,11 +11,9 @@ import QtQuick.Layouts 1.15
import org.kde.plasma.components 3.0 as PlasmaComponents3
import org.kde.plasma.core 2.1 as PlasmaCore
RowLayout {
PlasmaComponents3.ItemDelegate {
id: root
property alias icon: image.source
property alias label: title.text
property alias slider: control
property alias value: control.value
property alias maximumValue: control.to
@ -26,48 +24,62 @@ RowLayout {
signal moved()
spacing: PlasmaCore.Units.gridUnit
background.visible: highlighted
highlighted: activeFocus
hoverEnabled: false
PlasmaCore.IconItem {
id: image
Layout.alignment: Qt.AlignTop
Layout.preferredWidth: PlasmaCore.Units.iconSizes.medium
Layout.preferredHeight: PlasmaCore.Units.iconSizes.medium
}
Accessible.description: percent.text
Accessible.role: Accessible.Slider
Keys.forwardTo: [slider]
contentItem: RowLayout {
spacing: PlasmaCore.Units.gridUnit
ColumnLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
spacing: 0
PlasmaCore.IconItem {
id: image
Layout.alignment: Qt.AlignTop
Layout.preferredWidth: PlasmaCore.Units.iconSizes.medium
Layout.preferredHeight: PlasmaCore.Units.iconSizes.medium
source: root.icon.name
}
RowLayout {
ColumnLayout {
Layout.fillWidth: true
spacing: PlasmaCore.Units.smallSpacing
Layout.alignment: Qt.AlignTop
spacing: 0
PlasmaComponents3.Label {
id: title
RowLayout {
Layout.fillWidth: true
spacing: PlasmaCore.Units.smallSpacing
PlasmaComponents3.Label {
id: title
Layout.fillWidth: true
text: root.text
}
PlasmaComponents3.Label {
id: percent
Layout.alignment: Qt.AlignRight
text: i18nc("Placeholder is brightness percentage", "%1%", root.percentage)
}
}
PlasmaComponents3.Label {
id: percent
Layout.alignment: Qt.AlignRight
text: i18nc("Placeholder is brightness percentage", "%1%", root.percentage)
}
}
PlasmaComponents3.Slider {
id: control
Layout.fillWidth: true
PlasmaComponents3.Slider {
id: control
Layout.fillWidth: true
// Don't allow the slider to turn off the screen
// Please see https://git.reviewboard.kde.org/r/122505/ for more information
from: to > 100 ? 1 : 0
stepSize: 1
activeFocusOnTab: false
// Don't allow the slider to turn off the screen
// Please see https://git.reviewboard.kde.org/r/122505/ for more information
from: to > 100 ? 1 : 0
stepSize: 1
Accessible.name: root.label
Accessible.description: percent.text
Accessible.name: root.text
Accessible.description: percent.text
onMoved: root.moved()
onMoved: root.moved()
}
}
}
}

@ -16,7 +16,7 @@ import org.kde.plasma.extras 2.0 as PlasmaExtras
PlasmaExtras.Representation {
id: dialog
property alias model: batteryList.model
property alias model: batteryRepeater.model
property bool pluggedIn
property int remainingTime
@ -48,6 +48,8 @@ PlasmaExtras.Representation {
collapseMarginsHint: true
KeyNavigation.down: pmSwitch.pmCheckBox
header: PlasmaExtras.PlasmoidHeading {
leftPadding: PlasmaCore.Units.smallSpacing
contentItem: PowerManagementItem {
@ -57,127 +59,134 @@ PlasmaExtras.Representation {
inhibitsLidAction: dialog.inhibitsLidAction
pluggedIn: dialog.pluggedIn
onDisabledChanged: powerManagementChanged(disabled)
KeyNavigation.tab: if (batteryList.headerItem) {
if (isBrightnessAvailable) {
return batteryList.headerItem.children[1];
} else if (isKeyboardBrightnessAvailable) {
return batteryList.headerItem.children[2];
} else if (dialog.profiles.length > 0) {
return batteryList.headerItem.children[3];
} else {
return batteryList;
}
}
}
}
PlasmaComponents3.ScrollView {
focus: true
anchors.fill: parent
contentItem: PlasmaComponents3.ScrollView {
id: scrollView
focus: false
// HACK: workaround for https://bugreports.qt.io/browse/QTBUG-83890
PlasmaComponents3.ScrollBar.horizontal.policy: PlasmaComponents3.ScrollBar.AlwaysOff
contentItem: ListView {
Column {
id: batteryList
keyNavigationEnabled: true
leftMargin: PlasmaCore.Units.smallSpacing * 2
rightMargin: PlasmaCore.Units.smallSpacing * 2
topMargin: PlasmaCore.Units.smallSpacing * 2
bottomMargin: PlasmaCore.Units.smallSpacing * 2
spacing: PlasmaCore.Units.smallSpacing
// header so that it scroll with the content of the ListView
header: ColumnLayout {
spacing: PlasmaCore.Units.smallSpacing * 2
width: parent.width
BrightnessItem {
id: brightnessSlider
Layout.fillWidth: true
icon: "video-display-brightness"
label: i18n("Display Brightness")
visible: isBrightnessAvailable
value: batterymonitor.screenBrightness
maximumValue: batterymonitor.maximumScreenBrightness
KeyNavigation.tab: if (isKeyboardBrightnessAvailable) {
return keyboardBrightnessSlider;
} else if (dialog.profiles.length > 0) {
return powerProfileItem
} else {
return batteryList
}
stepSize: batterymonitor.maximumScreenBrightness/100
onMoved: batterymonitor.screenBrightness = value
spacing: PlasmaCore.Units.smallSpacing * 2
// Manually dragging the slider around breaks the binding
Connections {
target: batterymonitor
function onScreenBrightnessChanged() {
brightnessSlider.value = batterymonitor.screenBrightness;
}
}
readonly property Item firstHeaderItem: {
if (brightnessSlider.visible) {
return brightnessSlider;
} else if (keyboardBrightnessSlider.visible) {
return keyboardBrightnessSlider;
} else if (powerProfileItem.visible) {
return powerProfileItem;
}
return null;
}
readonly property Item lastHeaderItem: {
if (powerProfileItem.visible) {
return powerProfileItem;
} else if (keyboardBrightnessSlider.visible) {
return keyboardBrightnessSlider;
} else if (brightnessSlider.visible) {
return brightnessSlider;
}
return null;
}
BrightnessItem {
id: keyboardBrightnessSlider
Layout.fillWidth: true
icon: "input-keyboard-brightness"
label: i18n("Keyboard Brightness")
showPercentage: false
value: batterymonitor.keyboardBrightness
maximumValue: batterymonitor.maximumKeyboardBrightness
visible: isKeyboardBrightnessAvailable
KeyNavigation.tab: if (dialog.profiles.length > 0) {
return powerProfileItem
} else {
return batteryList
}
BrightnessItem {
id: brightnessSlider
width: scrollView.availableWidth
onMoved: batterymonitor.keyboardBrightness = value
icon.name: "video-display-brightness"
text: i18n("Display Brightness")
visible: isBrightnessAvailable
value: batterymonitor.screenBrightness
maximumValue: batterymonitor.maximumScreenBrightness
// Manually dragging the slider around breaks the binding
Connections {
target: batterymonitor
function onKeyboardBrightnessChanged() {
keyboardBrightnessSlider.value = batterymonitor.keyboardBrightness;
}
KeyNavigation.up: pmSwitch.pmCheckBox
KeyNavigation.down: keyboardBrightnessSlider.visible ? keyboardBrightnessSlider : keyboardBrightnessSlider.KeyNavigation.down
KeyNavigation.backtab: KeyNavigation.up
KeyNavigation.tab: KeyNavigation.down
stepSize: batterymonitor.maximumScreenBrightness/100
onMoved: batterymonitor.screenBrightness = value
// Manually dragging the slider around breaks the binding
Connections {
target: batterymonitor
function onScreenBrightnessChanged() {
brightnessSlider.value = batterymonitor.screenBrightness;
}
}
}
PowerProfileItem {
id: powerProfileItem
Layout.fillWidth: true
KeyNavigation.tab: batteryList
activeProfile: dialog.activeProfile
inhibitionReason: dialog.inhibitionReason
visible: dialog.profiles.length > 0
degradationReason: dialog.degradationReason
profileHolds: dialog.profileHolds
onActivateProfileRequested: dialog.activateProfileRequested(profile)
}
Item {
Layout.fillWidth: true
// additional margin, because the bottom of PowerProfileItem
// and the top of BatteryItem are more dense.
BrightnessItem {
id: keyboardBrightnessSlider
width: scrollView.availableWidth
icon.name: "input-keyboard-brightness"
text: i18n("Keyboard Brightness")
showPercentage: false
value: batterymonitor.keyboardBrightness
maximumValue: batterymonitor.maximumKeyboardBrightness
visible: isKeyboardBrightnessAvailable
KeyNavigation.up: brightnessSlider.visible ? brightnessSlider : brightnessSlider.KeyNavigation.up
KeyNavigation.down: powerProfileItem.visible ? powerProfileItem : powerProfileItem.KeyNavigation.down
KeyNavigation.backtab: KeyNavigation.up
KeyNavigation.tab: KeyNavigation.down
onMoved: batterymonitor.keyboardBrightness = value
// Manually dragging the slider around breaks the binding
Connections {
target: batterymonitor
function onKeyboardBrightnessChanged() {
keyboardBrightnessSlider.value = batterymonitor.keyboardBrightness;
}
}
}
delegate: BatteryItem {
width: ListView.view.width - PlasmaCore.Units.smallSpacing * 4
PowerProfileItem {
id: powerProfileItem
width: scrollView.availableWidth
KeyNavigation.up: keyboardBrightnessSlider.visible ? keyboardBrightnessSlider : keyboardBrightnessSlider.KeyNavigation.up
KeyNavigation.down: batteryRepeater.count > 0 ? batteryRepeater.itemAt(0) : null
KeyNavigation.backtab: KeyNavigation.up
KeyNavigation.tab: KeyNavigation.down
battery: model
remainingTime: dialog.remainingTime
matchHeightOfSlider: ListView.view.headerItem ? ListView.view.headerItem.children[1].slider : null
activeProfile: dialog.activeProfile
inhibitionReason: dialog.inhibitionReason
visible: dialog.profiles.length > 0
degradationReason: dialog.degradationReason
profileHolds: dialog.profileHolds
onActivateProfileRequested: dialog.activateProfileRequested(profile)
}
Repeater {
id: batteryRepeater
delegate: BatteryItem {
width: scrollView.availableWidth
battery: model
remainingTime: dialog.remainingTime
matchHeightOfSlider: batteryList.firstHeaderItem ? batteryList.firstHeaderItem.slider : null
KeyNavigation.up: index === 0 ? batteryList.lastHeaderItem : batteryRepeater.itemAt(index - 1)
KeyNavigation.down: index + 1 < batteryRepeater.count ? batteryRepeater.itemAt(index + 1) : null
KeyNavigation.backtab: KeyNavigation.up
KeyNavigation.tab: KeyNavigation.down
}
}
}
}
}

@ -15,6 +15,7 @@ import org.kde.plasma.core 2.1 as PlasmaCore
ColumnLayout {
id: root
property alias pmCheckBox: pmCheckBox
property alias disabled: pmCheckBox.checked
property bool pluggedIn
@ -35,6 +36,12 @@ ColumnLayout {
Layout.fillWidth: true
text: i18nc("Minimize the length of this string as much as possible", "Manually block sleep and screen locking")
checked: false
focus: true
KeyNavigation.up: dialog.KeyNavigation.up
KeyNavigation.down: batteryList.children[0]
KeyNavigation.backtab: dialog.KeyNavigation.backtab
KeyNavigation.tab: KeyNavigation.down
}
// Separator line

@ -11,9 +11,11 @@ import QtQuick.Layouts 1.15
import org.kde.plasma.components 3.0 as PlasmaComponents3
import org.kde.plasma.core 2.1 as PlasmaCore
RowLayout {
PlasmaComponents3.ItemDelegate {
id: root
property alias slider: slider
property string activeProfile
property string inhibitionReason
@ -51,190 +53,204 @@ RowLayout {
signal activateProfileRequested(string profile)
spacing: PlasmaCore.Units.gridUnit
background.visible: highlighted
highlighted: activeFocus
hoverEnabled: false
text: i18n("Power Profile")
PlasmaCore.IconItem {
source: "speedometer"
Layout.alignment: Qt.AlignTop
Layout.preferredWidth: PlasmaCore.Units.iconSizes.medium
Layout.preferredHeight: PlasmaCore.Units.iconSizes.medium
}
Accessible.description: activeProfileLabel.text
Accessible.role: Accessible.Slider
Keys.forwardTo: [slider]
ColumnLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
spacing: 0
contentItem: RowLayout {
spacing: PlasmaCore.Units.gridUnit
PlasmaCore.IconItem {
source: "speedometer"
Layout.alignment: Qt.AlignTop
Layout.preferredWidth: PlasmaCore.Units.iconSizes.medium
Layout.preferredHeight: PlasmaCore.Units.iconSizes.medium
}
RowLayout {
ColumnLayout {
Layout.fillWidth: true
spacing: PlasmaCore.Units.smallSpacing
Layout.alignment: Qt.AlignTop
spacing: 0
PlasmaComponents3.Label {
RowLayout {
Layout.fillWidth: true
elide: Text.ElideRight
text: i18n("Power Profile")
}
spacing: PlasmaCore.Units.smallSpacing
PlasmaComponents3.Label {
Layout.alignment: Qt.AlignRight
text: activeProfileData ? activeProfileData.label : ""
PlasmaComponents3.Label {
Layout.fillWidth: true
elide: Text.ElideRight
text: root.text
}
PlasmaComponents3.Label {
id: activeProfileLabel
Layout.alignment: Qt.AlignRight
text: activeProfileData ? activeProfileData.label : ""
}
}
}
PlasmaComponents3.Slider {
Layout.fillWidth: true
PlasmaComponents3.Slider {
id: slider
Layout.fillWidth: true
from: 0
to: 2
stepSize: 1
value: root.activeProfileIndex
snapMode: PlasmaComponents3.Slider.SnapAlways
onMoved: {
const { canBeInhibited, profile } = root.profileData[value];
if (!(canBeInhibited && root.inhibited)) {
activateProfileRequested(profile);
} else {
value = Qt.binding(() => root.activeProfileIndex);
activeFocusOnTab: false
from: 0
to: 2
stepSize: 1
value: root.activeProfileIndex
snapMode: PlasmaComponents3.Slider.SnapAlways
onMoved: {
const { canBeInhibited, profile } = root.profileData[value];
if (!(canBeInhibited && root.inhibited)) {
activateProfileRequested(profile);
} else {
value = Qt.binding(() => root.activeProfileIndex);
}
}
}
// fake having a disabled second half
Rectangle {
z: -1
visible: root.inhibited
color: PlasmaCore.Theme.backgroundColor
anchors {
top: parent.background.top
left: parent.horizontalCenter
leftMargin: 1
right: parent.right
bottom: parent.background.bottom
// fake having a disabled second half
Rectangle {
z: -1
visible: root.inhibited
color: PlasmaCore.Theme.backgroundColor
anchors {
top: parent.background.top
left: parent.horizontalCenter
leftMargin: 1
right: parent.right
bottom: parent.background.bottom
}
opacity: 0.4
}
opacity: 0.4
}
}
RowLayout {
spacing: 0
Layout.topMargin: PlasmaCore.Units.smallSpacing
Layout.bottomMargin: PlasmaCore.Units.smallSpacing
Layout.fillWidth: true
RowLayout {
spacing: 0
Layout.topMargin: PlasmaCore.Units.smallSpacing
Layout.bottomMargin: PlasmaCore.Units.smallSpacing
Layout.fillWidth: true
PlasmaCore.Svg {
id: svg
imagePath: "icons/battery"
}
PlasmaCore.Svg {
id: svg
imagePath: "icons/battery"
}
PlasmaCore.SvgItem {
Layout.preferredHeight: PlasmaCore.Units.iconSizes.smallMedium
Layout.preferredWidth: PlasmaCore.Units.iconSizes.smallMedium
svg: svg
elementId: "profile-powersave"
PlasmaCore.SvgItem {
Layout.preferredHeight: PlasmaCore.Units.iconSizes.smallMedium
Layout.preferredWidth: PlasmaCore.Units.iconSizes.smallMedium
svg: svg
elementId: "profile-powersave"
HoverHandler {
id: powersaveIconHover
}
HoverHandler {
id: powersaveIconHover
}
PlasmaComponents3.ToolTip {
text: root.profileData.find(profile => profile.profile === "power-saver").label
visible: powersaveIconHover.hovered
PlasmaComponents3.ToolTip {
text: root.profileData.find(profile => profile.profile === "power-saver").label
visible: powersaveIconHover.hovered
}
}
}
Item {
Layout.fillWidth: true
}
Item {
Layout.fillWidth: true
}
PlasmaCore.SvgItem {
Layout.preferredHeight: PlasmaCore.Units.iconSizes.smallMedium
Layout.preferredWidth: PlasmaCore.Units.iconSizes.smallMedium
svg: svg
elementId: "profile-performance"
PlasmaCore.SvgItem {
Layout.preferredHeight: PlasmaCore.Units.iconSizes.smallMedium
Layout.preferredWidth: PlasmaCore.Units.iconSizes.smallMedium
svg: svg
elementId: "profile-performance"
HoverHandler {
id: performanceIconHover
}
HoverHandler {
id: performanceIconHover
}
PlasmaComponents3.ToolTip {
text: root.profileData.find(profile => profile.profile === "performance").label
visible: performanceIconHover.hovered
PlasmaComponents3.ToolTip {
text: root.profileData.find(profile => profile.profile === "performance").label
visible: performanceIconHover.hovered
}
}
}
}
// NOTE Only one of these will be visible at a time since the daemon will only set one depending
// on its version
InhibitionHint {
id: inhibitionReasonHint
// NOTE Only one of these will be visible at a time since the daemon will only set one depending
// on its version
InhibitionHint {
id: inhibitionReasonHint
Layout.fillWidth: true
Layout.fillWidth: true
visible: root.inhibited
iconSource: "dialog-information"
text: switch(root.inhibitionReason) {
case "lap-detected":
return i18n("Performance mode has been disabled to reduce heat generation because the computer has detected that it may be sitting on your lap.")
case "high-operating-temperature":
return i18n("Performance mode is unavailable because the computer is running too hot.")
default:
return i18n("Performance mode is unavailable.")
visible: root.inhibited
iconSource: "dialog-information"
text: switch(root.inhibitionReason) {
case "lap-detected":
return i18n("Performance mode has been disabled to reduce heat generation because the computer has detected that it may be sitting on your lap.")
case "high-operating-temperature":
return i18n("Performance mode is unavailable because the computer is running too hot.")
default:
return i18n("Performance mode is unavailable.")
}
}
}
InhibitionHint {
id: inhibitionPerformanceHint
InhibitionHint {
id: inhibitionPerformanceHint
Layout.fillWidth: true
Layout.fillWidth: true
visible: root.activeProfile === "performance" && root.degradationReason !== ""
iconSource: "dialog-information"
text: switch(root.degradationReason) {
case "lap-detected":
return i18n("Performance may be lowered to reduce heat generation because the computer has detected that it may be sitting on your lap.")
case "high-operating-temperature":
return i18n("Performance may be reduced because the computer is running too hot.")
default:
return i18n("Performance may be reduced.")
visible: root.activeProfile === "performance" && root.degradationReason !== ""
iconSource: "dialog-information"
text: switch(root.degradationReason) {
case "lap-detected":
return i18n("Performance may be lowered to reduce heat generation because the computer has detected that it may be sitting on your lap.")
case "high-operating-temperature":
return i18n("Performance may be reduced because the computer is running too hot.")
default:
return i18n("Performance may be reduced.")
}
}
}
InhibitionHint {
id: inhibitionHoldersHint
InhibitionHint {
id: inhibitionHoldersHint
Layout.fillWidth: true
Layout.fillWidth: true
visible: root.activeHolds.length > 0 && root.activeProfileData !== undefined
text: root.activeProfileData !== undefined
? i18np("One application has requested activating %2:",
"%1 applications have requested activating %2:",
root.activeHolds.length,
i18n(root.activeProfileData.label))
: ""
}
visible: root.activeHolds.length > 0 && root.activeProfileData !== undefined
text: root.activeProfileData !== undefined
? i18np("One application has requested activating %2:",
"%1 applications have requested activating %2:",
root.activeHolds.length,
i18n(root.activeProfileData.label))
: ""
}
Repeater {
id: repeater
Repeater {
id: repeater
model: root.activeHolds
model: root.activeHolds
InhibitionHint {
Layout.fillWidth: true
InhibitionHint {
Layout.fillWidth: true
x: PlasmaCore.Units.smallSpacing
iconSource: modelData.Icon
text: i18nc("%1 is the name of the application, %2 is the reason provided by it for activating performance mode",
"%1: %2", modelData.Name, modelData.Reason)
x: PlasmaCore.Units.smallSpacing
iconSource: modelData.Icon
text: i18nc("%1 is the name of the application, %2 is the reason provided by it for activating performance mode",
"%1: %2", modelData.Name, modelData.Reason)
}
}
}
Item {
Layout.fillWidth: true
Layout.preferredHeight: PlasmaCore.Units.smallSpacing
Item {
Layout.fillWidth: true
Layout.preferredHeight: PlasmaCore.Units.smallSpacing
visible: repeater.visibleChildren > 0
|| inhibitionReasonHint.visible
|| inhibitionPerformanceHint.visible
|| inhibitionHoldersHint.visible
visible: repeater.visibleChildren > 0
|| inhibitionReasonHint.visible
|| inhibitionPerformanceHint.visible
|| inhibitionHoldersHint.visible
}
}
}
}

@ -249,7 +249,6 @@ Item {
id: dialogItem
model: Plasmoid.expanded ? batteries : null
focus: true
isBrightnessAvailable: batterymonitor.isBrightnessAvailable
isKeyboardBrightnessAvailable: batterymonitor.isKeyboardBrightnessAvailable

Loading…
Cancel
Save