# -*- coding: utf-8 -*- """ Progress-Dialog (Modal) fuer die TUI. Zeigt einen Fortschrittsbalken mit Cancel-Button waehrend lang laufender Aktionen (z.B. TTS-Generierung). """ from __future__ import annotations from textual.screen import ModalScreen from textual.containers import Vertical from textual.widgets import Static, Button, ProgressBar from textual.app import ComposeResult class ProgressDialog(ModalScreen[bool]): """ Modaler Progress-Dialog. Zeigt Titel, Statustext, Fortschrittsbalken und Cancel-Button. Gibt True zurueck wenn erfolgreich abgeschlossen, False bei Cancel. """ DEFAULT_CSS = """ ProgressDialog { align: center middle; } ProgressDialog > Vertical { width: 64; height: auto; max-height: 14; border: thick $accent; background: $surface; padding: 1 2; } ProgressDialog > Vertical > #progress-title { text-style: bold; margin-bottom: 1; } ProgressDialog > Vertical > #progress-status { margin-bottom: 1; } ProgressDialog > Vertical > ProgressBar { margin-bottom: 1; } ProgressDialog > Vertical > #progress-cancel { width: 100%; } """ def __init__(self, title: str = "Generierung", **kwargs) -> None: super().__init__(**kwargs) self._title = title self._cancelled = False @property def cancelled(self) -> bool: """Ob der Benutzer abgebrochen hat.""" return self._cancelled def compose(self) -> ComposeResult: with Vertical(): yield Static(self._title, id="progress-title") yield Static("[yellow]Wird vorbereitet...[/yellow]", id="progress-status") yield ProgressBar(total=100, show_eta=False, id="progress-bar") yield Button("Abbrechen", variant="warning", id="progress-cancel") def update_progress(self, current: int, total: int, message: str = "") -> None: """Aktualisiert Fortschritt und Status-Text.""" try: bar = self.query_one("#progress-bar", ProgressBar) bar.update(total=total, progress=current) except Exception: pass if message: try: status = self.query_one("#progress-status", Static) pct = int(current / max(total, 1) * 100) status.update(f"[yellow]{message} ({pct}%)[/yellow]") except Exception: pass def finish(self, message: str = "Fertig!") -> None: """Zeigt Abschluss-Nachricht und schliesst nach kurzer Pause.""" try: status = self.query_one("#progress-status", Static) status.update(f"[green]{message}[/green]") bar = self.query_one("#progress-bar", ProgressBar) bar.update(total=100, progress=100) btn = self.query_one("#progress-cancel", Button) btn.label = "Schliessen" btn.variant = "primary" except Exception: pass def show_error(self, message: str) -> None: """Zeigt Fehlermeldung.""" try: status = self.query_one("#progress-status", Static) status.update(f"[red]{message}[/red]") btn = self.query_one("#progress-cancel", Button) btn.label = "Schliessen" btn.variant = "error" except Exception: pass def on_button_pressed(self, event: Button.Pressed) -> None: """Cancel/Schliessen Button.""" if event.button.id == "progress-cancel": self._cancelled = True self.dismiss(False)