diff --git a/.githooks/pre-commit b/.githooks/pre-commit
new file mode 100755
index 0000000..be47b3c
--- /dev/null
+++ b/.githooks/pre-commit
@@ -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
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..20fef1e
--- /dev/null
+++ b/.gitignore
@@ -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
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..cc42f68
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,11 @@
+{
+ "overrides": [
+ {
+ "files": "*.json",
+ "options": {
+ "tabWidth": 4,
+ "useTabs": false
+ }
+ }
+ ]
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..57cf996
--- /dev/null
+++ b/.vscode/settings.json
@@ -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"]
+}
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..b0fb4bc
--- /dev/null
+++ b/Makefile
@@ -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)
diff --git a/README.md b/README.md
index 00b78f3..366d7db 100644
--- a/README.md
+++ b/README.md
@@ -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.
diff --git a/package/contents/config/config.qml b/package/contents/config/config.qml
new file mode 100644
index 0000000..164708b
--- /dev/null
+++ b/package/contents/config/config.qml
@@ -0,0 +1,11 @@
+import QtQuick
+import org.kde.plasma.configuration
+
+ConfigModel {
+ ConfigCategory {
+ name: i18n("General")
+ icon: "preferences-desktop"
+ source: "configGeneral.qml"
+ }
+
+}
diff --git a/package/contents/config/main.xml b/package/contents/config/main.xml
new file mode 100644
index 0000000..d9b11eb
--- /dev/null
+++ b/package/contents/config/main.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+ 100
+
+
+
+ Noto Sans
+
+
+
diff --git a/plasmoid/contents/ui/Player.qml b/package/contents/ui/Player.qml
similarity index 67%
rename from plasmoid/contents/ui/Player.qml
rename to package/contents/ui/Player.qml
index 752e87a..3cc174c 100644
--- a/plasmoid/contents/ui/Player.qml
+++ b/package/contents/ui/Player.qml
@@ -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;
+
+ }
+ }
+
}
diff --git a/plasmoid/contents/ui/Representation.qml b/package/contents/ui/Representation.qml
similarity index 80%
rename from plasmoid/contents/ui/Representation.qml
rename to package/contents/ui/Representation.qml
index e7a7990..efba567 100644
--- a/plasmoid/contents/ui/Representation.qml
+++ b/package/contents/ui/Representation.qml
@@ -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
}
+
}
+
}
+
}
diff --git a/package/contents/ui/configGeneral.qml b/package/contents/ui/configGeneral.qml
new file mode 100644
index 0000000..fa61994
--- /dev/null
+++ b/package/contents/ui/configGeneral.qml
@@ -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
+ }
+
+ }
+
+}
diff --git a/package/contents/ui/main.qml b/package/contents/ui/main.qml
new file mode 100644
index 0000000..1868611
--- /dev/null
+++ b/package/contents/ui/main.qml
@@ -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
+ }
+
+}
diff --git a/plasmoid/metadata.json b/package/metadata.json
similarity index 90%
rename from plasmoid/metadata.json
rename to package/metadata.json
index d3fceaa..df52c36 100644
--- a/plasmoid/metadata.json
+++ b/package/metadata.json
@@ -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.*"
}
diff --git a/plasmoid/contents/config/config.qml b/plasmoid/contents/config/config.qml
deleted file mode 100644
index 7253f1c..0000000
--- a/plasmoid/contents/config/config.qml
+++ /dev/null
@@ -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"
- }
-}
\ No newline at end of file
diff --git a/plasmoid/contents/config/main.xml b/plasmoid/contents/config/main.xml
deleted file mode 100644
index 7feb4f2..0000000
--- a/plasmoid/contents/config/main.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
- 100
-
-
-
- "Noto Sans"
-
-
-
-
-
diff --git a/plasmoid/contents/ui/GeneralConfig.qml b/plasmoid/contents/ui/GeneralConfig.qml
deleted file mode 100644
index 8ded248..0000000
--- a/plasmoid/contents/ui/GeneralConfig.qml
+++ /dev/null
@@ -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()
- }
- }
- }
-
- }
-}
diff --git a/plasmoid/contents/ui/main.qml b/plasmoid/contents/ui/main.qml
deleted file mode 100644
index e27e3a1..0000000
--- a/plasmoid/contents/ui/main.qml
+++ /dev/null
@@ -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
- }
-}
diff --git a/run b/run
deleted file mode 100755
index b4550cf..0000000
--- a/run
+++ /dev/null
@@ -1,3 +0,0 @@
-kpackagetool6 -t Plasma/Applet --install plasmoid/
-kpackagetool6 -t Plasma/Applet --upgrade plasmoid/
-plasmoidviewer -a ./plasmoid
\ No newline at end of file
diff --git a/scripts/watch.sh b/scripts/watch.sh
new file mode 100755
index 0000000..f185069
--- /dev/null
+++ b/scripts/watch.sh
@@ -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