wakeword: reversible tray pause toggle; document quiet-session fixes
Bug: a stale /tmp/wake_muted flag silently disabled wakeword detection with no in-app way to clear it (the flag was read but never written by any code or UI). - wakeword.py: expose MUTE_FILE + is_muted()/set_muted() helpers - tray.py: add a "Pause wakeword" CheckMenuItem (shown when wakeword is enabled) that toggles the flag and reflects current state - config.py: document the tray toggle instead of the bare /tmp file - CHANGELOG: record the wakeword pause toggle and the existing notify hygiene fixes (transient/single-bubble notifications, silent hands-free sessions) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
73ab26c90b
commit
93de455b01
@ -9,6 +9,22 @@ The version is defined in [`blitztext/__init__.py`](blitztext/__init__.py).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- **Pause wakeword (tray)**: a reversible "Pause wakeword" toggle appears in the
|
||||
system-tray menu when the wakeword is enabled. It pauses/resumes hands-free
|
||||
detection by toggling the `/tmp/wake_muted` flag (external scripts may toggle
|
||||
the same file).
|
||||
|
||||
### Fixed
|
||||
- **Wakeword stuck muted**: a leftover `/tmp/wake_muted` flag silently disabled
|
||||
detection with no in-app way to clear it. The state is now exposed and
|
||||
reversible from the tray, so a stale flag no longer kills hands-free use.
|
||||
- **Notification storm / lock-screen pile-up**: desktop notifications are now
|
||||
sent as transient with a short expiry and reuse a single bubble, so they no
|
||||
longer stack in the notification log or persist on the lock screen.
|
||||
- **Quiet hands-free sessions**: per-dictation notifications are suppressed for
|
||||
wakeword-triggered sessions (audio cues are used instead).
|
||||
|
||||
## [1.2.0] - 2026-06-05
|
||||
|
||||
### Added
|
||||
|
||||
@ -87,6 +87,20 @@ class Tray:
|
||||
menu.append(item)
|
||||
|
||||
menu.append(Gtk.SeparatorMenuItem())
|
||||
|
||||
# Hands-free wakeword: a reversible pause toggle. Without this, a stale
|
||||
# /tmp/wake_muted flag would silently disable detection with no way back.
|
||||
if getattr(self.app.cfg, "wakeword_enabled", False):
|
||||
from . import wakeword
|
||||
|
||||
self.mute_item = Gtk.CheckMenuItem(label="Pause wakeword")
|
||||
self.mute_item.set_active(wakeword.is_muted())
|
||||
self.mute_item.connect(
|
||||
"toggled", lambda i: wakeword.set_muted(i.get_active())
|
||||
)
|
||||
menu.append(self.mute_item)
|
||||
menu.append(Gtk.SeparatorMenuItem())
|
||||
|
||||
for label, cb in (
|
||||
("Show panel", self.app.show_panel),
|
||||
("Settings…", self.app.open_settings),
|
||||
|
||||
@ -19,7 +19,24 @@ from urllib.parse import urlparse
|
||||
|
||||
from . import logbuffer
|
||||
|
||||
_MUTE_FILE = "/tmp/wake_muted"
|
||||
MUTE_FILE = "/tmp/wake_muted"
|
||||
|
||||
|
||||
def is_muted() -> bool:
|
||||
"""True if wakeword detections are currently paused via the mute flag."""
|
||||
return os.path.exists(MUTE_FILE)
|
||||
|
||||
|
||||
def set_muted(muted: bool) -> None:
|
||||
"""Pause (create flag) or resume (remove flag) wakeword detection."""
|
||||
try:
|
||||
if muted:
|
||||
open(MUTE_FILE, "a").close()
|
||||
elif os.path.exists(MUTE_FILE):
|
||||
os.remove(MUTE_FILE)
|
||||
except OSError as e: # noqa: BLE001 - mute is best-effort, never crash
|
||||
logbuffer.log(f"[wakeword] Could not update mute flag: {e}")
|
||||
|
||||
|
||||
class WakewordListener:
|
||||
def __init__(self, uri: str, model: str, mic: str, on_detect):
|
||||
@ -142,8 +159,8 @@ class WakewordListener:
|
||||
if time.time() < self._cooldown_until:
|
||||
return
|
||||
|
||||
if os.path.exists(_MUTE_FILE):
|
||||
logbuffer.log("[wakeword] Detected, but muted via /tmp/wake_muted")
|
||||
if is_muted():
|
||||
logbuffer.log("[wakeword] Detected, but paused (resume via tray)")
|
||||
return
|
||||
|
||||
logbuffer.log(f"[wakeword] Detected '{self.model}'!")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user