feat(theme-sync): persistent switch notification so slow switches read as progress
The "Applying theme — rebuilding…" toast used the default timeout, so it vanished seconds into a multi-minute home-manager switch — leaving the user with no signal and the impression the selection failed. Now it's persistent (timeout 0) and all theme notifications share a synchronous tag, so swaync REPLACES it in place with "Theme applied ✓" (or a critical failure toast that persists) when the rebuild finishes. notify() grew persistent/urgency/summary params. Honest indeterminate feedback — HM exposes no percentage, so no fake progress bar. Verified: py_compile clean; the full apply→switch→notify path runs end to end (dummy NOMARCHY_REBUILD). The in-place replacement is visible only in a real swaync session. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -59,10 +59,27 @@ def die(msg: str) -> "None":
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def notify(body: str) -> None:
|
||||
if shutil.which("notify-send"):
|
||||
subprocess.run(["notify-send", "-a", "Nomarchy", "Nomarchy", body],
|
||||
capture_output=True)
|
||||
# All Nomarchy theme notifications share this synchronous tag, so the
|
||||
# notification daemon (swaync) REPLACES the previous one in place instead
|
||||
# of stacking — the "rebuilding…" toast becomes the "applied ✓" toast.
|
||||
NOTIFY_SYNC_TAG = "nomarchy-theme-sync"
|
||||
|
||||
|
||||
def notify(body: str, summary: str = "Nomarchy", *,
|
||||
persistent: bool = False, urgency: str = "normal") -> None:
|
||||
"""Desktop notification. persistent (timeout 0) keeps it up for the
|
||||
whole rebuild so a slow switch never reads as a failed selection;
|
||||
the success/failure call replaces it via the synchronous tag."""
|
||||
if shutil.which("notify-send") is None:
|
||||
return
|
||||
subprocess.run(
|
||||
["notify-send", "-a", "Nomarchy",
|
||||
"-u", urgency,
|
||||
"-t", "0" if persistent else "5000",
|
||||
"-h", f"string:x-canonical-private-synchronous:{NOTIFY_SYNC_TAG}",
|
||||
summary, body],
|
||||
capture_output=True,
|
||||
)
|
||||
|
||||
|
||||
# ─── State management ─────────────────────────────────────────────────────
|
||||
@@ -145,10 +162,13 @@ def run_switch() -> None:
|
||||
return
|
||||
|
||||
log(f"rebuilding: {' '.join(argv)}")
|
||||
notify("Applying theme — rebuilding the desktop…")
|
||||
# Persistent (timeout 0): stays up for the whole rebuild — replaced
|
||||
# in place by the success/failure notification below — so a multi-
|
||||
# minute switch never looks like it silently failed.
|
||||
notify("Applying theme — rebuilding the desktop…", persistent=True)
|
||||
result = subprocess.run(argv) # stream output to the caller's terminal
|
||||
if result.returncode != 0:
|
||||
notify("Theme rebuild FAILED — see terminal / journal")
|
||||
notify("Theme rebuild FAILED — see terminal / journal", urgency="critical")
|
||||
die("rebuild failed (state file already updated; fix and re-run)")
|
||||
notify("Theme applied ✓")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user