Remove need for polkit, launch any ArchUpdater update through terminal

ArchUpdater: rely on `TERMINAL` environment variable
README: Add explanation for the `TERMINAL` environment variable
This commit is contained in:
Ly-sec 2025-08-30 02:28:48 +02:00
parent 5ab76c98e5
commit 299add4a15
19 changed files with 1232 additions and 799 deletions

View file

@ -188,7 +188,7 @@ ColumnLayout {
}
NText {
text: `${Math.round(ScalingService.getMonitorScale(modelData.name) * 100)}%`
text: `${Math.round(ScalingService.scaleByName(modelData.name) * 100)}%`
Layout.alignment: Qt.AlignVCenter
Layout.minimumWidth: 50 * scaling
horizontalAlignment: Text.AlignRight
@ -204,8 +204,12 @@ ColumnLayout {
from: 0.7
to: 1.8
stepSize: 0.01
value: ScalingService.getMonitorScale(modelData.name)
onPressedChanged: ScalingService.setMonitorScale(modelData.name, value)
value: ScalingService.scaleByName(modelData.name)
onPressedChanged: {
var data = Settings.data.monitorsScaling || {}
data[modelData.name] = value
Settings.data.monitorsScaling = data
}
Layout.fillWidth: true
Layout.minimumWidth: 150 * scaling
}
@ -213,7 +217,11 @@ ColumnLayout {
NIconButton {
icon: "refresh"
tooltipText: "Reset Scaling"
onClicked: ScalingService.setMonitorScale(modelData.name, 1.0)
onClicked: {
var data = Settings.data.monitorsScaling || {}
data[modelData.name] = 1.0
Settings.data.monitorsScaling = data
}
}
}
}

View file

@ -23,12 +23,13 @@ ColumnLayout {
Layout.fillWidth: true
Layout.preferredHeight: 140 * scaling
radius: Style.radiusM * scaling
color: Color.mSecondary
color: Color.mPrimary
NImageRounded {
id: currentWallpaperImage
anchors.fill: parent
anchors.margins: Style.marginXS * scaling
imagePath: WallpaperService.getWallpaper(screen.name)
imagePath: WallpaperService.currentWallpaper
fallbackIcon: "image"
imageRadius: Style.radiusM * scaling
}
@ -61,44 +62,41 @@ ColumnLayout {
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
NText {
text: Settings.data.wallpaper.swww.enabled ? "Wallpapers will change with " + Settings.data.wallpaper.swww.transitionType
+ " transition." : "Wallpapers will change instantly."
color: Color.mOnSurface
font.pointSize: Style.fontSizeXS * scaling
visible: Settings.data.wallpaper.swww.enabled
}
}
NIconButton {
icon: "refresh"
tooltipText: "Refresh wallpaper list"
onClicked: {
WallpaperService.refreshWallpapersList()
WallpaperService.listWallpapers()
}
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
Layout.alignment: Qt.AlignTop | Qt.AlignRight
}
}
property list<string> wallpapersList: WallpaperService.getWallpapersList(screen.name)
NToggle {
label: "Assign selection to all monitors"
description: "Set selected wallpaper on all monitors at once."
checked: Settings.data.wallpaper.setWallpaperOnAllMonitors
onToggled: checked => Settings.data.wallpaper.setWallpaperOnAllMonitors = checked
visible: (wallpapersList.length > 0)
}
// Wallpaper grid container
Item {
visible: !WallpaperService.scanning
Layout.fillWidth: true
Layout.preferredHeight: {
return Math.ceil(wallpapersList.length / wallpaperGridView.columns) * wallpaperGridView.cellHeight
return Math.ceil(WallpaperService.wallpaperList.length / wallpaperGridView.columns) * wallpaperGridView.cellHeight
}
GridView {
id: wallpaperGridView
anchors.fill: parent
clip: true
model: wallpapersList
model: WallpaperService.wallpaperList
boundsBehavior: Flickable.StopAtBounds
flickableDirection: Flickable.VerticalFlick
flickableDirection: Flickable.AutoFlickDirection
interactive: false
property int columns: 5
@ -116,7 +114,7 @@ ColumnLayout {
id: wallpaperItem
property string wallpaperPath: modelData
property bool isSelected: wallpaperPath === WallpaperService.getWallpaper(screen.name)
property bool isSelected: wallpaperPath === WallpaperService.currentWallpaper
width: wallpaperGridView.itemSize
height: Math.floor(wallpaperGridView.itemSize * 0.67)
@ -181,65 +179,46 @@ ColumnLayout {
acceptedButtons: Qt.LeftButton
hoverEnabled: true
onClicked: {
if (Settings.data.wallpaper.setWallpaperOnAllMonitors) {
WallpaperService.changeWallpaper(undefined, wallpaperPath)
} else {
WallpaperService.changeWallpaper(screen.name, wallpaperPath)
}
WallpaperService.changeWallpaper(wallpaperPath)
}
}
}
}
}
// Empty state
Rectangle {
color: Color.mSurface
radius: Style.radiusM * scaling
border.color: Color.mOutline
border.width: Math.max(1, Style.borderS * scaling)
visible: wallpapersList.length === 0 || WallpaperService.scanning
Layout.fillWidth: true
Layout.preferredHeight: 130 * scaling
ColumnLayout {
// Empty state
Rectangle {
anchors.fill: parent
visible: WallpaperService.scanning
NBusyIndicator {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
}
color: Color.mSurface
radius: Style.radiusM * scaling
border.color: Color.mOutline
border.width: Math.max(1, Style.borderS * scaling)
visible: WallpaperService.wallpaperList.length === 0 && !WallpaperService.scanning
ColumnLayout {
anchors.fill: parent
visible: wallpapersList.length === 0 && !WallpaperService.scanning
Item {
Layout.fillHeight: true
}
ColumnLayout {
anchors.centerIn: parent
spacing: Style.marginM * scaling
NIcon {
text: "folder_open"
font.pointSize: Style.fontSizeXL * scaling
color: Color.mOnSurface
Layout.alignment: Qt.AlignHCenter
}
NIcon {
text: "folder_open"
font.pointSize: Style.fontSizeL * scaling
color: Color.mOnSurface
Layout.alignment: Qt.AlignHCenter
}
NText {
text: "No wallpaper found."
color: Color.mOnSurface
font.weight: Style.fontWeightBold
Layout.alignment: Qt.AlignHCenter
}
NText {
text: "No wallpapers found"
color: Color.mOnSurface
font.weight: Style.fontWeightBold
Layout.alignment: Qt.AlignHCenter
}
NText {
text: "Make sure your wallpaper directory is configured and contains image files."
color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap
Layout.alignment: Qt.AlignHCenter
}
Item {
Layout.fillHeight: true
NText {
text: "Make sure your wallpaper directory is configured and contains image files."
color: Color.mOnSurface
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
Layout.preferredWidth: Style.sliderWidth * 1.5 * scaling
}
}
}
}

View file

@ -1,7 +1,6 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import qs.Commons
import qs.Services
@ -10,62 +9,36 @@ import qs.Widgets
ColumnLayout {
id: root
ColumnLayout {
spacing: Style.marginL * scaling
Layout.fillWidth: true
NTextInput {
label: "Wallpaper Directory"
description: "Path to your common wallpaper directory."
text: Settings.data.wallpaper.directory
onEditingFinished: {
Settings.data.wallpaper.directory = text
}
Layout.maximumWidth: 420 * scaling
}
// Process to check if swww is installed
Process {
id: swwwCheck
command: ["which", "swww"]
running: false
// Monitor-specific directories
NToggle {
label: "Monitor-specific directories"
description: "Enable multi-monitor wallpaper directory management."
checked: Settings.data.wallpaper.enableMultiMonitorDirectories
onToggled: checked => Settings.data.wallpaper.enableMultiMonitorDirectories = checked
}
NBox {
visible: Settings.data.wallpaper.enableMultiMonitorDirectories
Layout.fillWidth: true
Layout.minimumWidth: 550 * scaling
radius: Style.radiusM * scaling
color: Color.mSurfaceVariant
border.color: Color.mOutline
border.width: Math.max(1, Style.borderS * scaling)
implicitHeight: contentCol.implicitHeight + Style.marginXL * 2 * scaling
ColumnLayout {
id: contentCol
anchors.fill: parent
anchors.margins: Style.marginXL * scaling
spacing: Style.marginM * scaling
Repeater {
model: Quickshell.screens || []
delegate: RowLayout {
NText {
text: (modelData.name || "Unknown")
color: Color.mSecondary
font.weight: Style.fontWeightBold
Layout.preferredWidth: 90 * scaling
}
NTextInput {
Layout.fillWidth: true
text: WallpaperService.getMonitorDirectory(modelData.name)
onEditingFinished: WallpaperService.setMonitorDirectory(modelData.name, text)
Layout.maximumWidth: 420 * scaling
}
}
}
onExited: function (exitCode) {
if (exitCode === 0) {
// SWWW exists, enable it
Settings.data.wallpaper.swww.enabled = true
WallpaperService.startSWWWDaemon()
ToastService.showNotice("Swww", "Enabled")
} else {
// SWWW not found
ToastService.showWarning("Swww", "Not installed")
}
}
stdout: StdioCollector {}
stderr: StdioCollector {}
}
NTextInput {
label: "Wallpaper Directory"
description: "Path to your wallpaper directory."
text: Settings.data.wallpaper.directory
onEditingFinished: {
Settings.data.wallpaper.directory = text
}
Layout.maximumWidth: 420 * scaling
}
NDivider {
@ -89,42 +62,10 @@ ColumnLayout {
NToggle {
label: "Random Wallpaper"
description: "Automatically select random wallpapers from the folder."
checked: Settings.data.wallpaper.randomEnabled
onToggled: checked => Settings.data.wallpaper.randomEnabled = checked
}
// Transition Type
NComboBox {
label: "Transition Type"
description: "Animation type when switching between wallpapers."
model: WallpaperService.transitionsModel
currentKey: Settings.data.wallpaper.transitionType
onSelected: key => Settings.data.wallpaper.transitionType = key
}
// Transition Duration
ColumnLayout {
NLabel {
label: "Transition Duration"
description: "Duration of transition animations in seconds."
}
RowLayout {
spacing: Style.marginL * scaling
NSlider {
Layout.fillWidth: true
from: 100
to: 5000
stepSize: 100
value: Settings.data.wallpaper.transitionDuration
onMoved: Settings.data.wallpaper.transitionDuration = value
cutoutColor: Color.mSurface
}
NText {
text: (Settings.data.wallpaper.transitionDuration / 1000).toFixed(2) + "s"
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
}
}
checked: Settings.data.wallpaper.isRandom
onToggled: checked => {
Settings.data.wallpaper.isRandom = checked
}
}
// Interval (slider + H:M inputs)
@ -138,28 +79,25 @@ ColumnLayout {
NText {
// Show friendly H:MM format from current settings
text: Time.formatVagueHumanReadableDuration(Settings.data.wallpaper.randomIntervalSec)
text: Time.formatVagueHumanReadableDuration(Settings.data.wallpaper.randomInterval)
Layout.alignment: Qt.AlignBottom | Qt.AlignRight
}
}
// Preset chips using Repeater
// Preset chips
RowLayout {
id: presetRow
spacing: Style.marginS * scaling
// Factorized presets data
property var intervalPresets: [5 * 60, 10 * 60, 15 * 60, 30 * 60, 45 * 60, 60 * 60, 90 * 60, 120 * 60]
// Preset seconds list
property var presets: [15 * 60, 30 * 60, 45 * 60, 60 * 60, 90 * 60, 120 * 60]
// Whether current interval equals one of the presets
property bool isCurrentPreset: {
return intervalPresets.some(seconds => seconds === Settings.data.wallpaper.randomIntervalSec)
}
property bool isCurrentPreset: presets.indexOf(Settings.data.wallpaper.randomInterval) !== -1
// Allow user to force open the custom input; otherwise it's auto-open when not a preset
property bool customForcedVisible: false
function setIntervalSeconds(sec) {
Settings.data.wallpaper.randomIntervalSec = sec
Settings.data.wallpaper.randomInterval = sec
WallpaperService.restartRandomWallpaperTimer()
// Hide custom when selecting a preset
customForcedVisible = false
@ -167,25 +105,168 @@ ColumnLayout {
// Helper to color selected chip
function isSelected(sec) {
return Settings.data.wallpaper.randomIntervalSec === sec
return Settings.data.wallpaper.randomInterval === sec
}
// Repeater for preset chips
Repeater {
model: presetRow.intervalPresets
delegate: IntervalPresetChip {
seconds: modelData
label: Time.formatVagueHumanReadableDuration(modelData)
selected: presetRow.isSelected(modelData)
onClicked: presetRow.setIntervalSeconds(modelData)
// 15m
Rectangle {
radius: height * 0.5
color: presetRow.isSelected(15 * 60) ? Color.mPrimary : Color.mSurfaceVariant
implicitHeight: Math.max(Style.baseWidgetSize * 0.55 * scaling, 24 * scaling)
implicitWidth: label15.implicitWidth + Style.marginM * 1.5 * scaling
border.width: 1
border.color: presetRow.isSelected(15 * 60) ? Color.transparent : Color.mOutline
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: presetRow.setIntervalSeconds(15 * 60)
}
NText {
id: label15
anchors.centerIn: parent
text: "15m"
font.pointSize: Style.fontSizeS * scaling
font.weight: Style.fontWeightMedium
color: presetRow.isSelected(15 * 60) ? Color.mOnPrimary : Color.mOnSurface
}
}
// 30m
Rectangle {
radius: height * 0.5
color: presetRow.isSelected(30 * 60) ? Color.mPrimary : Color.mSurfaceVariant
implicitHeight: Math.max(Style.baseWidgetSize * 0.55 * scaling, 24 * scaling)
implicitWidth: label30.implicitWidth + Style.marginM * 1.5 * scaling
border.width: 1
border.color: presetRow.isSelected(30 * 60) ? Color.transparent : Color.mOutline
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: presetRow.setIntervalSeconds(30 * 60)
}
NText {
id: label30
anchors.centerIn: parent
text: "30m"
font.pointSize: Style.fontSizeS * scaling
font.weight: Style.fontWeightMedium
color: presetRow.isSelected(30 * 60) ? Color.mOnPrimary : Color.mOnSurface
}
}
// 45m
Rectangle {
radius: height * 0.5
color: presetRow.isSelected(45 * 60) ? Color.mPrimary : Color.mSurfaceVariant
implicitHeight: Math.max(Style.baseWidgetSize * 0.55 * scaling, 24 * scaling)
implicitWidth: label45.implicitWidth + Style.marginM * 1.5 * scaling
border.width: 1
border.color: presetRow.isSelected(45 * 60) ? Color.transparent : Color.mOutline
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: presetRow.setIntervalSeconds(45 * 60)
}
NText {
id: label45
anchors.centerIn: parent
text: "45m"
font.pointSize: Style.fontSizeS * scaling
font.weight: Style.fontWeightMedium
color: presetRow.isSelected(45 * 60) ? Color.mOnPrimary : Color.mOnSurface
}
}
// 1h
Rectangle {
radius: height * 0.5
color: presetRow.isSelected(60 * 60) ? Color.mPrimary : Color.mSurfaceVariant
implicitHeight: Math.max(Style.baseWidgetSize * 0.55 * scaling, 24 * scaling)
implicitWidth: label1h.implicitWidth + Style.marginM * 1.5 * scaling
border.width: 1
border.color: presetRow.isSelected(60 * 60) ? Color.transparent : Color.mOutline
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: presetRow.setIntervalSeconds(60 * 60)
}
NText {
id: label1h
anchors.centerIn: parent
text: "1h"
font.pointSize: Style.fontSizeS * scaling
font.weight: Style.fontWeightMedium
color: presetRow.isSelected(60 * 60) ? Color.mOnPrimary : Color.mOnSurface
}
}
// 1h 30m
Rectangle {
radius: height * 0.5
color: presetRow.isSelected(90 * 60) ? Color.mPrimary : Color.mSurfaceVariant
implicitHeight: Math.max(Style.baseWidgetSize * 0.55 * scaling, 24 * scaling)
implicitWidth: label90.implicitWidth + Style.marginM * 1.5 * scaling
border.width: 1
border.color: presetRow.isSelected(90 * 60) ? Color.transparent : Color.mOutline
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: presetRow.setIntervalSeconds(90 * 60)
}
NText {
id: label90
anchors.centerIn: parent
text: "1h 30m"
font.pointSize: Style.fontSizeS * scaling
font.weight: Style.fontWeightMedium
color: presetRow.isSelected(90 * 60) ? Color.mOnPrimary : Color.mOnSurface
}
}
// 2h
Rectangle {
radius: height * 0.5
color: presetRow.isSelected(120 * 60) ? Color.mPrimary : Color.mSurfaceVariant
implicitHeight: Math.max(Style.baseWidgetSize * 0.55 * scaling, 24 * scaling)
implicitWidth: label2h.implicitWidth + Style.marginM * 1.5 * scaling
border.width: 1
border.color: presetRow.isSelected(120 * 60) ? Color.transparent : Color.mOutline
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: presetRow.setIntervalSeconds(120 * 60)
}
NText {
id: label2h
anchors.centerIn: parent
text: "2h"
font.pointSize: Style.fontSizeS * scaling
font.weight: Style.fontWeightMedium
color: presetRow.isSelected(120 * 60) ? Color.mOnPrimary : Color.mOnSurface
}
}
// Custom opens inline input
IntervalPresetChip {
label: customRow.visible ? "Custom" : "Custom…"
selected: customRow.visible
onClicked: presetRow.customForcedVisible = !presetRow.customForcedVisible
Rectangle {
radius: height * 0.5
color: customRow.visible ? Color.mPrimary : Color.mSurfaceVariant
implicitHeight: Math.max(Style.baseWidgetSize * 0.55 * scaling, 24 * scaling)
implicitWidth: labelCustom.implicitWidth + Style.marginM * 1.5 * scaling
border.width: 1
border.color: customRow.visible ? Color.transparent : Color.mOutline
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: presetRow.customForcedVisible = !presetRow.customForcedVisible
}
NText {
id: labelCustom
anchors.centerIn: parent
text: customRow.visible ? "Custom" : "Custom…"
font.pointSize: Style.fontSizeS * scaling
font.weight: Style.fontWeightMedium
color: customRow.visible ? Color.mOnPrimary : Color.mOnSurface
}
}
}
@ -201,11 +282,12 @@ ColumnLayout {
description: "Enter time as HH:MM (e.g., 01:30)."
inputMaxWidth: 100 * scaling
text: {
const s = Settings.data.wallpaper.randomIntervalSec
const s = Settings.data.wallpaper.randomInterval
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) {
@ -215,7 +297,7 @@ ColumnLayout {
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)
Settings.data.wallpaper.randomInterval = (h * 3600) + (min * 60)
WallpaperService.restartRandomWallpaperTimer()
// Keep custom visible after manual entry
presetRow.customForcedVisible = true
@ -226,32 +308,193 @@ ColumnLayout {
}
}
// Reusable component for interval preset chips
component IntervalPresetChip: Rectangle {
property int seconds: 0
property string label: ""
property bool selected: false
signal clicked
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginXL * scaling
Layout.bottomMargin: Style.marginXL * scaling
}
radius: height * 0.5
color: selected ? Color.mPrimary : Color.mSurfaceVariant
implicitHeight: Math.max(Style.baseWidgetSize * 0.55 * scaling, 24 * scaling)
implicitWidth: chipLabel.implicitWidth + Style.marginM * 1.5 * scaling
border.width: 1
border.color: selected ? Color.transparent : Color.mOutline
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: parent.clicked()
}
// -------------------------------
// Swww
ColumnLayout {
spacing: Style.marginL * scaling
Layout.fillWidth: true
NText {
id: chipLabel
anchors.centerIn: parent
text: parent.label
font.pointSize: Style.fontSizeS * scaling
color: parent.selected ? Color.mOnPrimary : Color.mOnSurface
text: "Swww"
font.pointSize: Style.fontSizeXXL * scaling
font.weight: Style.fontWeightBold
color: Color.mSecondary
}
// Use SWWW
NToggle {
label: "Use Swww"
description: "Use Swww daemon for advanced wallpaper management."
checked: Settings.data.wallpaper.swww.enabled
onToggled: checked => {
if (checked) {
// Check if swww is installed
swwwCheck.running = true
} else {
Settings.data.wallpaper.swww.enabled = false
ToastService.showNotice("Swww", "Disabled")
}
}
}
// SWWW Settings (only visible when useSWWW is enabled)
ColumnLayout {
spacing: Style.marginS * scaling
Layout.fillWidth: true
Layout.topMargin: Style.marginS * scaling
visible: Settings.data.wallpaper.swww.enabled
// Resize Mode
NComboBox {
label: "Resize Mode"
description: "How Swww should resize wallpapers to fit the screen."
model: ListModel {
ListElement {
key: "no"
name: "No"
}
ListElement {
key: "crop"
name: "Crop"
}
ListElement {
key: "fit"
name: "Fit"
}
ListElement {
key: "stretch"
name: "Stretch"
}
}
currentKey: Settings.data.wallpaper.swww.resizeMethod
onSelected: key => {
Settings.data.wallpaper.swww.resizeMethod = key
}
}
// Transition Type
NComboBox {
label: "Transition Type"
description: "Animation type when switching between wallpapers."
model: ListModel {
ListElement {
key: "none"
name: "None"
}
ListElement {
key: "simple"
name: "Simple"
}
ListElement {
key: "fade"
name: "Fade"
}
ListElement {
key: "left"
name: "Left"
}
ListElement {
key: "right"
name: "Right"
}
ListElement {
key: "top"
name: "Top"
}
ListElement {
key: "bottom"
name: "Bottom"
}
ListElement {
key: "wipe"
name: "Wipe"
}
ListElement {
key: "wave"
name: "Wave"
}
ListElement {
key: "grow"
name: "Grow"
}
ListElement {
key: "center"
name: "Center"
}
ListElement {
key: "any"
name: "Any"
}
ListElement {
key: "outer"
name: "Outer"
}
ListElement {
key: "random"
name: "Random"
}
}
currentKey: Settings.data.wallpaper.swww.transitionType
onSelected: key => {
Settings.data.wallpaper.swww.transitionType = key
}
}
// Transition FPS
ColumnLayout {
NLabel {
label: "Transition FPS"
description: "Frames per second for transition animations."
}
RowLayout {
spacing: Style.marginL * scaling
NSlider {
Layout.fillWidth: true
from: 30
to: 500
stepSize: 5
value: Settings.data.wallpaper.swww.transitionFps
onMoved: Settings.data.wallpaper.swww.transitionFps = Math.round(value)
cutoutColor: Color.mSurface
}
NText {
text: Settings.data.wallpaper.swww.transitionFps + " FPS"
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
}
}
}
// Transition Duration
ColumnLayout {
NLabel {
label: "Transition Duration"
description: "Duration of transition animations in seconds."
}
RowLayout {
spacing: Style.marginL * scaling
NSlider {
Layout.fillWidth: true
from: 0.25
to: 10
stepSize: 0.05
value: Settings.data.wallpaper.swww.transitionDuration
onMoved: Settings.data.wallpaper.swww.transitionDuration = value
cutoutColor: Color.mSurface
}
NText {
text: Settings.data.wallpaper.swww.transitionDuration.toFixed(2) + "s"
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
}
}
}
}
}