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 import "logic.js" as Logic
RowLayout { PlasmaComponents3.ItemDelegate {
id: root id: root
// We'd love to use `required` properties, especially since the model provides role names for them; // 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 {} property PlasmaComponents3.Slider matchHeightOfSlider: PlasmaComponents3.Slider {}
readonly property real extraMargin: Math.max(0, Math.floor((matchHeightOfSlider.height - chargeBar.height) / 2)) 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 { Accessible.description: `${isPowerSupplyLabel.text} ${percentLabel.text}; ${details.Accessible.description}`
id: batteryIcon
Layout.alignment: Qt.AlignTop contentItem: RowLayout {
Layout.preferredWidth: PlasmaCore.Units.iconSizes.medium spacing: PlasmaCore.Units.gridUnit
Layout.preferredHeight: PlasmaCore.Units.iconSizes.medium
batteryType: root.battery.Type BatteryIcon {
percent: root.battery.Percent id: batteryIcon
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"]
}
PlasmaComponents3.Label { Layout.alignment: Qt.AlignTop
text: Logic.stringForBatteryState(root.battery) Layout.preferredWidth: PlasmaCore.Units.iconSizes.medium
visible: root.battery["Is Power Supply"] Layout.preferredHeight: PlasmaCore.Units.iconSizes.medium
enabled: false
}
PlasmaComponents3.Label { batteryType: root.battery.Type
horizontalAlignment: Text.AlignRight percent: root.battery.Percent
visible: root.isPresent hasBattery: root.isPresent
text: i18nc("Placeholder is battery percentage", "%1%", root.battery.Percent) pluggedIn: root.battery.State === "Charging" && root.battery["Is Power Supply"]
}
} }
PlasmaComponents3.ProgressBar { ColumnLayout {
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
Layout.fillWidth: true 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 PlasmaComponents3.ProgressBar {
columnSpacing: PlasmaCore.Units.smallSpacing id: chargeBar
rowSpacing: 0
component LeftLabel : PlasmaComponents3.Label {
// fillWidth is true, so using internal alignment
horizontalAlignment: Text.AlignLeft
Layout.fillWidth: true Layout.fillWidth: true
font: PlasmaCore.Theme.smallestFont Layout.topMargin: root.extraMargin
wrapMode: Text.WordWrap Layout.bottomMargin: root.extraMargin
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 { from: 0
Layout.fillWidth: true to: 100
Layout.columnSpan: 2 visible: root.isPresent
value: Number(root.battery.Percent)
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 // This gridLayout basically emulates an at-most-two-rows table with a
&& root.remainingTime > 0 // single wide fillWidth/columnSpan header. Not really worth it trying
&& root.battery["Is Power Supply"] // to refactor it into some more clever fancy model-delegate stuff.
&& ["Discharging", "Charging"].includes(root.battery.State) GridLayout {
id: details
LeftLabel {
text: root.battery.State === "Charging"
? i18n("Time To Full:")
: i18n("Remaining Time:")
visible: details.remainingTimeRowVisible
}
RightLabel { Layout.fillWidth: true
text: KCoreAddons.Format.formatDuration(root.remainingTime, KCoreAddons.FormatTypes.HideSeconds) Layout.topMargin: PlasmaCore.Units.smallSpacing
visible: details.remainingTimeRowVisible
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 InhibitionHint {
&& root.battery["Is Power Supply"] Layout.fillWidth: true
&& root.battery.Capacity !== "" Layout.topMargin: PlasmaCore.Units.smallSpacing
&& typeof root.battery.Capacity === "number"
&& !root.isBroken
LeftLabel {
text: i18n("Battery Health:")
visible: details.healthRowVisible
}
RightLabel { readonly property var chargeStopThreshold: pmSource.data["Battery"] ? pmSource.data["Battery"]["Charge Stop Threshold"] : undefined
text: details.healthRowVisible readonly property bool pluggedIn: pmSource.data["AC Adapter"] !== undefined && pmSource.data["AC Adapter"]["Plugged in"]
? i18nc("Placeholder is battery health percentage", "%1%", root.battery.Capacity) visible: pluggedIn && root.isPowerSupply && typeof chargeStopThreshold === "number" && chargeStopThreshold > 0 && chargeStopThreshold < 100
: "" iconSource: "kt-speed-limits" // FIXME good icon
visible: details.healthRowVisible 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.components 3.0 as PlasmaComponents3
import org.kde.plasma.core 2.1 as PlasmaCore import org.kde.plasma.core 2.1 as PlasmaCore
RowLayout { PlasmaComponents3.ItemDelegate {
id: root id: root
property alias icon: image.source
property alias label: title.text
property alias slider: control property alias slider: control
property alias value: control.value property alias value: control.value
property alias maximumValue: control.to property alias maximumValue: control.to
@ -26,48 +24,62 @@ RowLayout {
signal moved() signal moved()
spacing: PlasmaCore.Units.gridUnit background.visible: highlighted
highlighted: activeFocus
hoverEnabled: false
PlasmaCore.IconItem { Accessible.description: percent.text
id: image Accessible.role: Accessible.Slider
Layout.alignment: Qt.AlignTop Keys.forwardTo: [slider]
Layout.preferredWidth: PlasmaCore.Units.iconSizes.medium
Layout.preferredHeight: PlasmaCore.Units.iconSizes.medium contentItem: RowLayout {
} spacing: PlasmaCore.Units.gridUnit
ColumnLayout { PlasmaCore.IconItem {
Layout.fillWidth: true id: image
Layout.alignment: Qt.AlignTop Layout.alignment: Qt.AlignTop
spacing: 0 Layout.preferredWidth: PlasmaCore.Units.iconSizes.medium
Layout.preferredHeight: PlasmaCore.Units.iconSizes.medium
source: root.icon.name
}
RowLayout { ColumnLayout {
Layout.fillWidth: true Layout.fillWidth: true
spacing: PlasmaCore.Units.smallSpacing Layout.alignment: Qt.AlignTop
spacing: 0
PlasmaComponents3.Label { RowLayout {
id: title
Layout.fillWidth: true 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 { PlasmaComponents3.Slider {
id: percent id: control
Layout.alignment: Qt.AlignRight Layout.fillWidth: true
text: i18nc("Placeholder is brightness percentage", "%1%", root.percentage)
}
}
PlasmaComponents3.Slider { activeFocusOnTab: false
id: control // Don't allow the slider to turn off the screen
Layout.fillWidth: true // Please see https://git.reviewboard.kde.org/r/122505/ for more information
// Don't allow the slider to turn off the screen from: to > 100 ? 1 : 0
// Please see https://git.reviewboard.kde.org/r/122505/ for more information stepSize: 1
from: to > 100 ? 1 : 0
stepSize: 1
Accessible.name: root.label Accessible.name: root.text
Accessible.description: percent.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 { PlasmaExtras.Representation {
id: dialog id: dialog
property alias model: batteryList.model property alias model: batteryRepeater.model
property bool pluggedIn property bool pluggedIn
property int remainingTime property int remainingTime
@ -48,6 +48,8 @@ PlasmaExtras.Representation {
collapseMarginsHint: true collapseMarginsHint: true
KeyNavigation.down: pmSwitch.pmCheckBox
header: PlasmaExtras.PlasmoidHeading { header: PlasmaExtras.PlasmoidHeading {
leftPadding: PlasmaCore.Units.smallSpacing leftPadding: PlasmaCore.Units.smallSpacing
contentItem: PowerManagementItem { contentItem: PowerManagementItem {
@ -57,127 +59,134 @@ PlasmaExtras.Representation {
inhibitsLidAction: dialog.inhibitsLidAction inhibitsLidAction: dialog.inhibitsLidAction
pluggedIn: dialog.pluggedIn pluggedIn: dialog.pluggedIn
onDisabledChanged: powerManagementChanged(disabled) 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 { contentItem: PlasmaComponents3.ScrollView {
focus: true id: scrollView
anchors.fill: parent
focus: false
// HACK: workaround for https://bugreports.qt.io/browse/QTBUG-83890 // HACK: workaround for https://bugreports.qt.io/browse/QTBUG-83890
PlasmaComponents3.ScrollBar.horizontal.policy: PlasmaComponents3.ScrollBar.AlwaysOff PlasmaComponents3.ScrollBar.horizontal.policy: PlasmaComponents3.ScrollBar.AlwaysOff
contentItem: ListView { Column {
id: batteryList 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 readonly property Item firstHeaderItem: {
Connections { if (brightnessSlider.visible) {
target: batterymonitor return brightnessSlider;
function onScreenBrightnessChanged() { } else if (keyboardBrightnessSlider.visible) {
brightnessSlider.value = batterymonitor.screenBrightness; 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 { BrightnessItem {
id: keyboardBrightnessSlider id: brightnessSlider
Layout.fillWidth: true width: scrollView.availableWidth
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
}
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 KeyNavigation.up: pmSwitch.pmCheckBox
Connections { KeyNavigation.down: keyboardBrightnessSlider.visible ? keyboardBrightnessSlider : keyboardBrightnessSlider.KeyNavigation.down
target: batterymonitor KeyNavigation.backtab: KeyNavigation.up
function onKeyboardBrightnessChanged() { KeyNavigation.tab: KeyNavigation.down
keyboardBrightnessSlider.value = batterymonitor.keyboardBrightness; 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 { BrightnessItem {
id: powerProfileItem id: keyboardBrightnessSlider
Layout.fillWidth: true
width: scrollView.availableWidth
KeyNavigation.tab: batteryList
activeProfile: dialog.activeProfile icon.name: "input-keyboard-brightness"
inhibitionReason: dialog.inhibitionReason text: i18n("Keyboard Brightness")
visible: dialog.profiles.length > 0 showPercentage: false
degradationReason: dialog.degradationReason value: batterymonitor.keyboardBrightness
profileHolds: dialog.profileHolds maximumValue: batterymonitor.maximumKeyboardBrightness
onActivateProfileRequested: dialog.activateProfileRequested(profile) visible: isKeyboardBrightnessAvailable
}
Item { KeyNavigation.up: brightnessSlider.visible ? brightnessSlider : brightnessSlider.KeyNavigation.up
Layout.fillWidth: true KeyNavigation.down: powerProfileItem.visible ? powerProfileItem : powerProfileItem.KeyNavigation.down
// additional margin, because the bottom of PowerProfileItem KeyNavigation.backtab: KeyNavigation.up
// and the top of BatteryItem are more dense. 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 { PowerProfileItem {
width: ListView.view.width - PlasmaCore.Units.smallSpacing * 4 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 activeProfile: dialog.activeProfile
remainingTime: dialog.remainingTime inhibitionReason: dialog.inhibitionReason
matchHeightOfSlider: ListView.view.headerItem ? ListView.view.headerItem.children[1].slider : null 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 { ColumnLayout {
id: root id: root
property alias pmCheckBox: pmCheckBox
property alias disabled: pmCheckBox.checked property alias disabled: pmCheckBox.checked
property bool pluggedIn property bool pluggedIn
@ -35,6 +36,12 @@ ColumnLayout {
Layout.fillWidth: true Layout.fillWidth: true
text: i18nc("Minimize the length of this string as much as possible", "Manually block sleep and screen locking") text: i18nc("Minimize the length of this string as much as possible", "Manually block sleep and screen locking")
checked: false 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 // Separator line

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

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

Loading…
Cancel
Save