# Automatic timezone detection (opt-in) — the system timezone, and so the # Waybar clock, follows your location, so travelling to another zone updates # the time on its own. Geoclue feeds `automatic-timezoned`, which drives # /etc/localtime at runtime. # # In-flake state, menu-driven (the keyboard/night-light philosophy): the on/off # flag lives in the same theme-state.json under `settings.autoTimezone` # (git-tracked, reproducible), written by the System-menu toggle # (nomarchy-autotimezone). Because this is a SYSTEM service — not a user unit it # can start/stop instantly like night-light — the toggle drives a system rebuild # (plus a home switch for the Waybar-refresh watcher in timezone.nix home-side). { config, lib, pkgs, ... }: let cfg = config.nomarchy.system; # Read the same state file the rest of the system side uses (Plymouth too), # wired by lib.mkFlake. The flag defaults off when stateFile is null; # a set-but-missing/invalid path fails closed via theme-state-read.nix. state = if cfg.stateFile != null then import ../theme-state-read.nix { inherit lib; } cfg.stateFile else { }; stateEnabled = (state.settings or { }).autoTimezone or false; sync = lib.getExe pkgs.nomarchy-theme-sync; # Menu/CLI toggle. Runs as the normal user (it owns the flake checkout + # writes the state); sudos only the system switch, like sys-update. Writes # the in-flake flag, then rebuilds: the system rebuild bakes the service + # the time.timeZone override, the home switch installs/removes the Waybar # refresh watcher — both read the same flag we just wrote. nomarchy-autotimezone = pkgs.writeShellScriptBin "nomarchy-autotimezone" '' set -e if [ "$(id -u)" -eq 0 ]; then echo "nomarchy-autotimezone: run as your normal user (it sudos the rebuild itself)" >&2 exit 1 fi flake="''${NOMARCHY_PATH:-$HOME/.nomarchy}" cur=$(${sync} get settings.autoTimezone 2>/dev/null) || cur=false case "''${1:-toggle}" in on) new=true ;; off) new=false ;; toggle) case "$cur" in true|True) new=false ;; *) new=true ;; esac ;; status) echo "$cur"; exit 0 ;; *) echo "usage: nomarchy-autotimezone [toggle|on|off|status]" >&2; exit 64 ;; esac ${sync} --quiet set settings.autoTimezone "$new" --no-switch if [ "$new" = true ]; then notify-send "Auto timezone" "Enabling — rebuilding the system…" 2>/dev/null || true else notify-send "Auto timezone" "Disabling — rebuilding the system…" 2>/dev/null || true fi sudo nixos-rebuild switch --flake "$flake#default" home-manager switch --flake "$flake" if [ "$new" = true ]; then notify-send "Auto timezone on" "The clock now follows your location." 2>/dev/null || true else notify-send "Auto timezone off" "Back to the fixed timezone in system.nix." 2>/dev/null || true fi ''; in { config = lib.mkMerge [ { # Shipped unconditionally so the menu can enable the feature even while # it's off. Track the in-flake flag; mkDefault so a hand-set # nomarchy.system.autoTimezone.enable in system.nix still wins. environment.systemPackages = [ nomarchy-autotimezone ]; nomarchy.system.autoTimezone.enable = lib.mkDefault stateEnabled; } (lib.mkIf cfg.autoTimezone.enable { services.geoclue2.enable = true; services.automatic-timezoned.enable = true; # A runtime timezone needs /etc/localtime writable. automatic-timezoned # sets time.timeZone = null itself, but the installer writes a static # value at normal priority, which would collide (a hard eval error) — # mkForce null overrides both and resolves cleanly. time.timeZone = lib.mkForce null; }) ]; }