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. 24
      applets/batterymonitor/package/contents/ui/BatteryItem.qml
  2. 20
      applets/batterymonitor/package/contents/ui/BrightnessItem.qml
  3. 119
      applets/batterymonitor/package/contents/ui/PopupDialog.qml
  4. 7
      applets/batterymonitor/package/contents/ui/PowerManagementItem.qml
  5. 20
      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,6 +54,13 @@ RowLayout {
property PlasmaComponents3.Slider matchHeightOfSlider: PlasmaComponents3.Slider {}
readonly property real extraMargin: Math.max(0, Math.floor((matchHeightOfSlider.height - chargeBar.height) / 2))
background.visible: highlighted
highlighted: activeFocus
text: battery["Pretty Name"]
Accessible.description: `${isPowerSupplyLabel.text} ${percentLabel.text}; ${details.Accessible.description}`
contentItem: RowLayout {
spacing: PlasmaCore.Units.gridUnit
BatteryIcon {
@ -80,16 +87,18 @@ RowLayout {
PlasmaComponents3.Label {
Layout.fillWidth: true
elide: Text.ElideRight
text: root.battery["Pretty Name"]
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)
@ -122,6 +131,16 @@ RowLayout {
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
@ -198,4 +217,5 @@ RowLayout {
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,6 +24,15 @@ RowLayout {
signal moved()
background.visible: highlighted
highlighted: activeFocus
hoverEnabled: false
Accessible.description: percent.text
Accessible.role: Accessible.Slider
Keys.forwardTo: [slider]
contentItem: RowLayout {
spacing: PlasmaCore.Units.gridUnit
PlasmaCore.IconItem {
@ -33,6 +40,7 @@ RowLayout {
Layout.alignment: Qt.AlignTop
Layout.preferredWidth: PlasmaCore.Units.iconSizes.medium
Layout.preferredHeight: PlasmaCore.Units.iconSizes.medium
source: root.icon.name
}
ColumnLayout {
@ -47,6 +55,7 @@ RowLayout {
PlasmaComponents3.Label {
id: title
Layout.fillWidth: true
text: root.text
}
PlasmaComponents3.Label {
@ -59,15 +68,18 @@ RowLayout {
PlasmaComponents3.Slider {
id: control
Layout.fillWidth: true
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.name: root.text
Accessible.description: percent.text
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,60 +59,58 @@ 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
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: brightnessSlider
Layout.fillWidth: true
width: scrollView.availableWidth
icon: "video-display-brightness"
label: i18n("Display Brightness")
icon.name: "video-display-brightness"
text: 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
}
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
@ -127,19 +127,19 @@ PlasmaExtras.Representation {
BrightnessItem {
id: keyboardBrightnessSlider
Layout.fillWidth: true
width: scrollView.availableWidth
icon: "input-keyboard-brightness"
label: i18n("Keyboard Brightness")
icon.name: "input-keyboard-brightness"
text: 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
}
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
@ -154,9 +154,14 @@ PlasmaExtras.Representation {
PowerProfileItem {
id: powerProfileItem
Layout.fillWidth: true
KeyNavigation.tab: batteryList
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
activeProfile: dialog.activeProfile
inhibitionReason: dialog.inhibitionReason
visible: dialog.profiles.length > 0
@ -164,20 +169,24 @@ PlasmaExtras.Representation {
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.
}
}
Repeater {
id: batteryRepeater
delegate: BatteryItem {
width: ListView.view.width - PlasmaCore.Units.smallSpacing * 4
width: scrollView.availableWidth
battery: model
remainingTime: dialog.remainingTime
matchHeightOfSlider: ListView.view.headerItem ? ListView.view.headerItem.children[1].slider : null
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,6 +53,16 @@ RowLayout {
signal activateProfileRequested(string profile)
background.visible: highlighted
highlighted: activeFocus
hoverEnabled: false
text: i18n("Power Profile")
Accessible.description: activeProfileLabel.text
Accessible.role: Accessible.Slider
Keys.forwardTo: [slider]
contentItem: RowLayout {
spacing: PlasmaCore.Units.gridUnit
PlasmaCore.IconItem {
@ -72,18 +84,21 @@ RowLayout {
PlasmaComponents3.Label {
Layout.fillWidth: true
elide: Text.ElideRight
text: i18n("Power Profile")
text: root.text
}
PlasmaComponents3.Label {
id: activeProfileLabel
Layout.alignment: Qt.AlignRight
text: activeProfileData ? activeProfileData.label : ""
}
}
PlasmaComponents3.Slider {
id: slider
Layout.fillWidth: true
activeFocusOnTab: false
from: 0
to: 2
stepSize: 1
@ -237,4 +252,5 @@ RowLayout {
|| 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