mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
DesktopMediaPlayer: improve options for visual customization
This commit is contained in:
@@ -1472,20 +1472,28 @@
|
||||
"label": "Hiding mode"
|
||||
},
|
||||
"show-background": {
|
||||
"description": "Show the background container for the media player widget.",
|
||||
"description": "Show the background container.",
|
||||
"label": "Show background"
|
||||
},
|
||||
"rounded-corners": {
|
||||
"description": "Enable rounded corners on the widget edges.",
|
||||
"label": "Rounded corners"
|
||||
},
|
||||
"show-album-art": {
|
||||
"description": "Show the album artwork and track information (title and artist).",
|
||||
"label": "Show album art & title"
|
||||
},
|
||||
"show-buttons": {
|
||||
"description": "Show media control buttons (play/pause, previous, next) on the media player widget.",
|
||||
"description": "Show media control buttons (play/pause, previous, next).",
|
||||
"label": "Show buttons"
|
||||
},
|
||||
"visualizer-type": {
|
||||
"description": "Choose a visualization type for the desktop media player background.",
|
||||
"label": "Visualization type"
|
||||
"show-visualizer": {
|
||||
"description": "Show the audio visualizer overlay.",
|
||||
"label": "Show visualizer"
|
||||
},
|
||||
"visualizer-visibility": {
|
||||
"description": "Control when the audio visualizer is visible.",
|
||||
"label": "Audio visualizer visibility"
|
||||
"visualizer-type": {
|
||||
"description": "Choose a visualization type.",
|
||||
"label": "Visualization type"
|
||||
}
|
||||
},
|
||||
"title": "Desktop Widgets",
|
||||
|
||||
@@ -34,22 +34,53 @@ Variants {
|
||||
id: screenLoader
|
||||
required property ShellScreen modelData
|
||||
|
||||
// Reactive property for widgets on this specific screen
|
||||
property var screenWidgets: {
|
||||
property ListModel screenWidgetsModel: ListModel {}
|
||||
|
||||
property var settingsWatcher: Settings.data.desktopWidgets.monitorWidgets
|
||||
onSettingsWatcherChanged: Qt.callLater(updateModel)
|
||||
|
||||
Component.onCompleted: Qt.callLater(updateModel)
|
||||
|
||||
function updateModel() {
|
||||
if (!modelData || !modelData.name) {
|
||||
return [];
|
||||
screenWidgetsModel.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
var monitorWidgets = Settings.data.desktopWidgets.monitorWidgets || [];
|
||||
var newWidgets = [];
|
||||
for (var i = 0; i < monitorWidgets.length; i++) {
|
||||
if (monitorWidgets[i].name === modelData.name) {
|
||||
return monitorWidgets[i].widgets || [];
|
||||
newWidgets = monitorWidgets[i].widgets || [];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return [];
|
||||
|
||||
// Update in-place to preserve delegates
|
||||
for (var j = 0; j < Math.min(newWidgets.length, screenWidgetsModel.count); j++) {
|
||||
var item = screenWidgetsModel.get(j);
|
||||
var newData = newWidgets[j];
|
||||
// Update each property individually
|
||||
for (var key in newData) {
|
||||
if (item[key] !== newData[key]) {
|
||||
item[key] = newData[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove excess
|
||||
while (screenWidgetsModel.count > newWidgets.length) {
|
||||
screenWidgetsModel.remove(screenWidgetsModel.count - 1);
|
||||
}
|
||||
|
||||
// Append new
|
||||
for (var k = screenWidgetsModel.count; k < newWidgets.length; k++) {
|
||||
screenWidgetsModel.append(newWidgets[k]);
|
||||
}
|
||||
}
|
||||
|
||||
// Only create PanelWindow if enabled AND screen has widgets
|
||||
active: modelData && Settings.data.desktopWidgets.enabled && screenWidgets.length > 0 && !PowerProfileService.noctaliaPerformanceMode
|
||||
active: modelData && Settings.data.desktopWidgets.enabled && screenWidgetsModel.count > 0 && !PowerProfileService.noctaliaPerformanceMode
|
||||
|
||||
sourceComponent: PanelWindow {
|
||||
id: window
|
||||
@@ -264,33 +295,33 @@ Variants {
|
||||
|
||||
// Load widgets dynamically from per-monitor array
|
||||
Repeater {
|
||||
model: screenLoader.screenWidgets
|
||||
model: screenLoader.screenWidgetsModel
|
||||
|
||||
delegate: Loader {
|
||||
id: widgetLoader
|
||||
// Bind to registeredWidgets and pluginReloadCounter to re-evaluate when plugins register/unregister
|
||||
active: (modelData.id in root.registeredWidgets) && (root.pluginReloadCounter >= 0)
|
||||
active: (model.id in root.registeredWidgets) && (root.pluginReloadCounter >= 0)
|
||||
|
||||
property var widgetData: modelData
|
||||
required property var model
|
||||
property int widgetIndex: index
|
||||
|
||||
sourceComponent: {
|
||||
// Access registeredWidgets and pluginReloadCounter to create reactive binding
|
||||
var _ = root.pluginReloadCounter;
|
||||
var widgets = root.registeredWidgets;
|
||||
return widgets[modelData.id] || null;
|
||||
return widgets[model.id] || null;
|
||||
}
|
||||
|
||||
onLoaded: {
|
||||
if (item) {
|
||||
item.screen = window.screen;
|
||||
item.parent = widgetsContainer;
|
||||
item.widgetData = widgetData;
|
||||
item.widgetData = Qt.binding(function() { return widgetLoader.model; });
|
||||
item.widgetIndex = widgetIndex;
|
||||
|
||||
// Inject plugin API for plugin widgets
|
||||
if (DesktopWidgetRegistry.isPluginWidget(modelData.id)) {
|
||||
var pluginId = modelData.id.replace("plugin:", "");
|
||||
if (DesktopWidgetRegistry.isPluginWidget(model.id)) {
|
||||
var pluginId = model.id.replace("plugin:", "");
|
||||
var api = PluginService.getPluginAPI(pluginId);
|
||||
if (api && item.hasOwnProperty("pluginApi")) {
|
||||
item.pluginApi = api;
|
||||
|
||||
@@ -22,6 +22,7 @@ Item {
|
||||
readonly property bool isScaling: internal.isScaling
|
||||
|
||||
property bool showBackground: (widgetData && widgetData.showBackground !== undefined) ? widgetData.showBackground : true
|
||||
property bool roundedCorners: (widgetData && widgetData.roundedCorners !== undefined) ? widgetData.roundedCorners : true
|
||||
|
||||
property real widgetScale: (widgetData && widgetData.scale !== undefined) ? widgetData.scale : 1.0
|
||||
property real minScale: 0.5
|
||||
@@ -265,7 +266,7 @@ Item {
|
||||
Rectangle {
|
||||
id: container
|
||||
anchors.fill: parent
|
||||
radius: Style.radiusL
|
||||
radius: root.roundedCorners ? Style.radiusL : 0
|
||||
color: Color.mSurface
|
||||
border {
|
||||
width: 1
|
||||
|
||||
@@ -17,6 +17,10 @@ DraggableDesktopWidget {
|
||||
// Widget settings
|
||||
readonly property string hideMode: (widgetData.hideMode !== undefined) ? widgetData.hideMode : "visible"
|
||||
readonly property bool showButtons: (widgetData.showButtons !== undefined) ? widgetData.showButtons : true
|
||||
readonly property bool showAlbumArt: (widgetData.showAlbumArt !== undefined) ? widgetData.showAlbumArt : true
|
||||
readonly property bool showVisualizer: (widgetData.showVisualizer !== undefined) ? widgetData.showVisualizer : true
|
||||
readonly property string visualizerType: (widgetData.visualizerType && widgetData.visualizerType !== "") ? widgetData.visualizerType : "linear"
|
||||
readonly property bool roundedCorners: (widgetData.roundedCorners !== undefined) ? widgetData.roundedCorners : true
|
||||
readonly property bool hasPlayer: MediaService.currentPlayer !== null
|
||||
readonly property bool isPlaying: MediaService.isPlaying
|
||||
readonly property bool hasActiveTrack: hasPlayer && (MediaService.trackTitle || MediaService.trackArtist)
|
||||
@@ -52,13 +56,9 @@ DraggableDesktopWidget {
|
||||
readonly property bool showPrev: hasPlayer && MediaService.canGoPrevious
|
||||
readonly property bool showNext: hasPlayer && MediaService.canGoNext
|
||||
readonly property int visibleButtonCount: root.showButtons ? (1 + (showPrev ? 1 : 0) + (showNext ? 1 : 0)) : 0
|
||||
readonly property int baseWidth: 400 * Style.uiScaleRatio
|
||||
readonly property int buttonWidth: 32 * Style.uiScaleRatio
|
||||
readonly property int buttonSpacing: Style.marginXS
|
||||
readonly property int controlsWidth: visibleButtonCount * buttonWidth + (visibleButtonCount > 1 ? (visibleButtonCount - 1) * buttonSpacing : 0)
|
||||
|
||||
implicitWidth: baseWidth - (3 - visibleButtonCount) * (buttonWidth + buttonSpacing)
|
||||
implicitHeight: contentLayout.implicitHeight + Style.marginM * 2
|
||||
implicitWidth: 400 * Style.uiScaleRatio
|
||||
implicitHeight: 64 * Style.uiScaleRatio + Style.marginM * 2
|
||||
width: implicitWidth
|
||||
height: implicitHeight
|
||||
|
||||
@@ -80,7 +80,7 @@ DraggableDesktopWidget {
|
||||
sourceItem: Rectangle {
|
||||
width: root.width - Style.marginXS * 2
|
||||
height: root.height - Style.marginXS * 2
|
||||
radius: Math.max(0, Style.radiusL - Style.marginXS)
|
||||
radius: root.roundedCorners ? Math.max(0, Style.radiusL - Style.marginXS) : 0
|
||||
color: "white"
|
||||
antialiasing: true
|
||||
smooth: true
|
||||
@@ -92,27 +92,29 @@ DraggableDesktopWidget {
|
||||
}
|
||||
|
||||
// Visualizer visibility mode
|
||||
readonly property string visualizerVisibility: (widgetData && widgetData.visualizerVisibility !== undefined) ? widgetData.visualizerVisibility : "always"
|
||||
readonly property bool shouldShowVisualizer: {
|
||||
if (!(widgetData && widgetData.visualizerType) || widgetData.visualizerType === "" || widgetData.visualizerType === "none")
|
||||
if (!root.showVisualizer)
|
||||
return false;
|
||||
if (visualizerVisibility === "always")
|
||||
return true;
|
||||
if (visualizerVisibility === "with-background")
|
||||
return root.showBackground;
|
||||
return true; // default to always visible
|
||||
if (root.visualizerType === "" || root.visualizerType === "none")
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Visualizer overlay (visibility controlled by visualizerVisibility setting)
|
||||
Loader {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginXS
|
||||
anchors.leftMargin: Style.marginXS
|
||||
anchors.rightMargin: Style.marginXS
|
||||
anchors.topMargin: Style.marginXS
|
||||
anchors.bottomMargin: 0
|
||||
z: 0
|
||||
clip: true
|
||||
active: shouldShowVisualizer
|
||||
layer.enabled: true
|
||||
layer.smooth: true
|
||||
layer.samples: 4
|
||||
layer.samples: 8
|
||||
layer.mipmap: true
|
||||
layer.textureSize: Qt.size(width * 2, height * 2)
|
||||
layer.effect: MultiEffect {
|
||||
maskEnabled: true
|
||||
maskThresholdMin: 0.95
|
||||
@@ -120,8 +122,8 @@ DraggableDesktopWidget {
|
||||
maskSource: ShaderEffectSource {
|
||||
sourceItem: Rectangle {
|
||||
width: root.width - Style.marginXS * 2
|
||||
height: root.height - Style.marginXS * 2
|
||||
radius: Math.max(0, Style.radiusL - Style.marginXS)
|
||||
height: root.height - Style.marginXS
|
||||
radius: root.roundedCorners ? Math.max(0, Style.radiusL - Style.marginXS) : 0
|
||||
color: "white"
|
||||
antialiasing: true
|
||||
smooth: true
|
||||
@@ -132,8 +134,7 @@ DraggableDesktopWidget {
|
||||
}
|
||||
|
||||
sourceComponent: {
|
||||
var visualizerType = (widgetData && widgetData.visualizerType) ? widgetData.visualizerType : "";
|
||||
switch (visualizerType) {
|
||||
switch (root.visualizerType) {
|
||||
case "linear":
|
||||
return linearComponent;
|
||||
case "mirrored":
|
||||
@@ -151,7 +152,7 @@ DraggableDesktopWidget {
|
||||
anchors.fill: parent
|
||||
values: CavaService.values
|
||||
fillColor: Color.mPrimary
|
||||
opacity: 0.6
|
||||
opacity: 1.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,7 +162,7 @@ DraggableDesktopWidget {
|
||||
anchors.fill: parent
|
||||
values: CavaService.values
|
||||
fillColor: Color.mPrimary
|
||||
opacity: 0.6
|
||||
opacity: 1.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,19 +172,45 @@ DraggableDesktopWidget {
|
||||
anchors.fill: parent
|
||||
values: CavaService.values
|
||||
fillColor: Color.mPrimary
|
||||
opacity: 0.6
|
||||
opacity: 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: contentLayout
|
||||
anchors.fill: parent
|
||||
states: [
|
||||
State {
|
||||
when: root.showButtons
|
||||
AnchorChanges {
|
||||
target: contentLayout
|
||||
anchors.horizontalCenter: undefined
|
||||
anchors.verticalCenter: undefined
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
}
|
||||
},
|
||||
State {
|
||||
when: !root.showButtons
|
||||
AnchorChanges {
|
||||
target: contentLayout
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.top: undefined
|
||||
anchors.bottom: undefined
|
||||
anchors.left: undefined
|
||||
anchors.right: undefined
|
||||
}
|
||||
}
|
||||
]
|
||||
anchors.margins: Style.marginM
|
||||
spacing: Style.marginS
|
||||
z: 2
|
||||
|
||||
Item {
|
||||
visible: root.showAlbumArt
|
||||
Layout.preferredWidth: 64 * Style.uiScaleRatio
|
||||
Layout.preferredHeight: 64 * Style.uiScaleRatio
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
@@ -208,7 +235,9 @@ DraggableDesktopWidget {
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
visible: root.showAlbumArt
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: root.showButtons ? Qt.AlignVCenter : Qt.AlignCenter
|
||||
spacing: 0
|
||||
|
||||
NText {
|
||||
@@ -238,6 +267,7 @@ DraggableDesktopWidget {
|
||||
spacing: Style.marginXS
|
||||
z: 10
|
||||
visible: root.showButtons
|
||||
Layout.alignment: root.showAlbumArt ? Qt.AlignVCenter : Qt.AlignCenter
|
||||
|
||||
NIconButton {
|
||||
visible: showPrev
|
||||
|
||||
@@ -12,18 +12,26 @@ ColumnLayout {
|
||||
property var widgetMetadata: null
|
||||
|
||||
property bool valueShowBackground: widgetData.showBackground !== undefined ? widgetData.showBackground : widgetMetadata.showBackground
|
||||
property string valueVisualizerType: widgetData.visualizerType !== undefined ? widgetData.visualizerType : widgetMetadata.visualizerType
|
||||
property string valueVisualizerType: (widgetData.visualizerType && widgetData.visualizerType !== "") ? widgetData.visualizerType : (widgetMetadata.visualizerType || "linear")
|
||||
property string valueHideMode: widgetData.hideMode !== undefined ? widgetData.hideMode : widgetMetadata.hideMode
|
||||
property string valueVisualizerVisibility: widgetData.visualizerVisibility !== undefined ? widgetData.visualizerVisibility : (widgetMetadata.visualizerVisibility !== undefined ? widgetMetadata.visualizerVisibility : "always")
|
||||
property bool valueShowButtons: widgetData.showButtons !== undefined ? widgetData.showButtons : (widgetMetadata.showButtons !== undefined ? widgetMetadata.showButtons : true)
|
||||
property bool valueShowAlbumArt: widgetData.showAlbumArt !== undefined ? widgetData.showAlbumArt : (widgetMetadata.showAlbumArt !== undefined ? widgetMetadata.showAlbumArt : true)
|
||||
property bool valueShowVisualizer: widgetData.showVisualizer !== undefined ? widgetData.showVisualizer : (widgetMetadata.showVisualizer !== undefined ? widgetMetadata.showVisualizer : true)
|
||||
property bool valueRoundedCorners: widgetData.roundedCorners !== undefined ? widgetData.roundedCorners : (widgetMetadata.roundedCorners !== undefined ? widgetMetadata.roundedCorners : true)
|
||||
|
||||
function saveSettings() {
|
||||
var settings = Object.assign({}, widgetData || {});
|
||||
settings.showBackground = valueShowBackground;
|
||||
settings.visualizerType = valueVisualizerType;
|
||||
settings.hideMode = valueHideMode;
|
||||
settings.visualizerVisibility = valueVisualizerVisibility;
|
||||
settings.showButtons = valueShowButtons;
|
||||
settings.showAlbumArt = valueShowAlbumArt;
|
||||
settings.showVisualizer = valueShowVisualizer;
|
||||
settings.roundedCorners = valueRoundedCorners;
|
||||
|
||||
// Clean up legacy property
|
||||
delete settings.visualizerVisibility;
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
@@ -35,6 +43,30 @@ ColumnLayout {
|
||||
onToggled: checked => valueShowBackground = checked
|
||||
}
|
||||
|
||||
NToggle {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("settings.desktop-widgets.media-player.rounded-corners.label")
|
||||
description: I18n.tr("settings.desktop-widgets.media-player.rounded-corners.description")
|
||||
checked: valueRoundedCorners
|
||||
onToggled: checked => valueRoundedCorners = checked
|
||||
}
|
||||
|
||||
NToggle {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("settings.desktop-widgets.media-player.show-album-art.label")
|
||||
description: I18n.tr("settings.desktop-widgets.media-player.show-album-art.description")
|
||||
checked: valueShowAlbumArt
|
||||
onToggled: checked => valueShowAlbumArt = checked
|
||||
}
|
||||
|
||||
NToggle {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("settings.desktop-widgets.media-player.show-visualizer.label")
|
||||
description: I18n.tr("settings.desktop-widgets.media-player.show-visualizer.description")
|
||||
checked: valueShowVisualizer
|
||||
onToggled: checked => valueShowVisualizer = checked
|
||||
}
|
||||
|
||||
NToggle {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("settings.desktop-widgets.media-player.show-buttons.label")
|
||||
@@ -47,11 +79,8 @@ ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("settings.desktop-widgets.media-player.visualizer-type.label")
|
||||
description: I18n.tr("settings.desktop-widgets.media-player.visualizer-type.description")
|
||||
enabled: valueShowVisualizer
|
||||
model: [
|
||||
{
|
||||
"key": "",
|
||||
"name": I18n.tr("options.visualizer-types.none")
|
||||
},
|
||||
{
|
||||
"key": "linear",
|
||||
"name": I18n.tr("options.visualizer-types.linear")
|
||||
@@ -69,25 +98,6 @@ ColumnLayout {
|
||||
onSelected: key => valueVisualizerType = key
|
||||
}
|
||||
|
||||
NComboBox {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("settings.desktop-widgets.media-player.visualizer-visibility.label")
|
||||
description: I18n.tr("settings.desktop-widgets.media-player.visualizer-visibility.description")
|
||||
enabled: valueVisualizerType && valueVisualizerType !== "" && valueVisualizerType !== "none"
|
||||
model: [
|
||||
{
|
||||
"key": "always",
|
||||
"name": I18n.tr("options.visualizer-visibility.always")
|
||||
},
|
||||
{
|
||||
"key": "with-background",
|
||||
"name": I18n.tr("options.visualizer-visibility.with-background")
|
||||
}
|
||||
]
|
||||
currentKey: valueVisualizerVisibility
|
||||
onSelected: key => valueVisualizerVisibility = key
|
||||
}
|
||||
|
||||
NComboBox {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("settings.desktop-widgets.media-player.hide-mode.label")
|
||||
|
||||
@@ -67,7 +67,10 @@ Singleton {
|
||||
"showBackground": true,
|
||||
"visualizerType": "linear",
|
||||
"hideMode": "visible",
|
||||
"showButtons": true
|
||||
"showButtons": true,
|
||||
"showAlbumArt": true,
|
||||
"showVisualizer": true,
|
||||
"roundedCorners": true
|
||||
},
|
||||
"Weather": {
|
||||
"allowUserSettings": true,
|
||||
|
||||
Reference in New Issue
Block a user