1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-11 07:52:50 -05:00

Initial commit for nightMode automation

This commit is contained in:
purian23
2025-08-28 17:18:59 -04:00
parent 6f11891b1c
commit 48a78c39e2
7 changed files with 1035 additions and 338 deletions

View File

@@ -5,6 +5,7 @@ import QtQuick
import Quickshell
import Quickshell.Io
import qs.Common
import qs.Services
Singleton {
id: root
@@ -245,6 +246,12 @@ Singleton {
}
function toggleNightMode() {
// Check if automation is active - show warning if trying to manually toggle
if (SessionData.nightModeAutoEnabled) {
ToastService.showWarning("Night mode is in automatic mode. Disable automation in settings to control manually.")
return
}
if (nightModeActive) {
disableNightMode()
} else {
@@ -271,10 +278,10 @@ Singleton {
onExited: function (exitCode) {
ddcAvailable = (exitCode === 0)
if (ddcAvailable) {
console.log("BrightnessService: ddcutil detected")
console.log("DisplayService: ddcutil detected")
ddcDisplayDetectionProcess.running = true
} else {
console.log("BrightnessService: ddcutil not available")
console.log("DisplayService: ddcutil not available")
}
}
}
@@ -288,7 +295,7 @@ Singleton {
stdout: StdioCollector {
onStreamFinished: {
if (!text.trim()) {
console.log("BrightnessService: No DDC displays found")
console.log("DisplayService: No DDC displays found")
ddcDevices = []
return
}
@@ -311,7 +318,7 @@ Singleton {
}
ddcDevices = newDdcDevices
console.log("BrightnessService: Found", ddcDevices.length,
console.log("DisplayService: Found", ddcDevices.length,
"DDC displays")
// Queue initial brightness readings for DDC devices
@@ -339,7 +346,7 @@ Singleton {
}
}
} catch (error) {
console.warn("BrightnessService: Failed to parse DDC devices:",
console.warn("DisplayService: Failed to parse DDC devices:",
error)
ddcDevices = []
}
@@ -348,7 +355,7 @@ Singleton {
onExited: function (exitCode) {
if (exitCode !== 0) {
console.warn("BrightnessService: Failed to detect DDC displays:",
console.warn("DisplayService: Failed to detect DDC displays:",
exitCode)
ddcDevices = []
}
@@ -361,7 +368,7 @@ Singleton {
command: ["brightnessctl", "-m", "-l"]
onExited: function (exitCode) {
if (exitCode !== 0) {
console.warn("BrightnessService: Failed to list devices:",
console.warn("DisplayService: Failed to list devices:",
exitCode)
brightnessAvailable = false
}
@@ -370,7 +377,7 @@ Singleton {
stdout: StdioCollector {
onStreamFinished: {
if (!text.trim()) {
console.warn("BrightnessService: No devices found")
console.warn("DisplayService: No devices found")
return
}
const lines = text.trim().split("\n")
@@ -417,7 +424,7 @@ Singleton {
running: false
onExited: function (exitCode) {
if (exitCode !== 0)
console.warn("BrightnessService: Failed to set brightness:",
console.warn("DisplayService: Failed to set brightness:",
exitCode)
}
}
@@ -429,7 +436,7 @@ Singleton {
onExited: function (exitCode) {
if (exitCode !== 0)
console.warn(
"BrightnessService: Failed to set DDC brightness:",
"DisplayService: Failed to set DDC brightness:",
exitCode)
}
}
@@ -440,7 +447,7 @@ Singleton {
running: false
onExited: function (exitCode) {
if (exitCode !== 0)
console.warn("BrightnessService: Failed to get initial DDC brightness:",
console.warn("DisplayService: Failed to get initial DDC brightness:",
exitCode)
processNextDdcInit()
@@ -470,7 +477,7 @@ Singleton {
delete newPending[deviceName]
ddcPendingInit = newPending
console.log("BrightnessService: Initial DDC Device",
console.log("DisplayService: Initial DDC Device",
deviceName, "brightness:", brightness + "%")
}
}
@@ -484,7 +491,7 @@ Singleton {
running: false
onExited: function (exitCode) {
if (exitCode !== 0)
console.warn("BrightnessService: Failed to get brightness:",
console.warn("DisplayService: Failed to get brightness:",
exitCode)
}
@@ -508,7 +515,7 @@ Singleton {
}
brightnessInitialized = true
console.log("BrightnessService: Device", currentDevice,
console.log("DisplayService: Device", currentDevice,
"brightness:", brightness + "%")
brightnessChanged()
}
@@ -523,7 +530,7 @@ Singleton {
onExited: function (exitCode) {
if (exitCode !== 0)
console.warn(
"BrightnessService: Failed to get DDC brightness:",
"DisplayService: Failed to get DDC brightness:",
exitCode)
}
@@ -548,7 +555,7 @@ Singleton {
}
brightnessInitialized = true
console.log("BrightnessService: DDC Device", currentDevice,
console.log("DisplayService: DDC Device", currentDevice,
"brightness:", brightness + "%")
brightnessChanged()
}
@@ -569,7 +576,7 @@ Singleton {
SessionData.setNightModeEnabled(true)
} else {
// gammastep not found
console.warn("BrightnessService: gammastep not found")
console.warn("DisplayService: gammastep not found")
ToastService.showWarning(
"Night mode failed: gammastep not found")
}
@@ -588,7 +595,7 @@ Singleton {
onExited: function (exitCode) {
// If process exits with non-zero code while we think it should be running
if (nightModeActive && exitCode !== 0) {
console.warn("BrightnessService: Night mode process crashed with exit code:",
console.warn("DisplayService: Night mode process crashed with exit code:",
exitCode)
nightModeActive = false
SessionData.setNightModeEnabled(false)

View File

@@ -0,0 +1,363 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import Quickshell.Io
import qs.Common
Singleton {
id: root
property bool automationAvailable: false
property bool locationProviderAvailable: false
property var availableProviders: []
property string currentProvider: ""
property bool isAutomaticNightTime: false
property string currentLocation: ""
property real latitude: 0.0
property real longitude: 0.0
Component.onCompleted: {
console.log("NightModeAutomationService: Component completed")
checkAvailability()
updateFromSessionData()
if (SessionData.nightModeAutoEnabled) {
console.log("NightModeAutomationService: Auto-starting automation on init")
startAutomation()
}
}
function checkAvailability() {
gammaStepTestProcess.running = true
}
function startAutomation() {
if (!automationAvailable) {
console.warn("NightModeAutomationService: Gammastep not available")
return
}
const mode = SessionData.nightModeAutoMode || "manual"
switch (mode) {
case "time":
startTimeBasedMode()
break
case "location":
startLocationBasedMode()
break
case "manual":
default:
stopAutomation()
break
}
}
function stopAutomation() {
automationTimer.stop()
locationTimer.stop()
if (gammaStepAutomationProcess.running) {
gammaStepAutomationProcess.kill()
}
isAutomaticNightTime = false
}
function startTimeBasedMode() {
console.log("NightModeAutomationService: Starting time-based automation")
automationTimer.start()
checkTimeBasedMode()
}
function startLocationBasedMode() {
if (!locationProviderAvailable) {
console.warn("NightModeAutomationService: No location provider available, falling back to time-based mode")
startTimeBasedMode()
return
}
console.log("NightModeAutomationService: Starting location-based automation")
const temperature = SessionData.nightModeTemperature || 4500
const dayTemp = 6500
if (latitude !== 0.0 && longitude !== 0.0) {
gammaStepAutomationProcess.command = [
"gammastep",
"-m", "wayland",
"-l", `${latitude.toFixed(6)}:${longitude.toFixed(6)}`,
"-t", `${dayTemp}:${temperature}`,
"-v"
]
} else {
gammaStepAutomationProcess.command = [
"gammastep",
"-m", "wayland",
"-l", currentProvider || "manual",
"-t", `${dayTemp}:${temperature}`,
"-v"
]
}
gammaStepAutomationProcess.running = true
locationTimer.start()
}
function checkTimeBasedMode() {
if (!SessionData.nightModeAutoEnabled || SessionData.nightModeAutoMode !== "time") {
console.log("NightModeAutomationService: checkTimeBasedMode - not enabled or wrong mode")
return
}
const now = new Date()
const currentHour = now.getHours()
const currentMinute = now.getMinutes()
const currentTime = currentHour * 60 + currentMinute
const startTime = SessionData.nightModeStartTime || "20:00"
const endTime = SessionData.nightModeEndTime || "06:00"
const startParts = startTime.split(":")
const endParts = endTime.split(":")
const startMinutes = parseInt(startParts[0]) * 60 + parseInt(startParts[1])
const endMinutes = parseInt(endParts[0]) * 60 + parseInt(endParts[1])
let shouldBeNight = false
if (startMinutes > endMinutes) {
shouldBeNight = (currentTime >= startMinutes) || (currentTime < endMinutes)
} else {
shouldBeNight = (currentTime >= startMinutes) && (currentTime < endMinutes)
}
console.log(`NightModeAutomationService: Time check - Current: ${currentHour}:${currentMinute.toString().padStart(2, '0')} (${currentTime}), Range: ${startTime}-${endTime} (${startMinutes}-${endMinutes}), Should be night: ${shouldBeNight}`)
if (shouldBeNight !== isAutomaticNightTime) {
isAutomaticNightTime = shouldBeNight
console.log("NightModeAutomationService: Automatic night time status changed to:", shouldBeNight)
if (shouldBeNight) {
requestNightModeActivation()
} else {
requestNightModeDeactivation()
}
} else {
console.log("NightModeAutomationService: No change needed, isAutomaticNightTime already:", isAutomaticNightTime)
}
}
function requestNightModeActivation() {
console.log("NightModeAutomationService: Requesting night mode activation")
const temperature = SessionData.nightModeTemperature || 4500
console.log("NightModeAutomationService: Using temperature:", temperature + "K")
gammaStepOneTimeProcess.command = [
"gammastep",
"-m", "wayland",
"-O", String(temperature),
"-P"
]
console.log("NightModeAutomationService: Running gamma command:", gammaStepOneTimeProcess.command.join(" "))
gammaStepOneTimeProcess.running = true
SessionData.setNightModeEnabled(true)
}
function requestNightModeDeactivation() {
console.log("NightModeAutomationService: Requesting night mode deactivation")
gammaStepResetProcess.command = [
"gammastep",
"-m", "wayland",
"-O", "6500",
"-P"
]
gammaStepResetProcess.running = true
SessionData.setNightModeEnabled(false)
}
function setLocation(lat, lon) {
latitude = lat
longitude = lon
currentLocation = `${lat.toFixed(6)},${lon.toFixed(6)}`
if (SessionData.nightModeAutoEnabled && SessionData.nightModeAutoMode === "location") {
startLocationBasedMode()
}
}
function updateFromSessionData() {
console.log("NightModeAutomationService: Updating from SessionData - lat:", SessionData.latitude, "lng:", SessionData.longitude)
if (SessionData.latitude !== 0.0 && SessionData.longitude !== 0.0) {
setLocation(SessionData.latitude, SessionData.longitude)
}
}
function detectLocationProviders() {
locationProviderDetectionProcess.running = true
}
function testAutomationNow() {
console.log("NightModeAutomationService: Manual test triggered")
console.log("NightModeAutomationService: Current settings - autoEnabled:", SessionData.nightModeAutoEnabled, "mode:", SessionData.nightModeAutoMode)
if (SessionData.nightModeAutoMode === "time") {
checkTimeBasedMode()
} else if (SessionData.nightModeAutoMode === "location") {
console.log("NightModeAutomationService: Location mode - coordinates:", latitude, longitude)
}
}
Timer {
id: automationTimer
interval: 60000
running: false
repeat: true
onTriggered: {
checkTimeBasedMode()
}
}
Timer {
id: locationTimer
interval: 300000
running: false
repeat: true
onTriggered: {
if (SessionData.nightModeAutoEnabled && SessionData.nightModeAutoMode === "location") {
detectLocationProviders()
}
}
}
Process {
id: gammaStepTestProcess
command: ["which", "gammastep"]
running: false
onExited: function(exitCode) {
automationAvailable = (exitCode === 0)
if (automationAvailable) {
console.log("NightModeAutomationService: Gammastep available")
detectLocationProviders()
} else {
console.warn("NightModeAutomationService: Gammastep not available")
}
}
}
Process {
id: locationProviderDetectionProcess
command: ["gammastep", "-l", "list"]
running: false
stdout: StdioCollector {
onStreamFinished: {
if (text.trim()) {
availableProviders = text.trim().split('\n').filter(line => line.trim().length > 0)
locationProviderAvailable = availableProviders.length > 0
if (locationProviderAvailable && !currentProvider) {
currentProvider = availableProviders[0]
}
console.log("NightModeAutomationService: Available providers:", availableProviders)
}
}
}
onExited: function(exitCode) {
if (exitCode !== 0) {
console.warn("NightModeAutomationService: Failed to detect location providers")
locationProviderAvailable = false
}
}
}
Process {
id: gammaStepAutomationProcess
running: false
onExited: function(exitCode) {
if (SessionData.nightModeAutoEnabled && SessionData.nightModeAutoMode === "location" && exitCode !== 0) {
console.warn("NightModeAutomationService: Location-based automation failed, exit code:", exitCode)
restartTimer.start()
}
}
}
Process {
id: gammaStepOneTimeProcess
running: false
onExited: function(exitCode) {
if (exitCode !== 0) {
console.warn("NightModeAutomationService: Failed to enable night mode, exit code:", exitCode)
}
}
}
Process {
id: gammaStepResetProcess
running: false
onExited: function(exitCode) {
if (exitCode !== 0) {
console.warn("NightModeAutomationService: Failed to reset gamma, exit code:", exitCode)
}
}
}
Timer {
id: restartTimer
interval: 10000
running: false
repeat: false
onTriggered: {
if (SessionData.nightModeAutoEnabled && SessionData.nightModeAutoMode === "location") {
startLocationBasedMode()
}
}
}
Connections {
target: SessionData
function onNightModeAutoEnabledChanged() {
console.log("NightModeAutomationService: Auto enabled changed to", SessionData.nightModeAutoEnabled)
if (SessionData.nightModeAutoEnabled) {
startAutomation()
} else {
stopAutomation()
}
}
function onNightModeAutoModeChanged() {
if (SessionData.nightModeAutoEnabled) {
startAutomation()
}
}
function onNightModeStartTimeChanged() {
console.log("NightModeAutomationService: Start time changed to", SessionData.nightModeStartTime)
if (SessionData.nightModeAutoEnabled && SessionData.nightModeAutoMode === "time") {
checkTimeBasedMode()
}
}
function onNightModeEndTimeChanged() {
console.log("NightModeAutomationService: End time changed to", SessionData.nightModeEndTime)
if (SessionData.nightModeAutoEnabled && SessionData.nightModeAutoMode === "time") {
checkTimeBasedMode()
}
}
function onNightModeTemperatureChanged() {
if (SessionData.nightModeAutoEnabled) {
startAutomation()
}
}
function onLatitudeChanged() {
updateFromSessionData()
}
function onLongitudeChanged() {
updateFromSessionData()
}
}
}