17 Commits

Author SHA1 Message Date
ruinivist 34ce24c192 merge: sync remote main 2026-07-12 10:01:11 +00:00
ruinivist a3ae405280 feat: add source whitelist mode (#21) 2026-07-12 09:55:50 +00:00
ruinivist c5f24dbb67 docs: shorter + done update 2026-06-07 03:13:49 +02:00
ruinivist e9e693c0a5 fix(ui): keep artwork visible when widget grows 2026-06-07 00:36:55 +00:00
ruinivist 85d822346f fix(ui): add artwork controls gap 2026-06-07 00:21:50 +00:00
ruinivist bd85a4fd4f fix(ui): smooth label hover animation 2026-06-07 00:15:04 +00:00
ruinivist 50cfc9e66e fix(ui): size label rail from available space 2026-06-06 23:55:34 +00:00
ruinivist 88074ccb47 feat(settings): add source priority selection 2026-06-06 22:41:39 +00:00
ruinivist 5a48b1b3a9 fix(ui): soften text shadow rendering 2026-05-30 14:48:51 +00:00
ruinivist 42268d7266 refactor(qml): replace qt5compat opacitymask with multieffect 2026-05-30 13:03:34 +00:00
ruinivist 6d8f237547 refactor(ui): extract label content component 2026-05-30 12:43:00 +00:00
ruinivist 45906f07c6 fix(ui): preserve separator spacing when hidden 2026-05-30 12:02:13 +00:00
ruinivist c26793dfe2 feat(ui): add hide separator setting 2026-05-30 11:59:43 +00:00
ruinivist de22c05c33 docs: add commit style instructions for agents 2026-05-30 11:53:34 +00:00
ruinivist 3d334b9896 feat: add configurable image border radius 2026-05-30 11:47:17 +00:00
ruinivist 7045ecf8e6 feat: add option to disable media controls 2026-05-30 11:14:45 +00:00
ruinivist b88c2ba3c5 feat: add optional label artwork mode 2026-05-30 11:08:56 +00:00
9 changed files with 747 additions and 245 deletions
+19
View File
@@ -0,0 +1,19 @@
# AGENTS
## Commit Style
- Use Conventional Commits for every commit message.
- Required format: `type(scope): subject` or `type: subject`.
- Keep `type`, optional `scope`, and subject text lowercase.
- Use imperative, concise subjects.
- Proper nouns may keep their normal capitalization only when necessary.
Valid examples:
- `feat(ui): add artist text truncation`
- `fix: handle empty metadata values`
- `chore(release): bump plasmoid version`
Invalid examples:
- `Feat(ui): add artist text truncation` (uppercase type)
- `fix(UI): handle empty metadata values` (uppercase scope)
- `fix: Handle empty metadata values` (uppercase subject)
+2 -44
View File
@@ -2,9 +2,9 @@
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. 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.
Now on KDE 6: https://www.pling.com/p/2195583/ https://www.pling.com/p/2195583/
> Too little too late but I plan to update it regularly now if any issues are created - ruinivist > I think this is pretty much in a "done" state now feature-wise, except of course any bug fixes
## Prerequisites ## Prerequisites
@@ -50,48 +50,6 @@ Create a distributable package:
make package 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
```
## Customization ## Customization
The widget appearance can be tuned from the Plasma widget settings, including: The widget appearance can be tuned from the Plasma widget settings, including:
+24
View File
@@ -38,6 +38,14 @@
<default><![CDATA[NOW <default><![CDATA[NOW
PLAYING]]></default> PLAYING]]></default>
</entry> </entry>
<entry name="useLabelArtwork" type="Bool">
<label>Show track image when available</label>
<default>false</default>
</entry>
<entry name="imageBorderRadius" type="Int">
<label>Image border radius</label>
<default>8</default>
</entry>
<entry name="backgroundStyle" type="String"> <entry name="backgroundStyle" type="String">
<label>Background style</label> <label>Background style</label>
<default>custom</default> <default>custom</default>
@@ -58,6 +66,18 @@ PLAYING]]></default>
<label>Enable text shadow</label> <label>Enable text shadow</label>
<default>false</default> <default>false</default>
</entry> </entry>
<entry name="showMediaControls" type="Bool">
<label>Show media controls</label>
<default>true</default>
</entry>
<entry name="sourcePriority" type="String">
<label>Source priority</label>
<default></default>
</entry>
<entry name="sourceWhitelist" type="Bool">
<label>Only use listed sources</label>
<default>false</default>
</entry>
<entry name="trackTextVerticalSpacing" type="Int"> <entry name="trackTextVerticalSpacing" type="Int">
<label>Track text vertical spacing</label> <label>Track text vertical spacing</label>
<default>5</default> <default>5</default>
@@ -78,5 +98,9 @@ PLAYING]]></default>
<label>Separator height percent</label> <label>Separator height percent</label>
<default>90</default> <default>90</default>
</entry> </entry>
<entry name="hideSeparator" type="Bool">
<label>Hide separator</label>
<default>false</default>
</entry>
</group> </group>
</kcfg> </kcfg>
+284
View File
@@ -0,0 +1,284 @@
import QtQuick
import QtQuick.Effects
Item {
id: labelContent
required property string artworkSource
required property var labelLines
required property string fontFamily
required property real fontPixelSize
required property string textColor
required property bool textShadowEnabled
required property int verticalSpacing
required property int horizontalAlignment
required property int borderRadius
required property real artworkSize
property string currentArtworkSource: ""
property string incomingArtworkSource: ""
property real currentArtworkOpacity: 0
property real incomingArtworkOpacity: 0
property bool crossfadeActive: false
readonly property bool artworkVisible: currentArtworkOpacity > 0 || incomingArtworkOpacity > 0
readonly property bool holdsArtworkSlot: currentArtworkSource.length > 0 || artworkVisible
readonly property real textOpacity: crossfadeActive || (currentArtworkSource.length > 0 && incomingArtworkSource.length > 0) ? 0 : 1 - Math.max(currentArtworkOpacity, incomingArtworkOpacity)
function resetIncomingArtwork() {
incomingArtworkSource = "";
incomingArtworkOpacity = 0;
crossfadeActive = false;
}
function finishIncomingArtwork() {
currentArtworkSource = incomingArtworkSource;
currentArtworkOpacity = incomingArtworkOpacity;
resetIncomingArtwork();
}
function clearCurrentArtwork() {
currentArtworkSource = "";
currentArtworkOpacity = 0;
resetIncomingArtwork();
}
function startFadeOutToText() {
crossfadeAnimation.stop();
fadeInIncomingArtwork.stop();
resetIncomingArtwork();
if (currentArtworkSource.length === 0 && currentArtworkOpacity === 0) {
clearCurrentArtwork();
return ;
}
fadeOutCurrentArtwork.restart();
}
function handleArtworkSourceChange() {
const nextSource = artworkSource;
if (nextSource.length === 0) {
startFadeOutToText();
return ;
}
if (nextSource === currentArtworkSource) {
fadeOutCurrentArtwork.stop();
currentArtworkOpacity = currentArtworkSource.length > 0 ? 1 : 0;
resetIncomingArtwork();
return ;
}
if (nextSource === incomingArtworkSource)
return ;
fadeOutCurrentArtwork.stop();
if (currentArtworkSource.length > 0)
currentArtworkOpacity = 1;
crossfadeAnimation.stop();
fadeInIncomingArtwork.stop();
incomingArtworkSource = nextSource;
incomingArtworkOpacity = 0;
crossfadeActive = false;
}
function startIncomingTransition() {
if (incomingArtworkSource.length === 0 || incomingArtworkSource !== artworkSource)
return ;
fadeOutCurrentArtwork.stop();
incomingArtworkOpacity = 0;
if (currentArtworkSource.length > 0 && currentArtworkOpacity > 0) {
crossfadeActive = true;
currentArtworkOpacity = 1;
crossfadeAnimation.restart();
} else {
crossfadeActive = false;
currentArtworkOpacity = 0;
fadeInIncomingArtwork.restart();
}
}
function handleIncomingArtworkFailure() {
if (incomingArtworkSource.length === 0)
return ;
resetIncomingArtwork();
startFadeOutToText();
}
clip: holdsArtworkSlot
implicitWidth: artworkSize
implicitHeight: artworkSize
onArtworkSourceChanged: handleArtworkSourceChange()
Component.onCompleted: handleArtworkSourceChange()
Image {
id: currentArtworkImage
anchors.fill: parent
asynchronous: true
cache: true
fillMode: Image.PreserveAspectCrop
opacity: 0
source: labelContent.currentArtworkSource
sourceSize.width: labelContent.artworkSize
sourceSize.height: labelContent.artworkSize
}
Image {
id: incomingArtworkImage
anchors.fill: parent
asynchronous: true
cache: true
fillMode: Image.PreserveAspectCrop
opacity: 0
source: labelContent.incomingArtworkSource
sourceSize.width: labelContent.artworkSize
sourceSize.height: labelContent.artworkSize
onSourceChanged: labelContent.incomingArtworkOpacity = 0
onStatusChanged: {
if (source.toString().length === 0)
return ;
if (status === Image.Ready)
labelContent.startIncomingTransition();
else if (status === Image.Error)
labelContent.handleIncomingArtworkFailure();
}
}
Rectangle {
id: artworkMaskShape
anchors.fill: parent
antialiasing: true
color: "white"
layer.enabled: true
radius: labelContent.borderRadius
visible: false
}
MultiEffect {
id: currentArtworkMask
anchors.fill: parent
autoPaddingEnabled: false
maskEnabled: true
maskSource: artworkMaskShape
source: currentArtworkImage
opacity: labelContent.currentArtworkOpacity
visible: labelContent.currentArtworkSource.length > 0 && opacity > 0
}
MultiEffect {
id: incomingArtworkMask
anchors.fill: parent
autoPaddingEnabled: false
maskEnabled: true
maskSource: artworkMaskShape
source: incomingArtworkImage
opacity: labelContent.incomingArtworkOpacity
visible: labelContent.incomingArtworkSource.length > 0 && opacity > 0
}
Column {
id: labelTextColumn
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: labelContent.verticalSpacing
opacity: labelContent.textOpacity
visible: opacity > 0
Repeater {
model: labelContent.labelLines
delegate: ShadowedLabel {
required property string modelData
width: labelTextColumn.width
shadowEnabled: labelContent.textShadowEnabled
text: modelData
lineHeight: 0.8
font.bold: true
font.pixelSize: labelContent.fontPixelSize
font.family: labelContent.fontFamily
color: labelContent.textColor
horizontalAlignment: labelContent.horizontalAlignment
}
}
Behavior on opacity {
NumberAnimation {
duration: 250
easing.type: Easing.InOutQuad
}
}
}
SequentialAnimation {
id: crossfadeAnimation
ParallelAnimation {
NumberAnimation {
target: labelContent
property: "currentArtworkOpacity"
to: 0
duration: 250
easing.type: Easing.InOutQuad
}
NumberAnimation {
target: labelContent
property: "incomingArtworkOpacity"
to: 1
duration: 250
easing.type: Easing.InOutQuad
}
}
ScriptAction {
script: labelContent.finishIncomingArtwork()
}
}
SequentialAnimation {
id: fadeInIncomingArtwork
NumberAnimation {
target: labelContent
property: "incomingArtworkOpacity"
to: 1
duration: 250
easing.type: Easing.InOutQuad
}
ScriptAction {
script: labelContent.finishIncomingArtwork()
}
}
SequentialAnimation {
id: fadeOutCurrentArtwork
NumberAnimation {
target: labelContent
property: "currentArtworkOpacity"
to: 0
duration: 250
easing.type: Easing.InOutQuad
}
ScriptAction {
script: labelContent.clearCurrentArtwork()
}
}
}
+116 -41
View File
@@ -11,82 +11,159 @@ import org.kde.plasma.private.mpris as Mpris
QtObject { QtObject {
id: root id: root
readonly property int containerRole: Qt.UserRole + 1
property string sourceName: "any" property string sourceName: "any"
property string sourcePriority: ""
property bool sourceWhitelist: false
property var mpris2Model property var mpris2Model
property int modelRevision: 0
readonly property var normalizedSourcePriority: parseSourcePriority(sourcePriority)
readonly property var resolvedPlayer: resolvePlayer()
readonly property bool ready: { readonly property bool ready: {
if (!mpris2Model.currentPlayer) if (!resolvedPlayer)
return false; return false;
return mpris2Model.currentPlayer.desktopEntry === sourceName || sourceName === "any"; return sourceName === "any" || entriesMatch(resolvedPlayer.desktopEntry, sourceName);
} }
readonly property string artists: ready ? mpris2Model.currentPlayer.artist : "" readonly property string artists: ready ? resolvedPlayer.artist : ""
readonly property string title: ready ? mpris2Model.currentPlayer.track : "" readonly property string title: ready ? resolvedPlayer.track : ""
readonly property int playbackStatus: ready ? mpris2Model.currentPlayer.playbackStatus : Mpris.PlaybackStatus.Unknown readonly property int playbackStatus: ready ? resolvedPlayer.playbackStatus : Mpris.PlaybackStatus.Unknown
readonly property int shuffle: ready ? mpris2Model.currentPlayer.shuffle : Mpris.ShuffleStatus.Unknown readonly property int shuffle: ready ? resolvedPlayer.shuffle : Mpris.ShuffleStatus.Unknown
readonly property string artUrl: ready ? mpris2Model.currentPlayer.artUrl : "" readonly property string artUrl: ready ? resolvedPlayer.artUrl : ""
readonly property int loopStatus: ready ? mpris2Model.currentPlayer.loopStatus : Mpris.LoopStatus.Unknown readonly property int loopStatus: ready ? resolvedPlayer.loopStatus : Mpris.LoopStatus.Unknown
readonly property double songPosition: ready ? mpris2Model.currentPlayer.position : 0 readonly property double songPosition: ready ? resolvedPlayer.position : 0
readonly property double songLength: ready ? mpris2Model.currentPlayer.length : 0 readonly property double songLength: ready ? resolvedPlayer.length : 0
readonly property real volume: ready ? mpris2Model.currentPlayer.volume : 0 readonly property real volume: ready ? resolvedPlayer.volume : 0
readonly property string identity: ready ? mpris2Model.currentPlayer.identity : "" readonly property string identity: ready ? resolvedPlayer.identity : ""
readonly property bool canGoNext: ready ? mpris2Model.currentPlayer.canGoNext : false readonly property bool canGoNext: ready ? resolvedPlayer.canGoNext : false
readonly property bool canGoPrevious: ready ? mpris2Model.currentPlayer.canGoPrevious : false readonly property bool canGoPrevious: ready ? resolvedPlayer.canGoPrevious : false
readonly property bool canPlay: ready ? mpris2Model.currentPlayer.canPlay : false readonly property bool canPlay: ready ? resolvedPlayer.canPlay : false
readonly property bool canPause: ready ? mpris2Model.currentPlayer.canPause : false readonly property bool canPause: ready ? resolvedPlayer.canPause : false
readonly property bool canSeek: ready ? mpris2Model.currentPlayer.canSeek : false readonly property bool canSeek: ready ? resolvedPlayer.canSeek : false
readonly property bool canRaise: ready ? mpris2Model.currentPlayer.canRaise : false readonly property bool canRaise: ready ? resolvedPlayer.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 do not have specific properties 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 ? resolvedPlayer.shuffle !== undefined : false
readonly property bool canChangeLoopStatus: ready ? mpris2Model.currentPlayer.loopStatus !== undefined : false readonly property bool canChangeLoopStatus: ready ? resolvedPlayer.loopStatus !== undefined : false
function normalizedEntry(value) {
return (value || "").toString().trim().toLowerCase();
}
function entriesMatch(left, right) {
const normalizedLeft = normalizedEntry(left);
const normalizedRight = normalizedEntry(right);
if (!normalizedLeft || !normalizedRight)
return false;
return normalizedLeft === normalizedRight;
}
function parseSourcePriority(value) {
return (value || "").split(",").map((entry) => {
return normalizedEntry(entry);
}).filter((entry) => {
return entry.length > 0;
});
}
function playerAt(row) {
if (!mpris2Model || row < 0 || row >= mpris2Model.rowCount())
return null;
return mpris2Model.data(mpris2Model.index(row, 0), containerRole);
}
function findPlayerByEntry(targetEntry) {
if (!targetEntry || !mpris2Model)
return null;
const playerCount = mpris2Model.rowCount();
for (let row = 0; row < playerCount; ++row) {
const player = playerAt(row);
if (player && entriesMatch(player.desktopEntry, targetEntry))
return player;
}
return null;
}
function resolvePlayer() {
modelRevision;
if (!mpris2Model)
return null;
for (const targetEntry of normalizedSourcePriority) {
const matchedPlayer = findPlayerByEntry(targetEntry);
if (matchedPlayer)
return matchedPlayer;
}
if (sourceWhitelist && normalizedSourcePriority.length > 0)
return null;
return mpris2Model.currentPlayer || null;
}
function togglePlayPause() { function togglePlayPause() {
if (mpris2Model.currentPlayer) if (resolvedPlayer)
mpris2Model.currentPlayer.PlayPause(); resolvedPlayer.PlayPause();
} }
function setPosition(position) { function setPosition(position) {
mpris2Model.currentPlayer.position = position; if (resolvedPlayer)
resolvedPlayer.position = position;
} }
function next() { function next() {
if (mpris2Model.currentPlayer) if (resolvedPlayer)
mpris2Model.currentPlayer.Next(); resolvedPlayer.Next();
} }
function previous() { function previous() {
if (mpris2Model.currentPlayer) if (resolvedPlayer)
mpris2Model.currentPlayer.Previous(); resolvedPlayer.Previous();
} }
function updatePosition() { function updatePosition() {
if (mpris2Model.currentPlayer) if (resolvedPlayer)
mpris2Model.currentPlayer.updatePosition(); resolvedPlayer.updatePosition();
} }
function setVolume(volume) { function setVolume(volume) {
mpris2Model.currentPlayer.volume = volume; if (resolvedPlayer)
resolvedPlayer.volume = volume;
} }
function changeVolume(delta, showOSD) { function changeVolume(delta, showOSD) {
mpris2Model.currentPlayer.changeVolume(delta, showOSD); if (resolvedPlayer)
resolvedPlayer.changeVolume(delta, showOSD);
} }
function setShuffle(shuffle) { function setShuffle(shuffle) {
mpris2Model.currentPlayer.shuffle = shuffle; if (resolvedPlayer)
resolvedPlayer.shuffle = shuffle;
} }
function setLoopStatus(loopStatus) { function setLoopStatus(loopStatus) {
mpris2Model.currentPlayer.loopStatus = loopStatus; if (resolvedPlayer)
resolvedPlayer.loopStatus = loopStatus;
} }
function raise() { function raise() {
mpris2Model.currentPlayer.Raise(); if (resolvedPlayer)
resolvedPlayer.Raise();
} }
function formatTrackTime(s) { function formatTrackTime(s) {
@@ -99,13 +176,11 @@ QtObject {
} }
mpris2Model: Mpris.Mpris2Model { mpris2Model: Mpris.Mpris2Model {
onRowsInserted: (_, rowIndex) => { onRowsInserted: root.modelRevision += 1
const CONTAINER_ROLE = Qt.UserRole + 1; onRowsRemoved: root.modelRevision += 1
const player = this.data(this.index(rowIndex, 0), CONTAINER_ROLE); onModelReset: root.modelRevision += 1
if (player.desktopEntry === root.sourceName) onDataChanged: root.modelRevision += 1
this.currentIndex = rowIndex; onCurrentPlayerChanged: root.modelRevision += 1
}
} }
} }
+88 -134
View File
@@ -2,7 +2,6 @@ import QtQuick
import QtQuick.Controls as QQC2 import QtQuick.Controls as QQC2
import QtQuick.Layouts import QtQuick.Layouts
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
@@ -14,23 +13,44 @@ MouseArea {
property string configuredLabelVisibilityMode: "auto" property string configuredLabelVisibilityMode: "auto"
property string configuredLabelPlacement: "left" property string configuredLabelPlacement: "left"
property string configuredLabelText: "NOW\nPLAYING" property string configuredLabelText: "NOW\nPLAYING"
property bool configuredUseLabelArtwork: false
property int configuredImageBorderRadius: 8
property string configuredBackgroundStyle: "custom" property string configuredBackgroundStyle: "custom"
property string configuredBackgroundColor: "transparent" property string configuredBackgroundColor: "transparent"
property int configuredBackgroundRadius: 0 property int configuredBackgroundRadius: 0
property string configuredForegroundColor: "white" property string configuredForegroundColor: "white"
property bool configuredTextShadowEnabled: false property bool configuredTextShadowEnabled: false
property bool configuredShowMediaControls: true
property int configuredTrackTextVerticalSpacing: 5 property int configuredTrackTextVerticalSpacing: 5
property int configuredLabelVerticalSpacing: 0 property int configuredLabelVerticalSpacing: 0
property int configuredSeparatorGapLabel: 4 property int configuredSeparatorGapLabel: 4
property int configuredSeparatorGapTrack: 4 property int configuredSeparatorGapTrack: 4
property int configuredSeparatorHeight: 90 property int configuredSeparatorHeight: 90
property bool configuredHideSeparator: false
readonly property double buttonSize: 16 readonly property double buttonSize: 16
readonly property string effectiveLabelVisibilityMode: configuredLabelVisibilityMode === "always" || configuredLabelVisibilityMode === "never" ? configuredLabelVisibilityMode : "auto" readonly property string effectiveLabelVisibilityMode: configuredLabelVisibilityMode === "always" || configuredLabelVisibilityMode === "never" ? configuredLabelVisibilityMode : "auto"
readonly property bool labelsOnRight: configuredLabelPlacement === "right" readonly property bool labelsOnRight: configuredLabelPlacement === "right"
readonly property bool hideNowPlayingArea: effectiveLabelVisibilityMode === "never" readonly property bool hideNowPlayingArea: effectiveLabelVisibilityMode === "never"
readonly property bool usesCustomBackground: configuredBackgroundStyle === "custom" readonly property bool usesCustomBackground: configuredBackgroundStyle === "custom"
readonly property int hideModeHorizontalPadding: 8 readonly property int hideModeHorizontalPadding: 8
readonly property int labelRailWidth: 100 readonly property int contentInset: 8
readonly property int availableContentWidth: Math.max(0, width - contentInset * 2)
readonly property int separatorReservedWidth: nowPlayingLabelsVisible && !hideNowPlayingArea ? 1 + effectiveSeparatorGapLabel + effectiveSeparatorGapTrack : 0
readonly property int maxLabelRailSize: Math.max(0, availableContentWidth - separatorReservedWidth)
readonly property int labelRailSize: Math.max(0, Math.min(height - contentInset * 2, maxLabelRailSize))
readonly property bool mediaControlsTargetShown: mediaControlsEnabled && controlsHoverActive && nowPlayingLabelsVisible && !hideNowPlayingArea
readonly property int artworkControlsGap: configuredUseLabelArtwork && player.artUrl.length > 0 ? 2 : 0
readonly property real labelShrunkScale: labelRailSize > 0 ? Math.max(0, (labelRailSize - buttonSize - artworkControlsGap) / labelRailSize) : 1
property real labelContentScale: mediaControlsTargetShown ? labelShrunkScale : 1
readonly property real controlsReveal: {
const range = 1 - labelShrunkScale;
if (range <= 0)
return mediaControlsTargetShown ? 1 : 0;
return Math.max(0, Math.min(1, (1 - labelContentScale) / range));
}
readonly property real labelContentSize: labelRailSize * labelContentScale
readonly property int effectiveImageBorderRadius: Math.max(0, configuredImageBorderRadius)
readonly property string effectiveBackgroundColor: configuredBackgroundColor || "transparent" readonly property string effectiveBackgroundColor: configuredBackgroundColor || "transparent"
readonly property int effectiveBackgroundRadius: Math.max(0, configuredBackgroundRadius) readonly property int effectiveBackgroundRadius: Math.max(0, configuredBackgroundRadius)
readonly property string effectiveForegroundColor: configuredForegroundColor || "white" readonly property string effectiveForegroundColor: configuredForegroundColor || "white"
@@ -43,9 +63,10 @@ MouseArea {
readonly property int effectiveSeparatorGapTrack: Math.max(0, configuredSeparatorGapTrack) readonly property int effectiveSeparatorGapTrack: Math.max(0, configuredSeparatorGapTrack)
readonly property int effectiveSeparatorHeight: Math.max(0, Math.min(100, configuredSeparatorHeight)) readonly property int effectiveSeparatorHeight: Math.max(0, Math.min(100, configuredSeparatorHeight))
readonly property var effectiveLabelLines: (configuredLabelText || "").split(/\r?\n/) readonly property var effectiveLabelLines: (configuredLabelText || "").split(/\r?\n/)
readonly property bool mediaControlsEnabled: configuredShowMediaControls
readonly property bool hasTrackInfo: player.ready && (((player.title || "").trim().length > 0) || ((player.artists || "").trim().length > 0)) readonly property bool hasTrackInfo: player.ready && (((player.title || "").trim().length > 0) || ((player.artists || "").trim().length > 0))
readonly property bool rawHoverActive: rootHoverHandler.hovered readonly property bool rawHoverActive: mediaControlsEnabled && rootHoverHandler.hovered
readonly property bool controlsHoverActive: rawHoverActive || hoverExitTimer.running readonly property bool controlsHoverActive: mediaControlsEnabled && (rawHoverActive || hoverExitTimer.running)
readonly property bool nowPlayingLabelsVisible: { readonly property bool nowPlayingLabelsVisible: {
if (effectiveLabelVisibilityMode === "always") if (effectiveLabelVisibilityMode === "always")
return true; return true;
@@ -60,12 +81,24 @@ MouseArea {
acceptedButtons: Qt.NoButton acceptedButtons: Qt.NoButton
hoverEnabled: true hoverEnabled: true
onRawHoverActiveChanged: { onRawHoverActiveChanged: {
if (!mediaControlsMouseArea.mediaControlsEnabled) {
hoverExitTimer.stop();
return;
}
if (rawHoverActive) if (rawHoverActive)
hoverExitTimer.stop(); hoverExitTimer.stop();
else else
hoverExitTimer.restart(); hoverExitTimer.restart();
} }
Keys.onPressed: (event) => { onMediaControlsEnabledChanged: {
if (!mediaControlsMouseArea.mediaControlsEnabled)
hoverExitTimer.stop();
}
Keys.onPressed: event => {
if (!mediaControlsMouseArea.mediaControlsEnabled) {
event.accepted = false;
return;
}
if (!event.modifiers) { if (!event.modifiers) {
event.accepted = true; event.accepted = true;
if (event.key === Qt.Key_Space || event.key === Qt.Key_K) if (event.key === Qt.Key_Space || event.key === Qt.Key_K)
@@ -82,7 +115,8 @@ MouseArea {
HoverHandler { HoverHandler {
id: rootHoverHandler id: rootHoverHandler
margin: 12 enabled: mediaControlsMouseArea.mediaControlsEnabled
margin: 60
} }
Timer { Timer {
@@ -91,6 +125,13 @@ MouseArea {
interval: 300 interval: 300
} }
Behavior on labelContentScale {
NumberAnimation {
duration: 250
easing.type: Easing.InOutQuad
}
}
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
visible: mediaControlsMouseArea.usesCustomBackground visible: mediaControlsMouseArea.usesCustomBackground
@@ -100,81 +141,65 @@ MouseArea {
RowLayout { RowLayout {
anchors.fill: parent anchors.fill: parent
anchors.margins: mediaControlsMouseArea.contentInset
layoutDirection: mediaControlsMouseArea.labelsOnRight ? Qt.RightToLeft : Qt.LeftToRight layoutDirection: mediaControlsMouseArea.labelsOnRight ? Qt.RightToLeft : Qt.LeftToRight
ColumnLayout { Item {
id: leftColumn id: leftColumn
visible: !mediaControlsMouseArea.hideNowPlayingArea visible: !mediaControlsMouseArea.hideNowPlayingArea
Layout.fillHeight: true Layout.fillHeight: true
Layout.minimumWidth: visible ? mediaControlsMouseArea.labelRailWidth : 0 Layout.minimumWidth: visible ? mediaControlsMouseArea.labelRailSize : 0
Layout.preferredWidth: visible ? mediaControlsMouseArea.labelRailWidth : 0 Layout.preferredWidth: visible ? mediaControlsMouseArea.labelRailSize : 0
Layout.maximumWidth: visible ? mediaControlsMouseArea.labelRailWidth : 0 Layout.maximumWidth: visible ? mediaControlsMouseArea.labelRailSize : 0
states: [
State {
name: "buttonsVisible"
when: mediaControlsMouseArea.controlsHoverActive
PropertyChanges {
target: nowPlayingLabels
Layout.bottomMargin: 10
}
},
State {
name: "buttonsHidden"
when: !mediaControlsMouseArea.controlsHoverActive
PropertyChanges {
target: nowPlayingLabels
Layout.bottomMargin: 0
}
}
]
Item { Item {
Layout.fillHeight: true id: labelSlot
Layout.fillWidth: true
}
ColumnLayout { readonly property bool showsArtwork: mediaControlsMouseArea.configuredUseLabelArtwork && player.artUrl.length > 0
id: nowPlayingLabels // Text is rasterized at whole pixel sizes, then lightly scaled between steps for smoother motion.
readonly property real textTargetFontSize: Math.max(1, mediaControlsMouseArea.effectiveLabelFontSize * mediaControlsMouseArea.labelContentScale)
readonly property int textRasterFontSize: Math.max(1, Math.round(textTargetFontSize))
readonly property real textResidualScale: textTargetFontSize / textRasterFontSize
Layout.alignment: mediaControlsMouseArea.labelsOnRight ? Qt.AlignLeft : Qt.AlignRight x: mediaControlsMouseArea.labelsOnRight ? 0 : leftColumn.width - width
Layout.fillWidth: true y: 0
spacing: mediaControlsMouseArea.effectiveLabelVerticalSpacing width: mediaControlsMouseArea.labelContentSize
height: mediaControlsMouseArea.labelContentSize
clip: true
visible: mediaControlsMouseArea.nowPlayingLabelsVisible visible: mediaControlsMouseArea.nowPlayingLabelsVisible
Repeater { LabelContent {
model: mediaControlsMouseArea.effectiveLabelLines anchors.left: parent.left
anchors.top: parent.top
delegate: ShadowedLabel { width: labelSlot.showsArtwork ? mediaControlsMouseArea.labelRailSize : mediaControlsMouseArea.labelContentSize / labelSlot.textResidualScale
required property string modelData height: labelSlot.showsArtwork ? mediaControlsMouseArea.labelRailSize : mediaControlsMouseArea.labelContentSize / labelSlot.textResidualScale
scale: labelSlot.showsArtwork ? mediaControlsMouseArea.labelContentScale : labelSlot.textResidualScale
Layout.alignment: mediaControlsMouseArea.labelsOnRight ? Qt.AlignLeft : Qt.AlignRight transformOrigin: Item.TopLeft
Layout.fillWidth: true artworkSource: mediaControlsMouseArea.configuredUseLabelArtwork ? player.artUrl : ""
shadowEnabled: mediaControlsMouseArea.configuredTextShadowEnabled labelLines: mediaControlsMouseArea.effectiveLabelLines
text: modelData fontFamily: mediaControlsMouseArea.configuredFontFamily
lineHeight: 0.8 fontPixelSize: labelSlot.showsArtwork ? mediaControlsMouseArea.effectiveLabelFontSize : labelSlot.textRasterFontSize
font.bold: true textColor: mediaControlsMouseArea.effectiveForegroundColor
font.pixelSize: mediaControlsMouseArea.effectiveLabelFontSize textShadowEnabled: mediaControlsMouseArea.configuredTextShadowEnabled
font.family: mediaControlsMouseArea.configuredFontFamily verticalSpacing: mediaControlsMouseArea.effectiveLabelVerticalSpacing
color: mediaControlsMouseArea.effectiveForegroundColor
horizontalAlignment: mediaControlsMouseArea.labelsOnRight ? Text.AlignLeft : Text.AlignRight horizontalAlignment: mediaControlsMouseArea.labelsOnRight ? Text.AlignLeft : Text.AlignRight
borderRadius: mediaControlsMouseArea.effectiveImageBorderRadius
artworkSize: labelSlot.showsArtwork ? mediaControlsMouseArea.labelRailSize : mediaControlsMouseArea.labelContentSize / labelSlot.textResidualScale
} }
}
} }
RowLayout { RowLayout {
id: mediaControls id: mediaControls
Layout.alignment: mediaControlsMouseArea.labelsOnRight ? Qt.AlignLeft : Qt.AlignRight x: mediaControlsMouseArea.labelsOnRight ? 0 : leftColumn.width - width
enabled: mediaControlsMouseArea.controlsHoverActive y: mediaControlsMouseArea.labelContentSize + mediaControlsMouseArea.artworkControlsGap
opacity: mediaControlsMouseArea.controlsHoverActive && mediaControlsMouseArea.nowPlayingLabelsVisible && !mediaControlsMouseArea.hideNowPlayingArea ? 1 : 0 width: implicitWidth
visible: mediaControlsMouseArea.controlsHoverActive && mediaControlsMouseArea.nowPlayingLabelsVisible && !mediaControlsMouseArea.hideNowPlayingArea height: mediaControlsMouseArea.buttonSize
clip: true
enabled: mediaControlsMouseArea.mediaControlsTargetShown
opacity: mediaControlsMouseArea.controlsReveal
visible: mediaControlsMouseArea.mediaControlsTargetShown || opacity > 0
QQC2.Button { QQC2.Button {
Layout.preferredWidth: buttonSize Layout.preferredWidth: buttonSize
@@ -190,7 +215,6 @@ MouseArea {
source: "media-skip-backward" source: "media-skip-backward"
color: mediaControlsMouseArea.effectiveForegroundColor color: mediaControlsMouseArea.effectiveForegroundColor
} }
} }
QQC2.Button { QQC2.Button {
@@ -209,7 +233,6 @@ MouseArea {
source: player.playbackStatus === 2 ? "media-playback-pause" : "media-playback-start" source: player.playbackStatus === 2 ? "media-playback-pause" : "media-playback-start"
color: mediaControlsMouseArea.effectiveForegroundColor color: mediaControlsMouseArea.effectiveForegroundColor
} }
} }
QQC2.Button { QQC2.Button {
@@ -223,33 +246,8 @@ MouseArea {
source: "media-skip-forward" source: "media-skip-forward"
color: mediaControlsMouseArea.effectiveForegroundColor color: mediaControlsMouseArea.effectiveForegroundColor
} }
} }
Behavior on opacity {
PropertyAnimation {
duration: 250
easing.type: Easing.InOutQuad
} }
}
}
Item {
Layout.fillHeight: true
Layout.fillWidth: true
}
transitions: Transition {
NumberAnimation {
duration: 250
easing.type: Easing.InOutQuad
properties: "Layout.bottomMargin"
}
}
} }
Item { Item {
@@ -268,9 +266,8 @@ MouseArea {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: 1 width: 1
height: Math.round(parent.height * mediaControlsMouseArea.effectiveSeparatorHeight / 100) height: Math.round(parent.height * mediaControlsMouseArea.effectiveSeparatorHeight / 100)
color: mediaControlsMouseArea.effectiveForegroundColor color: mediaControlsMouseArea.configuredHideSeparator ? "transparent" : mediaControlsMouseArea.effectiveForegroundColor
} }
} }
ColumnLayout { ColumnLayout {
@@ -307,49 +304,6 @@ MouseArea {
elide: Text.ElideRight elide: Text.ElideRight
horizontalAlignment: mediaControlsMouseArea.labelsOnRight ? Text.AlignRight : Text.AlignLeft horizontalAlignment: mediaControlsMouseArea.labelsOnRight ? Text.AlignRight : Text.AlignLeft
} }
} }
} }
component ShadowedLabel: Item {
id: shadowedLabel
property alias text: foregroundLabel.text
property alias font: foregroundLabel.font
property alias lineHeight: foregroundLabel.lineHeight
property alias elide: foregroundLabel.elide
property alias horizontalAlignment: foregroundLabel.horizontalAlignment
property alias verticalAlignment: foregroundLabel.verticalAlignment
property alias color: foregroundLabel.color
property bool shadowEnabled: false
implicitWidth: foregroundLabel.implicitWidth + (shadowEnabled ? 1 : 0)
implicitHeight: foregroundLabel.implicitHeight + (shadowEnabled ? 1 : 0)
PlasmaComponents.Label {
id: shadowLabel
visible: shadowedLabel.shadowEnabled
x: 1
y: 1
width: foregroundLabel.width
height: foregroundLabel.height
text: foregroundLabel.text
font: foregroundLabel.font
lineHeight: foregroundLabel.lineHeight
elide: foregroundLabel.elide
horizontalAlignment: foregroundLabel.horizontalAlignment
verticalAlignment: foregroundLabel.verticalAlignment
color: "#99000000"
}
PlasmaComponents.Label {
id: foregroundLabel
anchors.fill: parent
}
}
} }
+61
View File
@@ -0,0 +1,61 @@
import QtQuick
import QtQuick.Effects
import org.kde.plasma.components as PlasmaComponents
Item {
id: shadowedLabel
property alias text: foregroundLabel.text
property alias font: foregroundLabel.font
property alias lineHeight: foregroundLabel.lineHeight
property alias elide: foregroundLabel.elide
property alias horizontalAlignment: foregroundLabel.horizontalAlignment
property alias verticalAlignment: foregroundLabel.verticalAlignment
property alias color: foregroundLabel.color
property bool shadowEnabled: false
readonly property real contentWidth: width > 0 ? width : foregroundLabel.implicitWidth
readonly property real contentHeight: height > 0 ? height : foregroundLabel.implicitHeight
implicitWidth: foregroundLabel.implicitWidth
implicitHeight: foregroundLabel.implicitHeight
PlasmaComponents.Label {
id: shadowSourceLabel
visible: false
width: shadowedLabel.contentWidth
height: shadowedLabel.contentHeight
text: foregroundLabel.text
font: foregroundLabel.font
lineHeight: foregroundLabel.lineHeight
elide: foregroundLabel.elide
horizontalAlignment: foregroundLabel.horizontalAlignment
verticalAlignment: foregroundLabel.verticalAlignment
color: "white"
}
MultiEffect {
x: shadowSourceLabel.x
y: shadowSourceLabel.y
width: shadowSourceLabel.width
height: shadowSourceLabel.height
autoPaddingEnabled: true
shadowBlur: 0.5
shadowColor: "#3f4c66"
shadowEnabled: shadowedLabel.shadowEnabled
shadowHorizontalOffset: 0
shadowOpacity: 0.42
shadowScale: 1
shadowVerticalOffset: 2
source: shadowSourceLabel
visible: shadowedLabel.shadowEnabled
}
PlasmaComponents.Label {
id: foregroundLabel
width: shadowedLabel.contentWidth
height: shadowedLabel.contentHeight
}
}
+127 -23
View File
@@ -4,6 +4,7 @@ import QtQuick.Dialogs as Dialogs
import QtQuick.Layouts import QtQuick.Layouts
import org.kde.kcmutils as KCM import org.kde.kcmutils as KCM
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import org.kde.plasma.private.mpris as Mpris
KCM.SimpleKCM { KCM.SimpleKCM {
id: configRoot id: configRoot
@@ -16,17 +17,25 @@ KCM.SimpleKCM {
property string cfg_labelVisibilityMode property string cfg_labelVisibilityMode
property string cfg_labelPlacement property string cfg_labelPlacement
property alias cfg_labelText: labelTextArea.text property alias cfg_labelText: labelTextArea.text
property alias cfg_useLabelArtwork: useLabelArtworkCheckBox.checked
property alias cfg_imageBorderRadius: imageBorderRadiusSpinBox.value
property string cfg_backgroundStyle property string cfg_backgroundStyle
property alias cfg_backgroundColor: backgroundColorField.text property alias cfg_backgroundColor: backgroundColorField.text
property alias cfg_backgroundRadius: backgroundRadiusSpinBox.value property alias cfg_backgroundRadius: backgroundRadiusSpinBox.value
property alias cfg_foregroundColor: foregroundColorField.text property alias cfg_foregroundColor: foregroundColorField.text
property alias cfg_textShadowEnabled: textShadowCheckBox.checked property alias cfg_textShadowEnabled: textShadowCheckBox.checked
property alias cfg_showMediaControls: showMediaControlsCheckBox.checked
property alias cfg_sourcePriority: sourcePriorityField.text
property alias cfg_sourceWhitelist: sourceWhitelistCheckBox.checked
property alias cfg_trackTextVerticalSpacing: trackTextVerticalSpacingSpinBox.value property alias cfg_trackTextVerticalSpacing: trackTextVerticalSpacingSpinBox.value
property alias cfg_labelVerticalSpacing: labelVerticalSpacingSpinBox.value property alias cfg_labelVerticalSpacing: labelVerticalSpacingSpinBox.value
property alias cfg_separatorGapLabel: separatorGapLabelSpinBox.value property alias cfg_separatorGapLabel: separatorGapLabelSpinBox.value
property alias cfg_separatorGapTrack: separatorGapTrackSpinBox.value property alias cfg_separatorGapTrack: separatorGapTrackSpinBox.value
property alias cfg_separatorHeight: separatorHeightSpinBox.value property alias cfg_separatorHeight: separatorHeightSpinBox.value
property alias cfg_hideSeparator: hideSeparatorCheckBox.checked
readonly property int containerRole: Qt.UserRole + 1
readonly property var availableFonts: Qt.fontFamilies() readonly property var availableFonts: Qt.fontFamilies()
property var detectedSources: []
readonly property var labelVisibilityOptions: [{ readonly property var labelVisibilityOptions: [{
"text": i18n("Auto hide when idle"), "text": i18n("Auto hide when idle"),
"value": "auto" "value": "auto"
@@ -51,6 +60,9 @@ KCM.SimpleKCM {
"text": i18n("Solid background"), "text": i18n("Solid background"),
"value": "default" "value": "default"
}] }]
readonly property bool hasSourcePriorityEntries: sourcePriorityField.text.split(",").some((entry) => {
return normalizeDesktopEntry(entry).length > 0;
})
function syncComboByValue(comboBox, options, configuredValue, fallbackValue) { function syncComboByValue(comboBox, options, configuredValue, fallbackValue) {
const requestedValue = configuredValue || fallbackValue; const requestedValue = configuredValue || fallbackValue;
@@ -67,33 +79,29 @@ KCM.SimpleKCM {
return options[resolvedIndex].value; return options[resolvedIndex].value;
} }
component SectionHeader: Item { function normalizeDesktopEntry(value) {
required property string title return (value || "").toString().trim();
Kirigami.FormData.isSection: true
implicitHeight: sectionLayout.implicitHeight
ColumnLayout {
id: sectionLayout
anchors.left: parent.left
anchors.right: parent.right
spacing: Kirigami.Units.smallSpacing
QQC2.Label {
text: parent.parent.title
font.bold: true
}
Rectangle {
Layout.fillWidth: true
implicitHeight: 1
color: Kirigami.Theme.textColor
opacity: 0.25
}
} }
function refreshDetectedSources() {
const sources = [];
const seen = {
};
const playerCount = detectedSourcesModel.rowCount();
for (let row = 0; row < playerCount; ++row) {
const player = detectedSourcesModel.data(detectedSourcesModel.index(row, 0), containerRole);
const desktopEntry = normalizeDesktopEntry(player ? player.desktopEntry : "");
const desktopEntryKey = desktopEntry.toLowerCase();
if (!desktopEntry || seen[desktopEntryKey])
continue;
seen[desktopEntryKey] = true;
sources.push(desktopEntry);
}
detectedSources = sources;
} }
Component.onCompleted: cfg_sourceWhitelist = hasSourcePriorityEntries && cfg_sourceWhitelist
onCfg_fontFamilyChanged: { onCfg_fontFamilyChanged: {
const index = availableFonts.indexOf(cfg_fontFamily); const index = availableFonts.indexOf(cfg_fontFamily);
if (index >= 0 && fontFamilyComboBox.currentIndex !== index) if (index >= 0 && fontFamilyComboBox.currentIndex !== index)
@@ -207,6 +215,41 @@ KCM.SimpleKCM {
text: i18n("Enable") text: i18n("Enable")
} }
QQC2.CheckBox {
id: showMediaControlsCheckBox
Kirigami.FormData.label: i18n("Media controls:")
text: i18n("Show media controls")
}
QQC2.TextField {
id: sourcePriorityField
Kirigami.FormData.label: i18n("Source priority:")
Layout.fillWidth: true
placeholderText: i18n("example: spotify, firefox")
onTextChanged: configRoot.cfg_sourceWhitelist = configRoot.hasSourcePriorityEntries && configRoot.cfg_sourceWhitelist
}
QQC2.CheckBox {
id: sourceWhitelistCheckBox
Kirigami.FormData.label: ""
text: i18n("Only use listed sources")
enabled: configRoot.hasSourcePriorityEntries
}
QQC2.Label {
id: detectedSourcesField
Kirigami.FormData.label: i18n("Current sources being detected:")
Layout.fillWidth: true
Layout.preferredHeight: Math.max(implicitHeight, Kirigami.Units.gridUnit * 2)
textFormat: TextEdit.PlainText
wrapMode: TextEdit.WrapAnywhere
text: configRoot.detectedSources.length > 0 ? configRoot.detectedSources.join("\n") : i18n("No active MPRIS desktopEntry values detected")
}
QQC2.SpinBox { QQC2.SpinBox {
id: separatorHeightSpinBox id: separatorHeightSpinBox
@@ -215,6 +258,13 @@ KCM.SimpleKCM {
to: 100 to: 100
} }
QQC2.CheckBox {
id: hideSeparatorCheckBox
Kirigami.FormData.label: i18n("Separator:")
text: i18n("Hide separator")
}
SectionHeader { SectionHeader {
title: i18n("Label") title: i18n("Label")
} }
@@ -239,6 +289,21 @@ KCM.SimpleKCM {
onActivated: configRoot.cfg_labelPlacement = currentValue onActivated: configRoot.cfg_labelPlacement = currentValue
} }
QQC2.CheckBox {
id: useLabelArtworkCheckBox
Kirigami.FormData.label: i18n("Label image:")
text: i18n("Show track image when available")
}
QQC2.SpinBox {
id: imageBorderRadiusSpinBox
Kirigami.FormData.label: i18n("Image border radius:")
from: 0
to: 100
}
QQC2.TextArea { QQC2.TextArea {
id: labelTextArea id: labelTextArea
@@ -327,4 +392,43 @@ KCM.SimpleKCM {
onAccepted: configRoot.cfg_foregroundColor = selectedColor.toString() onAccepted: configRoot.cfg_foregroundColor = selectedColor.toString()
} }
Mpris.Mpris2Model {
id: detectedSourcesModel
onRowsInserted: configRoot.refreshDetectedSources()
onRowsRemoved: configRoot.refreshDetectedSources()
onModelReset: configRoot.refreshDetectedSources()
onDataChanged: configRoot.refreshDetectedSources()
Component.onCompleted: configRoot.refreshDetectedSources()
}
component SectionHeader: Item {
required property string title
Kirigami.FormData.isSection: true
implicitHeight: sectionLayout.implicitHeight
ColumnLayout {
id: sectionLayout
anchors.left: parent.left
anchors.right: parent.right
spacing: Kirigami.Units.smallSpacing
QQC2.Label {
text: parent.parent.title
font.bold: true
}
Rectangle {
Layout.fillWidth: true
implicitHeight: 1
color: Kirigami.Theme.textColor
opacity: 0.25
}
}
}
} }
+23
View File
@@ -27,6 +27,10 @@ PlasmoidItem {
// qmllint disable missing-property // qmllint disable missing-property
property string configuredLabelText: plasmoid.configuration.labelText property string configuredLabelText: plasmoid.configuration.labelText
// qmllint disable missing-property // qmllint disable missing-property
property bool configuredUseLabelArtwork: plasmoid.configuration.useLabelArtwork
// qmllint disable missing-property
property int configuredImageBorderRadius: plasmoid.configuration.imageBorderRadius
// qmllint disable missing-property
property string configuredBackgroundStyle: plasmoid.configuration.backgroundStyle property string configuredBackgroundStyle: plasmoid.configuration.backgroundStyle
// qmllint disable missing-property // qmllint disable missing-property
property string configuredBackgroundColor: plasmoid.configuration.backgroundColor property string configuredBackgroundColor: plasmoid.configuration.backgroundColor
@@ -37,6 +41,12 @@ PlasmoidItem {
// qmllint disable missing-property // qmllint disable missing-property
property bool configuredTextShadowEnabled: plasmoid.configuration.textShadowEnabled property bool configuredTextShadowEnabled: plasmoid.configuration.textShadowEnabled
// qmllint disable missing-property // qmllint disable missing-property
property bool configuredShowMediaControls: plasmoid.configuration.showMediaControls
// qmllint disable missing-property
property string configuredSourcePriority: plasmoid.configuration.sourcePriority
// qmllint disable missing-property
property bool configuredSourceWhitelist: plasmoid.configuration.sourceWhitelist
// qmllint disable missing-property
property int configuredTrackTextVerticalSpacing: plasmoid.configuration.trackTextVerticalSpacing property int configuredTrackTextVerticalSpacing: plasmoid.configuration.trackTextVerticalSpacing
// qmllint disable missing-property // qmllint disable missing-property
property int configuredLabelVerticalSpacing: plasmoid.configuration.labelVerticalSpacing property int configuredLabelVerticalSpacing: plasmoid.configuration.labelVerticalSpacing
@@ -46,6 +56,8 @@ PlasmoidItem {
property int configuredSeparatorGapTrack: plasmoid.configuration.separatorGapTrack property int configuredSeparatorGapTrack: plasmoid.configuration.separatorGapTrack
// qmllint disable missing-property // qmllint disable missing-property
property int configuredSeparatorHeight: plasmoid.configuration.separatorHeight property int configuredSeparatorHeight: plasmoid.configuration.separatorHeight
// qmllint disable missing-property
property bool configuredHideSeparator: plasmoid.configuration.hideSeparator
readonly property int resolvedBackgroundHints: { readonly property int resolvedBackgroundHints: {
if (configuredBackgroundStyle === "default") if (configuredBackgroundStyle === "default")
return PlasmaCore.Types.DefaultBackground | PlasmaCore.Types.ConfigurableBackground; return PlasmaCore.Types.DefaultBackground | PlasmaCore.Types.ConfigurableBackground;
@@ -65,6 +77,9 @@ PlasmoidItem {
Player { Player {
id: player id: player
sourcePriority: root.configuredSourcePriority
sourceWhitelist: root.configuredSourceWhitelist
} }
fullRepresentation: Representation { fullRepresentation: Representation {
@@ -81,16 +96,20 @@ PlasmoidItem {
configuredLabelVisibilityMode: root.configuredLabelVisibilityMode configuredLabelVisibilityMode: root.configuredLabelVisibilityMode
configuredLabelPlacement: root.configuredLabelPlacement configuredLabelPlacement: root.configuredLabelPlacement
configuredLabelText: root.configuredLabelText configuredLabelText: root.configuredLabelText
configuredUseLabelArtwork: root.configuredUseLabelArtwork
configuredImageBorderRadius: root.configuredImageBorderRadius
configuredBackgroundStyle: root.configuredBackgroundStyle configuredBackgroundStyle: root.configuredBackgroundStyle
configuredBackgroundColor: root.configuredBackgroundColor configuredBackgroundColor: root.configuredBackgroundColor
configuredBackgroundRadius: root.configuredBackgroundRadius configuredBackgroundRadius: root.configuredBackgroundRadius
configuredForegroundColor: root.configuredForegroundColor configuredForegroundColor: root.configuredForegroundColor
configuredTextShadowEnabled: root.configuredTextShadowEnabled configuredTextShadowEnabled: root.configuredTextShadowEnabled
configuredShowMediaControls: root.configuredShowMediaControls
configuredTrackTextVerticalSpacing: root.configuredTrackTextVerticalSpacing configuredTrackTextVerticalSpacing: root.configuredTrackTextVerticalSpacing
configuredLabelVerticalSpacing: root.configuredLabelVerticalSpacing configuredLabelVerticalSpacing: root.configuredLabelVerticalSpacing
configuredSeparatorGapLabel: root.configuredSeparatorGapLabel configuredSeparatorGapLabel: root.configuredSeparatorGapLabel
configuredSeparatorGapTrack: root.configuredSeparatorGapTrack configuredSeparatorGapTrack: root.configuredSeparatorGapTrack
configuredSeparatorHeight: root.configuredSeparatorHeight configuredSeparatorHeight: root.configuredSeparatorHeight
configuredHideSeparator: root.configuredHideSeparator
} }
compactRepresentation: Representation { compactRepresentation: Representation {
@@ -107,16 +126,20 @@ PlasmoidItem {
configuredLabelVisibilityMode: root.configuredLabelVisibilityMode configuredLabelVisibilityMode: root.configuredLabelVisibilityMode
configuredLabelPlacement: root.configuredLabelPlacement configuredLabelPlacement: root.configuredLabelPlacement
configuredLabelText: root.configuredLabelText configuredLabelText: root.configuredLabelText
configuredUseLabelArtwork: root.configuredUseLabelArtwork
configuredImageBorderRadius: root.configuredImageBorderRadius
configuredBackgroundStyle: root.configuredBackgroundStyle configuredBackgroundStyle: root.configuredBackgroundStyle
configuredBackgroundColor: root.configuredBackgroundColor configuredBackgroundColor: root.configuredBackgroundColor
configuredBackgroundRadius: root.configuredBackgroundRadius configuredBackgroundRadius: root.configuredBackgroundRadius
configuredForegroundColor: root.configuredForegroundColor configuredForegroundColor: root.configuredForegroundColor
configuredTextShadowEnabled: root.configuredTextShadowEnabled configuredTextShadowEnabled: root.configuredTextShadowEnabled
configuredShowMediaControls: root.configuredShowMediaControls
configuredTrackTextVerticalSpacing: root.configuredTrackTextVerticalSpacing configuredTrackTextVerticalSpacing: root.configuredTrackTextVerticalSpacing
configuredLabelVerticalSpacing: root.configuredLabelVerticalSpacing configuredLabelVerticalSpacing: root.configuredLabelVerticalSpacing
configuredSeparatorGapLabel: root.configuredSeparatorGapLabel configuredSeparatorGapLabel: root.configuredSeparatorGapLabel
configuredSeparatorGapTrack: root.configuredSeparatorGapTrack configuredSeparatorGapTrack: root.configuredSeparatorGapTrack
configuredSeparatorHeight: root.configuredSeparatorHeight configuredSeparatorHeight: root.configuredSeparatorHeight
configuredHideSeparator: root.configuredHideSeparator
} }
} }