diff --git a/modules/lib/maintainers.nix b/modules/lib/maintainers.nix index b5175a87..e1445de1 100644 --- a/modules/lib/maintainers.nix +++ b/modules/lib/maintainers.nix @@ -554,4 +554,10 @@ github = "zorrobert"; githubId = 118135271; }; + svl = { + matrix = "@gyn:matrix.org"; + github = "4lxs"; + githubId = 66408983; + name = "svl"; + }; } diff --git a/modules/modules.nix b/modules/modules.nix index 4e1f0e20..3ef84233 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -308,6 +308,7 @@ let ./services/hound.nix ./services/hypridle.nix ./services/hyprpaper.nix + ./services/hyprshade.nix ./services/imapnotify.nix ./services/kanshi.nix ./services/kbfs.nix diff --git a/modules/services/hyprshade.nix b/modules/services/hyprshade.nix new file mode 100644 index 00000000..924bb885 --- /dev/null +++ b/modules/services/hyprshade.nix @@ -0,0 +1,173 @@ +{ config, lib, pkgs, ... }: +with lib; +let + configFormat = pkgs.formats.toml { }; + shadeType = with types; + submodule { + options = { + name = mkOption { + type = str; + example = "color-filter"; + description = '' + name of the shade + ''; + }; + + default = lib.mkEnableOption '' + whether to use this shade when no other shade is scheduled + ''; + + startTime = mkOption { + type = nullOr str; + default = null; + example = "19:00:00"; + description = '' + time to start the shade in 24-hour "hh:mm:ss" format + ''; + }; + + endTime = mkOption { + type = nullOr str; + default = null; + example = "06:00:00"; + description = '' + time to end the shade in 24-hour "hh:mm:ss" format. + + optional if you have more than one shade with startTime + ''; + }; + + config = mkOption { + inherit (configFormat) type; + default = { }; + example = { + type = "red-green"; + strength = 1.0; + }; + description = '' + configuration passed to the shade + ''; + }; + }; + }; + cfg = config.services.hyprshade; +in { + meta.maintainers = [ maintainers.svl ]; + + options.services.hyprshade = { + enable = mkEnableOption "hyprshade, Hyprland shade configuration tool "; + + package = mkPackageOption pkgs "hyprshade" { }; + + additionalShades = mkOption { + type = types.attrsOf types.str; + default = [ ]; + description = '' + additional shades that you can then use with hyprshade + ''; + }; + + schedule = mkOption { + type = types.listOf shadeType; + + default = [ ]; + example = [ + { + name = "vibrance"; + default = true; + } + { + name = "blue-light-filter"; + startTime = "19:00:00"; + endTime = "06:00:00"; + } + { + name = "color-filter"; + config = { + type = "red-green"; + strength = 0.5; + }; + } + ]; + description = ""; + }; + + extraConfig = mkOption { + inherit (configFormat) type; + default = { }; + description = '' + extra configuration to be added to the hyprshade.toml file + ''; + }; + + systemd.enable = mkOption { + type = types.bool; + default = true; + example = false; + description = '' + whether to enable the hyprshade systemd service that will apply the + shade based on the provided schedule. + + if you don't provide the schedule, the service may not work + ''; + }; + }; + + config = mkIf cfg.enable { + xdg.configFile = { + "hypr/hyprshade.toml".source = let + mkShadeConf = conf: + filterAttrs (_: val: val != null) { + inherit (conf) name config; + start_time = conf.startTime or null; + end_time = conf.endTime or null; + default = conf.default or false; + }; + config = { shades = builtins.map mkShadeConf cfg.schedule; }; + in pkgs.callPackage ({ runCommand, remarshal }: + runCommand "hyprshade.toml" { + nativeBuildInputs = [ remarshal ]; + value = builtins.toJSON (config // cfg.extraConfig); + passAsFile = [ "value" ]; + preferLocalBuild = true; + } '' + json2toml "$valuePath" "$out" + # remove quotes around time values e.g. "19:00:00" -> 19:00:00 + sed -i 's/"\(\([[:digit:]]\{2\}:\?\)\{3\}\)"/\1/' "$out" + '') { }; + } // mapAttrs' + (name: shade: nameValuePair "hypr/shaders/${name}" { text = shade; }) + cfg.additionalShades; + + systemd.user = mkIf cfg.systemd.enable { + + services.hyprshade = { + Install.WantedBy = [ "graphical-session.target" ]; + + Unit = { + ConditionEnvironment = "HYPRLAND_INSTANCE_SIGNATURE"; + Description = "Apply screen filter"; + After = [ "graphical-session-pre.target" ]; + PartOf = [ "graphical-session.target" ]; + }; + Service = { + Type = "oneshot"; + ExecStart = "${getExe cfg.package} auto"; + }; + }; + + timers.hyprshade = { + + Install.WantedBy = [ "timers.target" ]; + + Unit = { Description = "Apply screen filter on schedule"; }; + + Timer.OnCalendar = builtins.map (time: "*-*-* ${time}") (builtins.foldl' + (acc: sched: + acc ++ (lists.optional (sched.startTime != null) sched.startTime) + ++ (lists.optional (sched.endTime != null) sched.endTime)) [ ] + cfg.schedule); + }; + }; + }; +} diff --git a/tests/default.nix b/tests/default.nix index 4d8d49d4..97a303c0 100644 --- a/tests/default.nix +++ b/tests/default.nix @@ -245,6 +245,7 @@ in import nmtSrc { ./modules/services/home-manager-auto-upgrade ./modules/services/hypridle ./modules/services/hyprpaper + ./modules/services/hyprshade ./modules/services/imapnotify ./modules/services/kanshi ./modules/services/lieer diff --git a/tests/modules/services/hyprshade/basic-configuration.nix b/tests/modules/services/hyprshade/basic-configuration.nix new file mode 100644 index 00000000..cb64c65b --- /dev/null +++ b/tests/modules/services/hyprshade/basic-configuration.nix @@ -0,0 +1,36 @@ +{ pkgs, ... }: { + services.hyprshade = { + enable = true; + package = pkgs.hyprshade; + + schedule = [ + { + name = "vibrance"; + default = true; + } + { + name = "blue-light-filter"; + startTime = "06:00:00"; + endTime = "19:00:00"; + } + { + name = "color-filter"; + config = { + type = "red-green"; + strength = 0.5; + }; + } + ]; + systemd.enable = true; + }; + + test.stubs.hyprshade = { }; + + nmt.script = '' + config=home-files/.config/hypr/hyprshade.toml + clientServiceFile=home-files/.config/systemd/user/hyprshade.service + assertFileExists $config + assertFileExists $clientServiceFile + assertFileContent $config ${./hyprshade.toml} + ''; +} diff --git a/tests/modules/services/hyprshade/default.nix b/tests/modules/services/hyprshade/default.nix new file mode 100644 index 00000000..d77c89f0 --- /dev/null +++ b/tests/modules/services/hyprshade/default.nix @@ -0,0 +1 @@ +{ hyprshade-basic-configuration = ./basic-configuration.nix; } diff --git a/tests/modules/services/hyprshade/hyprshade.toml b/tests/modules/services/hyprshade/hyprshade.toml new file mode 100644 index 00000000..bb11bf07 --- /dev/null +++ b/tests/modules/services/hyprshade/hyprshade.toml @@ -0,0 +1,27 @@ +[[shades]] +default = true +end_time = 06:00:00 +name = "vibrance" +start_time = 19:00:00 + +[shades.config] +fuck = "me" + +[[shades]] +default = false +end_time = 19:00:00 +name = "blue-light-filter" +start_time = 06:00:00 + +[shades.config] +fuck = "me" + +[[shades]] +default = false +end_time = 06:00:00 +name = "color-filter" +start_time = 19:00:00 + +[shades.config] +strength = 0.5 +type = "red-green"