refactor: migration to be based on https://github.com/ruinivist/kde-6-widget-starter
This commit is contained in:
Executable
+14
@@ -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
@@ -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
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": "*.json",
|
||||||
|
"options": {
|
||||||
|
"tabWidth": 4,
|
||||||
|
"useTabs": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Vendored
+5
@@ -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"]
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
@@ -1,12 +1,95 @@
|
|||||||
# NowPlaying
|
# 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,\
|
## Prerequisites
|
||||||
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.
|
|
||||||
|
|
||||||
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.
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import QtQuick
|
||||||
|
import org.kde.plasma.configuration
|
||||||
|
|
||||||
|
ConfigModel {
|
||||||
|
ConfigCategory {
|
||||||
|
name: i18n("General")
|
||||||
|
icon: "preferences-desktop"
|
||||||
|
source: "configGeneral.qml"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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
|
looked handy, ty
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import QtQml.Models
|
||||||
import QtQuick 2.15
|
import QtQuick
|
||||||
import QtQml.Models 2.3
|
|
||||||
import org.kde.plasma.private.mpris as Mpris
|
import org.kde.plasma.private.mpris as Mpris
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: root
|
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 string sourceName: "any"
|
||||||
|
property var mpris2Model
|
||||||
readonly property bool ready: {
|
readonly property bool ready: {
|
||||||
if (!mpris2Model.currentPlayer) {
|
if (!mpris2Model.currentPlayer)
|
||||||
return false
|
return false;
|
||||||
}
|
|
||||||
return mpris2Model.currentPlayer.desktopEntry === sourceName || sourceName === "any";
|
return mpris2Model.currentPlayer.desktopEntry === sourceName || sourceName === "any";
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property string artists: ready ? mpris2Model.currentPlayer.artist : ""
|
readonly property string artists: ready ? mpris2Model.currentPlayer.artist : ""
|
||||||
readonly property string title: ready ? mpris2Model.currentPlayer.track : ""
|
readonly property string title: ready ? mpris2Model.currentPlayer.track : ""
|
||||||
readonly property int playbackStatus: ready ? mpris2Model.currentPlayer.playbackStatus : Mpris.PlaybackStatus.Unknown
|
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 double songLength: ready ? mpris2Model.currentPlayer.length : 0
|
||||||
readonly property real volume: ready ? mpris2Model.currentPlayer.volume : 0
|
readonly property real volume: ready ? mpris2Model.currentPlayer.volume : 0
|
||||||
readonly property string identity: ready ? mpris2Model.currentPlayer.identity : ""
|
readonly property string identity: ready ? mpris2Model.currentPlayer.identity : ""
|
||||||
|
|
||||||
readonly property bool canGoNext: ready ? mpris2Model.currentPlayer.canGoNext : false
|
readonly property bool canGoNext: ready ? mpris2Model.currentPlayer.canGoNext : false
|
||||||
readonly property bool canGoPrevious: ready ? mpris2Model.currentPlayer.canGoPrevious : false
|
readonly property bool canGoPrevious: ready ? mpris2Model.currentPlayer.canGoPrevious : false
|
||||||
readonly property bool canPlay: ready ? mpris2Model.currentPlayer.canPlay : false
|
readonly property bool canPlay: ready ? mpris2Model.currentPlayer.canPlay : false
|
||||||
readonly property bool canPause: ready ? mpris2Model.currentPlayer.canPause : false
|
readonly property bool canPause: ready ? mpris2Model.currentPlayer.canPause : false
|
||||||
readonly property bool canSeek: ready ? mpris2Model.currentPlayer.canSeek : false
|
readonly property bool canSeek: ready ? mpris2Model.currentPlayer.canSeek : false
|
||||||
readonly property bool canRaise: ready ? mpris2Model.currentPlayer.canRaise : 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,
|
// 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.
|
// CanPause, CanSeek, etc.
|
||||||
readonly property bool canChangeShuffle: ready ? mpris2Model.currentPlayer.shuffle != undefined : false
|
readonly property bool canChangeShuffle: ready ? mpris2Model.currentPlayer.shuffle !== undefined : false
|
||||||
readonly property bool canChangeLoopStatus: ready ? mpris2Model.currentPlayer.loopStatus != undefined : false
|
readonly property bool canChangeLoopStatus: ready ? mpris2Model.currentPlayer.loopStatus !== undefined : false
|
||||||
|
|
||||||
function togglePlayPause() {
|
function togglePlayPause() {
|
||||||
mpris2Model.currentPlayer?.PlayPause();
|
if (mpris2Model.currentPlayer)
|
||||||
|
mpris2Model.currentPlayer.PlayPause();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setPosition(position) {
|
function setPosition(position) {
|
||||||
@@ -64,19 +52,25 @@ QtObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function next() {
|
function next() {
|
||||||
mpris2Model.currentPlayer?.Next();
|
if (mpris2Model.currentPlayer)
|
||||||
|
mpris2Model.currentPlayer.Next();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function previous() {
|
function previous() {
|
||||||
mpris2Model.currentPlayer?.Previous();
|
if (mpris2Model.currentPlayer)
|
||||||
|
mpris2Model.currentPlayer.Previous();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function updatePosition() {
|
function updatePosition() {
|
||||||
mpris2Model.currentPlayer?.updatePosition();
|
if (mpris2Model.currentPlayer)
|
||||||
|
mpris2Model.currentPlayer.updatePosition();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setVolume(volume) {
|
function setVolume(volume) {
|
||||||
mpris2Model.currentPlayer.volume = volume
|
mpris2Model.currentPlayer.volume = volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeVolume(delta, showOSD) {
|
function changeVolume(delta, showOSD) {
|
||||||
@@ -84,11 +78,11 @@ QtObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setShuffle(shuffle) {
|
function setShuffle(shuffle) {
|
||||||
mpris2Model.currentPlayer.shuffle = shuffle
|
mpris2Model.currentPlayer.shuffle = shuffle;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setLoopStatus(loopStatus) {
|
function setLoopStatus(loopStatus) {
|
||||||
mpris2Model.currentPlayer.loopStatus = loopStatus
|
mpris2Model.currentPlayer.loopStatus = loopStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
function raise() {
|
function raise() {
|
||||||
@@ -96,12 +90,22 @@ QtObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function formatTrackTime(s) {
|
function formatTrackTime(s) {
|
||||||
var hours = Math.floor(s / 3600)
|
const hours = Math.floor(s / 3600);
|
||||||
var minutes = Math.floor((s - (hours * 3600)) / 60)
|
let minutes = Math.floor((s - hours * 3600) / 60);
|
||||||
var seconds = Math.ceil(s - (hours * 3600) - (minutes * 60))
|
let seconds = Math.ceil(s - hours * 3600 - minutes * 60);
|
||||||
minutes = (minutes < 10) ? "0" + minutes : minutes
|
minutes = minutes < 10 ? "0" + minutes : minutes;
|
||||||
seconds = (seconds < 10) ? "0" + seconds : seconds
|
seconds = seconds < 10 ? "0" + seconds : seconds;
|
||||||
var time = minutes + ":" + seconds
|
return minutes + ":" + seconds;
|
||||||
return time
|
}
|
||||||
|
|
||||||
|
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
|
||||||
import QtQuick.Layouts 1.15
|
import QtQuick.Controls as QQC2
|
||||||
import QtQuick.Controls 2.15
|
import QtQuick.Layouts
|
||||||
import org.kde.plasma.components as PlasmaComponents
|
|
||||||
import org.kde.plasma.core as PlasmaCore
|
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
|
import org.kde.plasma.components as PlasmaComponents
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: mediaControlsMouseArea
|
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
|
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 {
|
RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
Layout.fillHeight: true
|
|
||||||
id: leftColumn
|
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 {
|
Item {
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
@@ -38,80 +62,96 @@ MouseArea {
|
|||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: nowPlayingLabels
|
id: nowPlayingLabels
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
Label {
|
PlasmaComponents.Label {
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
text: "NOW"
|
text: "NOW"
|
||||||
lineHeight: 0.8
|
lineHeight: 0.8
|
||||||
font.pixelSize: 16
|
font.pixelSize: 16
|
||||||
font.bold: true
|
font.bold: true
|
||||||
|
// qmllint disable missing-property
|
||||||
font.family: plasmoid.configuration.fontFamily
|
font.family: plasmoid.configuration.fontFamily
|
||||||
}
|
}
|
||||||
Label {
|
|
||||||
|
PlasmaComponents.Label {
|
||||||
id: nowPlayingLabel2
|
id: nowPlayingLabel2
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
text: "PLAYING"
|
text: "PLAYING"
|
||||||
lineHeight: 0.8
|
lineHeight: 0.8
|
||||||
font.bold: true
|
font.bold: true
|
||||||
font.pixelSize: 16
|
font.pixelSize: 16
|
||||||
|
// qmllint disable missing-property
|
||||||
font.family: plasmoid.configuration.fontFamily
|
font.family: plasmoid.configuration.fontFamily
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: mediaControls
|
id: mediaControls
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
opacity: mediaControlsMouseArea.containsMouse ? 1 : 0
|
opacity: mediaControlsMouseArea.containsMouse ? 1 : 0
|
||||||
visible: opacity > 0
|
visible: opacity > 0
|
||||||
|
|
||||||
Behavior on opacity {
|
QQC2.Button {
|
||||||
PropertyAnimation {
|
|
||||||
easing.type: Easing.InOutQuad
|
|
||||||
duration: 250
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
Layout.preferredWidth: buttonSize
|
Layout.preferredWidth: buttonSize
|
||||||
Layout.preferredHeight: buttonSize
|
Layout.preferredHeight: buttonSize
|
||||||
|
padding: 0
|
||||||
|
background: null
|
||||||
|
onClicked: {
|
||||||
|
player.previous();
|
||||||
|
console.log("prev clicked");
|
||||||
|
}
|
||||||
|
|
||||||
contentItem: Kirigami.Icon {
|
contentItem: Kirigami.Icon {
|
||||||
source: "media-skip-backward"
|
source: "media-skip-backward"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QQC2.Button {
|
||||||
|
id: playButton
|
||||||
|
|
||||||
|
Layout.preferredWidth: buttonSize
|
||||||
|
Layout.preferredHeight: buttonSize
|
||||||
padding: 0
|
padding: 0
|
||||||
background: null
|
background: null
|
||||||
onClicked: {
|
onClicked: {
|
||||||
player.previous()
|
player.togglePlayPause();
|
||||||
console.log("prev clicked")
|
console.log("pause clicked");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Button {
|
|
||||||
Layout.preferredWidth: buttonSize
|
|
||||||
Layout.preferredHeight: buttonSize
|
|
||||||
id: playButton
|
|
||||||
contentItem: Kirigami.Icon {
|
contentItem: Kirigami.Icon {
|
||||||
source: player.playbackStatus === 2 ? "media-playback-pause" : "media-playback-start"
|
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.preferredWidth: buttonSize
|
||||||
Layout.preferredHeight: buttonSize
|
Layout.preferredHeight: buttonSize
|
||||||
|
padding: 0
|
||||||
|
background: null
|
||||||
|
onClicked: player.next()
|
||||||
|
|
||||||
contentItem: Kirigami.Icon {
|
contentItem: Kirigami.Icon {
|
||||||
source: "media-skip-forward"
|
source: "media-skip-forward"
|
||||||
}
|
}
|
||||||
onClicked: {
|
|
||||||
player.next()
|
|
||||||
}
|
}
|
||||||
padding: 0
|
|
||||||
background: null
|
Behavior on opacity {
|
||||||
|
PropertyAnimation {
|
||||||
|
duration: 250
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
@@ -119,61 +159,53 @@ MouseArea {
|
|||||||
Layout.fillWidth: true
|
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 {
|
transitions: Transition {
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
properties: "Layout.bottomMargin"
|
|
||||||
duration: 250
|
duration: 250
|
||||||
easing.type: Easing.InOutQuad
|
easing.type: Easing.InOutQuad
|
||||||
|
properties: "Layout.bottomMargin"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: separator
|
id: separator
|
||||||
width: 1
|
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
width: 1
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
Layout.fillWidth: true
|
|
||||||
id: infoColumn
|
id: infoColumn
|
||||||
PlasmaComponents.Label {
|
|
||||||
font.family: plasmoid.configuration.fontFamily
|
|
||||||
text: player.title
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
PlasmaComponents.Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: player.title
|
||||||
font.pixelSize: 28
|
font.pixelSize: 28
|
||||||
lineHeight: 0.8
|
|
||||||
font.bold: true
|
font.bold: true
|
||||||
|
// qmllint disable missing-property
|
||||||
|
font.family: plasmoid.configuration.fontFamily
|
||||||
|
lineHeight: 0.8
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
}
|
}
|
||||||
|
|
||||||
PlasmaComponents.Label {
|
PlasmaComponents.Label {
|
||||||
font.family: plasmoid.configuration.fontFamily
|
|
||||||
elide: Text.ElideRight
|
|
||||||
Layout.maximumWidth: 300
|
Layout.maximumWidth: 300
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: player.artists
|
text: player.artists
|
||||||
font.pixelSize: 26
|
font.pixelSize: 26
|
||||||
|
// qmllint disable missing-property
|
||||||
|
font.family: plasmoid.configuration.fontFamily
|
||||||
lineHeight: 0.8
|
lineHeight: 0.8
|
||||||
|
elide: Text.ElideRight
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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>
|
|
||||||
@@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
kpackagetool6 -t Plasma/Applet --install plasmoid/
|
|
||||||
kpackagetool6 -t Plasma/Applet --upgrade plasmoid/
|
|
||||||
plasmoidviewer -a ./plasmoid
|
|
||||||
Executable
+54
@@ -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
|
||||||
Reference in New Issue
Block a user