from __future__ import annotations import gi gi.require_version("Gtk", "3.0") from gi.repository import GLib, Gtk from pathlib import Path class Tray: def __init__(self, state_getter, on_quit): self.state_getter = state_getter self.on_quit = on_quit self.base = Path(__file__).parent / "assets" self.icon = Gtk.StatusIcon() self.icon.set_visible(True) self.icon.connect("popup-menu", self._on_menu) self.menu = Gtk.Menu() quit_item = Gtk.MenuItem(label="Quit") quit_item.connect("activate", lambda *_: self.on_quit()) self.menu.append(quit_item) self.menu.show_all() def _on_menu(self, _icon, _button, _time): self.menu.popup(None, None, None, None, 0, _time) def _icon_path(self, state: str) -> str: if state == "recording": return str(self.base / "recording.png") if state == "stt": return str(self.base / "transcribing.png") if state == "processing": return str(self.base / "processing.png") return str(self.base / "idle.png") def _title(self, state: str) -> str: if state == "recording": return "Recording" if state == "stt": return "STT" if state == "processing": return "AI Processing" return "Idle" def update(self): state = self.state_getter() self.icon.set_from_file(self._icon_path(state)) self.icon.set_tooltip_text(self._title(state)) return True def run_tray(state_getter, on_quit, on_settings): tray = Tray(state_getter, on_quit) tray.update() GLib.timeout_add(250, tray.update) if on_settings: settings_item = Gtk.MenuItem(label="Settings") settings_item.connect("activate", lambda *_: on_settings()) tray.menu.prepend(settings_item) tray.menu.show_all() Gtk.main()