This commit is contained in:
2026-04-12 12:05:16 +00:00
parent 8dfbb0dea7
commit 60711adff0
19 changed files with 613 additions and 230 deletions
+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -euo pipefail
repo_root="$(git rev-parse --show-toplevel)"
cd "$repo_root"
echo "[pre-commit] Running make format..."
make format
echo "[pre-commit] Staging formatting changes..."
git add -A
echo "[pre-commit] Running make lint..."
make lint
+26
View File
@@ -0,0 +1,26 @@
# KDE / Qt
.kdev4/
*.kdev4
.directory
*.user
*.pro.user
*.moc
*.o
*.obj
*.rcc
*.ui
*.qrc
.qmake.stash
# Build artifacts
build/
*.plasmoid
# Temporary files
*~
*.swp
*.bak
.DS_Store
# Logs
*.log
+11
View File
@@ -0,0 +1,11 @@
{
"overrides": [
{
"files": "*.json",
"options": {
"tabWidth": 4,
"useTabs": false
}
}
]
}
+5
View File
@@ -0,0 +1,5 @@
{
"qt-qml.qmlls.enabled": true,
"qt-qml.qmlls.customExePath": "/usr/lib/qt6/bin/qmlls",
"qt-qml.qmlls.customArgs": ["-I/usr/lib/qt6/qml", "-d/usr/share/doc/qt6"]
}
+155
View File
@@ -0,0 +1,155 @@
# Makefile for KDE 6 Plasma Widget Development
# Variables
PACKAGE_DIR := package
METADATA_FILE := $(PACKAGE_DIR)/metadata.json
WIDGET_ID := $(shell grep -oP '"Id": "\K[^"]+' $(METADATA_FILE))
BUILD_DIR := build
PLASMOID_FILE := $(WIDGET_ID).plasmoid
# Default target
.PHONY: help
help:
@echo "KDE Plasma 6 Widget Developer Tools"
@echo ""
@echo "Usage:"
@echo " make dev Run widget in plasmoidviewer from local package (MODE=panel|desktop|hidpi)"
@echo " make watch Start Development Mode with Hot Reload"
@echo " make install Install/upgrade widget in local Plasma package store"
@echo " make uninstall Remove widget from local system"
@echo " make package Build .plasmoid file for distribution"
@echo " make clean Remove build artifacts"
@echo " make format Format QML, JSON, YAML, and Markdown files"
@echo " make lint Run non-mutating lint and formatting checks"
@echo " make hooks-install Configure Git to use versioned hooks from .githooks/"
# Git Hooks
# Configure Git to use versioned hooks stored in this repository.
.PHONY: hooks-install
hooks-install:
git config core.hooksPath .githooks
@echo "Configured core.hooksPath=.githooks"
# Testing Targets
# Run plasmoidviewer from the local package directory.
# Optional MODE values: panel, desktop, hidpi (omit MODE for default).
.PHONY: dev
dev:
@mode="$(MODE)"; \
case "$$mode" in \
""|default) \
plasmoidviewer -a $(PACKAGE_DIR) ;; \
panel) \
plasmoidviewer -a $(PACKAGE_DIR) -l topedge -f horizontal ;; \
desktop) \
plasmoidviewer -a $(PACKAGE_DIR) -l floating -f planar ;; \
hidpi) \
QT_SCALE_FACTOR=2 plasmoidviewer -a $(PACKAGE_DIR) ;; \
*) \
echo "Invalid MODE='$$mode'. Allowed: panel, desktop, hidpi (or omit MODE)."; \
exit 1 ;; \
esac
# Development Tools
# Start file watcher for iterative development and reload workflow.
.PHONY: watch
watch:
./scripts/watch.sh
# Format all QML files in the package directory in-place.
.PHONY: format-qml
format-qml:
@command -v qmlformat >/dev/null 2>&1 || { echo "Missing required tool: qmlformat"; exit 1; }
find $(PACKAGE_DIR) -name "*.qml" -type f -exec qmlformat -i {} +
# Format JSON/YAML/Markdown files with prettier.
.PHONY: format-prettier
format-prettier:
@command -v prettier >/dev/null 2>&1 || { echo "Missing required tool: prettier"; exit 1; }
find . -type f \
\( -name "*.json" -o -name "*.yml" -o -name "*.yaml" -o -name "*.md" -o -name ".prettierrc" \) \
-not -path "./.git/*" \
-not -path "./build/*" \
-print0 | xargs -0 -r prettier --write
# Run all formatting passes.
.PHONY: format
format: format-qml format-prettier
# Linting
# Check QML formatting without changing files.
.PHONY: lint-qml-format
lint-qml-format:
@command -v qmlformat >/dev/null 2>&1 || { echo "Missing required tool: qmlformat"; exit 1; }
@status=0; \
find $(PACKAGE_DIR) -name "*.qml" -type f -print0 | \
xargs -0 -r -I{} sh -c 'tmp_file="$$(mktemp)"; qmlformat "$$1" > "$$tmp_file"; if ! cmp -s "$$1" "$$tmp_file"; then echo "QML format mismatch: $$1"; rm -f "$$tmp_file"; exit 1; fi; rm -f "$$tmp_file"' _ {} || status=1; \
if [ "$$status" -ne 0 ]; then \
echo "Run 'make format-qml' to fix QML formatting."; \
exit 1; \
fi
# Run semantic QML lint checks.
.PHONY: lint-qml
lint-qml:
@command -v qmllint >/dev/null 2>&1 || { echo "Missing required tool: qmllint"; exit 1; }
find $(PACKAGE_DIR) -name "*.qml" -type f -print0 | xargs -0 -r qmllint
# Check JSON/YAML/Markdown formatting without changing files.
.PHONY: lint-prettier
lint-prettier:
@command -v prettier >/dev/null 2>&1 || { echo "Missing required tool: prettier"; exit 1; }
find . -type f \
\( -name "*.json" -o -name "*.yml" -o -name "*.yaml" -o -name "*.md" -o -name ".prettierrc" \) \
-not -path "./.git/*" \
-not -path "./build/*" \
-print0 | xargs -0 -r prettier --check
# Run all lint and formatting checks.
.PHONY: lint
lint: lint-qml-format lint-qml lint-prettier
# Installation
# Install/upgrade widget in local Plasma package store.
.PHONY: install
install:
@if kpackagetool6 --type Plasma/Applet --show $(WIDGET_ID) >/dev/null 2>&1; then \
echo "Upgrading existing package: $(WIDGET_ID)"; \
kpackagetool6 --type Plasma/Applet --upgrade $(PACKAGE_DIR); \
else \
echo "Installing new package: $(WIDGET_ID)"; \
kpackagetool6 --type Plasma/Applet --install $(PACKAGE_DIR); \
fi
# Upgrade an already installed widget package with local changes.
.PHONY: upgrade
upgrade:
kpackagetool6 --type Plasma/Applet --upgrade $(PACKAGE_DIR)
# Remove installed widget package from local system.
.PHONY: uninstall
uninstall:
@if kpackagetool6 --type Plasma/Applet --show $(WIDGET_ID) >/dev/null 2>&1; then \
echo "Removing package registration: $(WIDGET_ID)"; \
kpackagetool6 --type Plasma/Applet --remove $(WIDGET_ID); \
else \
echo "Package not registered: $(WIDGET_ID)"; \
fi
# Packaging
# Create distributable .plasmoid archive from current package contents.
.PHONY: package
package:
mkdir -p $(BUILD_DIR)
rm -f $(BUILD_DIR)/$(PLASMOID_FILE)
# Zip package contents
cd $(PACKAGE_DIR) && zip -r ../$(BUILD_DIR)/$(PLASMOID_FILE) .
@echo ""
@echo "Package built at: $(BUILD_DIR)/$(PLASMOID_FILE)"
# Delete all generated build artifacts for a clean workspace.
.PHONY: clean
clean:
rm -rf $(BUILD_DIR)
+90 -7
View File
@@ -1,12 +1,95 @@
# NowPlaying
## now on kde 6: https://www.pling.com/p/2195583/
NowPlaying is a KDE Plasma 6 widget inspired by the Cleartext Rainmeter widget. It displays the current song and artist with compact media controls, and is meant to live on the desktop rather than in a panel.
A KDE Plasma widget inspired from the Cleartext rainmeter widget. Still in beta.
Now on KDE 6: https://www.pling.com/p/2195583/
Hello,\
Full credit to the guy windows guy for the idea, I just made a clone.\
Now of course, it is not as feature fledged (read as no features) as that one but I aim to add most, if not all of it, if time permits.\
Feel free to open any issues, requests, suggestions etc.
## Prerequisites
PS: Don't forget to star the project. I care about fake internet points.
You need the basic KDE and Qt 6 tools for Plasma widget development.
On Arch Linux, this is roughly:
```bash
sudo pacman -S plasma-sdk inotify-tools kirigami2 qt6-base qt6-declarative
```
## Development
Run the widget directly from the local package:
```bash
make dev
```
Other test modes are available:
```bash
make dev MODE=panel
make dev MODE=desktop
make dev MODE=hidpi
```
Use hot reload while editing:
```bash
make watch
```
Install or upgrade the widget in your local Plasma package store:
```bash
make install
```
Create a distributable package:
```bash
make package
```
The package is written to `build/org.ruiny.NowPlaying.plasmoid`.
## Project Structure
```text
.
├── package/
│ ├── metadata.json
│ └── contents/
│ ├── config/
│ │ ├── config.qml
│ │ └── main.xml
│ └── ui/
│ ├── configGeneral.qml
│ ├── main.qml
│ ├── Player.qml
│ └── Representation.qml
├── scripts/
│ └── watch.sh
└── Makefile
```
## Maintenance
Format files:
```bash
make format
```
Run lint checks:
```bash
make lint
```
Enable the repository pre-commit hook:
```bash
make hooks-install
```
## Credits
Full credit to the Windows creator for the original idea. I just made a KDE clone.
+11
View File
@@ -0,0 +1,11 @@
import QtQuick
import org.kde.plasma.configuration
ConfigModel {
ConfigCategory {
name: i18n("General")
icon: "preferences-desktop"
source: "configGeneral.qml"
}
}
+17
View File
@@ -0,0 +1,17 @@
<?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="opacity" type="Int">
<label>Opacity</label>
<default>100</default>
</entry>
<entry name="fontFamily" type="String">
<label>Font family</label>
<default>Noto Sans</default>
</entry>
</group>
</kcfg>
@@ -4,33 +4,21 @@ Credits: https://github.com/ccatterina/plasmusic-toolbar
looked handy, ty
*/
import QtQuick 2.15
import QtQml.Models 2.3
import QtQml.Models
import QtQuick
import org.kde.plasma.private.mpris as Mpris
QtObject {
id: root
property var mpris2Model: Mpris.Mpris2Model {
onRowsInserted: (_, rowIndex) => {
const CONTAINER_ROLE = Qt.UserRole + 1
const player = this.data(this.index(rowIndex, 0), CONTAINER_ROLE)
if (player.desktopEntry === root.sourceName) {
this.currentIndex = rowIndex;
}
}
}
property string sourceName: "any"
property var mpris2Model
readonly property bool ready: {
if (!mpris2Model.currentPlayer) {
return false
}
if (!mpris2Model.currentPlayer)
return false;
return mpris2Model.currentPlayer.desktopEntry === sourceName || sourceName === "any";
}
readonly property string artists: ready ? mpris2Model.currentPlayer.artist : ""
readonly property string title: ready ? mpris2Model.currentPlayer.track : ""
readonly property int playbackStatus: ready ? mpris2Model.currentPlayer.playbackStatus : Mpris.PlaybackStatus.Unknown
@@ -41,22 +29,22 @@ QtObject {
readonly property double songLength: ready ? mpris2Model.currentPlayer.length : 0
readonly property real volume: ready ? mpris2Model.currentPlayer.volume : 0
readonly property string identity: ready ? mpris2Model.currentPlayer.identity : ""
readonly property bool canGoNext: ready ? mpris2Model.currentPlayer.canGoNext : false
readonly property bool canGoPrevious: ready ? mpris2Model.currentPlayer.canGoPrevious : false
readonly property bool canPlay: ready ? mpris2Model.currentPlayer.canPlay : false
readonly property bool canPause: ready ? mpris2Model.currentPlayer.canPause : false
readonly property bool canSeek: ready ? mpris2Model.currentPlayer.canSeek : false
readonly property bool canRaise: ready ? mpris2Model.currentPlayer.canRaise : false
// To know whether Shuffle and Loop can be changed we have to check if the property is defined,
// unlike the other commands, LoopStatus and Shuffle hasn't a specific propety such as
// unlike the other commands, LoopStatus and Shuffle do not have specific properties such as
// CanPause, CanSeek, etc.
readonly property bool canChangeShuffle: ready ? mpris2Model.currentPlayer.shuffle != undefined : false
readonly property bool canChangeLoopStatus: ready ? mpris2Model.currentPlayer.loopStatus != undefined : false
readonly property bool canChangeShuffle: ready ? mpris2Model.currentPlayer.shuffle !== undefined : false
readonly property bool canChangeLoopStatus: ready ? mpris2Model.currentPlayer.loopStatus !== undefined : false
function togglePlayPause() {
mpris2Model.currentPlayer?.PlayPause();
if (mpris2Model.currentPlayer)
mpris2Model.currentPlayer.PlayPause();
}
function setPosition(position) {
@@ -64,19 +52,25 @@ QtObject {
}
function next() {
mpris2Model.currentPlayer?.Next();
if (mpris2Model.currentPlayer)
mpris2Model.currentPlayer.Next();
}
function previous() {
mpris2Model.currentPlayer?.Previous();
if (mpris2Model.currentPlayer)
mpris2Model.currentPlayer.Previous();
}
function updatePosition() {
mpris2Model.currentPlayer?.updatePosition();
if (mpris2Model.currentPlayer)
mpris2Model.currentPlayer.updatePosition();
}
function setVolume(volume) {
mpris2Model.currentPlayer.volume = volume
mpris2Model.currentPlayer.volume = volume;
}
function changeVolume(delta, showOSD) {
@@ -84,11 +78,11 @@ QtObject {
}
function setShuffle(shuffle) {
mpris2Model.currentPlayer.shuffle = shuffle
mpris2Model.currentPlayer.shuffle = shuffle;
}
function setLoopStatus(loopStatus) {
mpris2Model.currentPlayer.loopStatus = loopStatus
mpris2Model.currentPlayer.loopStatus = loopStatus;
}
function raise() {
@@ -96,12 +90,22 @@ QtObject {
}
function formatTrackTime(s) {
var hours = Math.floor(s / 3600)
var minutes = Math.floor((s - (hours * 3600)) / 60)
var seconds = Math.ceil(s - (hours * 3600) - (minutes * 60))
minutes = (minutes < 10) ? "0" + minutes : minutes
seconds = (seconds < 10) ? "0" + seconds : seconds
var time = minutes + ":" + seconds
return time
const hours = Math.floor(s / 3600);
let minutes = Math.floor((s - hours * 3600) / 60);
let seconds = Math.ceil(s - hours * 3600 - minutes * 60);
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
return minutes + ":" + seconds;
}
mpris2Model: Mpris.Mpris2Model {
onRowsInserted: (_, rowIndex) => {
const CONTAINER_ROLE = Qt.UserRole + 1;
const player = this.data(this.index(rowIndex, 0), CONTAINER_ROLE);
if (player.desktopEntry === root.sourceName)
this.currentIndex = rowIndex;
}
}
}
@@ -1,36 +1,60 @@
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import org.kde.plasma.components as PlasmaComponents
import org.kde.plasma.core as PlasmaCore
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.plasma.components as PlasmaComponents
MouseArea {
id: mediaControlsMouseArea
focus: true
Keys.onPressed: {
if (!event.modifiers) {
event.accepted = true
if (event.key === Qt.Key_Space || event.key === Qt.Key_K) {
player.togglePlayPause()
} else if (event.key === Qt.Key_P) {
player.previous()
} else if (event.key === Qt.Key_N) {
player.next()
} else {
event.accepted = false
}
}
}
hoverEnabled: true
readonly property double buttonSize: 16
focus: true
hoverEnabled: true
Keys.onPressed: (event) => {
if (!event.modifiers) {
event.accepted = true;
if (event.key === Qt.Key_Space || event.key === Qt.Key_K)
player.togglePlayPause();
else if (event.key === Qt.Key_P)
player.previous();
else if (event.key === Qt.Key_N)
player.next();
else
event.accepted = false;
}
}
RowLayout {
anchors.fill: parent
ColumnLayout {
Layout.fillHeight: true
id: leftColumn
Layout.fillHeight: true
states: [
State {
name: "buttonsVisible"
when: mediaControlsMouseArea.containsMouse
PropertyChanges {
target: nowPlayingLabels
Layout.bottomMargin: 10
}
},
State {
name: "buttonsHidden"
when: !mediaControlsMouseArea.containsMouse
PropertyChanges {
target: nowPlayingLabels
Layout.bottomMargin: 0
}
}
]
Item {
Layout.fillHeight: true
Layout.fillWidth: true
@@ -38,80 +62,96 @@ MouseArea {
ColumnLayout {
id: nowPlayingLabels
Layout.alignment: Qt.AlignRight
spacing: 0
Label {
Layout.alignment: Qt.AlignRight
PlasmaComponents.Label {
Layout.alignment: Qt.AlignRight
text: "NOW"
lineHeight: 0.8
font.pixelSize: 16
font.bold: true
// qmllint disable missing-property
font.family: plasmoid.configuration.fontFamily
}
Label {
PlasmaComponents.Label {
id: nowPlayingLabel2
Layout.alignment: Qt.AlignRight
text: "PLAYING"
lineHeight: 0.8
font.bold: true
font.pixelSize: 16
// qmllint disable missing-property
font.family: plasmoid.configuration.fontFamily
}
}
RowLayout {
id: mediaControls
Layout.alignment: Qt.AlignHCenter
opacity: mediaControlsMouseArea.containsMouse ? 1 : 0
visible: opacity > 0
Behavior on opacity {
PropertyAnimation {
easing.type: Easing.InOutQuad
duration: 250
}
}
Button {
QQC2.Button {
Layout.preferredWidth: buttonSize
Layout.preferredHeight: buttonSize
padding: 0
background: null
onClicked: {
player.previous();
console.log("prev clicked");
}
contentItem: Kirigami.Icon {
source: "media-skip-backward"
}
}
QQC2.Button {
id: playButton
Layout.preferredWidth: buttonSize
Layout.preferredHeight: buttonSize
padding: 0
background: null
onClicked: {
player.previous()
console.log("prev clicked")
player.togglePlayPause();
console.log("pause clicked");
}
}
Button {
Layout.preferredWidth: buttonSize
Layout.preferredHeight: buttonSize
id: playButton
contentItem: Kirigami.Icon {
source: player.playbackStatus === 2 ? "media-playback-pause" : "media-playback-start"
}
padding: 0
background: null
onClicked: {
player.togglePlayPause()
console.log("pause clicked")
}
}
Button {
QQC2.Button {
Layout.preferredWidth: buttonSize
Layout.preferredHeight: buttonSize
padding: 0
background: null
onClicked: player.next()
contentItem: Kirigami.Icon {
source: "media-skip-forward"
}
onClicked: {
player.next()
}
padding: 0
background: null
}
Behavior on opacity {
PropertyAnimation {
duration: 250
easing.type: Easing.InOutQuad
}
}
}
Item {
@@ -119,61 +159,53 @@ MouseArea {
Layout.fillWidth: true
}
states: [
State {
name: "buttonsVisible"
when: mediaControlsMouseArea.containsMouse
PropertyChanges {
target: nowPlayingLabels
Layout.bottomMargin: 10
}
},
State {
name: "buttonsHidden"
when: !mediaControlsMouseArea.containsMouse
PropertyChanges {
target: nowPlayingLabels
Layout.bottomMargin: 0
}
}
]
transitions: Transition {
NumberAnimation {
properties: "Layout.bottomMargin"
duration: 250
easing.type: Easing.InOutQuad
properties: "Layout.bottomMargin"
}
}
}
Rectangle {
id: separator
width: 1
Layout.fillHeight: true
width: 1
}
ColumnLayout {
Layout.fillWidth: true
id: infoColumn
Layout.fillWidth: true
PlasmaComponents.Label {
font.family: plasmoid.configuration.fontFamily
text: player.title
Layout.fillWidth: true
text: player.title
font.pixelSize: 28
lineHeight: 0.8
font.bold: true
// qmllint disable missing-property
font.family: plasmoid.configuration.fontFamily
lineHeight: 0.8
elide: Text.ElideRight
}
PlasmaComponents.Label {
font.family: plasmoid.configuration.fontFamily
elide: Text.ElideRight
Layout.maximumWidth: 300
Layout.fillWidth: true
text: player.artists
font.pixelSize: 26
// qmllint disable missing-property
font.family: plasmoid.configuration.fontFamily
lineHeight: 0.8
elide: Text.ElideRight
}
}
}
}
+40
View File
@@ -0,0 +1,40 @@
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kcmutils as KCM
import org.kde.kirigami as Kirigami
KCM.SimpleKCM {
id: configRoot
property alias cfg_opacity: opacitySpinBox.value
property string cfg_fontFamily
readonly property var availableFonts: Qt.fontFamilies()
onCfg_fontFamilyChanged: {
const index = availableFonts.indexOf(cfg_fontFamily);
if (index >= 0 && fontFamilyComboBox.currentIndex !== index)
fontFamilyComboBox.currentIndex = index;
}
Kirigami.FormLayout {
QQC2.SpinBox {
id: opacitySpinBox
Kirigami.FormData.label: i18n("Opacity percent:")
from: 0
to: 100
}
QQC2.ComboBox {
id: fontFamilyComboBox
Kirigami.FormData.label: i18n("Font:")
model: configRoot.availableFonts
onActivated: configRoot.cfg_fontFamily = currentText
}
}
}
+37
View File
@@ -0,0 +1,37 @@
import QtQuick
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.plasma.plasmoid
PlasmoidItem {
id: root
// Properties accessed from configuration.
// "qmllint" sees `plasmoid` as QObject here, but Plasma injects `configuration` at runtime.
// qmllint disable missing-property
property int configuredOpacity: plasmoid.configuration.opacity
width: Kirigami.Units.gridUnit * 25
height: Kirigami.Units.gridUnit * 5
Layout.minimumWidth: Kirigami.Units.gridUnit * 25
Layout.minimumHeight: Kirigami.Units.gridUnit * 5
Plasmoid.backgroundHints: "NoBackground"
opacity: configuredOpacity / 100
Player {
id: player
}
fullRepresentation: Representation {
Layout.minimumWidth: Kirigami.Units.gridUnit * 25
Layout.minimumHeight: Kirigami.Units.gridUnit * 5
Layout.preferredWidth: root.width
Layout.preferredHeight: root.height
}
compactRepresentation: Representation {
Layout.minimumWidth: Kirigami.Units.gridUnit * 25
Layout.minimumHeight: Kirigami.Units.gridUnit * 5
}
}
@@ -16,6 +16,6 @@
},
"KPackageStructure": "Plasma/Applet",
"X-Plasma-API-Minimum-Version": "6.0",
"X-Plasma-Provides": [ "org.kde.plasma.multimediacontrols" ],
"X-Plasma-Provides": ["org.kde.plasma.multimediacontrols"],
"X-Plasma-DBusActivationService": "org.mpris.MediaPlayer2.*"
}
-10
View File
@@ -1,10 +0,0 @@
import QtQuick 2.12
import org.kde.plasma.configuration 2.0
ConfigModel {
ConfigCategory {
name: i18n("General")
icon: "preferences-desktop"
source: "GeneralConfig.qml"
}
}
-19
View File
@@ -1,19 +0,0 @@
<?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="opacity" type="Int">
<default>100</default>
<label>Opacity</label>
</entry>
<entry name="fontFamily" type="String">
<default>"Noto Sans"</default>
<label>Font family</label>
</entry>
</group>
</kcfg>
-46
View File
@@ -1,46 +0,0 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import org.kde.plasma.core as PlasmaCore
import org.kde.kirigami as Kirigami
Item {
id: configRoot
signal configurationChanged
property alias cfg_opacity: opacitySpinBox.value
property string cfg_fontFamily
ColumnLayout {
spacing: Kirigami.Units.mediumSpacing
RowLayout{
Label {
text: i18n("Opacity percent")
}
SpinBox {
id: opacitySpinBox
from: 0
to: 100
}
}
RowLayout{
Label {
text: i18n("Font")
}
ComboBox{
id: fontFamilyComboBox
model: Qt.fontFamilies()
onCurrentIndexChanged: {
var current = Qt.fontFamilies()[currentIndex]
cfg_fontFamily=current
configRoot.configurationChanged()
}
}
}
}
}
-28
View File
@@ -1,28 +0,0 @@
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import org.kde.plasma.plasmoid
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.plasma5support as Plasma5Support
import org.kde.plasma.private.mpris as Mpris
import org.kde.kirigami as Kirigami
PlasmoidItem {
id: root
Layout.minimumWidth: Kirigami.Units.gridUnit*25
Layout.minimumHeight: Kirigami.Units.gridUnit*5
Plasmoid.backgroundHints: "NoBackground"
opacity: plasmoid.configuration.opacity/100
Representation{
anchors.fill: parent
}
Player{
id: player
}
}
-3
View File
@@ -1,3 +0,0 @@
kpackagetool6 -t Plasma/Applet --install plasmoid/
kpackagetool6 -t Plasma/Applet --upgrade plasmoid/
plasmoidviewer -a ./plasmoid
+54
View File
@@ -0,0 +1,54 @@
#!/bin/bash
# Get the directory where the script is located.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
PACKAGE_DIR="$SCRIPT_DIR/package"
PLASMOID_NAME=$(grep -oP '"Id": "\K[^"]+' "$PACKAGE_DIR/metadata.json")
# Check for inotify-tools.
if ! command -v inotifywait &> /dev/null; then
echo "Error: inotify-tools is typically not installed."
echo "Please install it with your package manager (e.g., sudo apt install inotify-tools)"
exit 1
fi
echo "Found Widget ID: $PLASMOID_NAME"
echo "Starting Hot Reload Watcher..."
echo "Press Ctrl+C to stop."
# Cleanup function to kill the viewer when the script exits.
cleanup() {
echo -e "\nStopping watcher..."
if [ -n "$PID" ]; then
kill "$PID" 2>/dev/null
fi
exit
}
trap cleanup SIGINT SIGTERM
# Initial start.
echo -e "\n[$(date +%T)] Starting plasmoidviewer..."
plasmoidviewer -a "$PACKAGE_DIR" &
PID=$!
# Watch loop.
while true; do
# Wait for any file modification in the package directory.
inotifywait -r -e modify -e create -e delete "$PACKAGE_DIR" -q
echo -e "\n[$(date +%T)] Change detected! Reloading..."
# Kill the current instance.
if [ -n "$PID" ]; then
kill "$PID" 2>/dev/null
wait "$PID" 2>/dev/null
fi
# Small delay to let Qt/KDE clean up properly.
sleep 0.5
# Restart with absolute path.
plasmoidviewer -a "$PACKAGE_DIR" &
PID=$!
done