From 3dbe83a0e14cd6408ff4ec616612bf15ca83edf7 Mon Sep 17 00:00:00 2001 From: zach Date: Sun, 12 Apr 2026 23:30:39 +0200 Subject: [PATCH] wallpapers in settings --- Drawers/Interactions.qml | 2 + Helpers/Wallpapers.qml | 2 + Modules/Settings/Categories/Background.qml | 11 +- Modules/Settings/Controls/SettingsPage.qml | 54 +++++--- Modules/Settings/Controls/WallpaperGrid.qml | 146 ++++++++++++++++++++ 5 files changed, 191 insertions(+), 24 deletions(-) create mode 100644 Modules/Settings/Controls/WallpaperGrid.qml diff --git a/Drawers/Interactions.qml b/Drawers/Interactions.qml index 7d5c225..3371f0d 100644 --- a/Drawers/Interactions.qml +++ b/Drawers/Interactions.qml @@ -189,6 +189,7 @@ CustomMouseArea { if (root.visibilities.settings) { root.visibilities.resources = false; root.visibilities.dashboard = false; + root.visibilities.sidebar = false; root.panels.popouts.hasCurrent = false; root.visibilities.launcher = false; } @@ -197,6 +198,7 @@ CustomMouseArea { function onSidebarChanged() { if (root.visibilities.sidebar) { root.visibilities.dashboard = false; + root.visibilities.settings = false; root.popouts.hasCurrent = false; } } diff --git a/Helpers/Wallpapers.qml b/Helpers/Wallpapers.qml index afbe9e8..3febca8 100644 --- a/Helpers/Wallpapers.qml +++ b/Helpers/Wallpapers.qml @@ -27,6 +27,8 @@ Searcher { actualCurrent = path; WallpaperPath.currentWallpaperPath = path; Quickshell.execDetached(["zshell-cli", "wallpaper", "lockscreen", "--input-image", `${root.actualCurrent}`, "--output-path", `${Paths.state}/lockscreen_bg.png`, "--blur-amount", `${Config.lock.blurAmount}`]); + if (Config.general.color.schemeGeneration) + Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--image-path", `${root.actualCurrent}`, "--scheme", `${Config.colors.schemeType}`, "--mode", `${Config.general.color.mode}`]); } function stopPreview(): void { diff --git a/Modules/Settings/Categories/Background.qml b/Modules/Settings/Categories/Background.qml index 20f5dac..63c8d65 100644 --- a/Modules/Settings/Categories/Background.qml +++ b/Modules/Settings/Categories/Background.qml @@ -1,3 +1,4 @@ +import QtQuick.Layouts import qs.Modules.Settings.Controls import qs.Config @@ -21,11 +22,19 @@ SettingsPage { } SettingSpinBox { - name: "Fade duration" min: 0 + name: "Fade duration" object: Config.background setting: "wallFadeDuration" step: 50 } } + + SettingsSection { + sectionId: "Wallpapers" + + WallpaperGrid { + Layout.fillWidth: true + } + } } diff --git a/Modules/Settings/Controls/SettingsPage.qml b/Modules/Settings/Controls/SettingsPage.qml index f478ad5..e7b42e8 100644 --- a/Modules/Settings/Controls/SettingsPage.qml +++ b/Modules/Settings/Controls/SettingsPage.qml @@ -4,7 +4,7 @@ import qs.Components import qs.Config import qs.Helpers -CustomFlickable { +CustomClippingRect { id: root default property alias contentData: clayout.data @@ -17,7 +17,7 @@ CustomFlickable { if (section.sectionId === sectionId) { // Scroll to the section with some padding const targetY = section.y - Appearance.padding.normal; - contentY = Math.max(0, Math.min(targetY, contentHeight - height)); + flickable.contentY = Math.max(0, Math.min(targetY, flickable.contentHeight - flickable.height)); // Use the singleton to highlight the setting SettingsHighlight.highlight(settingName); @@ -27,33 +27,41 @@ CustomFlickable { return false; } - contentHeight: clayout.implicitHeight + radius: Appearance.rounding.normal - Appearance.padding.smaller - TapHandler { - acceptedButtons: Qt.LeftButton + CustomFlickable { + id: flickable - onTapped: function (eventPoint) { - const menu = SettingsDropdowns.activeMenu; - if (!menu) - return; + anchors.fill: parent + clip: true + contentHeight: clayout.implicitHeight - const p = eventPoint.scenePosition; + TapHandler { + acceptedButtons: Qt.LeftButton - if (SettingsDropdowns.hit(SettingsDropdowns.activeTrigger, p)) - return; + onTapped: function (eventPoint) { + const menu = SettingsDropdowns.activeMenu; + if (!menu) + return; - if (SettingsDropdowns.hit(menu, p)) - return; + const p = eventPoint.scenePosition; - SettingsDropdowns.closeActive(); + if (SettingsDropdowns.hit(SettingsDropdowns.activeTrigger, p)) + return; + + if (SettingsDropdowns.hit(menu, p)) + return; + + SettingsDropdowns.closeActive(); + } + } + + ColumnLayout { + id: clayout + + anchors.left: parent.left + anchors.right: parent.right + spacing: Appearance.spacing.small } } - - ColumnLayout { - id: clayout - - anchors.left: parent.left - anchors.right: parent.right - spacing: Appearance.spacing.small - } } diff --git a/Modules/Settings/Controls/WallpaperGrid.qml b/Modules/Settings/Controls/WallpaperGrid.qml new file mode 100644 index 0000000..764b10e --- /dev/null +++ b/Modules/Settings/Controls/WallpaperGrid.qml @@ -0,0 +1,146 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Layouts +import ZShell.Models +import qs.Components +import qs.Helpers +import qs.Config + +GridView { + id: root + + readonly property int columnsCount: Math.max(1, Math.floor(width / minCellWidth)) + readonly property int minCellWidth: 200 + Appearance.spacing.normal + + Layout.preferredHeight: contentHeight + cellHeight: 140 + Appearance.spacing.normal + cellWidth: width / columnsCount + clip: true + interactive: false + model: Wallpapers.list + + delegate: Item { + required property int index + readonly property bool isCurrent: modelData && modelData.path === Wallpapers.actualCurrent + readonly property real itemMargin: Appearance.spacing.normal / 2 + readonly property real itemRadius: Appearance.rounding.normal + required property var modelData + + height: root.cellHeight + width: root.cellWidth + + StateLayer { + function onClicked(): void { + Wallpapers.setWallpaper(modelData.path); + } + + anchors.bottomMargin: itemMargin + anchors.fill: parent + anchors.leftMargin: itemMargin + anchors.rightMargin: itemMargin + anchors.topMargin: itemMargin + radius: itemRadius + } + + CustomClippingRect { + id: image + + anchors.bottomMargin: itemMargin + anchors.fill: parent + anchors.leftMargin: itemMargin + anchors.rightMargin: itemMargin + anchors.topMargin: itemMargin + antialiasing: true + color: DynamicColors.tPalette.m3surfaceContainer + layer.enabled: true + layer.smooth: true + radius: itemRadius + + CachingImage { + id: cachingImage + + anchors.fill: parent + antialiasing: true + cache: true + fillMode: Image.PreserveAspectCrop + opacity: status === Image.Ready ? 1 : 0 + path: modelData.path + smooth: true + sourceSize: Qt.size(width, height) + visible: opacity > 0 + + Behavior on opacity { + NumberAnimation { + duration: 1000 + easing.type: Easing.OutQuad + } + } + } + + Image { + id: fallbackImage + + anchors.fill: parent + antialiasing: true + asynchronous: true + cache: true + fillMode: Image.PreserveAspectCrop + opacity: status === Image.Ready && cachingImage.status !== Image.Ready ? 1 : 0 + smooth: true + source: fallbackTimer.triggered && cachingImage.status !== Image.Ready ? modelData.path : "" + sourceSize: Qt.size(width, height) + visible: opacity > 0 + + Behavior on opacity { + NumberAnimation { + duration: 1000 + easing.type: Easing.OutQuad + } + } + } + + Timer { + id: fallbackTimer + + property bool triggered: false + + interval: 800 + running: cachingImage.status === Image.Loading || cachingImage.status === Image.Null + + onTriggered: triggered = true + } + } + + Rectangle { + anchors.bottomMargin: itemMargin + anchors.fill: parent + anchors.leftMargin: itemMargin + anchors.rightMargin: itemMargin + anchors.topMargin: itemMargin + antialiasing: true + border.color: DynamicColors.palette.m3primary + border.width: isCurrent ? 2 : 0 + color: "transparent" + radius: itemRadius - border.width + smooth: true + + Behavior on border.width { + NumberAnimation { + duration: 150 + easing.type: Easing.OutQuad + } + } + + MaterialIcon { + anchors.margins: Appearance.padding.small + anchors.right: parent.right + anchors.top: parent.top + color: DynamicColors.palette.m3primary + font.pointSize: Appearance.font.size.large + text: "check_circle" + visible: isCurrent + } + } + } +}