From 5c58bcac7326b7c191b9bb5094ec75f7e5c5810f Mon Sep 17 00:00:00 2001 From: Lysec Date: Sat, 14 Mar 2026 23:42:01 +0100 Subject: [PATCH 1/3] feat(Wallpaper): change random wallpaper time buttons to NSpinBox --- .../Tabs/Wallpaper/AutomationSubTab.qml | 124 +++--------------- 1 file changed, 15 insertions(+), 109 deletions(-) diff --git a/Modules/Panels/Settings/Tabs/Wallpaper/AutomationSubTab.qml b/Modules/Panels/Settings/Tabs/Wallpaper/AutomationSubTab.qml index 3c6bbe4f3..bcf119bd5 100644 --- a/Modules/Panels/Settings/Tabs/Wallpaper/AutomationSubTab.qml +++ b/Modules/Panels/Settings/Tabs/Wallpaper/AutomationSubTab.qml @@ -43,117 +43,23 @@ ColumnLayout { defaultValue: Settings.getDefaultValue("wallpaper.transitionType") } - RowLayout { - NLabel { - label: I18n.tr("panels.wallpaper.automation-interval-label") - description: I18n.tr("panels.wallpaper.automation-interval-description") - Layout.fillWidth: true - } - - NText { - text: Time.formatVagueHumanReadableDuration(Settings.data.wallpaper.randomIntervalSec) - Layout.alignment: Qt.AlignBottom | Qt.AlignRight - } - } - - RowLayout { - id: presetRow - spacing: Style.marginS - opacity: enabled ? 1.0 : 0.6 - - property var intervalPresets: [5 * 60, 10 * 60, 15 * 60, 30 * 60, 45 * 60, 60 * 60, 90 * 60, 120 * 60] - property bool isCurrentPreset: { - return intervalPresets.some(seconds => seconds === Settings.data.wallpaper.randomIntervalSec); - } - property bool customForcedVisible: false - - function setIntervalSeconds(sec) { - Settings.data.wallpaper.randomIntervalSec = sec; - WallpaperService.restartRandomWallpaperTimer(); - customForcedVisible = false; - } - - function isSelected(sec) { - return Settings.data.wallpaper.randomIntervalSec === sec; - } - - Repeater { - model: presetRow.intervalPresets - delegate: IntervalPresetChip { - seconds: modelData - label: Time.formatVagueHumanReadableDuration(modelData) - selected: presetRow.isSelected(modelData) && !customRow.visible - onClicked: presetRow.setIntervalSeconds(modelData) + NSpinBox { + label: I18n.tr("panels.wallpaper.automation-interval-label") + description: I18n.tr("panels.wallpaper.automation-interval-description") + Layout.fillWidth: true + from: 1 + to: 1440 + stepSize: 1 + suffix: "m" + value: Math.round(Settings.data.wallpaper.randomIntervalSec / 60) + defaultValue: Settings.getDefaultValue("wallpaper.randomIntervalSec") !== undefined ? Math.round(Settings.getDefaultValue("wallpaper.randomIntervalSec") / 60) : undefined + onValueChanged: { + let newSec = value * 60; + if (newSec !== Settings.data.wallpaper.randomIntervalSec) { + Settings.data.wallpaper.randomIntervalSec = newSec; + WallpaperService.restartRandomWallpaperTimer(); } } - - IntervalPresetChip { - label: customRow.visible ? "Custom" : "Custom…" - selected: customRow.visible - onClicked: presetRow.customForcedVisible = !presetRow.customForcedVisible - } - } - - RowLayout { - id: customRow - - visible: presetRow.customForcedVisible || !presetRow.isCurrentPreset - spacing: Style.marginS - opacity: enabled ? 1.0 : 0.6 - Layout.topMargin: Style.marginS - - NTextInput { - label: I18n.tr("panels.wallpaper.automation-custom-interval-label") - description: I18n.tr("panels.wallpaper.automation-custom-interval-description") - text: { - const s = Settings.data.wallpaper.randomIntervalSec; - const h = Math.floor(s / 3600); - const m = Math.floor((s % 3600) / 60); - return h + ":" + (m < 10 ? ("0" + m) : m); - } - onEditingFinished: { - const m = text.trim().match(/^(\d{1,2}):(\d{2})$/); - if (m) { - let h = parseInt(m[1]); - let min = parseInt(m[2]); - if (isNaN(h) || isNaN(min)) - return; - h = Math.max(0, Math.min(24, h)); - min = Math.max(0, Math.min(59, min)); - Settings.data.wallpaper.randomIntervalSec = (h * 3600) + (min * 60); - WallpaperService.restartRandomWallpaperTimer(); - presetRow.customForcedVisible = true; - } - } - } - } - } - - component IntervalPresetChip: Rectangle { - property int seconds: 0 - property string label: "" - property bool selected: false - signal clicked - - radius: Style.iRadiusS - color: selected ? Color.mPrimary : Color.mSurfaceVariant - implicitHeight: Math.max(Style.baseWidgetSize * 0.55, 24) - implicitWidth: chipLabel.implicitWidth + Style.marginM * 1.5 - border.width: Style.borderS - border.color: selected ? "transparent" : Color.mOutline - - MouseArea { - anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: parent.clicked() - } - - NText { - id: chipLabel - anchors.centerIn: parent - text: parent.label - pointSize: Style.fontSizeS - color: parent.selected ? Color.mOnPrimary : Color.mOnSurface } } } From 73a3d3c252bb637d262e5a16b27a535dd0271682 Mon Sep 17 00:00:00 2001 From: "Braian A. Diez" Date: Sat, 14 Mar 2026 20:40:13 -0300 Subject: [PATCH 2/3] fix(clipboard): add color preview Signed-off-by: Braian A. Diez --- Modules/Panels/Launcher/LauncherListDelegate.qml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Modules/Panels/Launcher/LauncherListDelegate.qml b/Modules/Panels/Launcher/LauncherListDelegate.qml index aba61b5bb..57cdeb5d9 100644 --- a/Modules/Panels/Launcher/LauncherListDelegate.qml +++ b/Modules/Panels/Launcher/LauncherListDelegate.qml @@ -105,12 +105,22 @@ NBox { } } + // Color swatch - shown for clipboard color entries + Rectangle { + anchors.fill: parent + radius: Style.radiusXS + color: modelData.colorHex || "transparent" + visible: !!modelData.colorHex + border.color: Color.mOnSurface + border.width: Style.borderM + } + Loader { id: iconLoader anchors.fill: parent anchors.margins: Style.marginXS - visible: (!modelData.isImage && !modelData.displayString) || (!!modelData.isImage && imagePreview.status === Image.Error) + visible: (!modelData.isImage && !modelData.displayString && !modelData.colorHex) || (!!modelData.isImage && imagePreview.status === Image.Error) active: visible sourceComponent: Component { From bf234e502da5fb1d6c9b462c5b20e5aeae736bae Mon Sep 17 00:00:00 2001 From: Lemmy Date: Sat, 14 Mar 2026 20:42:33 -0400 Subject: [PATCH 3/3] feat(wallpaper): added ability for granular pick of transitions via checkboxes --- Assets/settings-default.json | 9 +++- Assets/settings-search-index.json | 2 +- Commons/Migrations/Migration59.qml | 25 ++++++++++ Commons/Migrations/MigrationRegistry.qml | 4 +- Commons/Settings.qml | 4 +- Modules/Background/Background.qml | 30 +++++++----- .../Tabs/Wallpaper/AutomationSubTab.qml | 2 +- .../Tabs/Wallpaper/LookAndFeelSubTab.qml | 47 ++++++++++++++++--- 8 files changed, 98 insertions(+), 25 deletions(-) create mode 100644 Commons/Migrations/Migration59.qml diff --git a/Assets/settings-default.json b/Assets/settings-default.json index 682d860fb..27cf5b45b 100644 --- a/Assets/settings-default.json +++ b/Assets/settings-default.json @@ -205,7 +205,14 @@ "wallpaperChangeMode": "random", "randomIntervalSec": 300, "transitionDuration": 1500, - "transitionType": "random", + "transitionType": [ + "fade", + "disc", + "stripes", + "wipe", + "pixelate", + "honeycomb" + ], "skipStartupTransition": false, "transitionEdgeSmoothness": 0.05, "panelPosition": "follow_bar", diff --git a/Assets/settings-search-index.json b/Assets/settings-search-index.json index 18351bef8..cbc3af07c 100644 --- a/Assets/settings-search-index.json +++ b/Assets/settings-search-index.json @@ -2499,7 +2499,7 @@ { "labelKey": "panels.wallpaper.look-feel-transition-type-label", "descriptionKey": "panels.wallpaper.look-feel-transition-type-description", - "widget": "NComboBox", + "widget": "NLabel", "tab": 3, "tabLabel": "common.wallpaper", "subTab": 1, diff --git a/Commons/Migrations/Migration59.qml b/Commons/Migrations/Migration59.qml new file mode 100644 index 000000000..89d8bba23 --- /dev/null +++ b/Commons/Migrations/Migration59.qml @@ -0,0 +1,25 @@ +import QtQuick + +QtObject { + function migrate(adapter, logger, rawJson) { + logger.i("Settings", "Migrating settings to v59 (wallpaper.transitionType: string -> array)"); + + if (rawJson && rawJson.wallpaper && typeof rawJson.wallpaper.transitionType === "string") { + var oldValue = rawJson.wallpaper.transitionType; + var newValue; + + if (oldValue === "random") { + newValue = ["fade", "disc", "stripes", "wipe", "pixelate", "honeycomb"]; + } else if (oldValue === "none") { + newValue = []; + } else { + newValue = [oldValue]; + } + + adapter.wallpaper.transitionType = newValue; + logger.i("Settings", "Migrated wallpaper.transitionType:", oldValue, "->", JSON.stringify(newValue)); + } + + return true; + } +} diff --git a/Commons/Migrations/MigrationRegistry.qml b/Commons/Migrations/MigrationRegistry.qml index 10a8a4301..80a957157 100644 --- a/Commons/Migrations/MigrationRegistry.qml +++ b/Commons/Migrations/MigrationRegistry.qml @@ -30,7 +30,8 @@ QtObject { 55: migration55Component, 56: migration56Component, 57: migration57Component, - 58: migration58Component + 58: migration58Component, + 59: migration59Component }) // Migration components @@ -58,4 +59,5 @@ QtObject { property Component migration56Component: Migration56 {} property Component migration57Component: Migration57 {} property Component migration58Component: Migration58 {} + property Component migration59Component: Migration59 {} } diff --git a/Commons/Settings.qml b/Commons/Settings.qml index fd9b2f597..fe44e8bab 100644 --- a/Commons/Settings.qml +++ b/Commons/Settings.qml @@ -25,7 +25,7 @@ Singleton { - Default cache directory: ~/.cache/noctalia */ readonly property alias data: adapter // Used to access via Settings.data.xxx.yyy - readonly property int settingsVersion: 58 + readonly property int settingsVersion: 59 property bool isDebug: Quickshell.env("NOCTALIA_DEBUG") === "1" readonly property string shellName: "noctalia" readonly property string configDir: Quickshell.env("NOCTALIA_CONFIG_DIR") || (Quickshell.env("XDG_CONFIG_HOME") || Quickshell.env("HOME") + "/.config") + "/" + shellName + "/" @@ -389,7 +389,7 @@ Singleton { property string wallpaperChangeMode: "random" // "random" or "alphabetical" property int randomIntervalSec: 300 // 5 min property int transitionDuration: 1500 // 1500 ms - property string transitionType: "random" + property list transitionType: ["fade", "disc", "stripes", "wipe", "pixelate", "honeycomb"] property bool skipStartupTransition: false property real transitionEdgeSmoothness: 0.05 property string panelPosition: "follow_bar" diff --git a/Modules/Background/Background.qml b/Modules/Background/Background.qml index ea74e5b70..3f3c6cdf8 100644 --- a/Modules/Background/Background.qml +++ b/Modules/Background/Background.qml @@ -673,12 +673,15 @@ Variants { // ------------------------------------------------------ // Main method that actually trigger the wallpaper change function changeWallpaper() { - // Get the transitionType from the settings - transitionType = Settings.data.wallpaper.transitionType; - - if (transitionType == "random") { - var index = Math.floor(Math.random() * allTransitions.length); - transitionType = allTransitions[index]; + // Pick a transition from the user's selected list + var selected = Settings.data.wallpaper.transitionType; + if (!selected || selected.length === 0) { + transitionType = "none"; + } else if (selected.length === 1) { + transitionType = selected[0]; + } else { + var index = Math.floor(Math.random() * selected.length); + transitionType = selected[index]; } // Ensure the transition type really exists @@ -732,12 +735,15 @@ Variants { return; } - // Get the transitionType from the settings - transitionType = Settings.data.wallpaper.transitionType; - - if (transitionType == "random") { - var index = Math.floor(Math.random() * allTransitions.length); - transitionType = allTransitions[index]; + // Pick a transition from the user's selected list + var selected = Settings.data.wallpaper.transitionType; + if (!selected || selected.length === 0) { + transitionType = "none"; + } else if (selected.length === 1) { + transitionType = selected[0]; + } else { + var index = Math.floor(Math.random() * selected.length); + transitionType = selected[index]; } // Ensure the transition type really exists diff --git a/Modules/Panels/Settings/Tabs/Wallpaper/AutomationSubTab.qml b/Modules/Panels/Settings/Tabs/Wallpaper/AutomationSubTab.qml index 3c6bbe4f3..818c2c21b 100644 --- a/Modules/Panels/Settings/Tabs/Wallpaper/AutomationSubTab.qml +++ b/Modules/Panels/Settings/Tabs/Wallpaper/AutomationSubTab.qml @@ -40,7 +40,7 @@ ColumnLayout { ] currentKey: Settings.data.wallpaper.wallpaperChangeMode || "random" onSelected: key => Settings.data.wallpaper.wallpaperChangeMode = key - defaultValue: Settings.getDefaultValue("wallpaper.transitionType") + defaultValue: Settings.getDefaultValue("wallpaper.wallpaperChangeMode") } RowLayout { diff --git a/Modules/Panels/Settings/Tabs/Wallpaper/LookAndFeelSubTab.qml b/Modules/Panels/Settings/Tabs/Wallpaper/LookAndFeelSubTab.qml index 72039c0bf..61ae26143 100644 --- a/Modules/Panels/Settings/Tabs/Wallpaper/LookAndFeelSubTab.qml +++ b/Modules/Panels/Settings/Tabs/Wallpaper/LookAndFeelSubTab.qml @@ -36,13 +36,46 @@ ColumnLayout { } } - NComboBox { - label: I18n.tr("panels.wallpaper.look-feel-transition-type-label") - description: I18n.tr("panels.wallpaper.look-feel-transition-type-description") - model: WallpaperService.transitionsModel - currentKey: Settings.data.wallpaper.transitionType - onSelected: key => Settings.data.wallpaper.transitionType = key - defaultValue: Settings.getDefaultValue("wallpaper.transitionType") + NDivider { + Layout.fillWidth: true + } + + ColumnLayout { + spacing: Style.marginS + Layout.fillWidth: true + + NLabel { + label: I18n.tr("panels.wallpaper.look-feel-transition-type-label") + description: I18n.tr("panels.wallpaper.look-feel-transition-type-description") + } + + Repeater { + model: WallpaperService.allTransitions + + NCheckbox { + required property string modelData + + label: { + var key = "wallpaper.transitions." + modelData; + return I18n.tr(key); + } + checked: Settings.data.wallpaper.transitionType.includes(modelData) + onToggled: { + var arr = Array.from(Settings.data.wallpaper.transitionType); + if (checked) { + if (!arr.includes(modelData)) + arr.push(modelData); + } else { + arr = arr.filter(k => k !== modelData); + } + Settings.data.wallpaper.transitionType = arr; + } + } + } + } + + NDivider { + Layout.fillWidth: true } NToggle {