@@ -587,7 +587,8 @@ def read_state():
587587 with open (STATE_FILE , "r" ) as f :
588588 state = f .read ().strip ()
589589 if state in ("recording" , "transcribing" , "diarizing" , "preparing" ,
590- "diarize-ready" , "switching" , "offline" ):
590+ "diarize-ready" , "switching" , "offline" ,
591+ "meeting-ui-open" , "meeting-recording" ):
591592 return state
592593 if state in ("cancelled" , "idle" ):
593594 return "idle"
@@ -596,6 +597,47 @@ def read_state():
596597 return None
597598
598599
600+ def _read_version ():
601+ """Return the version of the tray code that is actually running.
602+
603+ In a source checkout (dev: /usr/bin/dictee-tray is symlinked into the
604+ repo), resolve the symlink and read Cargo.toml + the current git short
605+ hash, so the About reflects the exact code running — not a previously
606+ installed package. In a real install, fall back to the
607+ /usr/share/dictee/VERSION file shipped by every package target.
608+ """
609+ real_dir = os .path .dirname (os .path .realpath (__file__ ))
610+ cargo = os .path .join (real_dir , "Cargo.toml" )
611+ if os .path .isfile (cargo ):
612+ ver = None
613+ try :
614+ with open (cargo ) as cf :
615+ for line in cf :
616+ if line .startswith ("version" ):
617+ ver = line .split ("=" , 1 )[1 ].strip ().strip ('"' )
618+ break
619+ except OSError :
620+ pass
621+ if ver :
622+ try :
623+ out = subprocess .run (
624+ ["git" , "-C" , real_dir , "rev-parse" , "--short" , "HEAD" ],
625+ capture_output = True , text = True , timeout = 2 ,
626+ ).stdout .strip ()
627+ return f"{ ver } (dev { out } )" if out else f"{ ver } (dev)"
628+ except Exception :
629+ return f"{ ver } (dev)"
630+ for vpath in ("/usr/share/dictee/VERSION" ,
631+ os .path .join (real_dir , "VERSION" )):
632+ if os .path .isfile (vpath ):
633+ try :
634+ with open (vpath ) as vf :
635+ return vf .read ().strip ()
636+ except OSError :
637+ pass
638+ return "dev"
639+
640+
599641def _detect_backend ():
600642 """Détecte le backend à utiliser : 'appindicator' ou 'qt'."""
601643 desktop = os .environ .get ("XDG_CURRENT_DESKTOP" , "" ).upper ()
@@ -793,6 +835,10 @@ def _build_menu(self):
793835 item_reset .connect ("activate" , lambda _ : self ._reset ())
794836 self .menu .append (item_reset )
795837
838+ item_about = Gtk .MenuItem (label = _ ("About Dictée" ))
839+ item_about .connect ("activate" , lambda _ : self ._show_about_gtk ())
840+ self .menu .append (item_about )
841+
796842 item_quit = Gtk .MenuItem (label = _ ("Quit icon" ))
797843 item_quit .connect ("activate" , lambda _ : self .Gtk .main_quit ())
798844 self .menu .append (item_quit )
@@ -1022,6 +1068,19 @@ def _on_force_cpu_toggled_gtk(self, item):
10221068
10231069 def _delayed_daemon_refresh (self ):
10241070 self ._check_daemon ()
1071+
1072+ def _show_about_gtk (self ):
1073+ ver = _read_version ()
1074+ dialog = self .Gtk .AboutDialog ()
1075+ dialog .set_program_name ("Dictée" )
1076+ dialog .set_version (ver )
1077+ dialog .set_comments (
1078+ _ ("Voice dictation for Linux (Parakeet / Vosk / Whisper)." ))
1079+ dialog .set_website ("https://github.com/rcspam/dictee" )
1080+ dialog .set_website_label ("github.com/rcspam/dictee" )
1081+ dialog .set_copyright ("© rcspam" )
1082+ dialog .run ()
1083+ dialog .destroy ()
10251084 self ._check_state ()
10261085 self ._apply_state ()
10271086 return False # one-shot
@@ -1236,6 +1295,7 @@ def _build_menu(self, QFont):
12361295 self .action_setup = self .menu .addAction (_ ("Configure Dictée" ))
12371296 self .menu .addSeparator ()
12381297 self .action_reset = self .menu .addAction (_ ("! Reset" ))
1298+ self .action_about = self .menu .addAction (_ ("About Dictée" ))
12391299 self .action_quit = self .menu .addAction (_ ("Quit icon" ))
12401300 self .menu .triggered .connect (self ._on_menu_triggered )
12411301 # Refresh toggles from dictee.conf each time the menu is about to show,
@@ -1281,9 +1341,25 @@ def _on_menu_triggered(self, action):
12811341 _spawn_detached (["dictee-setup" ])
12821342 elif action == self .action_reset :
12831343 self ._reset ()
1344+ elif action == self .action_about :
1345+ self ._show_about ()
12841346 elif action == self .action_quit :
12851347 self .app .quit ()
12861348
1349+ def _show_about (self ):
1350+ from PyQt6 .QtWidgets import QMessageBox
1351+ ver = _read_version ()
1352+ QMessageBox .about (
1353+ None ,
1354+ _ ("About Dictée" ),
1355+ _ ("<b>Dictée</b> {ver}<br><br>"
1356+ "Voice dictation for Linux "
1357+ "(Parakeet / Vosk / Whisper).<br>"
1358+ "<a href='https://github.com/rcspam/dictee'>"
1359+ "github.com/rcspam/dictee</a><br><br>"
1360+ "Maintained by rcspam." ).format (ver = ver ),
1361+ )
1362+
12871363 def _on_activated (self , reason ):
12881364 if reason == self .QSystemTrayIcon .ActivationReason .Trigger :
12891365 modifiers = self .QApplication .keyboardModifiers ()
0 commit comments