diff --git a/package/contents/config/main.xml b/package/contents/config/main.xml
index d9b11eb..0f73b03 100644
--- a/package/contents/config/main.xml
+++ b/package/contents/config/main.xml
@@ -13,5 +13,33 @@
Noto Sans
+
+
+ auto
+
+
+
+ left
+
+
+
+ custom
+
+
+
+ transparent
+
+
+
+ 0
+
+
+
+ white
+
+
+
+ false
+
diff --git a/package/contents/ui/Representation.qml b/package/contents/ui/Representation.qml
index efba567..14ba7ee 100644
--- a/package/contents/ui/Representation.qml
+++ b/package/contents/ui/Representation.qml
@@ -7,7 +7,35 @@ import org.kde.plasma.components as PlasmaComponents
MouseArea {
id: mediaControlsMouseArea
+ property string configuredFontFamily: "Noto Sans"
+ property string configuredLabelVisibilityMode: "auto"
+ property string configuredLabelPlacement: "left"
+ property string configuredBackgroundStyle: "custom"
+ property string configuredBackgroundColor: "transparent"
+ property int configuredBackgroundRadius: 0
+ property string configuredForegroundColor: "white"
+ property bool configuredTextShadowEnabled: false
readonly property double buttonSize: 16
+ readonly property string effectiveLabelVisibilityMode: configuredLabelVisibilityMode === "always" || configuredLabelVisibilityMode === "never" ? configuredLabelVisibilityMode : "auto"
+ readonly property bool labelsOnRight: configuredLabelPlacement === "right"
+ readonly property bool hideNowPlayingArea: effectiveLabelVisibilityMode === "never"
+ readonly property bool usesCustomBackground: configuredBackgroundStyle === "custom"
+ readonly property int hideModeHorizontalPadding: 8
+ readonly property int labelRailWidth: 100
+ readonly property int separatorPadding: 4
+ readonly property string effectiveBackgroundColor: configuredBackgroundColor || "transparent"
+ readonly property int effectiveBackgroundRadius: Math.max(0, configuredBackgroundRadius)
+ readonly property string effectiveForegroundColor: configuredForegroundColor || "white"
+ readonly property bool hasTrackInfo: player.ready && (((player.title || "").trim().length > 0) || ((player.artists || "").trim().length > 0))
+ readonly property bool nowPlayingLabelsVisible: {
+ if (effectiveLabelVisibilityMode === "always")
+ return true;
+
+ if (effectiveLabelVisibilityMode === "never")
+ return false;
+
+ return hasTrackInfo;
+ }
focus: true
hoverEnabled: true
@@ -25,13 +53,25 @@ MouseArea {
}
}
+ Rectangle {
+ anchors.fill: parent
+ visible: mediaControlsMouseArea.usesCustomBackground
+ color: mediaControlsMouseArea.effectiveBackgroundColor
+ radius: mediaControlsMouseArea.effectiveBackgroundRadius
+ }
+
RowLayout {
anchors.fill: parent
+ layoutDirection: mediaControlsMouseArea.labelsOnRight ? Qt.RightToLeft : Qt.LeftToRight
ColumnLayout {
id: leftColumn
+ visible: !mediaControlsMouseArea.hideNowPlayingArea
Layout.fillHeight: true
+ Layout.minimumWidth: visible ? mediaControlsMouseArea.labelRailWidth : 0
+ Layout.preferredWidth: visible ? mediaControlsMouseArea.labelRailWidth : 0
+ Layout.maximumWidth: visible ? mediaControlsMouseArea.labelRailWidth : 0
states: [
State {
name: "buttonsVisible"
@@ -63,29 +103,34 @@ MouseArea {
ColumnLayout {
id: nowPlayingLabels
- Layout.alignment: Qt.AlignRight
+ Layout.alignment: mediaControlsMouseArea.labelsOnRight ? Qt.AlignLeft : Qt.AlignRight
spacing: 0
+ visible: mediaControlsMouseArea.nowPlayingLabelsVisible
- PlasmaComponents.Label {
- Layout.alignment: Qt.AlignRight
+ ShadowedLabel {
+ Layout.alignment: mediaControlsMouseArea.labelsOnRight ? Qt.AlignLeft : Qt.AlignRight
+ shadowEnabled: mediaControlsMouseArea.configuredTextShadowEnabled
text: "NOW"
lineHeight: 0.8
font.pixelSize: 16
font.bold: true
- // qmllint disable missing-property
- font.family: plasmoid.configuration.fontFamily
+ font.family: mediaControlsMouseArea.configuredFontFamily
+ color: mediaControlsMouseArea.effectiveForegroundColor
+ horizontalAlignment: mediaControlsMouseArea.labelsOnRight ? Text.AlignLeft : Text.AlignRight
}
- PlasmaComponents.Label {
+ ShadowedLabel {
id: nowPlayingLabel2
- Layout.alignment: Qt.AlignRight
+ Layout.alignment: mediaControlsMouseArea.labelsOnRight ? Qt.AlignLeft : Qt.AlignRight
+ shadowEnabled: mediaControlsMouseArea.configuredTextShadowEnabled
text: "PLAYING"
lineHeight: 0.8
font.bold: true
font.pixelSize: 16
- // qmllint disable missing-property
- font.family: plasmoid.configuration.fontFamily
+ font.family: mediaControlsMouseArea.configuredFontFamily
+ color: mediaControlsMouseArea.effectiveForegroundColor
+ horizontalAlignment: mediaControlsMouseArea.labelsOnRight ? Text.AlignLeft : Text.AlignRight
}
}
@@ -93,9 +138,9 @@ MouseArea {
RowLayout {
id: mediaControls
- Layout.alignment: Qt.AlignHCenter
- opacity: mediaControlsMouseArea.containsMouse ? 1 : 0
- visible: opacity > 0
+ Layout.alignment: mediaControlsMouseArea.labelsOnRight ? Qt.AlignLeft : Qt.AlignRight
+ opacity: mediaControlsMouseArea.containsMouse && mediaControlsMouseArea.nowPlayingLabelsVisible && !mediaControlsMouseArea.hideNowPlayingArea ? 1 : 0
+ visible: opacity > 0 && mediaControlsMouseArea.nowPlayingLabelsVisible && !mediaControlsMouseArea.hideNowPlayingArea
QQC2.Button {
Layout.preferredWidth: buttonSize
@@ -109,6 +154,7 @@ MouseArea {
contentItem: Kirigami.Icon {
source: "media-skip-backward"
+ color: mediaControlsMouseArea.effectiveForegroundColor
}
}
@@ -127,6 +173,7 @@ MouseArea {
contentItem: Kirigami.Icon {
source: player.playbackStatus === 2 ? "media-playback-pause" : "media-playback-start"
+ color: mediaControlsMouseArea.effectiveForegroundColor
}
}
@@ -140,6 +187,7 @@ MouseArea {
contentItem: Kirigami.Icon {
source: "media-skip-forward"
+ color: mediaControlsMouseArea.effectiveForegroundColor
}
}
@@ -173,39 +221,95 @@ MouseArea {
Rectangle {
id: separator
+ visible: mediaControlsMouseArea.nowPlayingLabelsVisible && !mediaControlsMouseArea.hideNowPlayingArea
Layout.fillHeight: true
- width: 1
+ Layout.leftMargin: visible ? mediaControlsMouseArea.separatorPadding : 0
+ Layout.rightMargin: visible ? mediaControlsMouseArea.separatorPadding : 0
+ Layout.topMargin: visible ? mediaControlsMouseArea.separatorPadding : 0
+ Layout.bottomMargin: visible ? mediaControlsMouseArea.separatorPadding : 0
+ Layout.minimumWidth: visible ? 1 : 0
+ Layout.preferredWidth: visible ? 1 : 0
+ Layout.maximumWidth: visible ? 1 : 0
+ color: mediaControlsMouseArea.effectiveForegroundColor
}
ColumnLayout {
id: infoColumn
Layout.fillWidth: true
+ Layout.minimumWidth: 0
+ Layout.leftMargin: mediaControlsMouseArea.hideNowPlayingArea ? mediaControlsMouseArea.hideModeHorizontalPadding : 0
+ Layout.rightMargin: mediaControlsMouseArea.hideNowPlayingArea ? mediaControlsMouseArea.hideModeHorizontalPadding : 0
- PlasmaComponents.Label {
+ ShadowedLabel {
Layout.fillWidth: true
+ shadowEnabled: mediaControlsMouseArea.configuredTextShadowEnabled
text: player.title
font.pixelSize: 28
font.bold: true
- // qmllint disable missing-property
- font.family: plasmoid.configuration.fontFamily
+ font.family: mediaControlsMouseArea.configuredFontFamily
+ color: mediaControlsMouseArea.effectiveForegroundColor
lineHeight: 0.8
elide: Text.ElideRight
+ horizontalAlignment: mediaControlsMouseArea.labelsOnRight ? Text.AlignRight : Text.AlignLeft
}
- PlasmaComponents.Label {
+ ShadowedLabel {
Layout.maximumWidth: 300
Layout.fillWidth: true
+ Layout.alignment: mediaControlsMouseArea.labelsOnRight ? Qt.AlignRight : Qt.AlignLeft
+ shadowEnabled: mediaControlsMouseArea.configuredTextShadowEnabled
text: player.artists
font.pixelSize: 26
- // qmllint disable missing-property
- font.family: plasmoid.configuration.fontFamily
+ font.family: mediaControlsMouseArea.configuredFontFamily
+ color: mediaControlsMouseArea.effectiveForegroundColor
lineHeight: 0.8
elide: Text.ElideRight
+ 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
+ }
+
+ }
+
}
diff --git a/package/contents/ui/configGeneral.qml b/package/contents/ui/configGeneral.qml
index fa61994..64ff334 100644
--- a/package/contents/ui/configGeneral.qml
+++ b/package/contents/ui/configGeneral.qml
@@ -1,5 +1,6 @@
import QtQuick
import QtQuick.Controls as QQC2
+import QtQuick.Dialogs as Dialogs
import QtQuick.Layouts
import org.kde.kcmutils as KCM
import org.kde.kirigami as Kirigami
@@ -9,13 +10,77 @@ KCM.SimpleKCM {
property alias cfg_opacity: opacitySpinBox.value
property string cfg_fontFamily
+ property string cfg_labelVisibilityMode
+ property string cfg_labelPlacement
+ property string cfg_backgroundStyle
+ property alias cfg_backgroundColor: backgroundColorField.text
+ property alias cfg_backgroundRadius: backgroundRadiusSpinBox.value
+ property alias cfg_foregroundColor: foregroundColorField.text
+ property alias cfg_textShadowEnabled: textShadowCheckBox.checked
readonly property var availableFonts: Qt.fontFamilies()
+ readonly property var labelVisibilityOptions: [{
+ "text": i18n("Auto hide when idle"),
+ "value": "auto"
+ }, {
+ "text": i18n("Always show"),
+ "value": "always"
+ }, {
+ "text": i18n("Always hide"),
+ "value": "never"
+ }]
+ readonly property var labelPlacementOptions: [{
+ "text": i18n("Left"),
+ "value": "left"
+ }, {
+ "text": i18n("Right"),
+ "value": "right"
+ }]
+ readonly property var backgroundStyleOptions: [{
+ "text": i18n("Default"),
+ "value": "custom"
+ }, {
+ "text": i18n("Solid background"),
+ "value": "default"
+ }]
+
+ function syncComboByValue(comboBox, options, configuredValue, fallbackValue) {
+ const requestedValue = configuredValue || fallbackValue;
+ const requestedIndex = options.findIndex((option) => {
+ return option.value === requestedValue;
+ });
+ const fallbackIndex = options.findIndex((option) => {
+ return option.value === fallbackValue;
+ });
+ const resolvedIndex = requestedIndex >= 0 ? requestedIndex : (fallbackIndex >= 0 ? fallbackIndex : 0);
+ if (comboBox.currentIndex !== resolvedIndex)
+ comboBox.currentIndex = resolvedIndex;
+
+ return options[resolvedIndex].value;
+ }
onCfg_fontFamilyChanged: {
const index = availableFonts.indexOf(cfg_fontFamily);
if (index >= 0 && fontFamilyComboBox.currentIndex !== index)
fontFamilyComboBox.currentIndex = index;
+ }
+ onCfg_labelVisibilityModeChanged: {
+ const resolvedValue = syncComboByValue(labelVisibilityModeComboBox, labelVisibilityOptions, cfg_labelVisibilityMode, "auto");
+ if (cfg_labelVisibilityMode !== resolvedValue)
+ cfg_labelVisibilityMode = resolvedValue;
+
+ }
+ onCfg_labelPlacementChanged: {
+ const resolvedValue = syncComboByValue(labelPlacementComboBox, labelPlacementOptions, cfg_labelPlacement, "left");
+ if (cfg_labelPlacement !== resolvedValue)
+ cfg_labelPlacement = resolvedValue;
+
+ }
+ onCfg_backgroundStyleChanged: {
+ const resolvedValue = syncComboByValue(backgroundStyleComboBox, backgroundStyleOptions, cfg_backgroundStyle, "custom");
+ if (cfg_backgroundStyle !== resolvedValue)
+ cfg_backgroundStyle = resolvedValue;
+
}
Kirigami.FormLayout {
@@ -35,6 +100,109 @@ KCM.SimpleKCM {
onActivated: configRoot.cfg_fontFamily = currentText
}
+ QQC2.ComboBox {
+ id: labelVisibilityModeComboBox
+
+ Kirigami.FormData.label: i18n("Now Playing labels:")
+ model: configRoot.labelVisibilityOptions
+ textRole: "text"
+ valueRole: "value"
+ onActivated: configRoot.cfg_labelVisibilityMode = currentValue
+ }
+
+ QQC2.ComboBox {
+ id: labelPlacementComboBox
+
+ Kirigami.FormData.label: i18n("Label placement:")
+ model: configRoot.labelPlacementOptions
+ textRole: "text"
+ valueRole: "value"
+ onActivated: configRoot.cfg_labelPlacement = currentValue
+ }
+
+ QQC2.ComboBox {
+ id: backgroundStyleComboBox
+
+ Kirigami.FormData.label: i18n("Background style:")
+ model: configRoot.backgroundStyleOptions
+ textRole: "text"
+ valueRole: "value"
+ onActivated: configRoot.cfg_backgroundStyle = currentValue
+ }
+
+ RowLayout {
+ Kirigami.FormData.label: i18n("Background color:")
+ enabled: configRoot.cfg_backgroundStyle === "custom"
+
+ QQC2.TextField {
+ id: backgroundColorField
+
+ Layout.fillWidth: true
+ placeholderText: i18n("transparent or #AARRGGBB")
+ }
+
+ QQC2.Button {
+ text: i18n("Pick...")
+ onClicked: {
+ backgroundColorDialog.selectedColor = backgroundColorField.text || "transparent";
+ backgroundColorDialog.open();
+ }
+ }
+
+ }
+
+ RowLayout {
+ Kirigami.FormData.label: i18n("Foreground color:")
+
+ QQC2.TextField {
+ id: foregroundColorField
+
+ Layout.fillWidth: true
+ placeholderText: i18n("white or #RRGGBB")
+ }
+
+ QQC2.Button {
+ text: i18n("Pick...")
+ onClicked: {
+ foregroundColorDialog.selectedColor = foregroundColorField.text || "white";
+ foregroundColorDialog.open();
+ }
+ }
+
+ }
+
+ QQC2.SpinBox {
+ id: backgroundRadiusSpinBox
+
+ Kirigami.FormData.label: i18n("Background radius:")
+ enabled: configRoot.cfg_backgroundStyle === "custom"
+ from: 0
+ to: 100
+ }
+
+ QQC2.CheckBox {
+ id: textShadowCheckBox
+
+ Kirigami.FormData.label: i18n("Text shadow:")
+ text: i18n("Enable")
+ }
+
+ }
+
+ Dialogs.ColorDialog {
+ id: backgroundColorDialog
+
+ title: i18n("Select background color")
+ options: Dialogs.ColorDialog.ShowAlphaChannel
+ onAccepted: configRoot.cfg_backgroundColor = selectedColor.toString()
+ }
+
+ Dialogs.ColorDialog {
+ id: foregroundColorDialog
+
+ title: i18n("Select foreground color")
+ options: Dialogs.ColorDialog.ShowAlphaChannel
+ onAccepted: configRoot.cfg_foregroundColor = selectedColor.toString()
}
}
diff --git a/package/contents/ui/main.qml b/package/contents/ui/main.qml
index 1868611..0bc2a18 100644
--- a/package/contents/ui/main.qml
+++ b/package/contents/ui/main.qml
@@ -1,6 +1,7 @@
import QtQuick
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
+import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.plasmoid
PlasmoidItem {
@@ -10,12 +11,37 @@ PlasmoidItem {
// "qmllint" sees `plasmoid` as QObject here, but Plasma injects `configuration` at runtime.
// qmllint disable missing-property
property int configuredOpacity: plasmoid.configuration.opacity
+ // qmllint disable missing-property
+ property string configuredFontFamily: plasmoid.configuration.fontFamily
+ // qmllint disable missing-property
+ property string configuredLabelVisibilityMode: plasmoid.configuration.labelVisibilityMode
+ // qmllint disable missing-property
+ property string configuredLabelPlacement: plasmoid.configuration.labelPlacement
+ // qmllint disable missing-property
+ property string configuredBackgroundStyle: plasmoid.configuration.backgroundStyle
+ // qmllint disable missing-property
+ property string configuredBackgroundColor: plasmoid.configuration.backgroundColor
+ // qmllint disable missing-property
+ property int configuredBackgroundRadius: plasmoid.configuration.backgroundRadius
+ // qmllint disable missing-property
+ property string configuredForegroundColor: plasmoid.configuration.foregroundColor
+ // qmllint disable missing-property
+ property bool configuredTextShadowEnabled: plasmoid.configuration.textShadowEnabled
+ readonly property int resolvedBackgroundHints: {
+ if (configuredBackgroundStyle === "default")
+ return PlasmaCore.Types.DefaultBackground | PlasmaCore.Types.ConfigurableBackground;
+
+ if (configuredBackgroundStyle === "none")
+ return PlasmaCore.Types.NoBackground;
+
+ return PlasmaCore.Types.NoBackground;
+ }
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"
+ Plasmoid.backgroundHints: resolvedBackgroundHints
opacity: configuredOpacity / 100
Player {
@@ -27,11 +53,29 @@ PlasmoidItem {
Layout.minimumHeight: Kirigami.Units.gridUnit * 5
Layout.preferredWidth: root.width
Layout.preferredHeight: root.height
+ configuredFontFamily: root.configuredFontFamily
+ configuredLabelVisibilityMode: root.configuredLabelVisibilityMode
+ configuredLabelPlacement: root.configuredLabelPlacement
+ configuredBackgroundStyle: root.configuredBackgroundStyle
+ configuredBackgroundColor: root.configuredBackgroundColor
+ configuredBackgroundRadius: root.configuredBackgroundRadius
+ configuredForegroundColor: root.configuredForegroundColor
+ configuredTextShadowEnabled: root.configuredTextShadowEnabled
}
compactRepresentation: Representation {
Layout.minimumWidth: Kirigami.Units.gridUnit * 25
Layout.minimumHeight: Kirigami.Units.gridUnit * 5
+ Layout.preferredWidth: root.width
+ Layout.preferredHeight: root.height
+ configuredFontFamily: root.configuredFontFamily
+ configuredLabelVisibilityMode: root.configuredLabelVisibilityMode
+ configuredLabelPlacement: root.configuredLabelPlacement
+ configuredBackgroundStyle: root.configuredBackgroundStyle
+ configuredBackgroundColor: root.configuredBackgroundColor
+ configuredBackgroundRadius: root.configuredBackgroundRadius
+ configuredForegroundColor: root.configuredForegroundColor
+ configuredTextShadowEnabled: root.configuredTextShadowEnabled
}
}