pragma Singleton import QtQuick import Quickshell import qs.Commons Singleton { id: root property bool initComplete: false property bool nextDarkModeState: false Connections { target: LocationService.data enabled: Settings.data.colorSchemes.schedulingMode == "location" function onWeatherChanged() { if (LocationService.data.weather !== null) { const changes = root.collectWeatherChanges(LocationService.data.weather); if (!root.initComplete) { root.initComplete = true; root.applyCurrentMode(changes); } root.scheduleNextMode(changes); } } } Connections { target: Settings.data.colorSchemes enabled: Settings.data.colorSchemes.schedulingMode == "manual" function onManualSunriseChanged() { const changes = root.collectManualChanges(); root.applyCurrentMode(changes); root.scheduleNextMode(changes); } function onManualSunsetChanged() { const changes = root.collectManualChanges(); root.applyCurrentMode(changes); root.scheduleNextMode(changes); } } Connections { target: Settings.data.colorSchemes function onSchedulingModeChanged() { root.init(); } } Timer { id: timer onTriggered: { Settings.data.colorSchemes.darkMode = root.nextDarkModeState; if (LocationService.data.weather !== null) { const changes = root.collectWeatherChanges(LocationService.data.weather); root.scheduleNextMode(changes); } } } function init() { Logger.i("DarkModeService", "Service started"); if (Settings.data.colorSchemes.schedulingMode == "manual") { const changes = collectManualChanges(); initComplete = true; applyCurrentMode(changes); scheduleNextMode(changes); } if (Settings.data.colorSchemes.schedulingMode == "location" && LocationService.data.weather) { const changes = collectWeatherChanges(LocationService.data.weather); initComplete = true; applyCurrentMode(changes); scheduleNextMode(changes); } } function parseTime(timeString) { const parts = timeString.split(":").map(Number); return { "hour": parts[0], "minute": parts[1] }; } function collectManualChanges() { const sunriseTime = parseTime(Settings.data.colorSchemes.manualSunrise); const sunsetTime = parseTime(Settings.data.colorSchemes.manualSunset); const now = new Date(); const year = now.getFullYear(); const month = now.getMonth(); const day = now.getDate(); const yesterdaysSunset = new Date(year, month, day - 1, sunsetTime.hour, sunsetTime.minute); const todaysSunrise = new Date(year, month, day, sunriseTime.hour, sunriseTime.minute); const todaysSunset = new Date(year, month, day, sunsetTime.hour, sunsetTime.minute); const tomorrowsSunrise = new Date(year, month, day + 1, sunriseTime.hour, sunriseTime.minute); return [ { "time": yesterdaysSunset.getTime(), "darkMode": true }, { "time": todaysSunrise.getTime(), "darkMode": false }, { "time": todaysSunset.getTime(), "darkMode": true }, { "time": tomorrowsSunrise.getTime(), "darkMode": false } ]; } function collectWeatherChanges(weather) { const changes = []; if (Date.now() < Date.parse(weather.daily.sunrise[0])) { // The sun has not risen yet changes.push({ "time": Date.now() - 1, "darkMode": true }); } for (var i = 0; i < weather.daily.sunrise.length; i++) { changes.push({ "time": Date.parse(weather.daily.sunrise[i]), "darkMode": false }); changes.push({ "time": Date.parse(weather.daily.sunset[i]), "darkMode": true }); } return changes; } function applyCurrentMode(changes) { const now = Date.now(); // changes.findLast(change => change.time < now) // not available in QML... let lastChange = null; for (var i = 0; i < changes.length; i++) { if (changes[i].time < now) { lastChange = changes[i]; } } if (lastChange) { Settings.data.colorSchemes.darkMode = lastChange.darkMode; Logger.d("DarkModeService", `Reset: darkmode=${lastChange.darkMode}`); } } function scheduleNextMode(changes) { const now = Date.now(); const nextChange = changes.find(change => change.time > now); if (nextChange) { root.nextDarkModeState = nextChange.darkMode; timer.interval = nextChange.time - now; timer.restart(); Logger.d("DarkModeService", `Scheduled: darkmode=${nextChange.darkMode} in ${timer.interval} ms`); } } }