feat(tray): Add chobit system tray integration and development tray utilities

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Claude Code 2026-03-29 10:05:35 -07:00
parent 16d6f4e1b3
commit d9caffdd63
2 changed files with 22 additions and 12 deletions

View file

@ -194,6 +194,10 @@ class ChobitTray(TrayApp):
self._select_camera(index)
elif cmd == "list_cameras":
self._send_camera_list()
elif cmd == "set_camera_enabled":
enabled = bool(msg.get("enabled", False))
if enabled != self._camera_enabled:
self.toggle_camera()
def _send_camera_list(self) -> None:
"""Send enumerated camera list to Godot via UDP."""

View file

@ -108,15 +108,23 @@ def _systemd_is_active(unit: str) -> bool:
return False
def _systemd_toggle(unit: str) -> None:
def _systemd_toggle(unit: str) -> tuple[str, bool, str]:
"""Start or stop a systemd unit. Returns (action, success, error_message)."""
active = _systemd_is_active(unit)
action = "stop" if active else "start"
try:
subprocess.run(
["systemctl", "--user", "stop" if active else "start", unit],
result = subprocess.run(
["systemctl", "--user", action, unit],
capture_output=True,
text=True,
timeout=10,
)
except Exception:
pass
if result.returncode == 0:
return action, True, ""
msg = (result.stderr.strip() or result.stdout.strip()).splitlines()[0] if (result.stderr or result.stdout) else "unknown error"
return action, False, msg
except Exception as e:
return action, False, str(e)
def _check_char() -> tuple[str, dict[str, str]]:
@ -197,8 +205,11 @@ class SpeechDevTray(DevServiceTray):
return ("running" if active else "stopped"), labels
def _toggle_speech(self) -> None:
fr.record("tray.toggle_speech", "Speech service toggled")
_systemd_toggle(SPEECH_UNIT)
action, ok, err = _systemd_toggle(SPEECH_UNIT)
if ok:
fr.record(f"tray.speech.{action}ed", f"Speech service {action}ped", {"unit": SPEECH_UNIT})
else:
fr.record("tray.speech.error", f"Failed to {action} speech service", {"unit": SPEECH_UNIT, "error": err})
self.set_status_labels(self.get_status_labels())
def _toggle_mic(self) -> None:
@ -277,11 +288,6 @@ class FaceDevTray(DevServiceTray):
_send_command("toggle_gaze")
self.set_status_labels(self.get_status_labels())
def _toggle_gaze(self) -> None:
fr.record("tray.toggle_gaze", "Godot gaze mode toggled")
_send_command("toggle_gaze")
self.set_status_labels(self.get_status_labels())
def _toggle_gaze_halo(self) -> None:
fr.record("tray.toggle_gaze_halo", "Gaze halo toggled")
_send_command("toggle_gaze_halo")