Revert "Remove need for polkit, launch any ArchUpdater update through terminal"
This reverts commit 299add4a15.
This commit is contained in:
parent
299add4a15
commit
3496169c68
19 changed files with 807 additions and 1240 deletions
|
|
@ -15,9 +15,8 @@ NPanel {
|
|||
|
||||
// When the panel opens
|
||||
onOpened: {
|
||||
console.log("ArchUpdaterPanel: Panel opened, refreshing package lists...")
|
||||
// Always refresh when panel opens to ensure we have the latest data
|
||||
ArchUpdaterService.forceRefresh()
|
||||
ArchUpdaterService.doPoll()
|
||||
ArchUpdaterService.doAurPoll()
|
||||
}
|
||||
|
||||
panelContent: Rectangle {
|
||||
|
|
@ -48,19 +47,6 @@ NPanel {
|
|||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
// Reset button (only show if update failed)
|
||||
NIconButton {
|
||||
visible: ArchUpdaterService.updateFailed
|
||||
icon: "refresh"
|
||||
tooltipText: "Reset update state"
|
||||
sizeRatio: 0.8
|
||||
colorBg: Color.mError
|
||||
colorFg: Color.mOnError
|
||||
onClicked: {
|
||||
ArchUpdaterService.resetUpdateState()
|
||||
}
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: "close"
|
||||
tooltipText: "Close"
|
||||
|
|
@ -73,10 +59,8 @@ NPanel {
|
|||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
// Update summary (only show when packages are available)
|
||||
// Update summary
|
||||
NText {
|
||||
visible: !ArchUpdaterService.updateInProgress && !ArchUpdaterService.updateFailed && !ArchUpdaterService.busy
|
||||
&& !ArchUpdaterService.aurBusy && ArchUpdaterService.totalUpdates > 0
|
||||
text: ArchUpdaterService.totalUpdates + " package" + (ArchUpdaterService.totalUpdates !== 1 ? "s" : "") + " can be updated"
|
||||
font.pointSize: Style.fontSizeL * scaling
|
||||
font.weight: Style.fontWeightMedium
|
||||
|
|
@ -84,184 +68,16 @@ NPanel {
|
|||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
// Package selection info (only show when not updating and have packages)
|
||||
// Package selection info
|
||||
NText {
|
||||
visible: !ArchUpdaterService.updateInProgress && !ArchUpdaterService.updateFailed && !ArchUpdaterService.busy
|
||||
&& !ArchUpdaterService.aurBusy && ArchUpdaterService.totalUpdates > 0
|
||||
text: ArchUpdaterService.selectedPackagesCount + " of " + ArchUpdaterService.totalUpdates + " packages selected"
|
||||
font.pointSize: Style.fontSizeS * scaling
|
||||
color: Color.mOnSurfaceVariant
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
// Update in progress state
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: ArchUpdaterService.updateInProgress
|
||||
spacing: Style.marginM * scaling
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
} // Spacer
|
||||
|
||||
NIcon {
|
||||
text: "hourglass_empty"
|
||||
font.pointSize: Style.fontSizeXXXL * scaling
|
||||
color: Color.mPrimary
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
NText {
|
||||
text: "Update in progress"
|
||||
font.pointSize: Style.fontSizeL * scaling
|
||||
color: Color.mOnSurface
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
NText {
|
||||
text: "Please check your terminal window for update progress and prompts."
|
||||
font.pointSize: Style.fontSizeNormal * scaling
|
||||
color: Color.mOnSurfaceVariant
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.Wrap
|
||||
Layout.maximumWidth: 280 * scaling
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
} // Spacer
|
||||
}
|
||||
|
||||
// Update failed state
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: ArchUpdaterService.updateFailed
|
||||
|
||||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
spacing: Style.marginM * scaling
|
||||
|
||||
NIcon {
|
||||
text: "error_outline"
|
||||
font.pointSize: Style.fontSizeXXXL * scaling
|
||||
color: Color.mError
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
NText {
|
||||
text: "Update failed"
|
||||
font.pointSize: Style.fontSizeL * scaling
|
||||
color: Color.mOnSurface
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
NText {
|
||||
text: "Check your terminal for error details and try again."
|
||||
font.pointSize: Style.fontSizeNormal * scaling
|
||||
color: Color.mOnSurfaceVariant
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.Wrap
|
||||
Layout.maximumWidth: 280 * scaling
|
||||
}
|
||||
|
||||
// Prominent refresh button
|
||||
NIconButton {
|
||||
icon: "refresh"
|
||||
tooltipText: "Refresh and try again"
|
||||
sizeRatio: 1.2
|
||||
colorBg: Color.mPrimary
|
||||
colorFg: Color.mOnPrimary
|
||||
onClicked: {
|
||||
ArchUpdaterService.resetUpdateState()
|
||||
}
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: Style.marginL * scaling
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No updates available state
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: !ArchUpdaterService.updateInProgress && !ArchUpdaterService.updateFailed && !ArchUpdaterService.busy
|
||||
&& !ArchUpdaterService.aurBusy && ArchUpdaterService.totalUpdates === 0
|
||||
|
||||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
spacing: Style.marginM * scaling
|
||||
|
||||
NIcon {
|
||||
text: "check_circle"
|
||||
font.pointSize: Style.fontSizeXXXL * scaling
|
||||
color: Color.mPrimary
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
NText {
|
||||
text: "System is up to date"
|
||||
font.pointSize: Style.fontSizeL * scaling
|
||||
color: Color.mOnSurface
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
NText {
|
||||
text: "All packages are current. Check back later for updates."
|
||||
font.pointSize: Style.fontSizeNormal * scaling
|
||||
color: Color.mOnSurfaceVariant
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.Wrap
|
||||
Layout.maximumWidth: 280 * scaling
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Checking for updates state
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: (ArchUpdaterService.busy || ArchUpdaterService.aurBusy) && !ArchUpdaterService.updateInProgress
|
||||
&& !ArchUpdaterService.updateFailed
|
||||
|
||||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
spacing: Style.marginM * scaling
|
||||
|
||||
NIcon {
|
||||
text: "refresh"
|
||||
font.pointSize: Style.fontSizeXXXL * scaling
|
||||
color: Color.mPrimary
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
NText {
|
||||
text: "Checking for updates"
|
||||
font.pointSize: Style.fontSizeL * scaling
|
||||
color: Color.mOnSurface
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
NText {
|
||||
text: "Scanning package databases for available updates..."
|
||||
font.pointSize: Style.fontSizeNormal * scaling
|
||||
color: Color.mOnSurfaceVariant
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.Wrap
|
||||
Layout.maximumWidth: 280 * scaling
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Package list (only show when not in any special state)
|
||||
// Unified list
|
||||
NBox {
|
||||
visible: !ArchUpdaterService.updateInProgress && !ArchUpdaterService.updateFailed && !ArchUpdaterService.busy
|
||||
&& !ArchUpdaterService.aurBusy && ArchUpdaterService.totalUpdates > 0
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
|
|
@ -348,49 +164,50 @@ NPanel {
|
|||
}
|
||||
}
|
||||
|
||||
// Action buttons (only show when not updating)
|
||||
// Action buttons
|
||||
RowLayout {
|
||||
visible: !ArchUpdaterService.updateInProgress && !ArchUpdaterService.updateFailed
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginL * scaling
|
||||
|
||||
NIconButton {
|
||||
icon: "refresh"
|
||||
tooltipText: "Refresh package lists"
|
||||
tooltipText: "Check for updates"
|
||||
onClicked: {
|
||||
ArchUpdaterService.forceRefresh()
|
||||
ArchUpdaterService.doPoll()
|
||||
ArchUpdaterService.doAurPoll()
|
||||
}
|
||||
colorBg: Color.mSurfaceVariant
|
||||
colorFg: Color.mOnSurface
|
||||
Layout.fillWidth: true
|
||||
enabled: !ArchUpdaterService.busy && !ArchUpdaterService.aurBusy
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: "system_update_alt"
|
||||
tooltipText: "Update all packages"
|
||||
enabled: ArchUpdaterService.totalUpdates > 0
|
||||
icon: ArchUpdaterService.updateInProgress ? "hourglass_empty" : "system_update_alt"
|
||||
tooltipText: ArchUpdaterService.updateInProgress ? "Update in progress..." : "Update all packages"
|
||||
enabled: !ArchUpdaterService.updateInProgress
|
||||
onClicked: {
|
||||
ArchUpdaterService.runUpdate()
|
||||
root.close()
|
||||
}
|
||||
colorBg: ArchUpdaterService.totalUpdates > 0 ? Color.mPrimary : Color.mSurfaceVariant
|
||||
colorFg: ArchUpdaterService.totalUpdates > 0 ? Color.mOnPrimary : Color.mOnSurfaceVariant
|
||||
colorBg: ArchUpdaterService.updateInProgress ? Color.mSurfaceVariant : Color.mPrimary
|
||||
colorFg: ArchUpdaterService.updateInProgress ? Color.mOnSurfaceVariant : Color.mOnPrimary
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: "check_box"
|
||||
tooltipText: "Update selected packages"
|
||||
enabled: ArchUpdaterService.selectedPackagesCount > 0
|
||||
icon: ArchUpdaterService.updateInProgress ? "hourglass_empty" : "check_box"
|
||||
tooltipText: ArchUpdaterService.updateInProgress ? "Update in progress..." : "Update selected packages"
|
||||
enabled: !ArchUpdaterService.updateInProgress && ArchUpdaterService.selectedPackagesCount > 0
|
||||
onClicked: {
|
||||
if (ArchUpdaterService.selectedPackagesCount > 0) {
|
||||
ArchUpdaterService.runSelectiveUpdate()
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
colorBg: ArchUpdaterService.selectedPackagesCount > 0 ? Color.mPrimary : Color.mSurfaceVariant
|
||||
colorFg: ArchUpdaterService.selectedPackagesCount > 0 ? Color.mOnPrimary : Color.mOnSurfaceVariant
|
||||
colorBg: ArchUpdaterService.updateInProgress ? Color.mSurfaceVariant : (ArchUpdaterService.selectedPackagesCount
|
||||
> 0 ? Color.mPrimary : Color.mSurfaceVariant)
|
||||
colorFg: ArchUpdaterService.updateInProgress ? Color.mOnSurfaceVariant : (ArchUpdaterService.selectedPackagesCount
|
||||
> 0 ? Color.mOnPrimary : Color.mOnSurfaceVariant)
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,27 +4,67 @@ import Quickshell.Wayland
|
|||
import qs.Commons
|
||||
import qs.Services
|
||||
|
||||
Loader {
|
||||
active: !Settings.data.wallpaper.swww.enabled
|
||||
Variants {
|
||||
id: backgroundVariants
|
||||
model: Quickshell.screens
|
||||
|
||||
sourceComponent: Variants {
|
||||
model: Quickshell.screens
|
||||
delegate: Loader {
|
||||
|
||||
delegate: PanelWindow {
|
||||
required property ShellScreen modelData
|
||||
property string wallpaperSource: WallpaperService.currentWallpaper !== ""
|
||||
&& !Settings.data.wallpaper.swww.enabled ? WallpaperService.currentWallpaper : ""
|
||||
required property ShellScreen modelData
|
||||
|
||||
visible: wallpaperSource !== "" && !Settings.data.wallpaper.swww.enabled
|
||||
active: Settings.isLoaded && WallpaperService.getWallpaper(modelData.name)
|
||||
|
||||
// Force update when SWWW setting changes
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
sourceComponent: PanelWindow {
|
||||
id: root
|
||||
|
||||
} else {
|
||||
// Internal state management
|
||||
property bool firstWallpaper: true
|
||||
property bool transitioning: false
|
||||
property real transitionProgress: 0.0
|
||||
|
||||
// Wipe direction: 0=left, 1=right, 2=up, 3=down
|
||||
property real wipeDirection: 0
|
||||
property real wipeSmoothness: 0.05
|
||||
|
||||
// External state management
|
||||
property string servicedWallpaper: WallpaperService.getWallpaper(modelData.name)
|
||||
onServicedWallpaperChanged: {
|
||||
if (servicedWallpaper && servicedWallpaper !== currentWallpaper.source) {
|
||||
|
||||
// Set wallpaper immediately on startup
|
||||
if (firstWallpaper) {
|
||||
firstWallpaper = false
|
||||
setWallpaperImmediate(servicedWallpaper)
|
||||
return
|
||||
}
|
||||
|
||||
switch (Settings.data.wallpaper.transitionType) {
|
||||
case "none":
|
||||
setWallpaperImmediate(servicedWallpaper)
|
||||
break
|
||||
case "wipe_left":
|
||||
wipeDirection = 0
|
||||
setWallpaperWithTransition(servicedWallpaper)
|
||||
break
|
||||
case "wipe_right":
|
||||
wipeDirection = 1
|
||||
setWallpaperWithTransition(servicedWallpaper)
|
||||
break
|
||||
case "wipe_up":
|
||||
wipeDirection = 2
|
||||
setWallpaperWithTransition(servicedWallpaper)
|
||||
break
|
||||
case "wipe_down":
|
||||
wipeDirection = 3
|
||||
setWallpaperWithTransition(servicedWallpaper)
|
||||
break
|
||||
default:
|
||||
setWallpaperWithTransition(servicedWallpaper)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
color: Color.transparent
|
||||
screen: modelData
|
||||
WlrLayershell.layer: WlrLayer.Background
|
||||
|
|
@ -38,18 +78,106 @@ Loader {
|
|||
left: true
|
||||
}
|
||||
|
||||
margins {
|
||||
top: 0
|
||||
}
|
||||
|
||||
Image {
|
||||
id: currentWallpaper
|
||||
anchors.fill: parent
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
source: wallpaperSource
|
||||
visible: wallpaperSource !== ""
|
||||
source: ""
|
||||
cache: true
|
||||
smooth: true
|
||||
mipmap: false
|
||||
visible: false
|
||||
}
|
||||
|
||||
Image {
|
||||
id: nextWallpaper
|
||||
anchors.fill: parent
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
source: ""
|
||||
cache: true
|
||||
smooth: true
|
||||
mipmap: false
|
||||
visible: false
|
||||
}
|
||||
|
||||
// Fade transition shader
|
||||
ShaderEffect {
|
||||
id: fadeShader
|
||||
anchors.fill: parent
|
||||
visible: Settings.data.wallpaper.transitionType === 'fade'
|
||||
|
||||
property variant source1: currentWallpaper
|
||||
property variant source2: nextWallpaper
|
||||
property real fade: transitionProgress
|
||||
fragmentShader: Qt.resolvedUrl("../../Shaders/qsb/wp_fade.frag.qsb")
|
||||
}
|
||||
|
||||
// Wipe transition shader
|
||||
ShaderEffect {
|
||||
id: wipeShader
|
||||
anchors.fill: parent
|
||||
visible: Settings.data.wallpaper.transitionType.startsWith('wipe_')
|
||||
|
||||
property variant source1: currentWallpaper
|
||||
property variant source2: nextWallpaper
|
||||
property real progress: transitionProgress
|
||||
property real direction: wipeDirection
|
||||
property real smoothness: wipeSmoothness
|
||||
fragmentShader: Qt.resolvedUrl("../../Shaders/qsb/wp_wipe.frag.qsb")
|
||||
}
|
||||
|
||||
// Animation for the transition progress
|
||||
NumberAnimation {
|
||||
id: transitionAnimation
|
||||
target: root
|
||||
property: "transitionProgress"
|
||||
from: 0.0
|
||||
to: 1.0
|
||||
duration: Settings.data.wallpaper.transitionDuration ?? 1000
|
||||
easing.type: {
|
||||
const transitionType = Settings.data.wallpaper.transitionType ?? 'fade'
|
||||
if (transitionType.startsWith('wipe_')) {
|
||||
return Easing.InOutCubic
|
||||
}
|
||||
return Easing.InOutCubic
|
||||
}
|
||||
|
||||
onFinished: {
|
||||
// Swap images after transition completes
|
||||
currentWallpaper.source = nextWallpaper.source
|
||||
transitionProgress = 0.0
|
||||
transitioning = false
|
||||
}
|
||||
}
|
||||
|
||||
function startTransition() {
|
||||
if (!transitioning && nextWallpaper.source != currentWallpaper.source) {
|
||||
transitioning = true
|
||||
transitionAnimation.start()
|
||||
}
|
||||
}
|
||||
|
||||
function setWallpaperImmediate(source) {
|
||||
currentWallpaper.source = source
|
||||
nextWallpaper.source = source
|
||||
transitionProgress = 0.0
|
||||
transitioning = false
|
||||
}
|
||||
|
||||
function setWallpaperWithTransition(source) {
|
||||
if (source != currentWallpaper.source) {
|
||||
|
||||
if (transitioning) {
|
||||
// We are interrupting a transition
|
||||
currentWallpaper.source = nextWallpaper.source
|
||||
transitionAnimation.stop()
|
||||
transitionProgress = 0
|
||||
transitioning = false
|
||||
}
|
||||
|
||||
nextWallpaper.source = source
|
||||
startTransition()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,24 +6,19 @@ import qs.Commons
|
|||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Loader {
|
||||
active: CompositorService.isNiri
|
||||
Variants {
|
||||
model: Quickshell.screens
|
||||
|
||||
Component.onCompleted: {
|
||||
if (CompositorService.isNiri) {
|
||||
Logger.log("Overview", "Loading Overview component for Niri")
|
||||
}
|
||||
}
|
||||
delegate: Loader {
|
||||
required property ShellScreen modelData
|
||||
|
||||
sourceComponent: Variants {
|
||||
model: Quickshell.screens
|
||||
active: Settings.isLoaded && CompositorService.isNiri
|
||||
|
||||
delegate: PanelWindow {
|
||||
required property ShellScreen modelData
|
||||
property string wallpaperSource: WallpaperService.currentWallpaper !== ""
|
||||
&& !Settings.data.wallpaper.swww.enabled ? WallpaperService.currentWallpaper : ""
|
||||
sourceComponent: PanelWindow {
|
||||
Component.onCompleted: {
|
||||
Logger.log("Overview", "Loading Overview component for Niri on", modelData.name)
|
||||
}
|
||||
|
||||
visible: wallpaperSource !== "" && !Settings.data.wallpaper.swww.enabled
|
||||
color: Color.transparent
|
||||
screen: modelData
|
||||
WlrLayershell.layer: WlrLayer.Background
|
||||
|
|
@ -39,19 +34,15 @@ Loader {
|
|||
|
||||
Image {
|
||||
id: bgImage
|
||||
|
||||
anchors.fill: parent
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
source: wallpaperSource
|
||||
source: WallpaperService.getWallpaper(modelData.name)
|
||||
cache: true
|
||||
smooth: true
|
||||
mipmap: false
|
||||
visible: wallpaperSource !== ""
|
||||
}
|
||||
|
||||
MultiEffect {
|
||||
id: overviewBgBlur
|
||||
|
||||
anchors.fill: parent
|
||||
source: bgImage
|
||||
blurEnabled: true
|
||||
|
|
|
|||
|
|
@ -64,5 +64,6 @@ NIconButton {
|
|||
|
||||
PanelService.getPanel("archUpdaterPanel").toggle(screen, this)
|
||||
ArchUpdaterService.doPoll()
|
||||
ArchUpdaterService.doAurPoll()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ Loader {
|
|||
id: lockBgImage
|
||||
anchors.fill: parent
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
source: WallpaperService.currentWallpaper !== "" ? WallpaperService.currentWallpaper : ""
|
||||
source: WallpaperService.getWallpaper(screen.name)
|
||||
cache: true
|
||||
smooth: true
|
||||
mipmap: false
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ ColumnLayout {
|
|||
}
|
||||
|
||||
NText {
|
||||
text: `${Math.round(ScalingService.scaleByName(modelData.name) * 100)}%`
|
||||
text: `${Math.round(ScalingService.getMonitorScale(modelData.name) * 100)}%`
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.minimumWidth: 50 * scaling
|
||||
horizontalAlignment: Text.AlignRight
|
||||
|
|
@ -204,12 +204,8 @@ ColumnLayout {
|
|||
from: 0.7
|
||||
to: 1.8
|
||||
stepSize: 0.01
|
||||
value: ScalingService.scaleByName(modelData.name)
|
||||
onPressedChanged: {
|
||||
var data = Settings.data.monitorsScaling || {}
|
||||
data[modelData.name] = value
|
||||
Settings.data.monitorsScaling = data
|
||||
}
|
||||
value: ScalingService.getMonitorScale(modelData.name)
|
||||
onPressedChanged: ScalingService.setMonitorScale(modelData.name, value)
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumWidth: 150 * scaling
|
||||
}
|
||||
|
|
@ -217,11 +213,7 @@ ColumnLayout {
|
|||
NIconButton {
|
||||
icon: "refresh"
|
||||
tooltipText: "Reset Scaling"
|
||||
onClicked: {
|
||||
var data = Settings.data.monitorsScaling || {}
|
||||
data[modelData.name] = 1.0
|
||||
Settings.data.monitorsScaling = data
|
||||
}
|
||||
onClicked: ScalingService.setMonitorScale(modelData.name, 1.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,13 +23,12 @@ ColumnLayout {
|
|||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 140 * scaling
|
||||
radius: Style.radiusM * scaling
|
||||
color: Color.mPrimary
|
||||
color: Color.mSecondary
|
||||
|
||||
NImageRounded {
|
||||
id: currentWallpaperImage
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginXS * scaling
|
||||
imagePath: WallpaperService.currentWallpaper
|
||||
imagePath: WallpaperService.getWallpaper(screen.name)
|
||||
fallbackIcon: "image"
|
||||
imageRadius: Style.radiusM * scaling
|
||||
}
|
||||
|
|
@ -62,41 +61,44 @@ 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.listWallpapers()
|
||||
WallpaperService.refreshWallpapersList()
|
||||
}
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignRight
|
||||
Layout.alignment: Qt.AlignVCenter | 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(WallpaperService.wallpaperList.length / wallpaperGridView.columns) * wallpaperGridView.cellHeight
|
||||
return Math.ceil(wallpapersList.length / wallpaperGridView.columns) * wallpaperGridView.cellHeight
|
||||
}
|
||||
|
||||
GridView {
|
||||
id: wallpaperGridView
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
model: WallpaperService.wallpaperList
|
||||
model: wallpapersList
|
||||
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
flickableDirection: Flickable.AutoFlickDirection
|
||||
flickableDirection: Flickable.VerticalFlick
|
||||
interactive: false
|
||||
|
||||
property int columns: 5
|
||||
|
|
@ -114,7 +116,7 @@ ColumnLayout {
|
|||
id: wallpaperItem
|
||||
|
||||
property string wallpaperPath: modelData
|
||||
property bool isSelected: wallpaperPath === WallpaperService.currentWallpaper
|
||||
property bool isSelected: wallpaperPath === WallpaperService.getWallpaper(screen.name)
|
||||
|
||||
width: wallpaperGridView.itemSize
|
||||
height: Math.floor(wallpaperGridView.itemSize * 0.67)
|
||||
|
|
@ -179,46 +181,65 @@ ColumnLayout {
|
|||
acceptedButtons: Qt.LeftButton
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
WallpaperService.changeWallpaper(wallpaperPath)
|
||||
if (Settings.data.wallpaper.setWallpaperOnAllMonitors) {
|
||||
WallpaperService.changeWallpaper(undefined, wallpaperPath)
|
||||
} else {
|
||||
WallpaperService.changeWallpaper(screen.name, wallpaperPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Empty state
|
||||
Rectangle {
|
||||
// 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 {
|
||||
anchors.fill: parent
|
||||
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
|
||||
visible: WallpaperService.scanning
|
||||
NBusyIndicator {
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
spacing: Style.marginM * scaling
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
visible: wallpapersList.length === 0 && !WallpaperService.scanning
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
NIcon {
|
||||
text: "folder_open"
|
||||
font.pointSize: Style.fontSizeL * scaling
|
||||
color: Color.mOnSurface
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
NIcon {
|
||||
text: "folder_open"
|
||||
font.pointSize: Style.fontSizeXL * scaling
|
||||
color: Color.mOnSurface
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
NText {
|
||||
text: "No wallpapers found"
|
||||
color: Color.mOnSurface
|
||||
font.weight: Style.fontWeightBold
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
NText {
|
||||
text: "No wallpaper 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.mOnSurface
|
||||
wrapMode: Text.WordWrap
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
Layout.preferredWidth: Style.sliderWidth * 1.5 * scaling
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Commons
|
||||
import qs.Services
|
||||
|
|
@ -9,36 +10,62 @@ import qs.Widgets
|
|||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
// Process to check if swww is installed
|
||||
Process {
|
||||
id: swwwCheck
|
||||
command: ["which", "swww"]
|
||||
running: false
|
||||
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
|
||||
}
|
||||
|
||||
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")
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
|
|
@ -62,10 +89,42 @@ ColumnLayout {
|
|||
NToggle {
|
||||
label: "Random Wallpaper"
|
||||
description: "Automatically select random wallpapers from the folder."
|
||||
checked: Settings.data.wallpaper.isRandom
|
||||
onToggled: checked => {
|
||||
Settings.data.wallpaper.isRandom = checked
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Interval (slider + H:M inputs)
|
||||
|
|
@ -79,25 +138,28 @@ ColumnLayout {
|
|||
|
||||
NText {
|
||||
// Show friendly H:MM format from current settings
|
||||
text: Time.formatVagueHumanReadableDuration(Settings.data.wallpaper.randomInterval)
|
||||
text: Time.formatVagueHumanReadableDuration(Settings.data.wallpaper.randomIntervalSec)
|
||||
Layout.alignment: Qt.AlignBottom | Qt.AlignRight
|
||||
}
|
||||
}
|
||||
|
||||
// Preset chips
|
||||
// Preset chips using Repeater
|
||||
RowLayout {
|
||||
id: presetRow
|
||||
spacing: Style.marginS * scaling
|
||||
|
||||
// Preset seconds list
|
||||
property var presets: [15 * 60, 30 * 60, 45 * 60, 60 * 60, 90 * 60, 120 * 60]
|
||||
// Factorized presets data
|
||||
property var intervalPresets: [5 * 60, 10 * 60, 15 * 60, 30 * 60, 45 * 60, 60 * 60, 90 * 60, 120 * 60]
|
||||
|
||||
// Whether current interval equals one of the presets
|
||||
property bool isCurrentPreset: presets.indexOf(Settings.data.wallpaper.randomInterval) !== -1
|
||||
property bool isCurrentPreset: {
|
||||
return intervalPresets.some(seconds => seconds === Settings.data.wallpaper.randomIntervalSec)
|
||||
}
|
||||
// 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.randomInterval = sec
|
||||
Settings.data.wallpaper.randomIntervalSec = sec
|
||||
WallpaperService.restartRandomWallpaperTimer()
|
||||
// Hide custom when selecting a preset
|
||||
customForcedVisible = false
|
||||
|
|
@ -105,168 +167,25 @@ ColumnLayout {
|
|||
|
||||
// Helper to color selected chip
|
||||
function isSelected(sec) {
|
||||
return Settings.data.wallpaper.randomInterval === sec
|
||||
return Settings.data.wallpaper.randomIntervalSec === sec
|
||||
}
|
||||
|
||||
// 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
|
||||
// Repeater for preset chips
|
||||
Repeater {
|
||||
model: presetRow.intervalPresets
|
||||
delegate: IntervalPresetChip {
|
||||
seconds: modelData
|
||||
label: Time.formatVagueHumanReadableDuration(modelData)
|
||||
selected: presetRow.isSelected(modelData)
|
||||
onClicked: presetRow.setIntervalSeconds(modelData)
|
||||
}
|
||||
}
|
||||
|
||||
// Custom… opens inline input
|
||||
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
|
||||
}
|
||||
IntervalPresetChip {
|
||||
label: customRow.visible ? "Custom" : "Custom…"
|
||||
selected: customRow.visible
|
||||
onClicked: presetRow.customForcedVisible = !presetRow.customForcedVisible
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -282,12 +201,11 @@ ColumnLayout {
|
|||
description: "Enter time as HH:MM (e.g., 01:30)."
|
||||
inputMaxWidth: 100 * scaling
|
||||
text: {
|
||||
const s = Settings.data.wallpaper.randomInterval
|
||||
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) {
|
||||
|
|
@ -297,7 +215,7 @@ ColumnLayout {
|
|||
return
|
||||
h = Math.max(0, Math.min(24, h))
|
||||
min = Math.max(0, Math.min(59, min))
|
||||
Settings.data.wallpaper.randomInterval = (h * 3600) + (min * 60)
|
||||
Settings.data.wallpaper.randomIntervalSec = (h * 3600) + (min * 60)
|
||||
WallpaperService.restartRandomWallpaperTimer()
|
||||
// Keep custom visible after manual entry
|
||||
presetRow.customForcedVisible = true
|
||||
|
|
@ -308,193 +226,32 @@ ColumnLayout {
|
|||
}
|
||||
}
|
||||
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Style.marginXL * scaling
|
||||
Layout.bottomMargin: Style.marginXL * scaling
|
||||
}
|
||||
// Reusable component for interval preset chips
|
||||
component IntervalPresetChip: Rectangle {
|
||||
property int seconds: 0
|
||||
property string label: ""
|
||||
property bool selected: false
|
||||
signal clicked
|
||||
|
||||
// -------------------------------
|
||||
// Swww
|
||||
ColumnLayout {
|
||||
spacing: Style.marginL * scaling
|
||||
Layout.fillWidth: true
|
||||
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()
|
||||
}
|
||||
|
||||
NText {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
id: chipLabel
|
||||
anchors.centerIn: parent
|
||||
text: parent.label
|
||||
font.pointSize: Style.fontSizeS * scaling
|
||||
color: parent.selected ? Color.mOnPrimary : Color.mOnSurface
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue