Coverage for src / lilbee / cli / tui / widgets / confirm_dialog.py: 100%

27 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-04-29 19:16 +0000

1"""Reusable confirmation modal dialog.""" 

2 

3from __future__ import annotations 

4 

5from typing import ClassVar 

6 

7from textual.app import ComposeResult 

8from textual.binding import Binding, BindingType 

9from textual.containers import Center, Vertical 

10from textual.screen import ModalScreen 

11from textual.widgets import Button, Label, Static 

12 

13 

14class ConfirmDialog(ModalScreen[bool]): 

15 """Modal yes/no dialog that returns True (confirmed) or False (cancelled).""" 

16 

17 CSS_PATH = "confirm_dialog.tcss" 

18 

19 BINDINGS: ClassVar[list[BindingType]] = [ 

20 Binding("y", "confirm", "Yes", show=True), 

21 Binding("enter", "confirm", "Confirm", show=False), 

22 Binding("n", "cancel", "No", show=True), 

23 Binding("escape", "cancel", "Cancel", show=False), 

24 ] 

25 

26 def __init__(self, title: str, message: str) -> None: 

27 super().__init__() 

28 self._title = title 

29 self._message = message 

30 

31 def compose(self) -> ComposeResult: 

32 with Vertical(): 

33 yield Static(self._title, id="confirm-title") 

34 yield Label(self._message, id="confirm-message") 

35 with Center(): 

36 yield Button("Yes (y)", variant="error", id="confirm-yes") 

37 yield Button("No (n)", variant="default", id="confirm-no") 

38 

39 def on_button_pressed(self, event: Button.Pressed) -> None: 

40 self.dismiss(event.button.id == "confirm-yes") 

41 

42 def action_confirm(self) -> None: 

43 self.dismiss(True) 

44 

45 def action_cancel(self) -> None: 

46 self.dismiss(False)