mirror of
https://gitgud.io/wackyideas/aerothemeplasma.git
synced 2024-08-15 00:43:43 +00:00
Very early KDE 6 release.
This commit is contained in:
parent
7cc4ccabbc
commit
686046d4f7
6272 changed files with 140920 additions and 529657 deletions
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2011 Viranch Mehta <viranch.mehta@gmail.com>
|
||||
* SPDX-FileCopyrightText: 2013 Kai Uwe Broulik <kde@privat.broulik.de>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property bool hasBattery
|
||||
property int percent
|
||||
property bool pluggedIn
|
||||
property string batteryType
|
||||
property bool active: false
|
||||
property string powerProfileIconName: ""
|
||||
property int health
|
||||
property bool broken
|
||||
|
||||
// Icon for current charge level, charging status, and optionally power
|
||||
// profile indication (for batteries that support it by setting
|
||||
// "powerProfileIconName" to something other than an empty string).
|
||||
Kirigami.Icon {
|
||||
anchors.fill: parent
|
||||
source: root.hasBattery ? fillElement(root.percent, root.health, root.broken) : "battery-missing"
|
||||
visible: !otherBatteriesIcon.visible
|
||||
active: root.active
|
||||
|
||||
function fillElement(p: int, h: int, b: bool): string {
|
||||
let name
|
||||
|
||||
if(b && typeof h !== "undefined") {
|
||||
return "battery-missing"
|
||||
}
|
||||
|
||||
if (p >= 95) {
|
||||
name = "battery-100";
|
||||
} else if (p >= 85) {
|
||||
name = "battery-090";
|
||||
} else if (p >= 75) {
|
||||
name = "battery-080";
|
||||
} else if (p >= 65) {
|
||||
name = "battery-070";
|
||||
} else if (p >= 55) {
|
||||
name = "battery-060";
|
||||
} else if (p >= 45) {
|
||||
name = "battery-050";
|
||||
} else if (p >= 35) {
|
||||
name = "battery-040";
|
||||
} else if (p >= 25) {
|
||||
name = "battery-030";
|
||||
} else if (p >= 15) {
|
||||
name = "battery-020";
|
||||
} else if (p > 5) {
|
||||
name = "battery-010";
|
||||
} else {
|
||||
name = "battery-000";
|
||||
}
|
||||
|
||||
if (root.pluggedIn) {
|
||||
name += "-charging";
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
// Generic icon for other types of batteries
|
||||
Kirigami.Icon {
|
||||
id: otherBatteriesIcon
|
||||
anchors.fill: parent
|
||||
source: elementForType(root.batteryType)
|
||||
visible: source !== ""
|
||||
active: root.active
|
||||
|
||||
function elementForType(t: string): string {
|
||||
switch(t) {
|
||||
case "Mouse":
|
||||
return "input-mouse-battery";
|
||||
case "Keyboard":
|
||||
return "input-keyboard-battery";
|
||||
case "Pda":
|
||||
return "phone-battery";
|
||||
case "Phone":
|
||||
return "phone-battery";
|
||||
case "Ups":
|
||||
return "battery-ups";
|
||||
case "GamingInput":
|
||||
return "input-gaming-battery";
|
||||
case "Bluetooth":
|
||||
return "preferences-system-bluetooth-battery";
|
||||
case "Headset":
|
||||
return "audio-headset-battery";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2012-2013 Daniel Nicoletti <dantti12@gmail.com>
|
||||
SPDX-FileCopyrightText: 2013-2015 Kai Uwe Broulik <kde@privat.broulik.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.kde.coreaddons as KCoreAddons
|
||||
import org.kde.plasma.components as PlasmaComponents3
|
||||
//import org.kde.plasma.workspace.components
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
import "logic.js" as Logic
|
||||
|
||||
PlasmaComponents3.ItemDelegate {
|
||||
id: root
|
||||
|
||||
// We'd love to use `required` properties, especially since the model provides role names for them;
|
||||
// but unfortunately some of those roles have whitespaces in their name, which QML doesn't have any
|
||||
// workaround for (raw identifiers like r#try in Rust would've helped here).
|
||||
//
|
||||
// type: {
|
||||
// Capacity: int,
|
||||
// Energy: real,
|
||||
// "Is Power Supply": bool,
|
||||
// Percent: int,
|
||||
// "Plugged In": bool,
|
||||
// "Pretty Name": string,
|
||||
// Product: string,
|
||||
// State: "Discharging"|"Charging"|"FullyCharged"|etc.,
|
||||
// Type: string,
|
||||
// Vendor: string,
|
||||
// }?
|
||||
property var battery
|
||||
|
||||
// NOTE: According to the UPower spec this property is only valid for primary batteries, however
|
||||
// UPower seems to set the Present property false when a device is added but not probed yet
|
||||
readonly property bool isPresent: root.battery["Plugged in"]
|
||||
|
||||
readonly property bool isPowerSupply: root.battery["Is Power Supply"]
|
||||
|
||||
readonly property bool isBroken: root.battery.Capacity > 0 && root.battery.Capacity < 50
|
||||
|
||||
property int remainingTime: 0
|
||||
|
||||
// Existing instance of a slider to use as a reference to calculate extra
|
||||
// margins for a progress bar, so that the row of labels on top of it
|
||||
// could visually look as if it were on the same distance from the bar as
|
||||
// they are from the slider.
|
||||
property PlasmaComponents3.Slider matchHeightOfSlider: PlasmaComponents3.Slider {}
|
||||
readonly property real extraMargin: Math.max(0, Math.floor((matchHeightOfSlider.height/* - chargeBar.height*/) / 2))
|
||||
|
||||
|
||||
highlighted: false
|
||||
down: false
|
||||
hoverEnabled: false
|
||||
text: battery["Pretty Name"]
|
||||
|
||||
property int batteryIndex
|
||||
|
||||
property string detailsDescription: {
|
||||
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(" ");
|
||||
}
|
||||
|
||||
Accessible.description: `${Logic.stringForBatteryState(root.battery, pmSource)} ${i18nc("Placeholder is battery percentage", "%1%", root.battery.Percent)}; ${detailsDescription}`
|
||||
|
||||
contentItem: RowLayout {
|
||||
//spacing: Kirigami.Units.gridUnit
|
||||
|
||||
FlyoutBatteryIcon {
|
||||
id: batteryIcon
|
||||
|
||||
visible: batteryIndex === 0
|
||||
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.medium
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.medium
|
||||
|
||||
batteryType: root.battery.Type
|
||||
percent: root.battery.Percent
|
||||
hasBattery: root.isPresent
|
||||
pluggedIn: root.battery.State === "Charging" && root.battery["Is Power Supply"]
|
||||
broken: root.isBroken
|
||||
health: root.battery.Capacity
|
||||
}
|
||||
|
||||
PlasmaComponents3.Label {
|
||||
id: batteryName
|
||||
//visible: batteryIndex !== 0
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignTop
|
||||
wrapMode: Text.Wrap
|
||||
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"]
|
||||
text: {
|
||||
if(batteryIndex === 0) {
|
||||
var txt = ""
|
||||
if(!root.isPresent)
|
||||
txt = "No battery is detected"
|
||||
else if(root.battery.State == "FullyCharged" || batterymonitor.isSomehowFullyCharged)
|
||||
txt = `Fully charged (${root.battery.Percent}%)`
|
||||
else
|
||||
txt = root.battery.Percent + "% available" + (root.battery.State == "Charging" ? " (plugged in, charging)" : "")
|
||||
|
||||
if(pluggedIn && root.isPowerSupply && typeof chargeStopThreshold === "number" && chargeStopThreshold > 0 && chargeStopThreshold < 100)
|
||||
txt += "\n" + i18n("Battery is configured to charge up to approximately %1%.", chargeStopThreshold || 0)
|
||||
if(root.isBroken && typeof root.battery.Capacity !== "undefined")
|
||||
txt += "\nConsider replacing your battery."
|
||||
|
||||
return txt;
|
||||
} else {
|
||||
return `${root.text} #${batteryIndex}: ` + root.isPresent ? "Not present" : (root.battery.Percent + "% available")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: root.isPresent ? Qt.AlignTop : Qt.AlignVCenter
|
||||
spacing: 0
|
||||
|
||||
RowLayout {
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
PlasmaComponents3.Label {
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
text: root.text
|
||||
}
|
||||
|
||||
PlasmaComponents3.Label {
|
||||
id: isPowerSupplyLabel
|
||||
text: Logic.stringForBatteryState(root.battery, pmSource)
|
||||
// For non-power supply batteries only show label for known-good states
|
||||
visible: root.isPowerSupply || ["Discharging", "FullyCharged", "Charging"].includes(root.battery.State)
|
||||
enabled: false
|
||||
}
|
||||
|
||||
PlasmaComponents3.Label {
|
||||
id: percentLabel
|
||||
horizontalAlignment: Text.AlignRight
|
||||
visible: root.isPresent
|
||||
text: i18nc("Placeholder is battery percentage", "%1%", root.battery.Percent)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Kirigami.Units.smallSpacing
|
||||
|
||||
columns: 2
|
||||
columnSpacing: Kirigami.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: Kirigami.Theme.smallFont
|
||||
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: Kirigami.Theme.smallFont
|
||||
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: Kirigami.Theme.smallFont
|
||||
color: Kirigami.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)
|
||||
readonly property bool isEstimatingRemainingTime: root.battery !== null
|
||||
&& root.isPowerSupply
|
||||
&& root.remainingTime === 0
|
||||
&& root.battery.State === "Discharging"
|
||||
|
||||
LeftLabel {
|
||||
text: root.battery.State === "Charging"
|
||||
? i18n("Time To Full:")
|
||||
: i18n("Remaining Time:")
|
||||
visible: details.remainingTimeRowVisible || details.isEstimatingRemainingTime
|
||||
}
|
||||
|
||||
RightLabel {
|
||||
text: details.isEstimatingRemainingTime ? i18nc("@info", "Estimating…")
|
||||
: KCoreAddons.Format.formatDuration(root.remainingTime, KCoreAddons.FormatTypes.HideSeconds)
|
||||
visible: details.remainingTimeRowVisible || details.isEstimatingRemainingTime
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
InhibitionHint {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Kirigami.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)
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2011 Sebastian Kügler <sebas@kde.org>
|
||||
SPDX-FileCopyrightText: 2011 Viranch Mehta <viranch.mehta@gmail.com>
|
||||
SPDX-FileCopyrightText: 2013 Kai Uwe Broulik <kde@privat.broulik.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.kde.plasma.plasmoid
|
||||
import org.kde.plasma.core as PlasmaCore
|
||||
import org.kde.plasma.workspace.components as WorkspaceComponents
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
MouseArea {
|
||||
id: root
|
||||
|
||||
property real itemSize: Math.min(root.height, root.width/view.count)
|
||||
readonly property bool isConstrained: Plasmoid.formFactor === PlasmaCore.Types.Vertical || Plasmoid.formFactor === PlasmaCore.Types.Horizontal
|
||||
property real brightnessError: 0
|
||||
property QtObject batteries
|
||||
property bool hasBatteries: false
|
||||
required property bool isSetToPerformanceMode
|
||||
required property bool isSetToPowerSaveMode
|
||||
required property bool isSomehowFullyCharged
|
||||
|
||||
activeFocusOnTab: true
|
||||
hoverEnabled: true
|
||||
|
||||
property bool wasExpanded
|
||||
|
||||
Accessible.name: Plasmoid.title
|
||||
Accessible.description: `${toolTipMainText}; ${toolTipSubText}`
|
||||
Accessible.role: Accessible.Button
|
||||
|
||||
onPressed: wasExpanded = batterymonitor.expanded
|
||||
onClicked: batterymonitor.expanded = !wasExpanded
|
||||
|
||||
// "No Batteries" case
|
||||
Kirigami.Icon {
|
||||
anchors.fill: parent
|
||||
visible: !root.hasBatteries
|
||||
source: Plasmoid.icon
|
||||
active: root.containsMouse
|
||||
}
|
||||
|
||||
// We have any batteries; show their status
|
||||
//Should we consider turning this into a Flow item?
|
||||
Row {
|
||||
visible: root.hasBatteries
|
||||
anchors.centerIn: parent
|
||||
Repeater {
|
||||
id: view
|
||||
|
||||
model: root.isConstrained ? 1 : root.batteries
|
||||
|
||||
Item {
|
||||
id: batteryContainer
|
||||
|
||||
property int percent: root.isConstrained ? pmSource.data["Battery"]["Percent"] : model["Percent"]
|
||||
property bool pluggedIn: pmSource.data["AC Adapter"] && pmSource.data["AC Adapter"]["Plugged in"] && (root.isConstrained || model["Is Power Supply"])
|
||||
|
||||
height: root.itemSize
|
||||
width: root.width/view.count
|
||||
|
||||
property real iconSize: Math.min(width, height)
|
||||
|
||||
// "Held on a Power Profile mode while plugged in" use case; show the
|
||||
// icon of the active mode so the user can notice this at a glance
|
||||
/*Kirigami.Icon {
|
||||
id: powerProfileModeIcon
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
visible: batteryContainer.pluggedIn && (root.isSetToPerformanceMode || root.isSetToPowerSaveMode)
|
||||
source: root.isSetToPerformanceMode
|
||||
? "battery-profile-performance-symbolic"
|
||||
: "battery-profile-powersave-symbolic"
|
||||
active: root.containsMouse
|
||||
}*/
|
||||
|
||||
// Show normal battery icon
|
||||
BatteryIcon {
|
||||
id: batteryIcon
|
||||
|
||||
anchors.centerIn: parent
|
||||
height: batteryContainer.iconSize
|
||||
width: height
|
||||
|
||||
active: root.containsMouse
|
||||
visible: !(batteryContainer.pluggedIn && (root.isSetToPerformanceMode || root.isSetToPowerSaveMode))
|
||||
hasBattery: root.hasBatteries
|
||||
percent: batteryContainer.percent
|
||||
pluggedIn: batteryContainer.pluggedIn
|
||||
broken: batterymonitor.isBroken
|
||||
health: batterymonitor.batteryCapacity
|
||||
}
|
||||
|
||||
WorkspaceComponents.BadgeOverlay {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
|
||||
visible: Plasmoid.configuration.showPercentage && !root.isSomehowFullyCharged
|
||||
|
||||
text: i18nc("battery percentage below battery icon", "%1%", percent)
|
||||
icon: batteryIcon
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2011 Viranch Mehta <viranch.mehta@gmail.com>
|
||||
* SPDX-FileCopyrightText: 2013 Kai Uwe Broulik <kde@privat.broulik.de>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property bool hasBattery
|
||||
property int percent
|
||||
property bool pluggedIn
|
||||
property string batteryType
|
||||
property bool active: false
|
||||
property string powerProfileIconName: ""
|
||||
property int health
|
||||
property bool broken
|
||||
|
||||
// Icon for current charge level, charging status, and optionally power
|
||||
// profile indication (for batteries that support it by setting
|
||||
// "powerProfileIconName" to something other than an empty string).
|
||||
Kirigami.Icon {
|
||||
id: mainBattery
|
||||
anchors.fill: parent
|
||||
source: root.hasBattery ? fillElement(root.percent, root.health, root.broken) : "flyout-battery-missing"
|
||||
visible: !otherBatteriesIcon.visible
|
||||
active: root.active
|
||||
|
||||
function fillElement(p: int, h: int, b: bool): string {
|
||||
let name = "flyout-"
|
||||
|
||||
if(b && typeof h !== "undefined") {
|
||||
return "flyout-battery-missing"
|
||||
}
|
||||
|
||||
if (p >= 95) {
|
||||
name += "battery-100";
|
||||
} else if (p >= 85) {
|
||||
name += "battery-090";
|
||||
} else if (p >= 75) {
|
||||
name += "battery-080";
|
||||
} else if (p >= 65) {
|
||||
name += "battery-070";
|
||||
} else if (p >= 55) {
|
||||
name += "battery-060";
|
||||
} else if (p >= 45) {
|
||||
name += "battery-050";
|
||||
} else if (p >= 35) {
|
||||
name += "battery-040";
|
||||
} else if (p >= 25) {
|
||||
name += "battery-030";
|
||||
} else if (p >= 15) {
|
||||
name += "battery-020";
|
||||
} else if (p > 5) {
|
||||
name += "battery-010";
|
||||
} else {
|
||||
name += "battery-000";
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
}
|
||||
Kirigami.Icon {
|
||||
anchors.fill: parent
|
||||
visible: !otherBatteriesIcon.visible && source != ""
|
||||
active: root.active
|
||||
source: {
|
||||
|
||||
if(batterymonitor.isPluggedIn) {
|
||||
return "flyout-battery-charging"
|
||||
} else if(mainBattery.source === "flyout-battery-000") {
|
||||
return "flyout-battery-critical";
|
||||
} else if(mainBattery.source === "flyout-battery-010") {
|
||||
return "flyout-battery-caution";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// Generic icon for other types of batteries
|
||||
Kirigami.Icon {
|
||||
id: otherBatteriesIcon
|
||||
anchors.fill: parent
|
||||
source: elementForType(root.batteryType)
|
||||
visible: source !== ""
|
||||
active: root.active
|
||||
|
||||
function elementForType(t: string): string {
|
||||
switch(t) {
|
||||
case "Mouse":
|
||||
return "input-mouse-battery";
|
||||
case "Keyboard":
|
||||
return "input-keyboard-battery";
|
||||
case "Pda":
|
||||
return "phone-battery";
|
||||
case "Phone":
|
||||
return "phone-battery";
|
||||
case "Ups":
|
||||
return "battery-ups";
|
||||
case "GamingInput":
|
||||
return "input-gaming-battery";
|
||||
case "Bluetooth":
|
||||
return "preferences-system-bluetooth-battery";
|
||||
case "Headset":
|
||||
return "audio-headset-battery";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2015 Kai Uwe Broulik <kde@privat.broulik.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.kde.plasma.components as PlasmaComponents3
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
RowLayout {
|
||||
property alias iconSource: iconItem.source
|
||||
property alias text: label.text
|
||||
property int leftPadding: 0
|
||||
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
Kirigami.Icon {
|
||||
id: iconItem
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.small
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.small
|
||||
Layout.leftMargin: leftPadding
|
||||
Layout.alignment: Qt.AlignTop
|
||||
visible: valid
|
||||
}
|
||||
|
||||
PlasmaComponents3.Label {
|
||||
id: label
|
||||
Layout.fillWidth: true
|
||||
//font: Kirigami.Theme.smallFont
|
||||
wrapMode: Text.WordWrap
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 4
|
||||
}
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2011 Viranch Mehta <viranch.mehta@gmail.com>
|
||||
SPDX-FileCopyrightText: 2013-2016 Kai Uwe Broulik <kde@privat.broulik.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.kde.plasma.components as PlasmaComponents3
|
||||
import org.kde.plasma.extras as PlasmaExtras
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
PlasmaExtras.Representation {
|
||||
id: dialog
|
||||
|
||||
property alias model: batteryRepeater.model
|
||||
property bool pluggedIn
|
||||
|
||||
property int remainingTime
|
||||
|
||||
property var profilesInstalled
|
||||
property string activeProfile
|
||||
property var profiles
|
||||
|
||||
// List of active power management inhibitions (applications that are
|
||||
// blocking sleep and screen locking).
|
||||
//
|
||||
// type: [{
|
||||
// Icon: string,
|
||||
// Name: string,
|
||||
// Reason: string,
|
||||
// }]
|
||||
property var inhibitions: []
|
||||
property bool manuallyInhibited
|
||||
property bool inhibitsLidAction
|
||||
|
||||
property string inhibitionReason
|
||||
property string degradationReason
|
||||
// type: [{ Name: string, Icon: string, Profile: string, Reason: string }]
|
||||
required property var profileHolds
|
||||
|
||||
signal powerManagementChanged(bool disabled)
|
||||
signal inhibitionChangeRequested(bool inhibit)
|
||||
signal activateProfileRequested(string profile)
|
||||
|
||||
collapseMarginsHint: true
|
||||
|
||||
KeyNavigation.down: pmSwitch.pmCheckBox
|
||||
|
||||
//footer:
|
||||
|
||||
contentItem: PlasmaComponents3.ScrollView {
|
||||
id: scrollView
|
||||
|
||||
focus: false
|
||||
|
||||
PlasmaComponents3.ScrollBar.horizontal.policy: PlasmaComponents3.ScrollBar.AlwaysOff
|
||||
function positionViewAtItem(item) {
|
||||
if (!PlasmaComponents3.ScrollBar.vertical.visible) {
|
||||
return;
|
||||
}
|
||||
const rect = batteryList.mapFromItem(item, 0, 0, item.width, item.height);
|
||||
if (rect.y < scrollView.contentItem.contentY) {
|
||||
scrollView.contentItem.contentY = rect.y;
|
||||
} else if (rect.y + rect.height > scrollView.contentItem.contentY + scrollView.height) {
|
||||
scrollView.contentItem.contentY = rect.y + rect.height - scrollView.height;
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: batteryList
|
||||
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
readonly property Item firstHeaderItem: {
|
||||
if (powerProfileItem.visible) {
|
||||
return powerProfileItem;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
readonly property Item lastHeaderItem: {
|
||||
if (powerProfileItem.visible) {
|
||||
return powerProfileItem;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: batteryRepeater
|
||||
|
||||
delegate: BatteryItem {
|
||||
width: scrollView.availableWidth
|
||||
|
||||
battery: model
|
||||
remainingTime: dialog.remainingTime
|
||||
batteryIndex: index
|
||||
|
||||
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
|
||||
|
||||
Keys.onTabPressed: event => {
|
||||
if (index === batteryRepeater.count - 1) {
|
||||
// Workaround to leave applet's focus on desktop
|
||||
nextItemInFocusChain(false).forceActiveFocus(Qt.TabFocusReason);
|
||||
} else {
|
||||
event.accepted = false;
|
||||
}
|
||||
}
|
||||
|
||||
onActiveFocusChanged: if (activeFocus) scrollView.positionViewAtItem(this)
|
||||
}
|
||||
}
|
||||
Separator {
|
||||
width: scrollView.availableWidth
|
||||
visible: model.count !== 0
|
||||
}
|
||||
PowerProfileItem {
|
||||
id: powerProfileItem
|
||||
|
||||
width: scrollView.availableWidth
|
||||
|
||||
KeyNavigation.down: batteryRepeater.count > 0 ? batteryRepeater.itemAt(0) : null
|
||||
KeyNavigation.backtab: KeyNavigation.up
|
||||
KeyNavigation.tab: KeyNavigation.down
|
||||
|
||||
profilesInstalled: dialog.profilesInstalled
|
||||
profilesAvailable: dialog.profiles.length > 0
|
||||
activeProfile: dialog.activeProfile
|
||||
inhibitionReason: dialog.inhibitionReason
|
||||
degradationReason: dialog.degradationReason
|
||||
profileHolds: dialog.profileHolds
|
||||
|
||||
onActivateProfileRequested: profile => {
|
||||
dialog.activateProfileRequested(profile);
|
||||
}
|
||||
|
||||
onActiveFocusChanged: if (activeFocus) scrollView.positionViewAtItem(this)
|
||||
}
|
||||
|
||||
PowerManagementItem {
|
||||
id: pmSwitch
|
||||
width: scrollView.availableWidth
|
||||
inhibitions: dialog.inhibitions
|
||||
manuallyInhibited: dialog.manuallyInhibited
|
||||
inhibitsLidAction: dialog.inhibitsLidAction
|
||||
pluggedIn: dialog.pluggedIn
|
||||
|
||||
onInhibitionChangeRequested: inhibit => {
|
||||
dialog.inhibitionChangeRequested(inhibit);
|
||||
}
|
||||
|
||||
onDisabledChanged: dialog.powerManagementChanged(disabled)
|
||||
}
|
||||
InhibitionHint {
|
||||
width: scrollView.availableWidth
|
||||
visible: batterymonitor.isBroken && typeof batterymonitor.batteryCapacity !== "undefined"
|
||||
iconSource: "info"
|
||||
leftPadding: Kirigami.Units.iconSizes.small
|
||||
text: "There is a problem with your battery, so your computer might shut down suddenly."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2012-2013 Daniel Nicoletti <dantti12@gmail.com>
|
||||
SPDX-FileCopyrightText: 2013, 2015 Kai Uwe Broulik <kde@privat.broulik.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls as QtControls
|
||||
|
||||
import org.kde.kwindowsystem
|
||||
import org.kde.plasma.components as PlasmaComponents3
|
||||
import org.kde.ksvg as KSvg
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
property alias pmCheckBox: pmCheckBox
|
||||
property alias disabled: pmCheckBox.checked
|
||||
property bool pluggedIn
|
||||
|
||||
signal inhibitionChangeRequested(bool inhibit)
|
||||
|
||||
// List of active power management inhibitions (applications that are
|
||||
// blocking sleep and screen locking).
|
||||
//
|
||||
// type: [{
|
||||
// Icon: string,
|
||||
// Name: string,
|
||||
// Reason: string,
|
||||
// }]
|
||||
property var inhibitions: []
|
||||
property bool manuallyInhibited
|
||||
property bool inhibitsLidAction
|
||||
|
||||
// UI to manually inhibit sleep and screen locking
|
||||
QtControls.CheckBox {
|
||||
id: pmCheckBox
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: Kirigami.Units.largeSpacing
|
||||
text: i18nc("Minimize the length of this string as much as possible", "Manually block sleep and screen locking")
|
||||
checked: root.manuallyInhibited
|
||||
focus: true
|
||||
|
||||
KeyNavigation.up: dialog.KeyNavigation.up
|
||||
KeyNavigation.down: batteryList.children[0]
|
||||
KeyNavigation.backtab: dialog.KeyNavigation.backtab
|
||||
KeyNavigation.tab: KeyNavigation.down
|
||||
|
||||
onToggled: {
|
||||
inhibitionChangeRequested(checked)
|
||||
}
|
||||
}
|
||||
|
||||
// Separator line
|
||||
Separator {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Kirigami.Units.smallSpacing
|
||||
Layout.leftMargin: -Kirigami.Units.largeSpacing - Kirigami.Units.smallSpacing
|
||||
Layout.rightMargin: -Kirigami.Units.largeSpacing
|
||||
visible: inhibitionReasonsLayout.visible
|
||||
}
|
||||
/*KSvg.SvgItem {
|
||||
Layout.fillWidth: true
|
||||
|
||||
visible: inhibitionReasonsLayout.visible
|
||||
|
||||
imagePath: "widgets/line"
|
||||
elementId: "horizontal-line"
|
||||
}*/
|
||||
|
||||
// list of automatic inhibitions
|
||||
ColumnLayout {
|
||||
id: inhibitionReasonsLayout
|
||||
|
||||
Layout.fillWidth: true
|
||||
visible: root.inhibitsLidAction || (root.inhibitions.length > 0)
|
||||
Layout.leftMargin: Kirigami.Units.iconSizes.small
|
||||
Layout.rightMargin: Kirigami.Units.iconSizes.small
|
||||
|
||||
InhibitionHint {
|
||||
Layout.fillWidth: true
|
||||
visible: root.inhibitsLidAction
|
||||
iconSource: "computer-laptop"
|
||||
text: i18nc("Minimize the length of this string as much as possible", "Your laptop is configured not to sleep when closing the lid while an external monitor is connected.")
|
||||
}
|
||||
|
||||
PlasmaComponents3.Label {
|
||||
id: inhibitionExplanation
|
||||
Layout.fillWidth: true
|
||||
visible: root.inhibitions.length > 1
|
||||
//font: Kirigami.Theme.smallFont
|
||||
wrapMode: Text.WordWrap
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 3
|
||||
text: i18np("%1 application is currently blocking sleep and screen locking:",
|
||||
"%1 applications are currently blocking sleep and screen locking:",
|
||||
root.inhibitions.length)
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: root.inhibitions
|
||||
|
||||
InhibitionHint {
|
||||
property string icon: modelData.Icon
|
||||
|| (KWindowSystem.isPlatformWayland ? "wayland" : "xorg")
|
||||
property string name: modelData.Name
|
||||
property string reason: modelData.Reason
|
||||
|
||||
Layout.fillWidth: true
|
||||
iconSource: icon
|
||||
text: {
|
||||
if (root.inhibitions.length === 1) {
|
||||
if (reason && name) {
|
||||
return i18n("%1 is currently blocking sleep and screen locking (%2)", name, reason)
|
||||
} else if (name) {
|
||||
return i18n("%1 is currently blocking sleep and screen locking (unknown reason)", name)
|
||||
} else if (reason) {
|
||||
return i18n("An application is currently blocking sleep and screen locking (%1)", reason)
|
||||
} else {
|
||||
return i18n("An application is currently blocking sleep and screen locking (unknown reason)")
|
||||
}
|
||||
} else {
|
||||
if (reason && name) {
|
||||
return i18nc("Application name: reason for preventing sleep and screen locking", "%1: %2", name, reason)
|
||||
} else if (name) {
|
||||
return i18nc("Application name: reason for preventing sleep and screen locking", "%1: unknown reason", name)
|
||||
} else if (reason) {
|
||||
return i18nc("Application name: reason for preventing sleep and screen locking", "Unknown application: %1", reason)
|
||||
} else {
|
||||
return i18nc("Application name: reason for preventing sleep and screen locking", "Unknown application: unknown reason")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,307 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 Kai Uwe Broulik <kde@broulik.de>
|
||||
* SPDX-FileCopyrightText: 2021 David Redondo <kde@david-redondo.de>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls as QtControls
|
||||
|
||||
import org.kde.plasma.components as PlasmaComponents3
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
PlasmaComponents3.ItemDelegate {
|
||||
id: root
|
||||
|
||||
//property alias slider: slider
|
||||
|
||||
property bool profilesInstalled
|
||||
property bool profilesAvailable
|
||||
|
||||
property string activeProfile
|
||||
|
||||
property string inhibitionReason
|
||||
readonly property bool inhibited: inhibitionReason !== ""
|
||||
|
||||
property string degradationReason
|
||||
|
||||
// type: [{ Name: string, Icon: string, Profile: string, Reason: string }]
|
||||
required property var profileHolds
|
||||
|
||||
// The canBeInhibited property mean that this profile's availability
|
||||
// depends on root.inhibited value (and thus on the
|
||||
// inhibitionReason string).
|
||||
readonly property var profileData: [
|
||||
{
|
||||
label: i18n("Power Save"),
|
||||
profile: "power-saver",
|
||||
canBeInhibited: false,
|
||||
}, {
|
||||
label: i18n("Balanced"),
|
||||
profile: "balanced",
|
||||
canBeInhibited: false,
|
||||
}, {
|
||||
label: i18n("Performance"),
|
||||
profile: "performance",
|
||||
canBeInhibited: true,
|
||||
}
|
||||
]
|
||||
|
||||
readonly property int activeProfileIndex: profileData.findIndex(data => data.profile === activeProfile)
|
||||
// type: typeof(profileData[])?
|
||||
readonly property var activeProfileData: activeProfileIndex !== -1 ? profileData[activeProfileIndex] : undefined
|
||||
// type: typeof(profileHolds)
|
||||
readonly property var activeHolds: profileHolds.filter(hold => hold.Profile === activeProfile)
|
||||
|
||||
signal activateProfileRequested(string profile)
|
||||
|
||||
highlighted: false
|
||||
down: false
|
||||
//background.visible: highlighted
|
||||
//highlighted: activeFocus
|
||||
//hoverEnabled: false
|
||||
//text: i18n("Power Profile")
|
||||
|
||||
Accessible.description: !root.profilesAvailable ? i18nc("Power profile", "Not available") : activeProfileData ? activeProfileData.label : ""
|
||||
Accessible.role: Accessible.Slider
|
||||
//Keys.forwardTo: [slider]
|
||||
|
||||
contentItem: RowLayout {
|
||||
spacing: Kirigami.Units.gridUnit
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignTop
|
||||
spacing: 0
|
||||
|
||||
/*RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
PlasmaComponents3.Label {
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
text: root.text
|
||||
}
|
||||
|
||||
PlasmaComponents3.Label {
|
||||
id: activeProfileLabel
|
||||
Layout.alignment: Qt.AlignRight
|
||||
text: !root.profilesAvailable ? i18nc("Power profile", "Not available") : activeProfileData ? activeProfileData.label : ""
|
||||
enabled: root.profilesAvailable
|
||||
}
|
||||
}*/
|
||||
|
||||
ColumnLayout {
|
||||
id: profileConfiguration
|
||||
|
||||
|
||||
visible: root.profilesAvailable
|
||||
PlasmaComponents3.Label {
|
||||
text: "Select a power plan:"
|
||||
opacity: 0.75
|
||||
}
|
||||
QtControls.ButtonGroup {
|
||||
buttons: radioButtons.children
|
||||
onClicked: (button) => {
|
||||
const { canBeInhibited, profile } = root.profileData[button.value];
|
||||
if (!(canBeInhibited && root.inhibited)) {
|
||||
activateProfileRequested(profile);
|
||||
}/* else {
|
||||
value = Qt.binding(() => root.activeProfileIndex);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
id: radioButtons
|
||||
QtControls.RadioButton {
|
||||
id: balancedRadio
|
||||
property string profileId: "balanced"
|
||||
property int value: 1
|
||||
text: root.profileData.find(profile => profile.profile === profileId).label
|
||||
checked: activeProfileData.profile == profileId
|
||||
}
|
||||
QtControls.RadioButton {
|
||||
id: powerSaverRadio
|
||||
property string profileId: "power-saver"
|
||||
property int value: 0
|
||||
text: root.profileData.find(profile => profile.profile === profileId).label
|
||||
checked: activeProfileData.profile == profileId
|
||||
}
|
||||
QtControls.RadioButton {
|
||||
id: performanceRadio
|
||||
property string profileId: "performance"
|
||||
property int value: 2
|
||||
text: root.profileData.find(profile => profile.profile === profileId).label
|
||||
checked: activeProfileData.profile == profileId
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*PlasmaComponents3.Slider {
|
||||
id: slider
|
||||
visible: root.profilesAvailable
|
||||
Layout.fillWidth: true
|
||||
|
||||
activeFocusOnTab: false
|
||||
from: 0
|
||||
to: 2
|
||||
stepSize: 1
|
||||
value: root.activeProfileIndex
|
||||
snapMode: PlasmaComponents3.Slider.SnapAlways
|
||||
onMoved: {
|
||||
|
||||
}
|
||||
|
||||
// fake having a disabled second half
|
||||
Rectangle {
|
||||
z: -1
|
||||
visible: root.inhibited
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
anchors {
|
||||
top: parent.background.top
|
||||
left: parent.horizontalCenter
|
||||
leftMargin: 1
|
||||
right: parent.right
|
||||
bottom: parent.background.bottom
|
||||
}
|
||||
opacity: 0.4
|
||||
}
|
||||
}*/
|
||||
|
||||
/*RowLayout {
|
||||
spacing: 0
|
||||
visible: root.profilesAvailable
|
||||
Layout.topMargin: Kirigami.Units.smallSpacing
|
||||
Layout.bottomMargin: Kirigami.Units.smallSpacing
|
||||
Layout.fillWidth: true
|
||||
|
||||
Kirigami.Icon {
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.smallMedium
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.smallMedium
|
||||
source: "battery-profile-powersave-symbolic"
|
||||
|
||||
HoverHandler {
|
||||
id: powersaveIconHover
|
||||
}
|
||||
|
||||
PlasmaComponents3.ToolTip {
|
||||
text: root.profileData.find(profile => profile.profile === "power-saver").label
|
||||
visible: powersaveIconHover.hovered
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Kirigami.Icon {
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.smallMedium
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.smallMedium
|
||||
source: "battery-profile-performance-symbolic"
|
||||
|
||||
HoverHandler {
|
||||
id: performanceIconHover
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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.")
|
||||
}
|
||||
}
|
||||
|
||||
InhibitionHint {
|
||||
id: inhibitionPerformanceHint
|
||||
|
||||
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.")
|
||||
}
|
||||
}
|
||||
|
||||
InhibitionHint {
|
||||
id: inhibitionHoldersHint
|
||||
|
||||
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))
|
||||
: ""
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: repeater
|
||||
|
||||
model: root.activeHolds
|
||||
|
||||
InhibitionHint {
|
||||
Layout.fillWidth: true
|
||||
|
||||
x: Kirigami.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: Kirigami.Units.smallSpacing
|
||||
|
||||
visible: repeater.visibleChildren > 0
|
||||
|| inhibitionReasonHint.visible
|
||||
|| inhibitionPerformanceHint.visible
|
||||
|| inhibitionHoldersHint.visible
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
visible: !root.profilesInstalled
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
PlasmaComponents3.Label {
|
||||
text: xi18n("Power profiles may be supported on your device.<nl/>Try installing the <command>power-profiles-daemon</command> package using your distribution's package manager and restarting the system.")
|
||||
enabled: false
|
||||
font: Kirigami.Theme.smallFont
|
||||
wrapMode: Text.Wrap
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
import QtQuick 2.0
|
||||
import QtQuick.Layouts
|
||||
|
||||
Rectangle {
|
||||
id: separator
|
||||
height: 1
|
||||
color: "#dde0e2"
|
||||
}
|
56
plasma/plasmoids/org.kde.plasma.battery/contents/ui/logic.js
Normal file
56
plasma/plasmoids/org.kde.plasma.battery/contents/ui/logic.js
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2011 Sebastian Kügler <sebas@kde.org>
|
||||
SPDX-FileCopyrightText: 2012 Viranch Mehta <viranch.mehta@gmail.com>
|
||||
SPDX-FileCopyrightText: 2014-2016 Kai Uwe Broulik <kde@privat.broulik.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
function stringForBatteryState(batteryData, source) {
|
||||
if (batteryData["Plugged in"]) {
|
||||
// When we are using a charge threshold, the kernel
|
||||
// may stop charging within a percentage point of the actual threshold
|
||||
// and this is considered correct behavior, so we have to handle
|
||||
// that. See https://bugzilla.kernel.org/show_bug.cgi?id=215531.
|
||||
if (typeof source.data["Battery"]["Charge Stop Threshold"] === "number"
|
||||
&& (batteryData.Percent >= source.data["Battery"]["Charge Stop Threshold"] - 1
|
||||
&& batteryData.Percent <= source.data["Battery"]["Charge Stop Threshold"] + 1)
|
||||
// Also, Upower may give us a status of "Not charging" rather than
|
||||
// "Fully charged", so we need to account for that as well. See
|
||||
// https://gitlab.freedesktop.org/upower/upower/-/issues/142.
|
||||
&& (batteryData.State === "NoCharge" || batteryData.State === "FullyCharged")
|
||||
&& batteryData["Is Power Supply"]
|
||||
) {
|
||||
return i18n("Fully Charged");
|
||||
}
|
||||
|
||||
// Otherwise, just look at the charge state
|
||||
switch(batteryData["State"]) {
|
||||
case "Discharging": return i18n("Discharging");
|
||||
case "FullyCharged": return i18n("Fully Charged");
|
||||
case "Charging": return i18n("Charging");
|
||||
// when in doubt we're not charging
|
||||
default: return i18n("Not Charging");
|
||||
}
|
||||
} else {
|
||||
return i18nc("Battery is currently not present in the bay", "Not present");
|
||||
}
|
||||
}
|
||||
|
||||
function updateInhibitions(rootItem, source) {
|
||||
const inhibitions = [];
|
||||
const manualInhibitions = [];
|
||||
|
||||
if (source.data["Inhibitions"]) {
|
||||
for (let key in pmSource.data["Inhibitions"]) {
|
||||
if (key === "plasmashell" || key === "plasmoidviewer") {
|
||||
manualInhibitions.push(key);
|
||||
} else {
|
||||
inhibitions.push(pmSource.data["Inhibitions"][key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rootItem.manuallyInhibited = manualInhibitions.length > 0;
|
||||
rootItem.inhibitions = inhibitions;
|
||||
}
|
349
plasma/plasmoids/org.kde.plasma.battery/contents/ui/main.qml
Normal file
349
plasma/plasmoids/org.kde.plasma.battery/contents/ui/main.qml
Normal file
|
@ -0,0 +1,349 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2011 Sebastian Kügler <sebas@kde.org>
|
||||
SPDX-FileCopyrightText: 2011 Viranch Mehta <viranch.mehta@gmail.com>
|
||||
SPDX-FileCopyrightText: 2013-2015 Kai Uwe Broulik <kde@privat.broulik.de>
|
||||
SPDX-FileCopyrightText: 2021-2022 ivan tkachenko <me@ratijas.tk>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.kde.coreaddons as KCoreAddons
|
||||
import org.kde.kcmutils // KCMLauncher
|
||||
import org.kde.config // KAuthorized
|
||||
import org.kde.notification
|
||||
import org.kde.plasma.core as PlasmaCore
|
||||
import org.kde.plasma.plasma5support as P5Support
|
||||
import org.kde.plasma.plasmoid
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.kitemmodels as KItemModels
|
||||
|
||||
import "logic.js" as Logic
|
||||
|
||||
PlasmoidItem {
|
||||
id: batterymonitor
|
||||
|
||||
property QtObject pmSource: P5Support.DataSource {
|
||||
id: pmSource
|
||||
engine: "powermanagement"
|
||||
connectedSources: sources
|
||||
onSourceAdded: source => {
|
||||
disconnectSource(source);
|
||||
connectSource(source);
|
||||
}
|
||||
onSourceRemoved: source => {
|
||||
disconnectSource(source);
|
||||
}
|
||||
onDataChanged: {
|
||||
Logic.updateInhibitions(batterymonitor, pmSource);
|
||||
}
|
||||
}
|
||||
property QtObject batteries: KItemModels.KSortFilterProxyModel {
|
||||
id: batteries
|
||||
filterRoleName: "Is Power Supply"
|
||||
sortOrder: Qt.DescendingOrder
|
||||
sourceModel: KItemModels.KSortFilterProxyModel {
|
||||
sortRoleName: "Pretty Name"
|
||||
sortOrder: Qt.AscendingOrder
|
||||
sortCaseSensitivity: Qt.CaseInsensitive
|
||||
sourceModel: P5Support.DataModel {
|
||||
dataSource: pmSource
|
||||
sourceFilter: "Battery[0-9]+"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
property int batteryCapacity: batteries.sourceModel.sourceModel.dataSource.data["Battery0"] !== undefined ? batteries.sourceModel.sourceModel.dataSource.data["Battery0"].Capacity : 0
|
||||
readonly property bool isBroken: batteryCapacity > 0 && batteryCapacity < 50
|
||||
readonly property bool hasBatteries: batteries.count > 0 && pmSource.data["Battery"]["Has Cumulative"]
|
||||
readonly property bool kcmAuthorized: KAuthorized.authorizeControlModule("powerdevilprofilesconfig")
|
||||
readonly property bool kcmEnergyInformationAuthorized: KAuthorized.authorizeControlModule("kcm_energyinfo")
|
||||
readonly property bool isPluggedIn: pmSource.data["AC Adapter"]["Plugged in"]
|
||||
readonly property bool isSomehowFullyCharged: (pmSource.data["AC Adapter"]["Plugged in"] && pmSource.data["Battery"]["State"] === "FullyCharged") ||
|
||||
// When we are using a charge threshold, the kernel
|
||||
// may stop charging within a percentage point of the actual threshold
|
||||
// and this is considered correct behavior, so we have to handle
|
||||
// that. See https://bugzilla.kernel.org/show_bug.cgi?id=215531.
|
||||
(pmSource.data["AC Adapter"]["Plugged in"]
|
||||
&& typeof pmSource.data["Battery"]["Charge Stop Threshold"] === "number"
|
||||
&& (pmSource.data.Battery.Percent >= pmSource.data["Battery"]["Charge Stop Threshold"] - 1
|
||||
&& pmSource.data.Battery.Percent <= pmSource.data["Battery"]["Charge Stop Threshold"] + 1)
|
||||
// Also, Upower may give us a status of "Not charging" rather than
|
||||
// "Fully charged", so we need to account for that as well. See
|
||||
// https://gitlab.freedesktop.org/upower/upower/-/issues/142.
|
||||
&& (pmSource.data["Battery"]["State"] === "NoCharge" || pmSource.data["Battery"]["State"] === "FullyCharged"))
|
||||
readonly property int remainingTime: Number(pmSource.data["Battery"]["Smoothed Remaining msec"])
|
||||
|
||||
readonly property var profiles: pmSource.data["Power Profiles"] ? (pmSource.data["Power Profiles"]["Profiles"] || []) : []
|
||||
property bool isManuallyInPerformanceMode: false // to be set on power profile requested through the applet
|
||||
property bool isManuallyInPowerSaveMode: false // to be set on power profile requested through the applet
|
||||
readonly property bool isSomehowInPerformanceMode: actuallyActiveProfile === "performance"// Don't care about whether it was manually one or due to holds
|
||||
readonly property bool isSomehowInPowerSaveMode: actuallyActiveProfile === "power-saver" // Don't care about whether it was manually one or due to holds
|
||||
readonly property bool isHeldOnPerformanceMode: isSomehowInPerformanceMode && activeProfileHolds.length > 0
|
||||
readonly property bool isHeldOnPowerSaveMode: isSomehowInPowerSaveMode && activeProfileHolds.length > 0
|
||||
|
||||
readonly property bool inPanel: (Plasmoid.location === PlasmaCore.Types.TopEdge
|
||||
|| Plasmoid.location === PlasmaCore.Types.RightEdge
|
||||
|| Plasmoid.location === PlasmaCore.Types.BottomEdge
|
||||
|| Plasmoid.location === PlasmaCore.Types.LeftEdge)
|
||||
|
||||
property bool powermanagementDisabled: false
|
||||
|
||||
// List of active power management inhibitions (applications that are
|
||||
// blocking sleep and screen locking).
|
||||
//
|
||||
// type: [{
|
||||
// Icon: string,
|
||||
// Name: string,
|
||||
// Reason: string,
|
||||
// }]
|
||||
property var inhibitions: []
|
||||
property bool manuallyInhibited: false
|
||||
readonly property var activeProfileHolds: pmSource.data["Power Profiles"] ? (pmSource.data["Power Profiles"]["Profile Holds"] || []) : []
|
||||
readonly property string actuallyActiveProfile: pmSource.data["Power Profiles"] ? (pmSource.data["Power Profiles"]["Current Profile"] || "") : ""
|
||||
|
||||
function symbolicizeIconName(iconName) {
|
||||
const symbolicSuffix = "-symbolic";
|
||||
if (iconName.endsWith(symbolicSuffix)) {
|
||||
return iconName;
|
||||
}
|
||||
|
||||
return iconName + symbolicSuffix;
|
||||
}
|
||||
|
||||
switchWidth: Kirigami.Units.gridUnit * 10
|
||||
switchHeight: Kirigami.Units.gridUnit * 10
|
||||
|
||||
Plasmoid.title: "More power options"//hasBatteries ? i18n("Power and Battery") : i18n("Power Management")
|
||||
|
||||
LayoutMirroring.enabled: Qt.application.layoutDirection == Qt.RightToLeft
|
||||
LayoutMirroring.childrenInherit: true
|
||||
|
||||
Plasmoid.status: {
|
||||
if (powermanagementDisabled) {
|
||||
return PlasmaCore.Types.ActiveStatus;
|
||||
}
|
||||
|
||||
if (pmSource.data.Battery["Has Cumulative"] && pmSource.data["Battery"]["State"] === "Discharging") {
|
||||
return PlasmaCore.Types.ActiveStatus;
|
||||
}
|
||||
|
||||
if (isManuallyInPerformanceMode || isManuallyInPowerSaveMode || isHeldOnPerformanceMode || isHeldOnPowerSaveMode) {
|
||||
return PlasmaCore.Types.ActiveStatus;
|
||||
}
|
||||
|
||||
return PlasmaCore.Types.PassiveStatus;
|
||||
}
|
||||
|
||||
toolTipMainText: {
|
||||
if (!hasBatteries) {
|
||||
return Plasmoid.title
|
||||
} else if (isSomehowFullyCharged) {
|
||||
return i18n("Fully Charged");
|
||||
}
|
||||
|
||||
const percent = pmSource.data.Battery.Percent;
|
||||
if (pmSource.data["AC Adapter"] && pmSource.data["AC Adapter"]["Plugged in"]) {
|
||||
const state = pmSource.data.Battery.State;
|
||||
if (state === "NoCharge") {
|
||||
return i18n("Battery at %1%, not Charging", percent);
|
||||
} else if (state === "Discharging") {
|
||||
return i18n("Battery at %1%, plugged in but still discharging", percent);
|
||||
} else if (state === "Charging") {
|
||||
return i18n("Battery at %1%, Charging", percent);
|
||||
}
|
||||
}
|
||||
return i18n("Battery at %1%", percent);
|
||||
}
|
||||
|
||||
toolTipSubText: {
|
||||
const parts = [];
|
||||
|
||||
// Add special text for the "plugged in but still discharging" case
|
||||
if (pmSource.data["AC Adapter"] && pmSource.data["AC Adapter"]["Plugged in"] && pmSource.data.Battery.State === "Discharging") {
|
||||
parts.push(i18n("The power supply is not powerful enough to charge the battery"));
|
||||
}
|
||||
|
||||
if (batteries.count === 0) {
|
||||
parts.push(i18n("No Batteries Available"));
|
||||
} else if (remainingTime > 0) {
|
||||
const remainingTimeString = KCoreAddons.Format.formatDuration(remainingTime, KCoreAddons.FormatTypes.HideSeconds);
|
||||
if (pmSource.data["Battery"]["State"] === "FullyCharged") {
|
||||
// Don't add anything
|
||||
} else if (pmSource.data["AC Adapter"] && pmSource.data["AC Adapter"]["Plugged in"] && pmSource.data.Battery.State === "Charging") {
|
||||
parts.push(i18nc("time until fully charged - HH:MM","%1 until fully charged", remainingTimeString));
|
||||
} else {
|
||||
parts.push(i18nc("remaining time left of battery usage - HH:MM","%1 remaining", remainingTimeString));
|
||||
}
|
||||
} else if (pmSource.data.Battery.State === "NoCharge" && !isSomehowFullyCharged) {
|
||||
parts.push(i18n("Not charging"));
|
||||
} // otherwise, don't add anything
|
||||
|
||||
if (powermanagementDisabled) {
|
||||
parts.push(i18n("Automatic sleep and screen locking are disabled"));
|
||||
}
|
||||
|
||||
if (isSomehowInPerformanceMode) {
|
||||
if (isHeldOnPerformanceMode) {
|
||||
parts.push(i18np("An application has requested activating Performance mode",
|
||||
"%1 applications have requested activating Performance mode",
|
||||
activeProfileHolds.length));
|
||||
} else {
|
||||
parts.push(i18n("System is in Performance mode"));
|
||||
}
|
||||
} else if (isSomehowInPowerSaveMode) {
|
||||
if (isHeldOnPowerSaveMode) {
|
||||
parts.push(i18np("An application has requested activating Power Save mode",
|
||||
"%1 applications have requested activating Power Save mode",
|
||||
activeProfileHolds.length));
|
||||
} else {
|
||||
parts.push(i18n("System is in Power Save mode"));
|
||||
}
|
||||
}
|
||||
|
||||
return parts.join("\n");
|
||||
}
|
||||
|
||||
Plasmoid.icon: {
|
||||
let iconName;
|
||||
if (hasBatteries) {
|
||||
iconName = "battery-full";
|
||||
} else {
|
||||
iconName = "battery-profile-performance";
|
||||
}
|
||||
|
||||
if (inPanel) {
|
||||
return symbolicizeIconName(iconName);
|
||||
}
|
||||
|
||||
return iconName;
|
||||
}
|
||||
|
||||
compactRepresentation: CompactRepresentation {
|
||||
hasBatteries: batterymonitor.hasBatteries
|
||||
batteries: batterymonitor.batteries
|
||||
isSetToPerformanceMode: batterymonitor.isHeldOnPerformanceMode || batterymonitor.isManuallyInPerformanceMode
|
||||
isSetToPowerSaveMode: batterymonitor.isHeldOnPowerSaveMode || batterymonitor.isManuallyInPowerSaveMode
|
||||
isSomehowFullyCharged: batterymonitor.isSomehowFullyCharged
|
||||
}
|
||||
|
||||
fullRepresentation: PopupDialog {
|
||||
id: dialogItem
|
||||
|
||||
readonly property var appletInterface: batterymonitor
|
||||
readonly property int flyoutIntendedWidth: Kirigami.Units.gridUnit * 15
|
||||
|
||||
Layout.minimumWidth: Kirigami.Units.gridUnit * 10
|
||||
Layout.maximumWidth: Kirigami.Units.gridUnit * 80
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 20
|
||||
|
||||
Layout.minimumHeight: Kirigami.Units.gridUnit * 10
|
||||
Layout.maximumHeight: Kirigami.Units.gridUnit * 40
|
||||
Layout.preferredHeight: implicitHeight
|
||||
|
||||
model: batteries
|
||||
|
||||
pluggedIn: pmSource.data["AC Adapter"] !== undefined && pmSource.data["AC Adapter"]["Plugged in"]
|
||||
remainingTime: batterymonitor.remainingTime
|
||||
activeProfile: batterymonitor.actuallyActiveProfile
|
||||
inhibitions: batterymonitor.inhibitions
|
||||
manuallyInhibited: batterymonitor.manuallyInhibited
|
||||
inhibitsLidAction: pmSource.data["PowerDevil"] && pmSource.data["PowerDevil"]["Is Lid Present"] && !pmSource.data["PowerDevil"]["Triggers Lid Action"] ? true : false
|
||||
profilesInstalled: pmSource.data["Power Profiles"] ? pmSource.data["Power Profiles"]["Installed"] : false
|
||||
profiles: pmSource.data["Power Profiles"] ? (pmSource.data["Power Profiles"]["Profiles"] || []) : []
|
||||
inhibitionReason: pmSource.data["Power Profiles"] ? (pmSource.data["Power Profiles"]["Performance Inhibited Reason"] || "") : ""
|
||||
degradationReason: pmSource.data["Power Profiles"] ? (pmSource.data["Power Profiles"]["Performance Degraded Reason"] || "") : ""
|
||||
profileHolds: batterymonitor.activeProfileHolds
|
||||
|
||||
onInhibitionChangeRequested: inhibit => {
|
||||
const service = pmSource.serviceForSource("PowerDevil");
|
||||
if (inhibit) {
|
||||
const reason = i18n("The battery applet has enabled system-wide inhibition");
|
||||
const op1 = service.operationDescription("beginSuppressingSleep");
|
||||
op1.reason = reason;
|
||||
const op2 = service.operationDescription("beginSuppressingScreenPowerManagement");
|
||||
op2.reason = reason;
|
||||
|
||||
const job1 = service.startOperationCall(op1);
|
||||
const job2 = service.startOperationCall(op2);
|
||||
} else {
|
||||
const op1 = service.operationDescription("stopSuppressingSleep");
|
||||
const op2 = service.operationDescription("stopSuppressingScreenPowerManagement");
|
||||
|
||||
const job1 = service.startOperationCall(op1);
|
||||
const job2 = service.startOperationCall(op2);
|
||||
}
|
||||
Logic.updateInhibitions(batterymonitor, pmSource);
|
||||
}
|
||||
onPowerManagementChanged: disabled => {
|
||||
batterymonitor.powermanagementDisabled = disabled
|
||||
}
|
||||
|
||||
Notification {
|
||||
id: powerProfileError
|
||||
componentName: "plasma_workspace"
|
||||
eventId: "warning"
|
||||
iconName: "speedometer"
|
||||
title: i18n("Power Management")
|
||||
}
|
||||
|
||||
onActivateProfileRequested: profile => {
|
||||
dialogItem.activeProfile = profile;
|
||||
const service = pmSource.serviceForSource("PowerDevil");
|
||||
const op = service.operationDescription("setPowerProfile");
|
||||
op.profile = profile;
|
||||
|
||||
const job = service.startOperationCall(op);
|
||||
job.finished.connect(job => {
|
||||
dialogItem.activeProfile = Qt.binding(() => actuallyActiveProfile);
|
||||
if (!job.result) {
|
||||
powerProfileError.text = i18n("Failed to activate %1 mode", profile);
|
||||
powerProfileError.sendEvent();
|
||||
return;
|
||||
}
|
||||
batterymonitor.isManuallyInPerformanceMode = profile == "performance";
|
||||
batterymonitor.isManuallyInPowerSaveMode = profile == "power-saver";
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Plasmoid.contextualActions: [
|
||||
PlasmaCore.Action {
|
||||
text: i18n("&Show Energy Information…")
|
||||
icon.name: "documentinfo"
|
||||
visible: batterymonitor.kcmEnergyInformationAuthorized
|
||||
onTriggered: KCMLauncher.openInfoCenter("kcm_energyinfo")
|
||||
}/*,
|
||||
PlasmaCore.Action {
|
||||
text: i18n("Show Battery Percentage on Icon When Not Fully Charged")
|
||||
icon.name: "format-number-percent"
|
||||
visible: batterymonitor.hasBatteries
|
||||
checkable: true
|
||||
checked: Plasmoid.configuration.showPercentage
|
||||
onTriggered: checked => {
|
||||
Plasmoid.configuration.showPercentage = checked
|
||||
}
|
||||
}*/
|
||||
]
|
||||
|
||||
PlasmaCore.Action {
|
||||
id: configureAction
|
||||
text: i18n("&Configure Energy Saving…")
|
||||
icon.name: "configure"
|
||||
shortcut: "alt+d, s"
|
||||
onTriggered: {
|
||||
KCMLauncher.openSystemSettings("kcm_powerdevilprofilesconfig");
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
Logic.updateInhibitions(batterymonitor, pmSource)
|
||||
|
||||
Plasmoid.setInternalAction("configure", configureAction);
|
||||
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue