mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-06-24 12:05:21 -04:00
1a39b7f66c
* feat: parallax-scroll wallpaper Add a `Scrolling` wallpaper fill mode that translates the wallpaper crop with the active workspace — like Android home-screen parallax, but along niri's vertical workspace axis. The image is scaled to cover the screen on its non-scroll axis, and the active workspace index drives a fractional offset into the cropped overflow along the scroll axis. Scroll position is spring-animated CPU-side and handed to a minimal single-texture shader as a UV offset. Per-monitor scroll position is published into SessionData so the lock screen renders the same crop as the active workspace, keeping visual continuity across lock/unlock. Two implementation details worth calling out for review: - QSG_USE_SIMPLE_ANIMATION_DRIVER=1 is exported to the spawned quickshell process. The default animation driver advances in fixed ~16ms steps, capping the scroll at 60Hz and desyncing it from compositor motion on high-refresh displays; the simple driver advances by real elapsed time, restoring native-refresh pacing. Removing it visibly regresses to 60Hz. - The wallpaper survives wl_output rebind cycles (e.g. OLED image-cleaning on DPMS soft-off), which otherwise leave a stuck or void background. Recovery re-anchors the scroll target on output-lifecycle signals, rebuilds the ShaderEffect against the current render context, and re-attaches the wallpaper-layer surface on unlock for parallax-active monitors — guarded against lock state so the shader gets reliable frame hints. * simplify bindings and gate lock screen shader in a loader --------- Co-authored-by: bbedward <bbedward@gmail.com>
1407 lines
71 KiB
QML
1407 lines
71 KiB
QML
import QtQuick
|
|
import QtQuick.Effects
|
|
import Quickshell
|
|
import qs.Common
|
|
import qs.Modals.FileBrowser
|
|
import qs.Services
|
|
import qs.Widgets
|
|
import qs.Modules.Settings.Widgets
|
|
|
|
Item {
|
|
id: root
|
|
|
|
LayoutMirroring.enabled: I18n.isRtl
|
|
LayoutMirroring.childrenInherit: true
|
|
|
|
property var parentModal: null
|
|
property string selectedMonitorName: {
|
|
var screens = Quickshell.screens;
|
|
return screens.length > 0 ? screens[0].name : "";
|
|
}
|
|
property string currentWallpaper: {
|
|
if (!SessionData.perMonitorWallpaper)
|
|
return SessionData.wallpaperPath;
|
|
var map = SessionData.monitorWallpapers;
|
|
var screens = Quickshell.screens;
|
|
for (var i = 0; i < screens.length; i++) {
|
|
if (screens[i].name !== selectedMonitorName)
|
|
continue;
|
|
var screen = screens[i];
|
|
if (map[screen.name] !== undefined)
|
|
return map[screen.name];
|
|
if (screen.model && map[screen.model] !== undefined)
|
|
return map[screen.model];
|
|
var displayName = SettingsData.getScreenDisplayName(screen);
|
|
if (displayName && map[displayName] !== undefined)
|
|
return map[displayName];
|
|
break;
|
|
}
|
|
return SessionData.wallpaperPath;
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
WallpaperCyclingService.cyclingActive;
|
|
}
|
|
|
|
DankFlickable {
|
|
anchors.fill: parent
|
|
clip: true
|
|
contentHeight: mainColumn.height + Theme.spacingXL
|
|
contentWidth: width
|
|
|
|
Column {
|
|
id: mainColumn
|
|
topPadding: 4
|
|
|
|
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
spacing: Theme.spacingXL
|
|
|
|
SettingsCard {
|
|
tab: "wallpaper"
|
|
tags: ["background", "image", "picture"]
|
|
title: I18n.tr("Wallpaper")
|
|
settingKey: "wallpaper"
|
|
iconName: "wallpaper"
|
|
|
|
Row {
|
|
width: parent.width
|
|
spacing: Theme.spacingL
|
|
|
|
StyledRect {
|
|
id: wallpaperPreview
|
|
width: 160
|
|
height: 90
|
|
radius: Theme.cornerRadius
|
|
color: Theme.surfaceVariant
|
|
|
|
Image {
|
|
anchors.fill: parent
|
|
anchors.margins: 1
|
|
source: {
|
|
var wp = root.currentWallpaper;
|
|
if (wp === "" || wp.startsWith("#"))
|
|
return "";
|
|
if (wp.startsWith("file://"))
|
|
wp = wp.substring(7);
|
|
return "file://" + wp.split('/').map(s => encodeURIComponent(s)).join('/');
|
|
}
|
|
fillMode: Image.PreserveAspectCrop
|
|
visible: root.currentWallpaper !== "" && !root.currentWallpaper.startsWith("#")
|
|
sourceSize.width: 160
|
|
sourceSize.height: 160
|
|
asynchronous: true
|
|
layer.enabled: true
|
|
layer.effect: MultiEffect {
|
|
maskEnabled: true
|
|
maskSource: wallpaperMask
|
|
maskThresholdMin: 0.5
|
|
maskSpreadAtMin: 1
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
anchors.margins: 1
|
|
radius: Theme.cornerRadius - 1
|
|
color: root.currentWallpaper.startsWith("#") ? root.currentWallpaper : "transparent"
|
|
visible: root.currentWallpaper !== "" && root.currentWallpaper.startsWith("#")
|
|
}
|
|
|
|
Rectangle {
|
|
id: wallpaperMask
|
|
anchors.fill: parent
|
|
anchors.margins: 1
|
|
radius: Theme.cornerRadius - 1
|
|
color: "black"
|
|
visible: false
|
|
layer.enabled: true
|
|
}
|
|
|
|
DankIcon {
|
|
anchors.centerIn: parent
|
|
name: "image"
|
|
size: Theme.iconSizeLarge + 8
|
|
color: Theme.surfaceVariantText
|
|
visible: root.currentWallpaper === ""
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
anchors.margins: 1
|
|
radius: Theme.cornerRadius - 1
|
|
color: Qt.rgba(0, 0, 0, 0.7)
|
|
visible: wallpaperMouseArea.containsMouse
|
|
|
|
Row {
|
|
anchors.centerIn: parent
|
|
spacing: 4
|
|
|
|
Rectangle {
|
|
width: 32
|
|
height: 32
|
|
radius: 16
|
|
color: Qt.rgba(255, 255, 255, 0.9)
|
|
|
|
DankIcon {
|
|
anchors.centerIn: parent
|
|
name: "folder_open"
|
|
size: 18
|
|
color: "black"
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: root.openMainWallpaperBrowser()
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
width: 32
|
|
height: 32
|
|
radius: 16
|
|
color: Qt.rgba(255, 255, 255, 0.9)
|
|
|
|
DankIcon {
|
|
anchors.centerIn: parent
|
|
name: "palette"
|
|
size: 18
|
|
color: "black"
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: {
|
|
if (!PopoutService.colorPickerModal)
|
|
return;
|
|
PopoutService.colorPickerModal.selectedColor = root.currentWallpaper.startsWith("#") ? root.currentWallpaper : Theme.primary;
|
|
PopoutService.colorPickerModal.pickerTitle = I18n.tr("Choose Wallpaper Color", "wallpaper color picker title");
|
|
PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) {
|
|
if (SessionData.perMonitorWallpaper) {
|
|
SessionData.setMonitorWallpaper(selectedMonitorName, selectedColor);
|
|
} else {
|
|
SessionData.setWallpaperColor(selectedColor);
|
|
}
|
|
};
|
|
PopoutService.colorPickerModal.show();
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
width: 32
|
|
height: 32
|
|
radius: 16
|
|
color: Qt.rgba(255, 255, 255, 0.9)
|
|
visible: root.currentWallpaper !== ""
|
|
|
|
DankIcon {
|
|
anchors.centerIn: parent
|
|
name: "clear"
|
|
size: 18
|
|
color: "black"
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: {
|
|
if (SessionData.perMonitorWallpaper) {
|
|
SessionData.setMonitorWallpaper(selectedMonitorName, "");
|
|
} else {
|
|
if (Theme.currentTheme === Theme.dynamic)
|
|
Theme.switchTheme("blue");
|
|
SessionData.clearWallpaper();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
id: wallpaperMouseArea
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
propagateComposedEvents: true
|
|
acceptedButtons: Qt.NoButton
|
|
}
|
|
}
|
|
|
|
Column {
|
|
width: parent.width - 160 - Theme.spacingL
|
|
spacing: Theme.spacingS
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
StyledText {
|
|
text: root.currentWallpaper ? root.currentWallpaper.split('/').pop() : I18n.tr("No wallpaper selected")
|
|
font.pixelSize: Theme.fontSizeLarge
|
|
color: Theme.surfaceText
|
|
elide: Text.ElideMiddle
|
|
maximumLineCount: 1
|
|
width: parent.width
|
|
horizontalAlignment: Text.AlignLeft
|
|
}
|
|
|
|
StyledText {
|
|
text: root.currentWallpaper
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
color: Theme.surfaceVariantText
|
|
elide: Text.ElideMiddle
|
|
maximumLineCount: 1
|
|
width: parent.width
|
|
horizontalAlignment: Text.AlignLeft
|
|
visible: root.currentWallpaper !== ""
|
|
}
|
|
|
|
Row {
|
|
anchors.left: parent.left
|
|
spacing: Theme.spacingS
|
|
layoutDirection: I18n.isRtl ? Qt.RightToLeft : Qt.LeftToRight
|
|
visible: root.currentWallpaper !== ""
|
|
|
|
DankActionButton {
|
|
buttonSize: 32
|
|
iconName: "skip_previous"
|
|
iconSize: Theme.iconSizeSmall
|
|
enabled: root.currentWallpaper && !root.currentWallpaper.startsWith("#") && !root.currentWallpaper.startsWith("we")
|
|
opacity: enabled ? 1 : 0.5
|
|
backgroundColor: Theme.surfaceContainerHigh
|
|
iconColor: Theme.surfaceText
|
|
onClicked: {
|
|
if (SessionData.perMonitorWallpaper) {
|
|
WallpaperCyclingService.cyclePrevForMonitor(selectedMonitorName);
|
|
} else {
|
|
WallpaperCyclingService.cyclePrevManually();
|
|
}
|
|
}
|
|
}
|
|
|
|
DankActionButton {
|
|
buttonSize: 32
|
|
iconName: "skip_next"
|
|
iconSize: Theme.iconSizeSmall
|
|
enabled: root.currentWallpaper && !root.currentWallpaper.startsWith("#") && !root.currentWallpaper.startsWith("we")
|
|
opacity: enabled ? 1 : 0.5
|
|
backgroundColor: Theme.surfaceContainerHigh
|
|
iconColor: Theme.surfaceText
|
|
onClicked: {
|
|
if (SessionData.perMonitorWallpaper) {
|
|
WallpaperCyclingService.cycleNextForMonitor(selectedMonitorName);
|
|
} else {
|
|
WallpaperCyclingService.cycleNextManually();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Item {
|
|
width: parent.width
|
|
height: fillModeGroup.height
|
|
visible: root.currentWallpaper !== "" && !root.currentWallpaper.startsWith("#")
|
|
|
|
DankButtonGroup {
|
|
id: fillModeGroup
|
|
property var internalModes: ["Stretch", "Fit", "Fill", "Scrolling", "Tile", "TileVertically", "TileHorizontally", "Pad"]
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
model: [I18n.tr("Stretch", "wallpaper fill mode"), I18n.tr("Fit", "wallpaper fill mode"), I18n.tr("Fill", "wallpaper fill mode"), I18n.tr("Scroll", "wallpaper fill mode"), I18n.tr("Tile", "wallpaper fill mode"), I18n.tr("Tile V", "wallpaper fill mode"), I18n.tr("Tile H", "wallpaper fill mode"), I18n.tr("Pad", "wallpaper fill mode")]
|
|
selectionMode: "single"
|
|
buttonHeight: 28
|
|
minButtonWidth: 48
|
|
buttonPadding: Theme.spacingS
|
|
checkIconSize: 0
|
|
textSize: Theme.fontSizeSmall
|
|
checkEnabled: false
|
|
currentIndex: {
|
|
var mode = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaperFillMode(selectedMonitorName) : SettingsData.wallpaperFillMode;
|
|
return internalModes.indexOf(mode);
|
|
}
|
|
onSelectionChanged: (index, selected) => {
|
|
if (!selected)
|
|
return;
|
|
if (SessionData.perMonitorWallpaper) {
|
|
SessionData.setMonitorWallpaperFillMode(selectedMonitorName, internalModes[index]);
|
|
} else {
|
|
SettingsData.set("wallpaperFillMode", internalModes[index]);
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: SettingsData
|
|
function onWallpaperFillModeChanged() {
|
|
if (SessionData.perMonitorWallpaper)
|
|
return;
|
|
fillModeGroup.currentIndex = fillModeGroup.internalModes.indexOf(SettingsData.wallpaperFillMode);
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: root
|
|
function onSelectedMonitorNameChanged() {
|
|
if (!SessionData.perMonitorWallpaper)
|
|
return;
|
|
fillModeGroup.currentIndex = Qt.binding(() => {
|
|
var mode = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaperFillMode(selectedMonitorName) : SettingsData.wallpaperFillMode;
|
|
return fillModeGroup.internalModes.indexOf(mode);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ColorDropdownRow {
|
|
tab: "wallpaper"
|
|
tags: ["background", "color", "fill", "fit", "custom"]
|
|
settingKey: "wallpaperBackgroundColorMode"
|
|
text: I18n.tr("Background Color")
|
|
description: I18n.tr("Color shown for areas not covered by wallpaper (e.g. Fit or Pad modes)")
|
|
visible: root.currentWallpaper !== "" && !root.currentWallpaper.startsWith("#")
|
|
dropdownWidth: 220
|
|
options: [
|
|
{
|
|
"value": "black",
|
|
"label": I18n.tr("Black")
|
|
},
|
|
{
|
|
"value": "white",
|
|
"label": I18n.tr("White")
|
|
},
|
|
{
|
|
"value": "primary",
|
|
"label": I18n.tr("Primary Theme Color")
|
|
},
|
|
{
|
|
"value": "surface",
|
|
"label": I18n.tr("Surface Container")
|
|
},
|
|
{
|
|
"value": "custom",
|
|
"label": I18n.tr("Custom")
|
|
}
|
|
]
|
|
currentMode: SettingsData.wallpaperBackgroundColorMode
|
|
customColor: SettingsData.wallpaperBackgroundCustomColor || "#000000"
|
|
pickerTitle: I18n.tr("Background Color")
|
|
onModeSelected: mode => SettingsData.set("wallpaperBackgroundColorMode", mode)
|
|
onCustomColorSelected: selectedColor => SettingsData.set("wallpaperBackgroundCustomColor", selectedColor.toString())
|
|
}
|
|
|
|
Rectangle {
|
|
width: parent.width
|
|
height: 1
|
|
color: Theme.outline
|
|
opacity: 0.2
|
|
visible: SessionData.wallpaperPath !== ""
|
|
}
|
|
|
|
SettingsToggleRow {
|
|
tab: "wallpaper"
|
|
tags: ["per-mode", "light", "dark", "theme"]
|
|
settingKey: "perModeWallpaper"
|
|
visible: SessionData.wallpaperPath !== ""
|
|
text: I18n.tr("Per-Mode Wallpapers")
|
|
description: I18n.tr("Set different wallpapers for light and dark mode")
|
|
checked: SessionData.perModeWallpaper
|
|
onToggled: toggled => SessionData.setPerModeWallpaper(toggled)
|
|
}
|
|
|
|
Column {
|
|
width: parent.width
|
|
spacing: Theme.spacingM
|
|
visible: SessionData.perModeWallpaper
|
|
leftPadding: Theme.spacingM
|
|
rightPadding: Theme.spacingM
|
|
|
|
Row {
|
|
width: parent.width - Theme.spacingM * 2
|
|
spacing: Theme.spacingL
|
|
|
|
Column {
|
|
width: (parent.width - Theme.spacingL) / 2
|
|
spacing: Theme.spacingS
|
|
|
|
StyledText {
|
|
text: I18n.tr("Light Mode")
|
|
font.pixelSize: Theme.fontSizeMedium
|
|
color: Theme.surfaceText
|
|
font.weight: Font.Medium
|
|
}
|
|
|
|
StyledRect {
|
|
width: parent.width
|
|
height: width * 9 / 16
|
|
radius: Theme.cornerRadius
|
|
color: Theme.surfaceVariant
|
|
|
|
Image {
|
|
anchors.fill: parent
|
|
anchors.margins: 1
|
|
source: {
|
|
var wp = SessionData.wallpaperPathLight;
|
|
if (wp === "" || wp.startsWith("#"))
|
|
return "";
|
|
if (wp.startsWith("file://"))
|
|
wp = wp.substring(7);
|
|
return "file://" + wp.split('/').map(s => encodeURIComponent(s)).join('/');
|
|
}
|
|
fillMode: Image.PreserveAspectCrop
|
|
visible: {
|
|
var lightWallpaper = SessionData.wallpaperPathLight;
|
|
return lightWallpaper !== "" && !lightWallpaper.startsWith("#");
|
|
}
|
|
sourceSize.width: 160
|
|
sourceSize.height: 160
|
|
asynchronous: true
|
|
layer.enabled: true
|
|
layer.effect: MultiEffect {
|
|
maskEnabled: true
|
|
maskSource: lightMask
|
|
maskThresholdMin: 0.5
|
|
maskSpreadAtMin: 1
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
anchors.margins: 1
|
|
radius: Theme.cornerRadius - 1
|
|
color: {
|
|
var lightWallpaper = SessionData.wallpaperPathLight;
|
|
return lightWallpaper.startsWith("#") ? lightWallpaper : "transparent";
|
|
}
|
|
visible: {
|
|
var lightWallpaper = SessionData.wallpaperPathLight;
|
|
return lightWallpaper !== "" && lightWallpaper.startsWith("#");
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: lightMask
|
|
anchors.fill: parent
|
|
anchors.margins: 1
|
|
radius: Theme.cornerRadius - 1
|
|
color: "black"
|
|
visible: false
|
|
layer.enabled: true
|
|
}
|
|
|
|
DankIcon {
|
|
anchors.centerIn: parent
|
|
name: "light_mode"
|
|
size: Theme.iconSizeLarge
|
|
color: Theme.surfaceVariantText
|
|
visible: SessionData.wallpaperPathLight === ""
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
anchors.margins: 1
|
|
radius: Theme.cornerRadius - 1
|
|
color: Qt.rgba(0, 0, 0, 0.7)
|
|
visible: lightModeMouseArea.containsMouse
|
|
|
|
Row {
|
|
anchors.centerIn: parent
|
|
spacing: 4
|
|
|
|
Rectangle {
|
|
width: 28
|
|
height: 28
|
|
radius: 14
|
|
color: Qt.rgba(255, 255, 255, 0.9)
|
|
|
|
DankIcon {
|
|
anchors.centerIn: parent
|
|
name: "folder_open"
|
|
size: 16
|
|
color: "black"
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: root.openLightWallpaperBrowser()
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
width: 28
|
|
height: 28
|
|
radius: 14
|
|
color: Qt.rgba(255, 255, 255, 0.9)
|
|
|
|
DankIcon {
|
|
anchors.centerIn: parent
|
|
name: "palette"
|
|
size: 16
|
|
color: "black"
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: {
|
|
if (!PopoutService.colorPickerModal)
|
|
return;
|
|
var lightWallpaper = SessionData.wallpaperPathLight;
|
|
PopoutService.colorPickerModal.selectedColor = lightWallpaper.startsWith("#") ? lightWallpaper : Theme.primary;
|
|
PopoutService.colorPickerModal.pickerTitle = I18n.tr("Choose Light Mode Color", "light mode wallpaper color picker title");
|
|
PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) {
|
|
SessionData.wallpaperPathLight = selectedColor;
|
|
SessionData.syncWallpaperForCurrentMode();
|
|
SessionData.saveSettings();
|
|
};
|
|
PopoutService.colorPickerModal.show();
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
width: 28
|
|
height: 28
|
|
radius: 14
|
|
color: Qt.rgba(255, 255, 255, 0.9)
|
|
visible: SessionData.wallpaperPathLight !== ""
|
|
|
|
DankIcon {
|
|
anchors.centerIn: parent
|
|
name: "clear"
|
|
size: 16
|
|
color: "black"
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: {
|
|
SessionData.wallpaperPathLight = "";
|
|
SessionData.syncWallpaperForCurrentMode();
|
|
SessionData.saveSettings();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
id: lightModeMouseArea
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
propagateComposedEvents: true
|
|
acceptedButtons: Qt.NoButton
|
|
}
|
|
}
|
|
|
|
StyledText {
|
|
text: {
|
|
var lightWallpaper = SessionData.wallpaperPathLight;
|
|
return lightWallpaper ? lightWallpaper.split('/').pop() : I18n.tr("Not set", "wallpaper not set label");
|
|
}
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
color: Theme.surfaceVariantText
|
|
elide: Text.ElideMiddle
|
|
maximumLineCount: 1
|
|
width: parent.width
|
|
}
|
|
}
|
|
|
|
Column {
|
|
width: (parent.width - Theme.spacingL) / 2
|
|
spacing: Theme.spacingS
|
|
|
|
StyledText {
|
|
text: I18n.tr("Dark Mode")
|
|
font.pixelSize: Theme.fontSizeMedium
|
|
color: Theme.surfaceText
|
|
font.weight: Font.Medium
|
|
}
|
|
|
|
StyledRect {
|
|
width: parent.width
|
|
height: width * 9 / 16
|
|
radius: Theme.cornerRadius
|
|
color: Theme.surfaceVariant
|
|
|
|
Image {
|
|
anchors.fill: parent
|
|
anchors.margins: 1
|
|
source: {
|
|
var wp = SessionData.wallpaperPathDark;
|
|
if (wp === "" || wp.startsWith("#"))
|
|
return "";
|
|
if (wp.startsWith("file://"))
|
|
wp = wp.substring(7);
|
|
return "file://" + wp.split('/').map(s => encodeURIComponent(s)).join('/');
|
|
}
|
|
fillMode: Image.PreserveAspectCrop
|
|
visible: {
|
|
var darkWallpaper = SessionData.wallpaperPathDark;
|
|
return darkWallpaper !== "" && !darkWallpaper.startsWith("#");
|
|
}
|
|
sourceSize.width: 160
|
|
sourceSize.height: 160
|
|
asynchronous: true
|
|
layer.enabled: true
|
|
layer.effect: MultiEffect {
|
|
maskEnabled: true
|
|
maskSource: darkMask
|
|
maskThresholdMin: 0.5
|
|
maskSpreadAtMin: 1
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
anchors.margins: 1
|
|
radius: Theme.cornerRadius - 1
|
|
color: {
|
|
var darkWallpaper = SessionData.wallpaperPathDark;
|
|
return darkWallpaper.startsWith("#") ? darkWallpaper : "transparent";
|
|
}
|
|
visible: {
|
|
var darkWallpaper = SessionData.wallpaperPathDark;
|
|
return darkWallpaper !== "" && darkWallpaper.startsWith("#");
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: darkMask
|
|
anchors.fill: parent
|
|
anchors.margins: 1
|
|
radius: Theme.cornerRadius - 1
|
|
color: "black"
|
|
visible: false
|
|
layer.enabled: true
|
|
}
|
|
|
|
DankIcon {
|
|
anchors.centerIn: parent
|
|
name: "dark_mode"
|
|
size: Theme.iconSizeLarge
|
|
color: Theme.surfaceVariantText
|
|
visible: SessionData.wallpaperPathDark === ""
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
anchors.margins: 1
|
|
radius: Theme.cornerRadius - 1
|
|
color: Qt.rgba(0, 0, 0, 0.7)
|
|
visible: darkModeMouseArea.containsMouse
|
|
|
|
Row {
|
|
anchors.centerIn: parent
|
|
spacing: 4
|
|
|
|
Rectangle {
|
|
width: 28
|
|
height: 28
|
|
radius: 14
|
|
color: Qt.rgba(255, 255, 255, 0.9)
|
|
|
|
DankIcon {
|
|
anchors.centerIn: parent
|
|
name: "folder_open"
|
|
size: 16
|
|
color: "black"
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: root.openDarkWallpaperBrowser()
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
width: 28
|
|
height: 28
|
|
radius: 14
|
|
color: Qt.rgba(255, 255, 255, 0.9)
|
|
|
|
DankIcon {
|
|
anchors.centerIn: parent
|
|
name: "palette"
|
|
size: 16
|
|
color: "black"
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: {
|
|
if (!PopoutService.colorPickerModal)
|
|
return;
|
|
var darkWallpaper = SessionData.wallpaperPathDark;
|
|
PopoutService.colorPickerModal.selectedColor = darkWallpaper.startsWith("#") ? darkWallpaper : Theme.primary;
|
|
PopoutService.colorPickerModal.pickerTitle = I18n.tr("Choose Dark Mode Color", "dark mode wallpaper color picker title");
|
|
PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) {
|
|
SessionData.wallpaperPathDark = selectedColor;
|
|
SessionData.syncWallpaperForCurrentMode();
|
|
SessionData.saveSettings();
|
|
};
|
|
PopoutService.colorPickerModal.show();
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
width: 28
|
|
height: 28
|
|
radius: 14
|
|
color: Qt.rgba(255, 255, 255, 0.9)
|
|
visible: SessionData.wallpaperPathDark !== ""
|
|
|
|
DankIcon {
|
|
anchors.centerIn: parent
|
|
name: "clear"
|
|
size: 16
|
|
color: "black"
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: {
|
|
SessionData.wallpaperPathDark = "";
|
|
SessionData.syncWallpaperForCurrentMode();
|
|
SessionData.saveSettings();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
id: darkModeMouseArea
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
propagateComposedEvents: true
|
|
acceptedButtons: Qt.NoButton
|
|
}
|
|
}
|
|
|
|
StyledText {
|
|
text: {
|
|
var darkWallpaper = SessionData.wallpaperPathDark;
|
|
return darkWallpaper ? darkWallpaper.split('/').pop() : I18n.tr("Not set", "wallpaper not set label");
|
|
}
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
color: Theme.surfaceVariantText
|
|
elide: Text.ElideMiddle
|
|
maximumLineCount: 1
|
|
width: parent.width
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
width: parent.width
|
|
height: 1
|
|
color: Theme.outline
|
|
opacity: 0.2
|
|
visible: CompositorService.isNiri
|
|
}
|
|
|
|
SettingsToggleRow {
|
|
tab: "wallpaper"
|
|
tags: ["blur", "overview", "niri"]
|
|
settingKey: "blurWallpaperOnOverview"
|
|
visible: CompositorService.isNiri
|
|
text: I18n.tr("Blur on Overview")
|
|
description: I18n.tr("Blur wallpaper when niri overview is open")
|
|
checked: SettingsData.blurWallpaperOnOverview
|
|
onToggled: checked => SettingsData.set("blurWallpaperOnOverview", checked)
|
|
}
|
|
|
|
Rectangle {
|
|
width: parent.width
|
|
height: 1
|
|
color: Theme.outline
|
|
opacity: 0.2
|
|
visible: SessionData.wallpaperPath !== ""
|
|
}
|
|
|
|
SettingsToggleRow {
|
|
tab: "wallpaper"
|
|
tags: ["per-monitor", "multi-monitor", "display"]
|
|
settingKey: "perMonitorWallpaper"
|
|
visible: SessionData.wallpaperPath !== ""
|
|
text: I18n.tr("Per-Monitor Wallpapers")
|
|
description: I18n.tr("Set different wallpapers for each connected monitor")
|
|
checked: SessionData.perMonitorWallpaper
|
|
onToggled: toggled => SessionData.setPerMonitorWallpaper(toggled)
|
|
}
|
|
|
|
Column {
|
|
width: parent.width
|
|
spacing: Theme.spacingM
|
|
visible: SessionData.perMonitorWallpaper
|
|
leftPadding: Theme.spacingM
|
|
rightPadding: Theme.spacingM
|
|
|
|
SettingsDropdownRow {
|
|
tab: "wallpaper"
|
|
tags: ["monitor", "display", "screen"]
|
|
settingKey: "selectedMonitor"
|
|
width: parent.width - Theme.spacingM * 2
|
|
text: I18n.tr("Wallpaper Monitor")
|
|
description: I18n.tr("Select monitor to configure wallpaper")
|
|
currentValue: {
|
|
var screens = Quickshell.screens;
|
|
for (var i = 0; i < screens.length; i++) {
|
|
if (screens[i].name === selectedMonitorName) {
|
|
return SettingsData.getScreenDisplayName(screens[i]);
|
|
}
|
|
}
|
|
return I18n.tr("No monitors", "no monitors available label");
|
|
}
|
|
options: {
|
|
var screenNames = [];
|
|
var screens = Quickshell.screens;
|
|
for (var i = 0; i < screens.length; i++) {
|
|
screenNames.push(SettingsData.getScreenDisplayName(screens[i]));
|
|
}
|
|
return screenNames;
|
|
}
|
|
onValueChanged: value => {
|
|
var screens = Quickshell.screens;
|
|
for (var i = 0; i < screens.length; i++) {
|
|
if (SettingsData.getScreenDisplayName(screens[i]) === value) {
|
|
selectedMonitorName = screens[i].name;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SettingsDropdownRow {
|
|
tab: "wallpaper"
|
|
tags: ["matugen", "target", "monitor", "theming"]
|
|
settingKey: "matugenTargetMonitor"
|
|
width: parent.width - Theme.spacingM * 2
|
|
text: I18n.tr("Matugen Target Monitor")
|
|
description: I18n.tr("Monitor whose wallpaper drives dynamic theming colors")
|
|
currentValue: {
|
|
var screens = Quickshell.screens;
|
|
if (!SettingsData.matugenTargetMonitor || SettingsData.matugenTargetMonitor === "") {
|
|
return screens.length > 0 ? SettingsData.getScreenDisplayName(screens[0]) + " " + I18n.tr("(Default)", "default monitor label suffix") : I18n.tr("No monitors", "no monitors available label");
|
|
}
|
|
for (var i = 0; i < screens.length; i++) {
|
|
if (screens[i].name === SettingsData.matugenTargetMonitor) {
|
|
return SettingsData.getScreenDisplayName(screens[i]);
|
|
}
|
|
}
|
|
return SettingsData.matugenTargetMonitor;
|
|
}
|
|
options: {
|
|
var screenNames = [];
|
|
var screens = Quickshell.screens;
|
|
for (var i = 0; i < screens.length; i++) {
|
|
var label = SettingsData.getScreenDisplayName(screens[i]);
|
|
if (i === 0 && (!SettingsData.matugenTargetMonitor || SettingsData.matugenTargetMonitor === "")) {
|
|
label += " " + I18n.tr("(Default)", "default monitor label suffix");
|
|
}
|
|
screenNames.push(label);
|
|
}
|
|
return screenNames;
|
|
}
|
|
onValueChanged: value => {
|
|
var cleanValue = value.replace(" " + I18n.tr("(Default)", "default monitor label suffix"), "");
|
|
var screens = Quickshell.screens;
|
|
for (var i = 0; i < screens.length; i++) {
|
|
if (SettingsData.getScreenDisplayName(screens[i]) === cleanValue) {
|
|
SettingsData.setMatugenTargetMonitor(screens[i].name);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
width: parent.width
|
|
height: 1
|
|
color: Theme.outline
|
|
opacity: 0.2
|
|
visible: (SessionData.wallpaperPath !== "" || SessionData.perMonitorWallpaper) && !SessionData.perModeWallpaper
|
|
}
|
|
|
|
SettingsToggleRow {
|
|
id: cyclingToggle
|
|
tab: "wallpaper"
|
|
tags: ["cycling", "automatic", "rotate", "slideshow"]
|
|
settingKey: "wallpaperCyclingEnabled"
|
|
visible: (SessionData.wallpaperPath !== "" || SessionData.perMonitorWallpaper) && !SessionData.perModeWallpaper
|
|
text: I18n.tr("Automatic Cycling")
|
|
description: I18n.tr("Automatically cycle through wallpapers in the same folder")
|
|
checked: SessionData.perMonitorWallpaper ? SessionData.getMonitorCyclingSettings(selectedMonitorName).enabled : SessionData.wallpaperCyclingEnabled
|
|
onToggled: toggled => {
|
|
if (SessionData.perMonitorWallpaper) {
|
|
SessionData.setMonitorCyclingEnabled(selectedMonitorName, toggled);
|
|
} else {
|
|
SessionData.setWallpaperCyclingEnabled(toggled);
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: root
|
|
function onSelectedMonitorNameChanged() {
|
|
cyclingToggle.checked = Qt.binding(() => {
|
|
return SessionData.perMonitorWallpaper ? SessionData.getMonitorCyclingSettings(selectedMonitorName).enabled : SessionData.wallpaperCyclingEnabled;
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
Column {
|
|
width: parent.width
|
|
spacing: Theme.spacingM
|
|
visible: SessionData.perMonitorWallpaper ? SessionData.getMonitorCyclingSettings(selectedMonitorName).enabled : SessionData.wallpaperCyclingEnabled
|
|
leftPadding: Theme.spacingM
|
|
rightPadding: Theme.spacingM
|
|
|
|
Row {
|
|
spacing: Theme.spacingL
|
|
width: parent.width - Theme.spacingM * 2
|
|
|
|
StyledText {
|
|
text: I18n.tr("Mode:")
|
|
font.pixelSize: Theme.fontSizeMedium
|
|
color: Theme.surfaceText
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
}
|
|
|
|
Item {
|
|
width: 200
|
|
height: 45 + Theme.spacingM
|
|
|
|
DankTabBar {
|
|
id: modeTabBar
|
|
width: 200
|
|
height: 45
|
|
model: [
|
|
{
|
|
"text": I18n.tr("Interval", "wallpaper cycling mode tab"),
|
|
"icon": "schedule"
|
|
},
|
|
{
|
|
"text": I18n.tr("Time", "wallpaper cycling mode tab"),
|
|
"icon": "access_time"
|
|
}
|
|
]
|
|
currentIndex: {
|
|
if (SessionData.perMonitorWallpaper) {
|
|
return SessionData.getMonitorCyclingSettings(selectedMonitorName).mode === "time" ? 1 : 0;
|
|
}
|
|
return SessionData.wallpaperCyclingMode === "time" ? 1 : 0;
|
|
}
|
|
onTabClicked: index => {
|
|
if (SessionData.perMonitorWallpaper) {
|
|
SessionData.setMonitorCyclingMode(selectedMonitorName, index === 1 ? "time" : "interval");
|
|
} else {
|
|
SessionData.setWallpaperCyclingMode(index === 1 ? "time" : "interval");
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: root
|
|
function onSelectedMonitorNameChanged() {
|
|
modeTabBar.currentIndex = Qt.binding(() => {
|
|
if (SessionData.perMonitorWallpaper) {
|
|
return SessionData.getMonitorCyclingSettings(selectedMonitorName).mode === "time" ? 1 : 0;
|
|
}
|
|
return SessionData.wallpaperCyclingMode === "time" ? 1 : 0;
|
|
});
|
|
Qt.callLater(modeTabBar.updateIndicator);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SettingsDropdownRow {
|
|
id: intervalDropdown
|
|
property var intervalOptions: [I18n.tr("5 seconds", "wallpaper interval"), I18n.tr("10 seconds", "wallpaper interval"), I18n.tr("15 seconds", "wallpaper interval"), I18n.tr("20 seconds", "wallpaper interval"), I18n.tr("25 seconds", "wallpaper interval"), I18n.tr("30 seconds", "wallpaper interval"), I18n.tr("35 seconds", "wallpaper interval"), I18n.tr("40 seconds", "wallpaper interval"), I18n.tr("45 seconds", "wallpaper interval"), I18n.tr("50 seconds", "wallpaper interval"), I18n.tr("55 seconds", "wallpaper interval"), I18n.tr("1 minute", "wallpaper interval"), I18n.tr("5 minutes", "wallpaper interval"), I18n.tr("15 minutes", "wallpaper interval"), I18n.tr("30 minutes", "wallpaper interval"), I18n.tr("1 hour", "wallpaper interval"), I18n.tr("1 hour 30 minutes", "wallpaper interval"), I18n.tr("2 hours", "wallpaper interval"), I18n.tr("3 hours", "wallpaper interval"), I18n.tr("4 hours", "wallpaper interval"), I18n.tr("6 hours", "wallpaper interval"), I18n.tr("8 hours", "wallpaper interval"), I18n.tr("12 hours", "wallpaper interval")]
|
|
|
|
property var intervalValues: [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 300, 900, 1800, 3600, 5400, 7200, 10800, 14400, 21600, 28800, 43200]
|
|
tab: "wallpaper"
|
|
tags: ["interval", "cycling", "time", "frequency"]
|
|
settingKey: "wallpaperCyclingInterval"
|
|
width: parent.width - Theme.spacingM * 2
|
|
visible: {
|
|
if (SessionData.perMonitorWallpaper) {
|
|
return SessionData.getMonitorCyclingSettings(selectedMonitorName).mode === "interval";
|
|
}
|
|
return SessionData.wallpaperCyclingMode === "interval";
|
|
}
|
|
text: I18n.tr("Interval")
|
|
description: I18n.tr("How often to change wallpaper")
|
|
options: intervalOptions
|
|
currentValue: {
|
|
var currentSeconds;
|
|
if (SessionData.perMonitorWallpaper) {
|
|
currentSeconds = SessionData.getMonitorCyclingSettings(selectedMonitorName).interval;
|
|
} else {
|
|
currentSeconds = SessionData.wallpaperCyclingInterval;
|
|
}
|
|
const index = intervalValues.indexOf(currentSeconds);
|
|
return index >= 0 ? intervalOptions[index] : I18n.tr("5 minutes", "wallpaper interval");
|
|
}
|
|
onValueChanged: value => {
|
|
const index = intervalOptions.indexOf(value);
|
|
if (index < 0)
|
|
return;
|
|
if (SessionData.perMonitorWallpaper) {
|
|
SessionData.setMonitorCyclingInterval(selectedMonitorName, intervalValues[index]);
|
|
} else {
|
|
SessionData.setWallpaperCyclingInterval(intervalValues[index]);
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: root
|
|
function onSelectedMonitorNameChanged() {
|
|
Qt.callLater(() => {
|
|
var currentSeconds;
|
|
if (SessionData.perMonitorWallpaper) {
|
|
currentSeconds = SessionData.getMonitorCyclingSettings(selectedMonitorName).interval;
|
|
} else {
|
|
currentSeconds = SessionData.wallpaperCyclingInterval;
|
|
}
|
|
const index = intervalDropdown.intervalValues.indexOf(currentSeconds);
|
|
intervalDropdown.currentValue = index >= 0 ? intervalDropdown.intervalOptions[index] : I18n.tr("5 minutes", "wallpaper interval");
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
Row {
|
|
spacing: Theme.spacingM
|
|
visible: {
|
|
if (SessionData.perMonitorWallpaper) {
|
|
return SessionData.getMonitorCyclingSettings(selectedMonitorName).mode === "time";
|
|
}
|
|
return SessionData.wallpaperCyclingMode === "time";
|
|
}
|
|
width: parent.width - Theme.spacingM * 2
|
|
|
|
StyledText {
|
|
text: I18n.tr("Daily at:")
|
|
font.pixelSize: Theme.fontSizeMedium
|
|
color: Theme.surfaceText
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
}
|
|
|
|
DankTextField {
|
|
id: timeTextField
|
|
width: 100
|
|
height: 40
|
|
text: {
|
|
if (SessionData.perMonitorWallpaper) {
|
|
return SessionData.getMonitorCyclingSettings(selectedMonitorName).time;
|
|
}
|
|
return SessionData.wallpaperCyclingTime;
|
|
}
|
|
placeholderText: "00:00"
|
|
maximumLength: 5
|
|
topPadding: Theme.spacingS
|
|
bottomPadding: Theme.spacingS
|
|
onAccepted: {
|
|
var isValid = /^([0-1][0-9]|2[0-3]):[0-5][0-9]$/.test(text);
|
|
if (isValid) {
|
|
if (SessionData.perMonitorWallpaper) {
|
|
SessionData.setMonitorCyclingTime(selectedMonitorName, text);
|
|
} else {
|
|
SessionData.setWallpaperCyclingTime(text);
|
|
}
|
|
} else {
|
|
if (SessionData.perMonitorWallpaper) {
|
|
text = SessionData.getMonitorCyclingSettings(selectedMonitorName).time;
|
|
} else {
|
|
text = SessionData.wallpaperCyclingTime;
|
|
}
|
|
}
|
|
}
|
|
onEditingFinished: {
|
|
var isValid = /^([0-1][0-9]|2[0-3]):[0-5][0-9]$/.test(text);
|
|
if (isValid) {
|
|
if (SessionData.perMonitorWallpaper) {
|
|
SessionData.setMonitorCyclingTime(selectedMonitorName, text);
|
|
} else {
|
|
SessionData.setWallpaperCyclingTime(text);
|
|
}
|
|
} else {
|
|
if (SessionData.perMonitorWallpaper) {
|
|
text = SessionData.getMonitorCyclingSettings(selectedMonitorName).time;
|
|
} else {
|
|
text = SessionData.wallpaperCyclingTime;
|
|
}
|
|
}
|
|
}
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
validator: RegularExpressionValidator {
|
|
regularExpression: /^([0-1][0-9]|2[0-3]):[0-5][0-9]$/
|
|
}
|
|
|
|
Connections {
|
|
target: root
|
|
function onSelectedMonitorNameChanged() {
|
|
Qt.callLater(() => {
|
|
if (SessionData.perMonitorWallpaper) {
|
|
timeTextField.text = SessionData.getMonitorCyclingSettings(selectedMonitorName).time;
|
|
} else {
|
|
timeTextField.text = SessionData.wallpaperCyclingTime;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
StyledText {
|
|
text: I18n.tr("24-Hour Format")
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
color: Theme.surfaceVariantText
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
width: parent.width
|
|
height: 1
|
|
color: Theme.outline
|
|
opacity: 0.2
|
|
}
|
|
|
|
SettingsDropdownRow {
|
|
tab: "wallpaper"
|
|
tags: ["transition", "effect", "animation", "change"]
|
|
settingKey: "wallpaperTransition"
|
|
text: I18n.tr("Transition Effect")
|
|
description: I18n.tr("Visual effect used when wallpaper changes")
|
|
|
|
function getTransitionLabel(t) {
|
|
switch (t) {
|
|
case "random":
|
|
return I18n.tr("Random", "wallpaper transition option");
|
|
case "none":
|
|
return I18n.tr("None", "wallpaper transition option");
|
|
case "fade":
|
|
return I18n.tr("Fade", "wallpaper transition option");
|
|
case "wipe":
|
|
return I18n.tr("Wipe", "wallpaper transition option");
|
|
case "disc":
|
|
return I18n.tr("Disc", "wallpaper transition option");
|
|
case "stripes":
|
|
return I18n.tr("Stripes", "wallpaper transition option");
|
|
case "iris bloom":
|
|
return I18n.tr("Iris Bloom", "wallpaper transition option");
|
|
case "pixelate":
|
|
return I18n.tr("Pixelate", "wallpaper transition option");
|
|
case "portal":
|
|
return I18n.tr("Portal", "wallpaper transition option");
|
|
default:
|
|
return t.charAt(0).toUpperCase() + t.slice(1);
|
|
}
|
|
}
|
|
|
|
currentValue: getTransitionLabel(SessionData.wallpaperTransition)
|
|
options: [I18n.tr("Random", "wallpaper transition option")].concat(SessionData.availableWallpaperTransitions.map(t => getTransitionLabel(t)))
|
|
onValueChanged: value => {
|
|
const transitionMap = {};
|
|
transitionMap[I18n.tr("Random", "wallpaper transition option")] = "random";
|
|
SessionData.availableWallpaperTransitions.forEach(t => {
|
|
transitionMap[getTransitionLabel(t)] = t;
|
|
});
|
|
SessionData.setWallpaperTransition(transitionMap[value] || value.toLowerCase());
|
|
}
|
|
}
|
|
|
|
Column {
|
|
width: parent.width
|
|
spacing: Theme.spacingS
|
|
visible: SessionData.wallpaperTransition === "random"
|
|
leftPadding: Theme.spacingM
|
|
rightPadding: Theme.spacingM
|
|
|
|
StyledText {
|
|
text: I18n.tr("Include Transitions")
|
|
font.pixelSize: Theme.fontSizeMedium
|
|
color: Theme.surfaceText
|
|
font.weight: Font.Medium
|
|
}
|
|
|
|
StyledText {
|
|
text: I18n.tr("Select which transitions to include in randomization")
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
color: Theme.surfaceVariantText
|
|
wrapMode: Text.WordWrap
|
|
width: parent.width - Theme.spacingM * 2
|
|
}
|
|
|
|
DankButtonGroup {
|
|
id: transitionGroup
|
|
width: parent.width - Theme.spacingM * 2
|
|
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.slice();
|
|
|
|
if (selected && !newIncluded.includes(transition)) {
|
|
newIncluded.push(transition);
|
|
} else if (!selected && newIncluded.includes(transition)) {
|
|
newIncluded = newIncluded.filter(t => t !== transition);
|
|
}
|
|
|
|
SessionData.includedTransitions = newIncluded;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SettingsCard {
|
|
tab: "wallpaper"
|
|
tags: ["external", "disable", "swww", "hyprpaper", "swaybg"]
|
|
title: I18n.tr("External Wallpaper Management", "wallpaper settings external management")
|
|
settingKey: "disableWallpaper"
|
|
iconName: "wallpaper"
|
|
|
|
SettingsToggleRow {
|
|
tab: "wallpaper"
|
|
tags: ["disable", "external", "management"]
|
|
settingKey: "disableWallpapers"
|
|
text: I18n.tr("Disable Built-in Wallpapers", "wallpaper settings disable toggle")
|
|
description: I18n.tr("Use an external wallpaper manager like swww, hyprpaper, or swaybg.", "wallpaper settings disable description")
|
|
checked: {
|
|
var prefs = SettingsData.screenPreferences?.wallpaper;
|
|
if (!prefs)
|
|
return false;
|
|
if (Array.isArray(prefs) && prefs.length === 0)
|
|
return true;
|
|
return false;
|
|
}
|
|
onToggled: checked => {
|
|
var prefs = SettingsData.screenPreferences || {};
|
|
var newPrefs = Object.assign({}, prefs);
|
|
newPrefs.wallpaper = checked ? [] : ["all"];
|
|
SettingsData.set("screenPreferences", newPrefs);
|
|
}
|
|
}
|
|
}
|
|
|
|
SettingsCard {
|
|
tab: "wallpaper"
|
|
tags: ["blur", "layer", "niri", "compositor"]
|
|
title: I18n.tr("Blur Wallpaper Layer")
|
|
settingKey: "blurWallpaper"
|
|
iconName: "blur_on"
|
|
visible: CompositorService.isNiri
|
|
|
|
SettingsToggleRow {
|
|
tab: "wallpaper"
|
|
tags: ["blur", "duplicate", "layer", "compositor"]
|
|
settingKey: "blurredWallpaperLayer"
|
|
text: I18n.tr("Duplicate Wallpaper with Blur")
|
|
description: I18n.tr("Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.")
|
|
checked: SettingsData.blurredWallpaperLayer
|
|
onToggled: checked => SettingsData.set("blurredWallpaperLayer", checked)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function openMainWallpaperBrowser() {
|
|
mainWallpaperBrowserLoader.active = true;
|
|
if (mainWallpaperBrowserLoader.item)
|
|
mainWallpaperBrowserLoader.item.open();
|
|
}
|
|
|
|
function openLightWallpaperBrowser() {
|
|
lightWallpaperBrowserLoader.active = true;
|
|
if (lightWallpaperBrowserLoader.item)
|
|
lightWallpaperBrowserLoader.item.open();
|
|
}
|
|
|
|
function openDarkWallpaperBrowser() {
|
|
darkWallpaperBrowserLoader.active = true;
|
|
if (darkWallpaperBrowserLoader.item)
|
|
darkWallpaperBrowserLoader.item.open();
|
|
}
|
|
|
|
LazyLoader {
|
|
id: mainWallpaperBrowserLoader
|
|
active: false
|
|
|
|
FileBrowserModal {
|
|
parentModal: root.parentModal
|
|
browserTitle: I18n.tr("Select Wallpaper", "wallpaper file browser title")
|
|
browserIcon: "wallpaper"
|
|
browserType: "wallpaper"
|
|
showHiddenFiles: true
|
|
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp", "*.jxl", "*.avif", "*.heif", "*.exr"]
|
|
onFileSelected: path => {
|
|
if (SessionData.perMonitorWallpaper) {
|
|
SessionData.setMonitorWallpaper(selectedMonitorName, path);
|
|
} else {
|
|
SessionData.setWallpaper(path);
|
|
}
|
|
close();
|
|
}
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: lightWallpaperBrowserLoader
|
|
active: false
|
|
|
|
FileBrowserModal {
|
|
parentModal: root.parentModal
|
|
browserTitle: I18n.tr("Select Wallpaper", "light mode wallpaper file browser title")
|
|
browserIcon: "light_mode"
|
|
browserType: "wallpaper"
|
|
showHiddenFiles: true
|
|
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp", "*.jxl", "*.avif", "*.heif", "*.exr"]
|
|
onFileSelected: path => {
|
|
SessionData.wallpaperPathLight = path;
|
|
SessionData.syncWallpaperForCurrentMode();
|
|
SessionData.saveSettings();
|
|
close();
|
|
}
|
|
}
|
|
}
|
|
|
|
LazyLoader {
|
|
id: darkWallpaperBrowserLoader
|
|
active: false
|
|
|
|
FileBrowserModal {
|
|
parentModal: root.parentModal
|
|
browserTitle: I18n.tr("Select Wallpaper", "dark mode wallpaper file browser title")
|
|
browserIcon: "dark_mode"
|
|
browserType: "wallpaper"
|
|
showHiddenFiles: true
|
|
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp", "*.jxl", "*.avif", "*.heif", "*.exr"]
|
|
onFileSelected: path => {
|
|
SessionData.wallpaperPathDark = path;
|
|
SessionData.syncWallpaperForCurrentMode();
|
|
SessionData.saveSettings();
|
|
close();
|
|
}
|
|
}
|
|
}
|
|
}
|