diff --git a/Commons/Settings.qml b/Commons/Settings.qml index 59f78e0..4e8ed11 100644 --- a/Commons/Settings.qml +++ b/Commons/Settings.qml @@ -250,13 +250,11 @@ Singleton { // night light property JsonObject nightLight: JsonObject { property bool enabled: false - property real intensity: 0.8 - property string startTime: "20:00" - property string stopTime: "07:00" - property bool autoSchedule: false - // wlsunset temperatures (Kelvin) - property int lowTemp: 3500 - property int highTemp: 6500 + property bool autoSchedule: true + property string nightTemp: "4000" + property string dayTemp: "6500" + property string manualSunrise: "06:30" + property string manualSunset: "18:30" } } } diff --git a/Modules/Bar/Widgets/Volume.qml b/Modules/Bar/Widgets/Volume.qml index 891ff24..8819cc9 100644 --- a/Modules/Bar/Widgets/Volume.qml +++ b/Modules/Bar/Widgets/Volume.qml @@ -76,7 +76,7 @@ Item { settingsPanel.requestedTab = SettingsPanel.Tab.AudioService settingsPanel.open(screen) } - onRightClicked : { + onRightClicked: { pwvucontrolProcess.running = true } } diff --git a/Modules/SettingsPanel/Tabs/DisplayTab.qml b/Modules/SettingsPanel/Tabs/DisplayTab.qml index a81a361..67905aa 100644 --- a/Modules/SettingsPanel/Tabs/DisplayTab.qml +++ b/Modules/SettingsPanel/Tabs/DisplayTab.qml @@ -263,38 +263,6 @@ ColumnLayout { } } - // Intensity settings - ColumnLayout { - visible: Settings.data.nightLight.enabled - NLabel { - label: "Intensity" - description: "Higher values create warmer tones." - } - RowLayout { - spacing: Style.marginS * scaling - - NSlider { - from: 0 - to: 1 - stepSize: 0.01 - value: Settings.data.nightLight.intensity - onMoved: { - Settings.data.nightLight.intensity = value - NightLightService.apply() - } - Layout.fillWidth: true - Layout.minimumWidth: 150 * scaling - } - - NText { - text: `${Math.round(Settings.data.nightLight.intensity * 100)}%` - Layout.alignment: Qt.AlignVCenter - Layout.minimumWidth: 60 * scaling - horizontalAlignment: Text.AlignRight - } - } - } - // Temperature ColumnLayout { spacing: Style.marginXS * scaling @@ -302,7 +270,7 @@ ColumnLayout { NLabel { label: "Color temperature" - description: "Select two temperatures in Kelvin" + description: "Choose two temperatures in Kelvin." } RowLayout { @@ -313,21 +281,23 @@ ColumnLayout { Layout.alignment: Qt.AlignVCenter NText { - text: "Low" + text: "Night" font.pointSize: Style.fontSizeM * scaling color: Color.mOnSurfaceVariant Layout.alignment: Qt.AlignVCenter } NTextInput { - text: Settings.data.nightLight.lowTemp.toString() + text: Settings.data.nightLight.nightTemp inputMethodHints: Qt.ImhDigitsOnly Layout.alignment: Qt.AlignVCenter onEditingFinished: { - var v = parseInt(text) - if (!isNaN(v)) { - Settings.data.nightLight.lowTemp = Math.max(1000, Math.min(6500, v)) - NightLightService.apply() + var nightTemp = parseInt(text) + var dayTemp = parseInt(Settings.data.nightLight.dayTemp) + if (!isNaN(nightTemp) && !isNaN(dayTemp)) { + // Clamp value between [1000 .. (dayTemp-500)] + var clampedValue = Math.min(dayTemp - 500, Math.max(1000, nightTemp)) + text = Settings.data.nightLight.nightTemp = clampedValue.toString() } } } @@ -335,20 +305,22 @@ ColumnLayout { Item {} NText { - text: "High" + text: "Day" font.pointSize: Style.fontSizeM * scaling color: Color.mOnSurfaceVariant Layout.alignment: Qt.AlignVCenter } NTextInput { - text: Settings.data.nightLight.highTemp.toString() + text: Settings.data.nightLight.dayTemp inputMethodHints: Qt.ImhDigitsOnly Layout.alignment: Qt.AlignVCenter onEditingFinished: { - var v = parseInt(text) - if (!isNaN(v)) { - Settings.data.nightLight.highTemp = Math.max(1000, Math.min(10000, v)) - NightLightService.apply() + var dayTemp = parseInt(text) + var nightTemp = parseInt(Settings.data.nightLight.nightTemp) + if (!isNaN(nightTemp) && !isNaN(dayTemp)) { + // Clamp value between [(nightTemp+500) .. 6500] + var clampedValue = Math.max(nightTemp + 500, Math.min(6500, dayTemp)) + text = Settings.data.nightLight.dayTemp = clampedValue.toString() } } } @@ -356,43 +328,41 @@ ColumnLayout { } NToggle { - label: "Auto Schedule" - description: "Automatically enable night light based on time schedule." + label: "Automatic Scheduling" + description: `Based on the sunset and sunrise time in ${LocationService.data.stableName} - recommended.` checked: Settings.data.nightLight.autoSchedule - onToggled: checked => { - Settings.data.nightLight.autoSchedule = checked - NightLightService.apply() - } + onToggled: checked => Settings.data.nightLight.autoSchedule = checked visible: Settings.data.nightLight.enabled } // Schedule settings ColumnLayout { spacing: Style.marginXS * scaling - visible: Settings.data.nightLight.enabled && Settings.data.nightLight.autoSchedule - - NLabel { - label: "Schedule" - description: "Set a start and end time for automatic schedule." - } + visible: Settings.data.nightLight.enabled && !Settings.data.nightLight.autoSchedule RowLayout { Layout.fillWidth: false spacing: Style.marginM * scaling + NLabel { + label: "Manual Scheduling" + } + + Item {// add a little more spacing + } + NText { - text: "Start Time" + text: "Sunrise Time" font.pointSize: Style.fontSizeM * scaling color: Color.mOnSurfaceVariant } NComboBox { model: timeOptions - currentKey: Settings.data.nightLight.startTime + currentKey: Settings.data.nightLight.manualSunrise placeholder: "Select start time" onSelected: key => { - Settings.data.nightLight.startTime = key - NightLightService.apply() + Settings.data.nightLight.manualSunrise = key } preferredWidth: 120 * scaling } @@ -401,17 +371,16 @@ ColumnLayout { } NText { - text: "Stop Time" + text: "Sunset Time" font.pointSize: Style.fontSizeM * scaling color: Color.mOnSurfaceVariant } NComboBox { model: timeOptions - currentKey: Settings.data.nightLight.stopTime + currentKey: Settings.data.nightLight.manualSunset placeholder: "Select stop time" onSelected: key => { - Settings.data.nightLight.stopTime = key - NightLightService.apply() + Settings.data.nightLight.manualSunset = key } preferredWidth: 120 * scaling } diff --git a/Services/NightLightService.qml b/Services/NightLightService.qml index 4395b76..9e940a4 100644 --- a/Services/NightLightService.qml +++ b/Services/NightLightService.qml @@ -11,75 +11,45 @@ Singleton { // Night Light properties - directly bound to settings readonly property var params: Settings.data.nightLight - // Deprecated overlay flag removed; service only manages wlsunset now - property bool isActive: false - property bool isRunning: false - property string lastCommand: "" - property var nextCommand: [] + property var lastCommand: [] - Component.onCompleted: apply() + function apply() { + var command = buildCommand() + + // Compare with previous command to avoid unecessary restart + if (JSON.stringify(command) !== JSON.stringify(lastCommand)) { + lastCommand = command + runner.command = command + + // Set running to false so it may restarts below if still enabled + runner.running = false + } + runner.running = params.enabled + } function buildCommand() { var cmd = ["wlsunset"] - // Use user-configured temps; if intensity is used, bias lowTemp towards user low - var i = Math.max(0, Math.min(1, params.intensity)) - var loCfg = params.lowTemp || 3500 - var hiCfg = params.highTemp || 6500 - var lowTemp = Math.round(hiCfg - (hiCfg - loCfg) * Math.pow(i, 0.6)) - cmd.push("-t", lowTemp.toString()) - cmd.push("-T", hiCfg.toString()) - if (params.autoSchedule && LocationService.data.coordinatesReady && LocationService.data.stableLatitude !== "" - && LocationService.data.stableLongitude !== "") { - cmd.push("-l", LocationService.data.stableLatitude) - cmd.push("-L", LocationService.data.stableLongitude) + cmd.push("-t", `${params.nightTemp}`, "-T", `${params.dayTemp}`) + if (params.autoSchedule) { + cmd.push("-l", `${LocationService.data.stableLatitude}`, "-L", `${LocationService.data.stableLongitude}`) } else { - // Manual schedule - if (params.startTime && params.stopTime) { - cmd.push("-S", params.startTime) - cmd.push("-s", params.stopTime) - } - // Optional: do not pass duration, use wlsunset defaults + cmd.push("-S", params.manualSunrise) + cmd.push("-s", params.manualSunset) } + cmd.push("-d", 60 * 15) // 15min progressive fade at sunset/sunrise return cmd } - function stopIfRunning() { - // Best-effort stop; wlsunset runs as foreground, so pkill is simplest - Quickshell.execDetached(["pkill", "-x", "wlsunset"]) - isRunning = false - } - - function apply() { - if (!params.enabled) { - // Disable immediately - debounceStart.stop() - nextCommand = [] - stopIfRunning() - return - } - // Debounce rapid changes (slider) - nextCommand = buildCommand() - lastCommand = nextCommand.join(" ") - stopIfRunning() - debounceStart.restart() - } - // Observe setting changes and location readiness Connections { target: Settings.data.nightLight function onEnabledChanged() { apply() } - function onIntensityChanged() { + function onNightTempChanged() { apply() } - function onAutoScheduleChanged() { - apply() - } - function onStartTimeChanged() { - apply() - } - function onStopTimeChanged() { + function onDayTempChanged() { apply() } } @@ -87,16 +57,7 @@ Singleton { Connections { target: LocationService.data function onCoordinatesReadyChanged() { - if (params.enabled && params.autoSchedule) - apply() - } - function onStableLatitudeChanged() { - if (params.enabled && params.autoSchedule) - apply() - } - function onStableLongitudeChanged() { - if (params.enabled && params.autoSchedule) - apply() + apply() } } @@ -105,28 +66,10 @@ Singleton { id: runner running: false onStarted: { - isRunning = true - Logger.log("NightLight", "Started wlsunset:", root.lastCommand) + Logger.log("NightLight", "Wlsunset started:", runner.command) } onExited: function (code, status) { - isRunning = false - Logger.log("NightLight", "wlsunset exited:", code, status) - // Do not auto-restart here; debounceStart handles starts - } - stdout: StdioCollector {} - stderr: StdioCollector {} - } - - // Debounce timer to avoid flicker when moving sliders - Timer { - id: debounceStart - interval: 300 - repeat: false - onTriggered: { - if (params.enabled && nextCommand.length > 0) { - runner.command = nextCommand - runner.running = true - } + Logger.log("NightLight", "Wlsunset exited:", code, status) } } } diff --git a/Widgets/NText.qml b/Widgets/NText.qml index e6986fb..1d54c89 100644 --- a/Widgets/NText.qml +++ b/Widgets/NText.qml @@ -9,8 +9,9 @@ Text { font.family: Settings.data.ui.fontDefault font.pointSize: Style.fontSizeM * scaling font.weight: Style.fontWeightMedium - color: Color.mOnSurface - renderType: Text.QtRendering font.hintingPreference: Font.PreferNoHinting font.kerning: true + color: Color.mOnSurface + renderType: Text.QtRendering + textFormat: Text.RichText } diff --git a/shell.qml b/shell.qml index 0d85497..4b7da7c 100644 --- a/shell.qml +++ b/shell.qml @@ -103,7 +103,10 @@ ShellRoot { // Save a ref. to our lockScreen so we can access it easily PanelService.lockScreen = lockScreen - // Ensure our singleton is created as soon as possible so we start fetching weather asap + // Ensure our location singleton is created as soon as possible so we start fetching weather asap LocationService.init() + + // Kickoff NightLight service + NightLightService.apply() } }