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
|
||||
|
||||
## 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.
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.*"
|
||||
}
|
||||
@@ -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