init: working version
This commit is contained in:
commit
7d8d7dacae
109 changed files with 15066 additions and 0 deletions
351
modules/bar/popouts/Battery.qml
Normal file
351
modules/bar/popouts/Battery.qml
Normal file
|
|
@ -0,0 +1,351 @@
|
|||
pragma ComponentBehavior: Bound
|
||||
|
||||
import qs.config
|
||||
import qs.custom
|
||||
import qs.services
|
||||
import Quickshell.Services.UPower
|
||||
import QtQuick
|
||||
import QtQuick.Shapes
|
||||
import QtQuick.Layouts
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
spacing: 4
|
||||
|
||||
readonly property color color: UPower.onBattery && UPower.displayDevice.percentage < 0.15 ?
|
||||
Config.colors.batteryWarning :
|
||||
Config.colors.battery
|
||||
|
||||
Loader {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
active: UPower.displayDevice.isLaptopBattery
|
||||
asynchronous: true
|
||||
|
||||
height: active ? (item?.implicitHeight ?? 0) : 0
|
||||
|
||||
sourceComponent: Item {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
implicitWidth: meter.width
|
||||
implicitHeight: meter.height + estimate.height + 8
|
||||
|
||||
Shape {
|
||||
id: meter
|
||||
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
visible: false
|
||||
|
||||
readonly property real size: 96
|
||||
readonly property real padding: 8
|
||||
readonly property real thickness: 8
|
||||
readonly property real angle: 280
|
||||
|
||||
ShapePath {
|
||||
id: path
|
||||
|
||||
fillColor: "transparent"
|
||||
strokeColor: Qt.alpha(root.color, 0.1)
|
||||
strokeWidth: meter.thickness
|
||||
capStyle: ShapePath.RoundCap
|
||||
|
||||
PathAngleArc {
|
||||
centerX: detail.x + detail.width / 2
|
||||
centerY: detail.y + detail.height / 2
|
||||
radiusX: (meter.size + meter.thickness) / 2 + meter.padding
|
||||
radiusY: radiusX
|
||||
startAngle: -90 - meter.angle / 2
|
||||
sweepAngle: meter.angle
|
||||
}
|
||||
|
||||
Behavior on strokeColor {
|
||||
CAnim {}
|
||||
}
|
||||
}
|
||||
|
||||
ShapePath {
|
||||
fillColor: "transparent"
|
||||
strokeColor: root.color
|
||||
strokeWidth: meter.thickness
|
||||
capStyle: ShapePath.RoundCap
|
||||
|
||||
PathAngleArc {
|
||||
centerX: detail.x + detail.width / 2
|
||||
centerY: detail.y + detail.height / 2
|
||||
radiusX: (meter.size + meter.thickness) / 2 + meter.padding
|
||||
radiusY: radiusX
|
||||
startAngle: -90 - meter.angle / 2
|
||||
sweepAngle: meter.angle * UPower.displayDevice.percentage
|
||||
}
|
||||
|
||||
Behavior on strokeColor {
|
||||
CAnim {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: detail
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.topMargin: (meter.size + meter.thickness - height) / 2 + meter.padding
|
||||
spacing: -6
|
||||
|
||||
// HACK: Prevent load order issues
|
||||
Component.onCompleted: meter.visible = true;
|
||||
|
||||
CustomText {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: Math.round(UPower.displayDevice.percentage * 100) + "%"
|
||||
font.pointSize: Config.font.size.largest
|
||||
}
|
||||
|
||||
CustomText {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottomMargin: 10
|
||||
text: UPowerDeviceState.toString(UPower.displayDevice.state)
|
||||
animate: true
|
||||
font.pointSize: Config.font.size.smaller
|
||||
|
||||
height: implicitHeight * 1.4
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: estimate
|
||||
|
||||
anchors.top: meter.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.topMargin: 3
|
||||
spacing: -3
|
||||
|
||||
CustomText {
|
||||
id: estimateTime
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
text: UPower.onBattery ? Time.formatSeconds(UPower.displayDevice.timeToEmpty) || "--"
|
||||
: Time.formatSeconds(UPower.displayDevice.timeToFull) || "--"
|
||||
animate: (from, to) => from === "--" || to === "--"
|
||||
font.family: Config.font.family.mono
|
||||
font.pointSize: Config.font.size.normal
|
||||
}
|
||||
|
||||
CustomText {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
text: UPower.onBattery ? "remaining" : "to full"
|
||||
animate: true
|
||||
font.family: Config.font.family.mono
|
||||
font.pointSize: Config.font.size.small
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
active: PowerProfiles.degradationReason !== PerformanceDegradationReason.None
|
||||
asynchronous: true
|
||||
|
||||
height: active ? (item?.implicitHeight ?? 0) : 0
|
||||
|
||||
sourceComponent: CustomRect {
|
||||
implicitWidth: child.implicitWidth + 20
|
||||
implicitHeight: child.implicitHeight + 20
|
||||
|
||||
color: Config.colors.errorBg
|
||||
border.color: Config.colors.error
|
||||
radius: 12
|
||||
|
||||
Column {
|
||||
id: child
|
||||
|
||||
anchors.centerIn: parent
|
||||
|
||||
Row {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: 7
|
||||
|
||||
MaterialIcon {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.verticalCenterOffset: -font.pointSize / 10
|
||||
|
||||
text: "warning"
|
||||
color: Config.colors.error
|
||||
}
|
||||
|
||||
CustomText {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: qsTr("Performance Degraded")
|
||||
color: Config.colors.error
|
||||
font.family: Config.font.family.mono
|
||||
font.weight: 500
|
||||
}
|
||||
|
||||
MaterialIcon {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.verticalCenterOffset: -font.pointSize / 10
|
||||
|
||||
text: "warning"
|
||||
color: Config.colors.error
|
||||
}
|
||||
}
|
||||
|
||||
CustomText {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
text: qsTr("Reason: %1").arg(PerformanceDegradationReason.toString(PowerProfiles.degradationReason))
|
||||
color: Config.colors.secondary
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CustomRect {
|
||||
id: profiles
|
||||
|
||||
Layout.topMargin: 4
|
||||
|
||||
property string current: {
|
||||
const p = PowerProfiles.profile;
|
||||
if (p === PowerProfile.PowerSaver)
|
||||
return saver.icon;
|
||||
if (p === PowerProfile.Performance)
|
||||
return perf.icon;
|
||||
return balance.icon;
|
||||
}
|
||||
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.leftMargin: 10
|
||||
Layout.rightMargin: 10
|
||||
|
||||
implicitWidth: saver.implicitHeight + balance.implicitHeight + perf.implicitHeight + 60
|
||||
implicitHeight: Math.max(saver.implicitHeight, balance.implicitHeight, perf.implicitHeight) + 8
|
||||
|
||||
color: Config.colors.container
|
||||
radius: 1000
|
||||
|
||||
CustomRect {
|
||||
id: indicator
|
||||
|
||||
color: root.color
|
||||
radius: 1000
|
||||
state: profiles.current
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: saver.icon
|
||||
|
||||
Fill {
|
||||
item: saver
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: balance.icon
|
||||
|
||||
Fill {
|
||||
item: balance
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: perf.icon
|
||||
|
||||
Fill {
|
||||
item: perf
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
transitions: Transition {
|
||||
AnchorAnimation {
|
||||
duration: Config.anim.durations.normal
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Config.anim.curves.emphasized
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Profile {
|
||||
id: saver
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 4
|
||||
|
||||
profile: PowerProfile.PowerSaver
|
||||
icon: "energy_savings_leaf"
|
||||
}
|
||||
|
||||
Profile {
|
||||
id: balance
|
||||
|
||||
anchors.centerIn: parent
|
||||
|
||||
profile: PowerProfile.Balanced
|
||||
icon: "balance"
|
||||
}
|
||||
|
||||
Profile {
|
||||
id: perf
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 4
|
||||
|
||||
profile: PowerProfile.Performance
|
||||
icon: "rocket_launch"
|
||||
}
|
||||
}
|
||||
|
||||
CustomText {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: -2
|
||||
text: "Performance: " + PowerProfile.toString(PowerProfiles.profile)
|
||||
animate: true
|
||||
color: Config.colors.secondary
|
||||
font.pointSize: Config.font.size.small
|
||||
font.weight: 500
|
||||
}
|
||||
|
||||
|
||||
component Fill: AnchorChanges {
|
||||
required property Item item
|
||||
|
||||
target: indicator
|
||||
anchors.left: item.left
|
||||
anchors.right: item.right
|
||||
anchors.top: item.top
|
||||
anchors.bottom: item.bottom
|
||||
}
|
||||
|
||||
component Profile: StateLayer {
|
||||
required property string icon
|
||||
required property int profile
|
||||
|
||||
implicitWidth: icon.implicitHeight + 5
|
||||
implicitHeight: icon.implicitHeight + 5
|
||||
|
||||
function onClicked(): void {
|
||||
PowerProfiles.profile = profile;
|
||||
}
|
||||
|
||||
MaterialIcon {
|
||||
id: icon
|
||||
|
||||
anchors.centerIn: parent
|
||||
|
||||
text: parent.icon
|
||||
font.pointSize: Config.font.size.larger
|
||||
color: profiles.current === text ? Config.colors.primaryDark : Config.colors.primary
|
||||
fill: profiles.current === text ? 1 : 0
|
||||
|
||||
Behavior on fill {
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue