diff options
| author | historia <historiavg@proton.me> | 2026-08-25 19:03:09 -0400 |
|---|---|---|
| committer | historia <historiavg@proton.me> | 2026-08-25 19:03:09 -0400 |
| commit | 8c9a782dfe94525dc5f0893c98fd19543648264b (patch) | |
| tree | fdff70d967ef06f0da560ca284842427cbe647a8 /app/ui | |
| parent | 64e9940d43fad1bc5908b39673b03e4fdc1e8f2f (diff) | |
| download | tts-audiobook-generator-8c9a782dfe94525dc5f0893c98fd19543648264b.tar.gz | |
fix: tui errors wait for getch()
Diffstat (limited to 'app/ui')
| -rw-r--r-- | app/ui/hub.py | 26 | ||||
| -rw-r--r-- | app/ui/runview.py | 3 | ||||
| -rw-r--r-- | app/ui/taskview.py | 6 | ||||
| -rw-r--r-- | app/ui/tui.py | 32 |
4 files changed, 48 insertions, 19 deletions
diff --git a/app/ui/hub.py b/app/ui/hub.py index d20b28e..c1f5dce 100644 --- a/app/ui/hub.py +++ b/app/ui/hub.py @@ -237,20 +237,32 @@ class _Hub: back to the menu that launched it. A crash flashes and does the same. """ def screen(): - try: - info.setup_screen(self.stdscr) - except tui.WizardCancelled: - pass - except Exception as exc: # noqa: BLE001 - keep the hub alive - tui.flash(self.stdscr, str(exc), "err") + self._run_setup(info) return tui.Wizard.BACK return screen + def _run_setup(self, info) -> None: + """Run one backend's setup wizard on this session (no stack frame).""" + try: + info.setup_screen(self.stdscr) + except tui.WizardCancelled: + pass + except Exception as exc: # noqa: BLE001 - keep the hub alive + tui.flash(self.stdscr, str(exc), "err") + def screen_install(self): + """Pick a backend to install and run its setup inline. + + The setup is not pushed as a stack frame: when it finishes this + screen returns BACK, popping straight past the picker to the + Configure menu, whose status table re-detects the new install. + Esc on the picker still pops back one screen normally. + """ info = self._pick_backend(installed_only=False) if info is None: return tui.Wizard.BACK - return self.screen_setup(info) + self._run_setup(info) + return tui.Wizard.BACK def screen_uninstall(self): """Pick a backend, confirm, then uninstall it inside the task view. diff --git a/app/ui/runview.py b/app/ui/runview.py index f016922..d49d949 100644 --- a/app/ui/runview.py +++ b/app/ui/runview.py @@ -301,6 +301,9 @@ class RunView: finally: self._monitor_stop.set() self._cancel.set() + # Leave the screen blocking again: the timed redraw getch must + # not make later hub dialogs (e.g. tui.flash) dismiss themselves. + self._blocking() def _get_key(self) -> Optional[int]: """One key from the screen (None on the redraw timeout).""" diff --git a/app/ui/taskview.py b/app/ui/taskview.py index c4fd35e..6708304 100644 --- a/app/ui/taskview.py +++ b/app/ui/taskview.py @@ -349,6 +349,9 @@ class TaskView: return self._result_rc() finally: self._cancel.set() + # Leave the screen blocking again: the timed redraw getch must + # not make later hub dialogs (e.g. tui.flash) dismiss themselves. + self._blocking() def _result_rc(self) -> int: """The exit code for the whole run (cancelled counts as failure).""" @@ -860,6 +863,9 @@ class LanesView: return self._result_rc() finally: self._cancel.set() + # Leave the screen blocking again: the timed redraw getch + # must not make later hub dialogs dismiss themselves. + self._blocking() finally: sys.stdout, sys.stderr = saved_out, saved_err diff --git a/app/ui/tui.py b/app/ui/tui.py index d675946..b1b18f1 100644 --- a/app/ui/tui.py +++ b/app/ui/tui.py @@ -123,17 +123,22 @@ def flash(scr, text: str, kind: str = "warn") -> None: Used by the hub for "not set up yet"-style messages. KIND is a theme key (warn/err/ok/info). The notice itself is the dialog's only content (no "Notice" heading); Esc dismisses it (it does not abort). + A timed-out getch (-1; the screen may still be in a redraw cadence) + is ignored so the notice really waits for a key. """ frame = Frame(scr, "", "Press any key to continue Esc = back") frame.mark(text, frame.theme.get(kind, frame.theme["body"])) frame.cursor = None frame.draw() - try: - key = scr.getch() - except KeyboardInterrupt: - raise WizardCancelled() from None - if key == 3: # Ctrl-C still aborts - raise WizardCancelled() + while True: + try: + key = scr.getch() + except KeyboardInterrupt: + raise WizardCancelled() from None + if key == 3: # Ctrl-C still aborts + raise WizardCancelled() + if key != -1: + return # On screens without typed text, Esc and 'q' mean the same thing: go @@ -581,12 +586,15 @@ class Frame: """Show TEXT on the status line until any key is pressed.""" self.status = (text, kind) self.draw() - try: - key = self.scr.getch() - if key == 3: # Ctrl-C still aborts - raise WizardCancelled() - except KeyboardInterrupt: - raise WizardCancelled() from None + while True: + try: + key = self.scr.getch() + if key == 3: # Ctrl-C still aborts + raise WizardCancelled() + except KeyboardInterrupt: + raise WizardCancelled() from None + if key != -1: + break self.status = None def edit_status(self, prompt: str = "") -> Optional[str]: |
