1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-06 05:25:41 -05:00
Files
DankMaterialShell/Services/WallpaperCyclingService.qml
2025-10-28 09:42:50 -04:00

437 lines
16 KiB
QML

pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import Quickshell.Io
import qs.Common
Singleton {
id: root
property bool cyclingActive: false
property string cachedCyclingTime: SessionData.wallpaperCyclingTime
property int cachedCyclingInterval: SessionData.wallpaperCyclingInterval
property string lastTimeCheck: ""
property var monitorTimers: ({})
property var monitorLastTimeChecks: ({})
property var monitorProcesses: ({})
Component {
id: monitorTimerComponent
Timer {
property string targetScreen: ""
running: false
repeat: true
onTriggered: {
if (typeof WallpaperCyclingService !== "undefined" && targetScreen !== "") {
WallpaperCyclingService.cycleNextForMonitor(targetScreen)
}
}
}
}
Component {
id: monitorProcessComponent
Process {
property string targetScreenName: ""
property string currentWallpaper: ""
property bool goToPrevious: false
running: false
stdout: StdioCollector {
onStreamFinished: {
if (text && text.trim()) {
const files = text.trim().split('\n').filter(file => file.length > 0)
if (files.length <= 1) return
const wallpaperList = files.sort()
const currentPath = currentWallpaper
let currentIndex = wallpaperList.findIndex(path => path === currentPath)
if (currentIndex === -1) currentIndex = 0
let targetIndex
if (goToPrevious) {
targetIndex = currentIndex === 0 ? wallpaperList.length - 1 : currentIndex - 1
} else {
targetIndex = (currentIndex + 1) % wallpaperList.length
}
const targetWallpaper = wallpaperList[targetIndex]
if (targetWallpaper && targetWallpaper !== currentPath) {
if (targetScreenName) {
SessionData.setMonitorWallpaper(targetScreenName, targetWallpaper)
} else {
SessionData.setWallpaper(targetWallpaper)
}
}
}
}
}
}
}
Connections {
target: SessionData
function onWallpaperCyclingEnabledChanged() {
updateCyclingState()
}
function onWallpaperCyclingModeChanged() {
updateCyclingState()
}
function onWallpaperCyclingIntervalChanged() {
cachedCyclingInterval = SessionData.wallpaperCyclingInterval
if (SessionData.wallpaperCyclingMode === "interval") {
updateCyclingState()
}
}
function onWallpaperCyclingTimeChanged() {
cachedCyclingTime = SessionData.wallpaperCyclingTime
if (SessionData.wallpaperCyclingMode === "time") {
updateCyclingState()
}
}
function onPerMonitorWallpaperChanged() {
updateCyclingState()
}
function onMonitorCyclingSettingsChanged() {
updateCyclingState()
}
}
function updateCyclingState() {
if (SessionData.perMonitorWallpaper) {
stopCycling()
updatePerMonitorCycling()
} else if (SessionData.wallpaperCyclingEnabled && SessionData.wallpaperPath) {
startCycling()
stopAllMonitorCycling()
} else {
stopCycling()
stopAllMonitorCycling()
}
}
function updatePerMonitorCycling() {
if (typeof Quickshell === "undefined") return
var screens = Quickshell.screens
for (var i = 0; i < screens.length; i++) {
var screenName = screens[i].name
var settings = SessionData.getMonitorCyclingSettings(screenName)
var wallpaper = SessionData.getMonitorWallpaper(screenName)
if (settings.enabled && wallpaper && !wallpaper.startsWith("#") && !wallpaper.startsWith("we:")) {
startMonitorCycling(screenName, settings)
} else {
stopMonitorCycling(screenName)
}
}
}
function stopAllMonitorCycling() {
var screenNames = Object.keys(monitorTimers)
for (var i = 0; i < screenNames.length; i++) {
stopMonitorCycling(screenNames[i])
}
}
function startCycling() {
if (SessionData.wallpaperCyclingMode === "interval") {
intervalTimer.interval = cachedCyclingInterval * 1000
intervalTimer.start()
cyclingActive = true
} else if (SessionData.wallpaperCyclingMode === "time") {
cyclingActive = true
checkTimeBasedCycling()
}
}
function stopCycling() {
intervalTimer.stop()
cyclingActive = false
}
function startMonitorCycling(screenName, settings) {
if (settings.mode === "interval") {
var timer = monitorTimers[screenName]
if (!timer && monitorTimerComponent && monitorTimerComponent.status === Component.Ready) {
var newTimers = Object.assign({}, monitorTimers)
newTimers[screenName] = monitorTimerComponent.createObject(root)
newTimers[screenName].targetScreen = screenName
monitorTimers = newTimers
timer = monitorTimers[screenName]
}
if (timer) {
timer.interval = settings.interval * 1000
timer.start()
}
} else if (settings.mode === "time") {
var newChecks = Object.assign({}, monitorLastTimeChecks)
newChecks[screenName] = ""
monitorLastTimeChecks = newChecks
}
}
function stopMonitorCycling(screenName) {
var timer = monitorTimers[screenName]
if (timer) {
timer.stop()
timer.destroy()
var newTimers = Object.assign({}, monitorTimers)
delete newTimers[screenName]
monitorTimers = newTimers
}
var process = monitorProcesses[screenName]
if (process) {
process.destroy()
var newProcesses = Object.assign({}, monitorProcesses)
delete newProcesses[screenName]
monitorProcesses = newProcesses
}
var newChecks = Object.assign({}, monitorLastTimeChecks)
delete newChecks[screenName]
monitorLastTimeChecks = newChecks
}
function cycleToNextWallpaper(screenName, wallpaperPath) {
const currentWallpaper = wallpaperPath || SessionData.wallpaperPath
if (!currentWallpaper) return
const wallpaperDir = currentWallpaper.substring(0, currentWallpaper.lastIndexOf('/'))
if (screenName && monitorProcessComponent && monitorProcessComponent.status === Component.Ready) {
// Use per-monitor process
var process = monitorProcesses[screenName]
if (!process) {
var newProcesses = Object.assign({}, monitorProcesses)
newProcesses[screenName] = monitorProcessComponent.createObject(root)
monitorProcesses = newProcesses
process = monitorProcesses[screenName]
}
if (process) {
process.command = ["sh", "-c", `ls -1 "${wallpaperDir}"/*.jpg "${wallpaperDir}"/*.jpeg "${wallpaperDir}"/*.png "${wallpaperDir}"/*.bmp "${wallpaperDir}"/*.gif "${wallpaperDir}"/*.webp 2>/dev/null | sort`]
process.targetScreenName = screenName
process.currentWallpaper = currentWallpaper
process.goToPrevious = false
process.running = true
}
} else {
// Use global process for fallback
cyclingProcess.command = ["sh", "-c", `ls -1 "${wallpaperDir}"/*.jpg "${wallpaperDir}"/*.jpeg "${wallpaperDir}"/*.png "${wallpaperDir}"/*.bmp "${wallpaperDir}"/*.gif "${wallpaperDir}"/*.webp 2>/dev/null | sort`]
cyclingProcess.targetScreenName = screenName || ""
cyclingProcess.currentWallpaper = currentWallpaper
cyclingProcess.running = true
}
}
function cycleToPrevWallpaper(screenName, wallpaperPath) {
const currentWallpaper = wallpaperPath || SessionData.wallpaperPath
if (!currentWallpaper) return
const wallpaperDir = currentWallpaper.substring(0, currentWallpaper.lastIndexOf('/'))
if (screenName && monitorProcessComponent && monitorProcessComponent.status === Component.Ready) {
// Use per-monitor process (same as next, but with prev flag)
var process = monitorProcesses[screenName]
if (!process) {
var newProcesses = Object.assign({}, monitorProcesses)
newProcesses[screenName] = monitorProcessComponent.createObject(root)
monitorProcesses = newProcesses
process = monitorProcesses[screenName]
}
if (process) {
process.command = ["sh", "-c", `ls -1 "${wallpaperDir}"/*.jpg "${wallpaperDir}"/*.jpeg "${wallpaperDir}"/*.png "${wallpaperDir}"/*.bmp "${wallpaperDir}"/*.gif "${wallpaperDir}"/*.webp 2>/dev/null | sort`]
process.targetScreenName = screenName
process.currentWallpaper = currentWallpaper
process.goToPrevious = true
process.running = true
}
} else {
// Use global process for fallback
prevCyclingProcess.command = ["sh", "-c", `ls -1 "${wallpaperDir}"/*.jpg "${wallpaperDir}"/*.jpeg "${wallpaperDir}"/*.png "${wallpaperDir}"/*.bmp "${wallpaperDir}"/*.gif "${wallpaperDir}"/*.webp 2>/dev/null | sort`]
prevCyclingProcess.targetScreenName = screenName || ""
prevCyclingProcess.currentWallpaper = currentWallpaper
prevCyclingProcess.running = true
}
}
function cycleNextManually() {
if (SessionData.wallpaperPath) {
cycleToNextWallpaper()
// Restart timers if cycling is active
if (cyclingActive && SessionData.wallpaperCyclingEnabled) {
if (SessionData.wallpaperCyclingMode === "interval") {
intervalTimer.interval = cachedCyclingInterval * 1000
intervalTimer.restart()
}
}
}
}
function cyclePrevManually() {
if (SessionData.wallpaperPath) {
cycleToPrevWallpaper()
// Restart timers if cycling is active
if (cyclingActive && SessionData.wallpaperCyclingEnabled) {
if (SessionData.wallpaperCyclingMode === "interval") {
intervalTimer.interval = cachedCyclingInterval * 1000
intervalTimer.restart()
}
}
}
}
function cycleNextForMonitor(screenName) {
if (!screenName) return
var currentWallpaper = SessionData.getMonitorWallpaper(screenName)
if (currentWallpaper) {
cycleToNextWallpaper(screenName, currentWallpaper)
}
}
function cyclePrevForMonitor(screenName) {
if (!screenName) return
var currentWallpaper = SessionData.getMonitorWallpaper(screenName)
if (currentWallpaper) {
cycleToPrevWallpaper(screenName, currentWallpaper)
}
}
function checkTimeBasedCycling() {
const currentTime = Qt.formatTime(systemClock.date, "hh:mm")
if (!SessionData.perMonitorWallpaper) {
if (currentTime === cachedCyclingTime && currentTime !== lastTimeCheck) {
lastTimeCheck = currentTime
cycleToNextWallpaper()
} else if (currentTime !== cachedCyclingTime) {
lastTimeCheck = ""
}
} else {
checkPerMonitorTimeBasedCycling(currentTime)
}
}
function checkPerMonitorTimeBasedCycling(currentTime) {
if (typeof Quickshell === "undefined") return
var screens = Quickshell.screens
for (var i = 0; i < screens.length; i++) {
var screenName = screens[i].name
var settings = SessionData.getMonitorCyclingSettings(screenName)
var wallpaper = SessionData.getMonitorWallpaper(screenName)
if (settings.enabled && settings.mode === "time" && wallpaper && !wallpaper.startsWith("#") && !wallpaper.startsWith("we:")) {
var lastCheck = monitorLastTimeChecks[screenName] || ""
if (currentTime === settings.time && currentTime !== lastCheck) {
var newChecks = Object.assign({}, monitorLastTimeChecks)
newChecks[screenName] = currentTime
monitorLastTimeChecks = newChecks
cycleNextForMonitor(screenName)
} else if (currentTime !== settings.time) {
var newChecks = Object.assign({}, monitorLastTimeChecks)
newChecks[screenName] = ""
monitorLastTimeChecks = newChecks
}
}
}
}
Timer {
id: intervalTimer
interval: cachedCyclingInterval * 1000
running: false
repeat: true
onTriggered: cycleToNextWallpaper()
}
SystemClock {
id: systemClock
precision: SystemClock.Minutes
onDateChanged: {
if ((SessionData.wallpaperCyclingMode === "time" && cyclingActive) || SessionData.perMonitorWallpaper) {
checkTimeBasedCycling()
}
}
}
Process {
id: cyclingProcess
property string targetScreenName: ""
property string currentWallpaper: ""
running: false
stdout: StdioCollector {
onStreamFinished: {
if (text && text.trim()) {
const files = text.trim().split('\n').filter(file => file.length > 0)
if (files.length <= 1) return
const wallpaperList = files.sort()
const currentPath = cyclingProcess.currentWallpaper
let currentIndex = wallpaperList.findIndex(path => path === currentPath)
if (currentIndex === -1) currentIndex = 0
const nextIndex = (currentIndex + 1) % wallpaperList.length
const nextWallpaper = wallpaperList[nextIndex]
if (nextWallpaper && nextWallpaper !== currentPath) {
if (cyclingProcess.targetScreenName) {
SessionData.setMonitorWallpaper(cyclingProcess.targetScreenName, nextWallpaper)
} else {
SessionData.setWallpaper(nextWallpaper)
}
}
}
}
}
}
Process {
id: prevCyclingProcess
property string targetScreenName: ""
property string currentWallpaper: ""
running: false
stdout: StdioCollector {
onStreamFinished: {
if (text && text.trim()) {
const files = text.trim().split('\n').filter(file => file.length > 0)
if (files.length <= 1) return
const wallpaperList = files.sort()
const currentPath = prevCyclingProcess.currentWallpaper
let currentIndex = wallpaperList.findIndex(path => path === currentPath)
if (currentIndex === -1) currentIndex = 0
const prevIndex = currentIndex === 0 ? wallpaperList.length - 1 : currentIndex - 1
const prevWallpaper = wallpaperList[prevIndex]
if (prevWallpaper && prevWallpaper !== currentPath) {
if (prevCyclingProcess.targetScreenName) {
SessionData.setMonitorWallpaper(prevCyclingProcess.targetScreenName, prevWallpaper)
} else {
SessionData.setWallpaper(prevWallpaper)
}
}
}
}
}
}
}