diff --git a/Common/SessionData.qml b/Common/SessionData.qml index 8ce00db8..c121b7e7 100644 --- a/Common/SessionData.qml +++ b/Common/SessionData.qml @@ -47,6 +47,8 @@ Singleton { property string lastBrightnessDevice: "" property string launchPrefix: "" property string wallpaperTransition: "fade" + readonly property var availableWallpaperTransitions: ["none", "fade", "wipe", "disc", "stripes", "iris bloom", "pixelate", "portal"] + property var includedTransitions: availableWallpaperTransitions.filter(t => t !== "none") // Power management settings - AC Power property int acMonitorTimeout: 0 // Never @@ -119,6 +121,7 @@ Singleton { lastBrightnessDevice = settings.lastBrightnessDevice !== undefined ? settings.lastBrightnessDevice : "" launchPrefix = settings.launchPrefix !== undefined ? settings.launchPrefix : "" wallpaperTransition = settings.wallpaperTransition !== undefined ? settings.wallpaperTransition : "fade" + includedTransitions = settings.includedTransitions !== undefined ? settings.includedTransitions : availableWallpaperTransitions.filter(t => t !== "none") acMonitorTimeout = settings.acMonitorTimeout !== undefined ? settings.acMonitorTimeout : 0 acLockTimeout = settings.acLockTimeout !== undefined ? settings.acLockTimeout : 0 @@ -173,6 +176,7 @@ Singleton { "lastBrightnessDevice": lastBrightnessDevice, "launchPrefix": launchPrefix, "wallpaperTransition": wallpaperTransition, + "includedTransitions": includedTransitions, "acMonitorTimeout": acMonitorTimeout, "acLockTimeout": acLockTimeout, "acSuspendTimeout": acSuspendTimeout, diff --git a/Modules/Settings/PersonalizationTab.qml b/Modules/Settings/PersonalizationTab.qml index d0db7cd5..ec8dba23 100644 --- a/Modules/Settings/PersonalizationTab.qml +++ b/Modules/Settings/PersonalizationTab.qml @@ -805,24 +805,60 @@ Item { text: "Transition Effect" description: "Visual effect used when wallpaper changes" currentValue: { - switch (SessionData.wallpaperTransition) { - case "none": return "None" - case "fade": return "Fade" - case "wipe": return "Wipe" - case "disc": return "Disc" - case "stripes": return "Stripes" - case "iris bloom": return "Iris Bloom" - case "pixelate": return "Pixelate" - case "portal": return "Portal" - default: return "Fade" - } + if (SessionData.wallpaperTransition === "random") return "Random" + return SessionData.wallpaperTransition.charAt(0).toUpperCase() + SessionData.wallpaperTransition.slice(1) } - options: ["None", "Fade", "Wipe", "Disc", "Stripes", "Iris Bloom", "Pixelate", "Portal"] + options: ["Random"].concat(SessionData.availableWallpaperTransitions.map(t => t.charAt(0).toUpperCase() + t.slice(1))) onValueChanged: value => { var transition = value.toLowerCase() SessionData.setWallpaperTransition(transition) } } + + Column { + width: parent.width + spacing: Theme.spacingS + visible: SessionData.wallpaperTransition === "random" + leftPadding: Theme.spacingM + rightPadding: Theme.spacingM + + StyledText { + text: "Include Transitions" + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceText + font.weight: Font.Medium + } + + StyledText { + text: "Select which transitions to include in randomization" + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + wrapMode: Text.WordWrap + width: parent.width - parent.leftPadding - parent.rightPadding + } + + DankButtonGroup { + id: transitionGroup + width: parent.width - parent.leftPadding - parent.rightPadding + selectionMode: "multi" + model: SessionData.availableWallpaperTransitions.filter(t => t !== "none") + initialSelection: SessionData.includedTransitions + currentSelection: SessionData.includedTransitions + + onSelectionChanged: (index, selected) => { + const transition = model[index] + let newIncluded = [...SessionData.includedTransitions] + + if (selected && !newIncluded.includes(transition)) { + newIncluded.push(transition) + } else if (!selected && newIncluded.includes(transition)) { + newIncluded = newIncluded.filter(t => t !== transition) + } + + SessionData.includedTransitions = newIncluded + } + } + } } } diff --git a/Modules/WallpaperBackground.qml b/Modules/WallpaperBackground.qml index eb91da8f..8df55da5 100644 --- a/Modules/WallpaperBackground.qml +++ b/Modules/WallpaperBackground.qml @@ -37,8 +37,24 @@ LazyLoader { property string source: SessionData.getMonitorWallpaper(modelData.name) || "" property bool isColorSource: source.startsWith("#") property string transitionType: SessionData.wallpaperTransition + property string actualTransitionType: transitionType onTransitionTypeChanged: { - currentWallpaper.visible = (transitionType === "none") + if (transitionType === "random") { + if (SessionData.includedTransitions.length === 0) { + actualTransitionType = "none" + } else { + actualTransitionType = SessionData.includedTransitions[Math.floor(Math.random() * SessionData.includedTransitions.length)] + } + } else { + actualTransitionType = transitionType + } + } + + onActualTransitionTypeChanged: { + if (actualTransitionType === "none") { + currentWallpaper.visible = true + nextWallpaper.visible = false + } } property real transitionProgress: 0 property real fillMode: 1.0 @@ -95,6 +111,8 @@ LazyLoader { root.transitionProgress = 0.0 currentWallpaper.source = newSource nextWallpaper.source = "" + currentWallpaper.visible = true + nextWallpaper.visible = false } function changeWallpaper(newPath, force) { @@ -115,17 +133,25 @@ LazyLoader { } // If transition is "none", set immediately - if (root.transitionType === "none") { + if (root.transitionType === "random") { + if (SessionData.includedTransitions.length === 0) { + root.actualTransitionType = "none" + } else { + root.actualTransitionType = SessionData.includedTransitions[Math.floor(Math.random() * SessionData.includedTransitions.length)] + } + } + + if (root.actualTransitionType === "none") { setWallpaperImmediate(newPath) return } - if (root.transitionType === "wipe") { + if (root.actualTransitionType === "wipe") { root.wipeDirection = Math.random() * 4 - } else if (root.transitionType === "disc") { + } else if (root.actualTransitionType === "disc") { root.discCenterX = Math.random() root.discCenterY = Math.random() - } else if (root.transitionType === "stripes") { + } else if (root.actualTransitionType === "stripes") { root.stripesCount = Math.round(Math.random() * 20 + 4) root.stripesAngle = Math.random() * 360 } @@ -165,7 +191,7 @@ LazyLoader { Image { id: currentWallpaper anchors.fill: parent - visible: root.transitionType === "none" + visible: root.actualTransitionType === "none" opacity: 1 layer.enabled: false asynchronous: true @@ -188,7 +214,7 @@ LazyLoader { onStatusChanged: { if (status !== Image.Ready) return - if (root.transitionType === "none") { + if (root.actualTransitionType === "none") { currentWallpaper.source = source nextWallpaper.source = "" root.transitionProgress = 0.0 @@ -206,7 +232,7 @@ LazyLoader { ShaderEffect { id: fadeShader anchors.fill: parent - visible: root.transitionType === "fade" && (root.hasCurrent || root.booting) + visible: root.actualTransitionType === "fade" && (root.hasCurrent || root.booting) property variant source1: root.hasCurrent ? currentWallpaper : transparentSource property variant source2: nextWallpaper @@ -226,7 +252,7 @@ LazyLoader { ShaderEffect { id: wipeShader anchors.fill: parent - visible: root.transitionType === "wipe" && (root.hasCurrent || root.booting) + visible: root.actualTransitionType === "wipe" && (root.hasCurrent || root.booting) property variant source1: root.hasCurrent ? currentWallpaper : transparentSource property variant source2: nextWallpaper @@ -248,7 +274,7 @@ LazyLoader { ShaderEffect { id: discShader anchors.fill: parent - visible: root.transitionType === "disc" && (root.hasCurrent || root.booting) + visible: root.actualTransitionType === "disc" && (root.hasCurrent || root.booting) property variant source1: root.hasCurrent ? currentWallpaper : transparentSource property variant source2: nextWallpaper @@ -272,7 +298,7 @@ LazyLoader { ShaderEffect { id: stripesShader anchors.fill: parent - visible: root.transitionType === "stripes" && (root.hasCurrent || root.booting) + visible: root.actualTransitionType === "stripes" && (root.hasCurrent || root.booting) property variant source1: root.hasCurrent ? currentWallpaper : transparentSource property variant source2: nextWallpaper @@ -296,7 +322,7 @@ LazyLoader { ShaderEffect { id: irisBloomShader anchors.fill: parent - visible: root.transitionType === "iris bloom" && (root.hasCurrent || root.booting) + visible: root.actualTransitionType === "iris bloom" && (root.hasCurrent || root.booting) property variant source1: root.hasCurrent ? currentWallpaper : transparentSource property variant source2: nextWallpaper @@ -320,7 +346,7 @@ LazyLoader { ShaderEffect { id: pixelateShader anchors.fill: parent - visible: root.transitionType === "pixelate" && (root.hasCurrent || root.booting) + visible: root.actualTransitionType === "pixelate" && (root.hasCurrent || root.booting) property variant source1: root.hasCurrent ? currentWallpaper : transparentSource property variant source2: nextWallpaper @@ -344,7 +370,7 @@ LazyLoader { ShaderEffect { id: portalShader anchors.fill: parent - visible: root.transitionType === "portal" && (root.hasCurrent || root.booting) + visible: root.actualTransitionType === "portal" && (root.hasCurrent || root.booting) property variant source1: root.hasCurrent ? currentWallpaper : transparentSource property variant source2: nextWallpaper @@ -371,7 +397,7 @@ LazyLoader { property: "transitionProgress" from: 0.0 to: 1.0 - duration: root.transitionType === "none" ? 0 : 1000 + duration: root.actualTransitionType === "none" ? 0 : 1000 easing.type: Easing.InOutCubic onFinished: { Qt.callLater(() => { @@ -380,7 +406,7 @@ LazyLoader { } nextWallpaper.source = "" nextWallpaper.visible = false - currentWallpaper.visible = root.transitionType === "none" + currentWallpaper.visible = root.actualTransitionType === "none" currentWallpaper.layer.enabled = false nextWallpaper.layer.enabled = false root.transitionProgress = 0.0 diff --git a/Widgets/DankButtonGroup.qml b/Widgets/DankButtonGroup.qml index 5a5b58a1..8b768827 100644 --- a/Widgets/DankButtonGroup.qml +++ b/Widgets/DankButtonGroup.qml @@ -2,13 +2,15 @@ import QtQuick import qs.Common import qs.Widgets -Row { +Flow { id: root property var model: [] property int currentIndex: -1 property string selectionMode: "single" property bool multiSelect: selectionMode === "multi" + property var initialSelection: [] + property var currentSelection: initialSelection property bool checkEnabled: true property int buttonHeight: 40 property int minButtonWidth: 64 @@ -29,11 +31,18 @@ Row { function selectItem(index) { if (multiSelect) { - const item = repeater.itemAt(index) - if (item) { - item.selected = !item.selected - selectionChanged(index, item.selected) + const modelValue = model[index] + let newSelection = [...currentSelection] + const isCurrentlySelected = newSelection.includes(modelValue) + + if (isCurrentlySelected) { + newSelection = newSelection.filter(item => item !== modelValue) + } else { + newSelection.push(modelValue) } + + currentSelection = newSelection + selectionChanged(index, !isCurrentlySelected) } else { const oldIndex = currentIndex currentIndex = index @@ -51,7 +60,7 @@ Row { delegate: Rectangle { id: segment - property bool selected: multiSelect ? false : (index === root.currentIndex) + property bool selected: multiSelect ? root.currentSelection.includes(modelData) : (index === root.currentIndex) property bool hovered: mouseArea.containsMouse property bool pressed: mouseArea.pressed property bool isFirst: index === 0 diff --git a/Widgets/DankDropdown.qml b/Widgets/DankDropdown.qml index b42fd685..07d7d817 100644 --- a/Widgets/DankDropdown.qml +++ b/Widgets/DankDropdown.qml @@ -335,6 +335,7 @@ Rectangle { onClicked: { root.currentValue = modelData root.valueChanged(modelData) + listView.popupRef.close() } } }