mirror of
https://github.com/danbulant/dots-hyprland
synced 2026-05-24 12:22:09 +00:00
night light: use hyprsunset <- gammastep
This commit is contained in:
parent
3d5ed9401c
commit
574a2a11e7
7 changed files with 148 additions and 35 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
# Bar, wallpaper
|
# Bar, wallpaper
|
||||||
exec-once = ~/.config/hypr/hyprland/scripts/start_geoclue_agent.sh & gammastep
|
exec-once = ~/.config/hypr/hyprland/scripts/start_geoclue_agent.sh
|
||||||
exec-once = qs -c $qsConfig &
|
exec-once = qs -c $qsConfig &
|
||||||
|
|
||||||
# Input method
|
# Input method
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ Singleton {
|
||||||
id: root
|
id: root
|
||||||
property string filePath: Directories.shellConfigPath
|
property string filePath: Directories.shellConfigPath
|
||||||
property alias options: configOptionsJsonAdapter
|
property alias options: configOptionsJsonAdapter
|
||||||
|
property bool ready: false
|
||||||
|
|
||||||
function setNestedValue(nestedKey, value) {
|
function setNestedValue(nestedKey, value) {
|
||||||
let keys = nestedKey.split(".");
|
let keys = nestedKey.split(".");
|
||||||
|
|
@ -41,10 +42,10 @@ Singleton {
|
||||||
|
|
||||||
FileView {
|
FileView {
|
||||||
path: root.filePath
|
path: root.filePath
|
||||||
|
|
||||||
watchChanges: true
|
watchChanges: true
|
||||||
onFileChanged: reload()
|
onFileChanged: reload()
|
||||||
onAdapterUpdated: writeAdapter()
|
onAdapterUpdated: writeAdapter()
|
||||||
|
onLoaded: root.ready = true
|
||||||
onLoadFailed: error => {
|
onLoadFailed: error => {
|
||||||
if (error == FileViewError.FileNotFound) {
|
if (error == FileViewError.FileNotFound) {
|
||||||
writeAdapter();
|
writeAdapter();
|
||||||
|
|
@ -171,6 +172,15 @@ Singleton {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
property JsonObject light: JsonObject {
|
||||||
|
property JsonObject night: JsonObject {
|
||||||
|
property bool automatic: true
|
||||||
|
property string from: "19:00" // Format: "HH:mm", 24-hour time
|
||||||
|
property string to: "06:30" // Format: "HH:mm", 24-hour time
|
||||||
|
property int colorTemperature: 5000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
property JsonObject networking: JsonObject {
|
property JsonObject networking: JsonObject {
|
||||||
property string userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"
|
property string userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,41 +1,28 @@
|
||||||
|
import QtQuick
|
||||||
import qs.modules.common
|
import qs.modules.common
|
||||||
import qs.modules.common.widgets
|
import qs.modules.common.widgets
|
||||||
import qs
|
import qs
|
||||||
|
import qs.services
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
|
|
||||||
QuickToggleButton {
|
QuickToggleButton {
|
||||||
id: nightLightButton
|
id: nightLightButton
|
||||||
property bool enabled: false
|
property bool enabled: Hyprsunset.active
|
||||||
toggled: enabled
|
toggled: enabled
|
||||||
buttonIcon: "nightlight"
|
buttonIcon: Config.options.light.night.automatic ? "night_sight_auto" : "bedtime"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
nightLightButton.enabled = !nightLightButton.enabled
|
Hyprsunset.toggle()
|
||||||
if (enabled) {
|
|
||||||
nightLightOn.startDetached()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
nightLightOff.startDetached()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Process {
|
|
||||||
id: nightLightOn
|
altAction: () => {
|
||||||
command: ["gammastep"]
|
Config.options.light.night.automatic = !Config.options.light.night.automatic
|
||||||
}
|
}
|
||||||
Process {
|
|
||||||
id: nightLightOff
|
Component.onCompleted: {
|
||||||
command: ["pkill", "gammastep"]
|
Hyprsunset.fetchState()
|
||||||
}
|
|
||||||
Process {
|
|
||||||
id: updateNightLightState
|
|
||||||
running: true
|
|
||||||
command: ["pidof", "gammastep"]
|
|
||||||
stdout: SplitParser {
|
|
||||||
onRead: (data) => { // if not empty then set toggled to true
|
|
||||||
nightLightButton.enabled = data.length > 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledToolTip {
|
StyledToolTip {
|
||||||
content: Translation.tr("Night Light")
|
content: Translation.tr("Night Light | Right-click to toggle Auto mode")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,16 +9,15 @@ pragma ComponentBehavior: Bound
|
||||||
* A nice wrapper for date and time strings.
|
* A nice wrapper for date and time strings.
|
||||||
*/
|
*/
|
||||||
Singleton {
|
Singleton {
|
||||||
|
property var clock: SystemClock {
|
||||||
|
id: clock
|
||||||
|
precision: SystemClock.Minutes
|
||||||
|
}
|
||||||
property string time: Qt.locale().toString(clock.date, Config.options?.time.format ?? "hh:mm")
|
property string time: Qt.locale().toString(clock.date, Config.options?.time.format ?? "hh:mm")
|
||||||
property string date: Qt.locale().toString(clock.date, Config.options?.time.dateFormat ?? "dddd, dd/MM")
|
property string date: Qt.locale().toString(clock.date, Config.options?.time.dateFormat ?? "dddd, dd/MM")
|
||||||
property string collapsedCalendarFormat: Qt.locale().toString(clock.date, "dd MMMM yyyy")
|
property string collapsedCalendarFormat: Qt.locale().toString(clock.date, "dd MMMM yyyy")
|
||||||
property string uptime: "0h, 0m"
|
property string uptime: "0h, 0m"
|
||||||
|
|
||||||
SystemClock {
|
|
||||||
id: clock
|
|
||||||
precision: SystemClock.Minutes
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
interval: 10
|
interval: 10
|
||||||
running: true
|
running: true
|
||||||
|
|
|
||||||
117
.config/quickshell/ii/services/Hyprsunset.qml
Normal file
117
.config/quickshell/ii/services/Hyprsunset.qml
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import qs.modules.common
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple hyprsunset service with automatic mode.
|
||||||
|
* In theory we don't need this because hyprsunset has a config file, but it somehow doesn't work.
|
||||||
|
* It should also be possible to control it via hyprctl, but it doesn't work consistently either so we're just killing and launching.
|
||||||
|
*/
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
property var manualActive
|
||||||
|
property string from: Config.options?.light?.night?.from ?? "19:00" // Default to 7 PM
|
||||||
|
property string to: Config.options?.light?.night?.to ?? "06:30" // Default to 6:30 AM
|
||||||
|
property bool automatic: Config.options?.light?.night?.automatic && (Config?.ready ?? true)
|
||||||
|
property int colorTemperature: Config.options?.light?.night?.colorTemperature ?? 5000 // Default color temperature
|
||||||
|
property bool shouldBeOn
|
||||||
|
property bool firstEvaluation: true
|
||||||
|
property bool active: false
|
||||||
|
|
||||||
|
property int fromHour: Number(from.split(":")[0])
|
||||||
|
property int fromMinute: Number(from.split(":")[1])
|
||||||
|
property int toHour: Number(to.split(":")[0])
|
||||||
|
property int toMinute: Number(to.split(":")[1])
|
||||||
|
|
||||||
|
property int clockHour: DateTime.clock.hours
|
||||||
|
property int clockMinute: DateTime.clock.minutes
|
||||||
|
|
||||||
|
|
||||||
|
function isNoLater(hour1, minute1, hour2, minute2) {
|
||||||
|
if (hour1 < hour2)
|
||||||
|
return true;
|
||||||
|
if (hour1 === hour2 && minute1 < minute2)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onClockMinuteChanged: reEvaluate()
|
||||||
|
onAutomaticChanged: {
|
||||||
|
root.manualActive = undefined;
|
||||||
|
root.firstEvaluation = true;
|
||||||
|
reEvaluate();
|
||||||
|
}
|
||||||
|
function reEvaluate() {
|
||||||
|
const toHourIsNextDay = !isNoLater(fromHour, fromMinute, toHour, toMinute);
|
||||||
|
const toHourWrapped = toHourIsNextDay ? toHour + 24 : toHour;
|
||||||
|
const toMinuteWrapped = toMinute;
|
||||||
|
root.shouldBeOn = isNoLater(fromHour, fromMinute, clockHour, clockMinute) && isNoLater(clockHour, clockMinute, toHourWrapped, toMinuteWrapped);
|
||||||
|
if (firstEvaluation) {
|
||||||
|
firstEvaluation = false;
|
||||||
|
root.ensureState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onShouldBeOnChanged: ensureState()
|
||||||
|
function ensureState() {
|
||||||
|
// console.log("[Hyprsunset] Ensuring state:", root.shouldBeOn, "Automatic mode:", root.automatic);
|
||||||
|
if (!root.automatic || root.manualActive !== undefined)
|
||||||
|
return;
|
||||||
|
if (root.shouldBeOn) {
|
||||||
|
root.enable();
|
||||||
|
} else {
|
||||||
|
root.disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function load() { } // Dummy to force init
|
||||||
|
|
||||||
|
function enable() {
|
||||||
|
root.active = true;
|
||||||
|
// console.log("[Hyprsunset] Enabling");
|
||||||
|
Quickshell.execDetached(["bash", "-c", `pidof hyprsunset || hyprsunset --temperature ${root.colorTemperature}`]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function disable() {
|
||||||
|
root.active = false;
|
||||||
|
// console.log("[Hyprsunset] Disabling");
|
||||||
|
Quickshell.execDetached(["bash", "-c", `pkill hyprsunset`]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchState() {
|
||||||
|
fetchProc.running = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: fetchProc
|
||||||
|
running: true
|
||||||
|
command: ["bash", "-c", "hyprctl hyprsunset temperature"]
|
||||||
|
stdout: StdioCollector {
|
||||||
|
id: stateCollector
|
||||||
|
onStreamFinished: {
|
||||||
|
const output = stateCollector.text.trim();
|
||||||
|
if (output.length == 0 || output.startsWith("Couldn't"))
|
||||||
|
root.active = false;
|
||||||
|
else
|
||||||
|
root.active = (output != "6500");
|
||||||
|
// console.log("[Hyprsunset] Fetched state:", output, "->", root.active);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggle() {
|
||||||
|
if (root.manualActive === undefined)
|
||||||
|
root.manualActive = root.active;
|
||||||
|
|
||||||
|
root.manualActive = !root.manualActive;
|
||||||
|
if (root.manualActive) {
|
||||||
|
root.enable();
|
||||||
|
} else {
|
||||||
|
root.disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -49,9 +49,10 @@ ShellRoot {
|
||||||
|
|
||||||
// Force initialization of some singletons
|
// Force initialization of some singletons
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
MaterialThemeLoader.reapplyTheme()
|
|
||||||
Cliphist.refresh()
|
Cliphist.refresh()
|
||||||
FirstRunExperience.load()
|
FirstRunExperience.load()
|
||||||
|
Hyprsunset.load()
|
||||||
|
MaterialThemeLoader.reapplyTheme()
|
||||||
}
|
}
|
||||||
|
|
||||||
LazyLoader { active: enableBar; component: Bar {} }
|
LazyLoader { active: enableBar; component: Bar {} }
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ pkgdesc='Illogical Impulse Backlight Dependencies'
|
||||||
arch=(any)
|
arch=(any)
|
||||||
license=(None)
|
license=(None)
|
||||||
depends=(
|
depends=(
|
||||||
gammastep
|
|
||||||
geoclue
|
geoclue
|
||||||
brightnessctl
|
brightnessctl
|
||||||
ddcutil
|
ddcutil
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue