UiDispatcher
def UiDispatcher(
root
):Dispatches callbacks from background threads to Tkinter’s main thread, ensuring UI updates are executed safely through the root event loop.
Show the current-session report when report data is available.
Show the last-session report when report data is available.
Start the tray integration and block in the Tkinter event loop until exit.
root = tk.Tk() runs at module-import time. This creates a GUI object as an import side effect and will also fail in headless environments. Confirm that import-time Tk initialization is intentional.
The report helpers call show_report from new daemon threads. This appears inconsistent with the project rule that Tkinter UI operations should run on the Tk main thread, preferably through root.after(...).
After pausing, pause_for calls open_current_session_report(controller). Because pausing ends the current session, confirm whether this should instead display the report for the just-ended session.
Cancelling the custom pause dialog performs no pause. It does not use DEFAULT_PAUSE_MINUTES; confirm whether this is the intended current behaviour.
root is exported as part of the module’s public API because its cell uses #| export. Confirm whether it should remain public or eventually become an internal implementation detail.
The public functions accept an untyped controller. The comments document how it is used, but the implementation does not identify a concrete controller type, so no type annotation has been invented.
The current notebook output shows that the failed pystray import prevented tk from being imported, which caused the later root = tk.Tk() cell to fail with NameError. This is a cascading notebook-execution failure rather than an independent missing import.