Compare commits

...

35 Commits

Author SHA1 Message Date
83aa943fd9 added contextmenu and hide tray icon 2024-06-08 18:41:43 +02:00
3a1a5588d4 remove fullrepresentation 2024-06-08 18:41:11 +02:00
8b68977425 wrong color 2024-06-07 16:33:19 +02:00
c1dae41baa update readme 2024-06-07 02:08:19 +02:00
6e47175625 bring back config 2024-06-07 02:05:50 +02:00
b2e7b948fe irgendwas mit json 2024-06-07 01:56:43 +02:00
6290a78666 plasma6 alpha 2024-03-07 12:44:01 +01:00
4adea966fa critical notification & bugfix 2024-01-25 16:53:07 +01:00
d821e5b5c0 notifications! 2024-01-25 16:21:39 +01:00
f3529afeb1 debug mode 2024-01-22 03:08:31 +01:00
b15a5946a7 fix 100% charge lol 2024-01-22 03:08:25 +01:00
ef3ed2726b fix configpage 2024-01-22 01:58:17 +01:00
5b423c2ab7 current status 2024-01-21 19:54:24 +01:00
f5ed9d0c64 short shmort 2024-01-20 16:47:54 +01:00
04ad311289 autism 2024-01-20 16:20:14 +01:00
65959a5c4b add three color gradient 2024-01-20 15:16:18 +01:00
1af112eb52 color yourself 2024-01-20 13:16:48 +01:00
58c37a9dce changed: README.md 2024-01-20 11:37:38 +01:00
6e4b12a298 adjustable battery height 2024-01-20 11:36:02 +01:00
ed47f2a542 fix: ReferenceError: Slider is not defined 2024-01-20 05:03:08 +01:00
2b1c3489e6 add requirements 2024-01-20 04:58:11 +01:00
bd243ec115 es2020 or smth 2024-01-20 04:55:08 +01:00
de0ae352cb icons & tweaks 2024-01-20 04:49:58 +01:00
c36eb8daae fix exit code and color 2024-01-20 03:20:23 +01:00
ecf5c67ffb outsource lib 2024-01-20 03:03:58 +01:00
d51555ee47 adjust colors 2024-01-20 03:03:42 +01:00
92c931d6aa new battery fml 2024-01-19 19:45:11 +01:00
c6e29f9c15 proper variable name 2024-01-19 19:43:45 +01:00
445a60a862 changed: README.md 2024-01-19 19:43:12 +01:00
026f9b740a cfg: slider for pollingrate 2024-01-19 02:57:59 +01:00
4cea131ed0 tooltip 2024-01-19 02:57:49 +01:00
2d04bddde9 add config page 2024-01-19 01:54:33 +01:00
8c221144d3 install instructions 2024-01-19 01:54:08 +01:00
cf01291e4b typo :< 2024-01-17 20:45:08 +01:00
1ff2e30132 new colors for the icons + xcf 2024-01-17 20:44:58 +01:00
16 changed files with 578 additions and 60 deletions

View File

@ -1 +1,26 @@
# Headset Battery Widget
## Requirements
- [HeadsetControl](https://github.com/Sapd/HeadsetControl) v3.0.0 or newer
## Install
```
git clone https://git.lat/Flummi/headsetcontrol-battery-widget.git
cd headsetcontrol-battery-widget
kpackagetool6 -t Plasma/Applet --install ./package
```
## Uninstall
```
kpackagetool6 -t Plasma/Applet --remove org.kde.plasma.headsetcontrol-battery-widget
```
## Development
```
cd headsetcontrol-battery-widget
kpackagetool6 -t Plasma/Applet --upgrade ./package ; systemctl --user restart plasma-plasmashell
```

View File

@ -0,0 +1,15 @@
import QtQuick
import org.kde.plasma.configuration
ConfigModel {
ConfigCategory {
name: i18n("General")
icon: "configure"
source: "config/general.qml"
}
ConfigCategory {
name: i18n("Debug")
icon: "cab_view"
source: "config/debug.qml"
}
}

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
<kcfgfile name=""/>
<group name="General">
<entry name="pollingrate" type="Int">
<default>10</default>
</entry>
<entry name="batteryheight" type="Int">
<default>8</default>
</entry>
<entry name="colorEmpty" type="String">
<default>#ff0000</default>
</entry>
<entry name="colorHalf" type="String">
<default>#ffff00</default>
</entry>
<entry name="colorFull" type="String">
<default>#008800</default>
</entry>
<entry name="batteryThreshold" type="Int">
<default>10</default>
</entry>
<entry name="notifications" type="Bool">
<default>true</default>
</entry>
<entry name="debug_active" type="Bool">
<default>false</default>
</entry>
<entry name="debug_charge" type="Int">
<default>0</default>
</entry>
</group>
</kcfg>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

View File

@ -0,0 +1,50 @@
import QtQuick
import QtQuick.Layouts
import org.kde.plasma.plasmoid
import org.kde.kirigami as Kirigami
import "./lib/helper.js" as Helper
Item {
Rectangle { // battery
id: container
anchors.fill: parent
anchors.rightMargin: 1
anchors.topMargin: 10 - batteryheight
anchors.bottomMargin: 10 - batteryheight
color: "transparent"
border.color: Kirigami.Theme.textColor
radius: 4
Item {
anchors.fill: parent
anchors.margins: 2
Rectangle { // battery fill
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
color: Helper.interpolateColor(batteryPercent / 100, [ colorEmpty, colorHalf, colorFull ])
width: parent.width * Math.max(0, Math.min(batteryPercent, 100)) / 100
}
Kirigami.Icon { // headphones icon
anchors.bottom: parent.bottom
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
anchors.topMargin: 1
anchors.bottomMargin: 1
source: Helper.batteryIcon(batteryStatus)
color: batteryPercent == -1 ? colorEmpty : Kirigami.Theme.textColor
}
}
}
Rectangle { // battery cap
anchors.left: container.right
anchors.leftMargin: 1
anchors.verticalCenter: parent.verticalCenter
radius: 4
height: parent.height / 3
width: 2
color: Kirigami.Theme.textColor
}
}

View File

@ -0,0 +1,77 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.components as PlasmaComponents
import org.kde.kirigami as Kirigami
import org.kde.kquickcontrols as KQControls
import org.kde.kcmutils as KCM
import "../lib/helper.js" as Helper
KCM.SimpleKCM {
id: root
property alias cfg_debug_active: debug_active.checked
property alias cfg_debug_charge: debug_charge.value
property bool debug_activeDefault
property int debug_chargeDefault
property int cfg_pollingrate
property int cfg_batteryheight
property string cfg_colorEmpty
property string cfg_colorHalf
property string cfg_colorFull
property bool cfg_notifications
property int cfg_batteryThreshold
property int cfg_pollingrateDefault
property int cfg_batteryheightDefault
property string cfg_colorEmptyDefault
property string cfg_colorHalfDefault
property string cfg_colorFullDefault
property bool cfg_notificationsDefault
property int cfg_batteryThresholdDefault
Kirigami.FormLayout {
anchors.fill: parent
wideMode: false
GridLayout {
columns: 3
rows: 2
rowSpacing: 10
// first row
Text {
text: "debug:"
color: PlasmaCore.Theme.textColor
}
PlasmaComponents.CheckBox {
id: debug_active
}
Text {
text: ""
}
// second row
Text {
text: "battery charge:"
color: PlasmaCore.Theme.textColor
}
Slider {
id: debug_charge
value: 0
from: 0
to: 100
stepSize: 1
}
Text {
text: cfg_debug_charge + "%"
color: PlasmaCore.Theme.textColor
}
}
}
}

View File

@ -0,0 +1,212 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.components as PlasmaComponents
import org.kde.kirigami as Kirigami
import org.kde.kquickcontrols as KQControls
import org.kde.kcmutils as KCM
import "../lib/helper.js" as Helper
KCM.SimpleKCM {
id: root
property alias cfg_pollingrate: pollingrate.value
property alias cfg_batteryheight: batteryheight.value
property alias cfg_colorEmpty: colorEmpty.color
property alias cfg_colorHalf: colorHalf.color
property alias cfg_colorFull: colorFull.color
property alias cfg_notifications: notifications.checked
property alias cfg_batteryThreshold: batteryThreshold.value
property int cfg_pollingrateDefault
property int cfg_batteryheightDefault
property string cfg_colorEmptyDefault
property string cfg_colorHalfDefault
property string cfg_colorFullDefault
property bool cfg_notificationsDefault
property int cfg_batteryThresholdDefault
property bool cfg_debug_active
property int cfg_debug_charge
property bool cfg_debug_activeDefault
property int cfg_debug_chargeDefault
Kirigami.FormLayout {
anchors.fill: parent
wideMode: false
GridLayout {
columns: 3
rows: 2
rowSpacing: 10
// first row
Text {
text: "polling rate:"
color: PlasmaCore.Theme.textColor
}
Slider {
id: pollingrate
value: 10
from: 2
to: 60
stepSize: 2
}
Text {
text: cfg_pollingrate + " seconds"
color: PlasmaCore.Theme.textColor
}
// second row
Text {
text: "battery height:"
color: PlasmaCore.Theme.textColor
}
Slider {
id: batteryheight
value: 8.0
from: 1
to: 10
stepSize: 1
}
Text {
text: cfg_batteryheight
color: PlasmaCore.Theme.textColor
}
}
// color config
GridLayout {
columns: 3
rows: 3
rowSpacing: 1
// first row
Text {
text: "empty:"
color: PlasmaCore.Theme.textColor
}
KQControls.ColorButton {
id: colorEmpty
color: cfg_colorEmpty
}
Text {
text: cfg_colorEmpty
color: PlasmaCore.Theme.textColor
}
// secod row
Text {
text: "half:"
color: PlasmaCore.Theme.textColor
}
KQControls.ColorButton {
id: colorHalf
color: cfg_colorHalf
}
Text {
text: cfg_colorHalf
color: PlasmaCore.Theme.textColor
}
// third row
Text {
text: "full:"
color: PlasmaCore.Theme.textColor
}
KQControls.ColorButton {
id: colorFull
color: cfg_colorFull
}
Text {
text: cfg_colorFull
color: PlasmaCore.Theme.textColor
}
}
// color gradient example
GridLayout {
columns: 10
rows: 1
rowSpacing: 0
Text {
text: "█"
color: Helper.interpolateColor(.1, [ cfg_colorEmpty.toString(), cfg_colorHalf.toString(), cfg_colorFull.toString() ])
}
Text {
text: "█"
color: Helper.interpolateColor(.2, [ cfg_colorEmpty.toString(), cfg_colorHalf.toString(), cfg_colorFull.toString() ])
}
Text {
text: "█"
color: Helper.interpolateColor(.3, [ cfg_colorEmpty.toString(), cfg_colorHalf.toString(), cfg_colorFull.toString() ])
}
Text {
text: "█"
color: Helper.interpolateColor(.4, [ cfg_colorEmpty.toString(), cfg_colorHalf.toString(), cfg_colorFull.toString() ])
}
Text {
text: "█"
color: Helper.interpolateColor(.5, [ cfg_colorEmpty.toString(), cfg_colorHalf.toString(), cfg_colorFull.toString() ])
}
Text {
text: "█"
color: Helper.interpolateColor(.6, [ cfg_colorEmpty.toString(), cfg_colorHalf.toString(), cfg_colorFull.toString() ])
}
Text {
text: "█"
color: Helper.interpolateColor(.7, [ cfg_colorEmpty.toString(), cfg_colorHalf.toString(), cfg_colorFull.toString() ])
}
Text {
text: "█"
color: Helper.interpolateColor(.8, [ cfg_colorEmpty.toString(), cfg_colorHalf.toString(), cfg_colorFull.toString() ])
}
Text {
text: "█"
color: Helper.interpolateColor(.9, [ cfg_colorEmpty.toString(), cfg_colorHalf.toString(), cfg_colorFull.toString() ])
}
Text {
text: "█"
color: Helper.interpolateColor( 1, [ cfg_colorEmpty.toString(), cfg_colorHalf.toString(), cfg_colorFull.toString() ])
}
}
GridLayout {
columns: 3
rows: 2
rowSpacing: 10
// first row
Text {
text: "notifications:"
color: PlasmaCore.Theme.textColor
}
PlasmaComponents.CheckBox {
id: notifications
}
Text {
text: ""
}
// second row
Text {
text: "battery threshold:"
color: PlasmaCore.Theme.textColor
}
Slider {
id: batteryThreshold
value: 10
from: 1
to: 50
stepSize: 1
}
Text {
text: cfg_batteryThreshold
color: PlasmaCore.Theme.textColor
}
}
}
}

View File

@ -0,0 +1,32 @@
const batteryLevel = (batteryStatus, batteryPercent) => ({
"BATTERY_UNAVAILABLE": "not connected",
"BATTERY_CHARGING": "charging (" + batteryPercent + "%)",
"HEADSET_UNAVAILABLE": "no headset connected"
})[batteryStatus] ?? batteryPercent + "%";
const batteryIcon = batteryStatus => ({
"BATTERY_UNAVAILABLE": "action-unavailable",
"BATTERY_AVAILABLE": "audio-headphones-symbolic",
"BATTERY_CHARGING": "freon-voltage-symbolic",
"HEADSET_UNAVAILABLE": "dialog-error"
})[batteryStatus] ?? "audio-headphones-symbolic";
const hex2rgb = (hex, h = hex.replace('#', '0x')) => ({ r: h >> 16 & 255, g: h >> 8 & 255, b: h & 255 });
const rgb2Hex = rgb => "#" + ((1 << 24) + (rgb.r << 16) + (rgb.g << 8) + rgb.b).toString(16).slice(1);
const interpolateColor = (f, c) => {
if(!f) return "transparent";
if(f >= 1) return c.pop();
if(f <= 0) return c.shift();
f *= c.length - 1;
const i = ~~f;
f -= i;
const [ c1, c2 ] = [ hex2rgb(c[i]), hex2rgb(c[i + 1]) ];
return rgb2Hex({
r: c1.r + ((c2.r - c1.r) * f) | 10,
g: c1.g + ((c2.g - c1.g) * f) | 10,
b: c1.b + ((c2.b - c1.b) * f) | 10
});
};

View File

@ -1,65 +1,128 @@
import QtQuick 2.0
import QtQuick.Layouts 1.3
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core 2.0 as PlasmaCore
import QtQuick
import QtQuick.Layouts
import org.kde.plasma.plasmoid
import org.kde.kirigami as Kirigami
import org.kde.plasma.plasma5support as Plasma5Support
import org.kde.plasma.core as PlasmaCore
Item {
id: main
import org.kde.notification
property int batteryPercent: -2
import "./lib/helper.js" as Helper
PlasmaCore.DataSource {
PlasmoidItem {
id: root
Plasmoid.status: PlasmaCore.Types.ActiveStatus
readonly property int pollingrate: Plasmoid.configuration.pollingrate
readonly property int batteryheight: Plasmoid.configuration.batteryheight
readonly property string colorEmpty: Plasmoid.configuration.colorEmpty
readonly property string colorHalf: Plasmoid.configuration.colorHalf
readonly property string colorFull: Plasmoid.configuration.colorFull
readonly property bool notifications: Plasmoid.configuration.notifications
readonly property int batteryThreshold: Plasmoid.configuration.batteryThreshold
readonly property bool debug_active: Plasmoid.configuration.debug_active
readonly property int debug_charge: Plasmoid.configuration.debug_charge
property string batteryStatus: "BATTERY_UNAVAILABLE"
property int batteryPercent: 0
property bool notification_sent: false
property variant deviceList: []
property int activeDevice: 0
//property variant capabilities: []
Plasma5Support.DataSource {
id: hsSource
engine: "executable"
connectedSources: ["headsetcontrol -bc"]
interval: 2000
onNewData: {
if(data['exit_code'] > 0)
return console.log('error lol');
batteryPercent = data['stdout'];
connectedSources: ["headsetcontrol -o json"]
interval: pollingrate * 1e3
onNewData: (_, data) => {
const res = JSON.parse(data.stdout);
if(res.device_count === 0) {
batteryStatus = "HEADSET_UNAVAILABLE";
batteryPercent = 0;
root.Plasmoid.status = PlasmaCore.Types.PassiveStatus;
return;
}
//if(capabilities.length != res.devices[activeDevice].capabilities_str.length)
// capabilities = res.devices[activeDevice].capabilities_str;
deviceList = res.devices.map(e => e.product);
batteryPercent = res.devices[activeDevice].battery.level;
batteryStatus = batteryPercent > 0 ? res.devices[activeDevice].battery.status : "BATTERY_UNAVAILABLE";
// debug deshmug
if(debug_active) {
batteryStatus = "BATTERY_AVAILABLE";
batteryPercent = debug_charge;
}
// hide trayicon if headset isn't connected
root.Plasmoid.status = batteryStatus == "BATTERY_UNAVAILABLE"
? PlasmaCore.Types.PassiveStatus
: PlasmaCore.Types.ActiveStatus;
// send notification if necessary
if(batteryPercent <= batteryThreshold && batteryPercent >= 0 && !notification_sent && notifications) {
notification_sent = true;
notification.text = "Battery Level is low (" + batteryPercent + "%)";
notification.title = "Headset Battery Level Alert";
notification.iconName = "notification-battery-low";
notification.sendEvent();
}
// reset notifications if battery level is over batteryThreshold
if((batteryPercent > batteryThreshold || batteryPercent < 0) && notification_sent && notifications) {
notification_sent = false;
}
return;
}
}
Plasmoid.preferredRepresentation: Plasmoid.compactRepresentation
toolTipMainText: "battery level: " + Helper.batteryLevel(batteryStatus, batteryPercent)
toolTipSubText: "polling rate: " + pollingrate + " seconds"
Plasmoid.compactRepresentation: Item {
Layout.minimumWidth: units.iconSizes.medium
preferredRepresentation: compactRepresentation
compactRepresentation: CompactRepresentation{}
fullRepresentation: Item{}
Image {
anchors.fill: parent
smooth: true
fillMode: Image.PreserveAspectFit
source: batteryIcon()
Plasmoid.toolTipMainText: "battery status:"
Plasmoid.toolTipSubText: batteryStatus()
Notification {
id: notification
componentName: "plasma_workspace"
eventId: "notification"
flags: Notification.DefaultEvent
urgency: Notification.CriticalUrgency
}
Instantiator {
model: deviceList
delegate: PlasmaCore.Action {
text: modelData
icon.name: "audio-headphones-symbolic"
/*onTriggered: {
console.log("headset lel");
}*/
}
function batteryIcon() {
let iconName = "battery_100"
if(batteryPercent == -1) // charing
iconName = "battery_charging"
else if(batteryPercent == -2) // not connected
iconName = "battery_nc";
else if(batteryPercent > 80)
iconName = "battery_100";
else if(batteryPercent > 60)
iconName = "battery_80";
else if(batteryPercent > 40)
iconName = "battery_60";
else if(batteryPercent > 20)
iconName = "battery_40";
else
iconName = "battery_20";
return "../icons/" + iconName + ".png";
onObjectAdded: (index, object) => {
Plasmoid.contextualActions.splice(Plasmoid.contextualActions.indexOf(separator2), 0, object)
}
function batteryStatus() {
if(batteryPercent == -1)
return "charging";
else if(batteryPercent == -2)
return "not connected";
else
return batteryPercent + " %";
onObjectRemoved: (index, object) => {
Plasmoid.contextualActions.splice(Plasmoid.contextualActions.indexOf(object), 1)
}
}
Plasmoid.contextualActions: [
PlasmaCore.Action {
id: separator1
isSeparator: true
},
PlasmaCore.Action {
id: separator2
isSeparator: true
}
]
}

View File

@ -1,21 +1,25 @@
{
"KPackageStructure": "Plasma/Applet",
"KPlugin": {
"Name": "Headset Battery Widget",
"Description": "Headset Battery Widget",
"Icon": "battery",
"Category": "System Information",
"Authors": [{
"Email": "flummi@srv.fail",
"Name": "Flummi"
}],
"Category": "System Information",
"Dependencies": [
],
"Icon": "battery",
"Id": "org.kde.plasma.headsetcontrol-battery-widget",
"Name": "Headset Battery Widget",
"License": "",
"Version": "1.7",
"EnabledByDefault": true,
"Website": "https://git.lat/Flummi/headsetcontrol-battery-widget",
"BugReportUrl": "https://git.lat/Flummi/headsetcontrol-battery-widget/issues",
"ServiceTypes": [
"Plasma/Applet"
],
"Version": "1",
"Website": "https://git.lat/Flummi/headsetcontrol-battery-widget"
]
},
"X-Plasma-API": "declarativeappletscript",
"X-Plasma-MainScript": "ui/main.qml"
"X-Plasma-NotificationArea": true,
"X-Plasma-NotificationAreaCategory": "Hardware",
"X-Plasma-API-Minimum-Version": "6.0"
}