Skip to content
Snippets Groups Projects
Commit 3e2b9e40 authored by Mateusz Żebrak's avatar Mateusz Żebrak
Browse files

Allow for no context in Form/FormScreen

parent c8f21976
Branches
No related tags found
2 merge requests!600v1.27.5.21 Release,!558Remove welcome profile from TUIWorld, set TUIWorld profile during CreateProfile wizard instead
...@@ -7,8 +7,9 @@ from queue import Queue ...@@ -7,8 +7,9 @@ from queue import Queue
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING, Any
from clive.__private.core.commands.abc.command import Command from clive.__private.core.commands.abc.command import Command
from clive.__private.core.contextual import ContextT, Contextual from clive.__private.core.contextual import ContextualHolder
from clive.__private.ui.clive_screen import CliveScreen from clive.__private.ui.clive_screen import CliveScreen
from clive.__private.ui.forms.form_context import FormContextT, NoContext
if TYPE_CHECKING: if TYPE_CHECKING:
from clive.__private.ui.forms.form_screen import FormScreenBase from clive.__private.ui.forms.form_screen import FormScreenBase
...@@ -16,38 +17,37 @@ if TYPE_CHECKING: ...@@ -16,38 +17,37 @@ if TYPE_CHECKING:
PostAction = Command | Callable[[], Any] PostAction = Command | Callable[[], Any]
class Form(Contextual[ContextT], CliveScreen[None]): class Form(ContextualHolder[FormContextT], CliveScreen[None]):
MINIMUM_SCREEN_COUNT = 2 # Rationale: it makes no sense to have only one screen in the form MINIMUM_SCREEN_COUNT = 2 # Rationale: it makes no sense to have only one screen in the form
def __init__(self) -> None: def __init__(self) -> None:
self._current_screen_index = 0 self._current_screen_index = 0
self._screen_types: list[type[FormScreenBase[ContextT]]] = [*list(self.compose_form())] self._screen_types: list[type[FormScreenBase[FormContextT]]] = [*list(self.compose_form())]
assert len(self._screen_types) >= self.MINIMUM_SCREEN_COUNT, "Form must have at least 2 screens" assert len(self._screen_types) >= self.MINIMUM_SCREEN_COUNT, "Form must have at least 2 screens"
self._rebuild_context()
self._post_actions = Queue[PostAction]() self._post_actions = Queue[PostAction]()
super().__init__() super().__init__(self._build_context())
@abstractmethod @abstractmethod
def compose_form(self) -> Iterator[type[FormScreenBase[ContextT]]]: def compose_form(self) -> Iterator[type[FormScreenBase[FormContextT]]]:
"""Yield screens types in the order they should be displayed.""" """Yield screens types in the order they should be displayed."""
@abstractmethod
def _rebuild_context(self) -> None:
"""Create brand new fresh context."""
@property @property
def screens_types(self) -> list[type[FormScreenBase[ContextT]]]: def screens_types(self) -> list[type[FormScreenBase[FormContextT]]]:
return self._screen_types return self._screen_types
@property @property
def current_screen_type(self) -> type[FormScreenBase[ContextT]]: def current_screen_type(self) -> type[FormScreenBase[FormContextT]]:
return self._screen_types[self._current_screen_index] return self._screen_types[self._current_screen_index]
def on_mount(self) -> None: async def on_mount(self) -> None:
assert self._current_screen_index == 0 assert self._current_screen_index == 0
await self.initialize()
self._push_current_screen() self._push_current_screen()
async def initialize(self) -> None:
"""Do actions that should be executed before the first form is displayed."""
def next_screen(self) -> None: def next_screen(self) -> None:
if not self._check_valid_range(self._current_screen_index + 1): if not self._check_valid_range(self._current_screen_index + 1):
return return
...@@ -83,6 +83,9 @@ class Form(Contextual[ContextT], CliveScreen[None]): ...@@ -83,6 +83,9 @@ class Form(Contextual[ContextT], CliveScreen[None]):
else: else:
action() action()
def _build_context(self) -> FormContextT:
return NoContext() # type: ignore[return-value]
def _push_current_screen(self) -> None: def _push_current_screen(self) -> None:
self.app.push_screen(self.current_screen_type(self)) self.app.push_screen(self.current_screen_type(self))
......
from __future__ import annotations
from typing_extensions import TypeVar
from clive.__private.core.contextual import Context
class NoContext(Context):
"""A class that signals that there is no context."""
FormContextT = TypeVar("FormContextT", bound=Context, default=NoContext)
...@@ -10,8 +10,9 @@ from textual.message import Message ...@@ -10,8 +10,9 @@ from textual.message import Message
from textual.reactive import var from textual.reactive import var
from clive.__private.core.constants.tui.bindings import NEXT_SCREEN_BINDING_KEY, PREVIOUS_SCREEN_BINDING_KEY from clive.__private.core.constants.tui.bindings import NEXT_SCREEN_BINDING_KEY, PREVIOUS_SCREEN_BINDING_KEY
from clive.__private.core.contextual import ContextT, Contextual from clive.__private.core.contextual import Contextual
from clive.__private.ui.clive_screen import CliveScreen from clive.__private.ui.clive_screen import CliveScreen
from clive.__private.ui.forms.form_context import FormContextT
from clive.__private.ui.forms.navigation_buttons import NextScreenButton, PreviousScreenButton from clive.__private.ui.forms.navigation_buttons import NextScreenButton, PreviousScreenButton
from clive.__private.ui.widgets.inputs.clive_input import CliveInput from clive.__private.ui.widgets.inputs.clive_input import CliveInput
...@@ -22,17 +23,17 @@ if TYPE_CHECKING: ...@@ -22,17 +23,17 @@ if TYPE_CHECKING:
BackScreenModes = Literal["back_to_unlock", "nothing_to_back", "back_to_previous"] BackScreenModes = Literal["back_to_unlock", "nothing_to_back", "back_to_previous"]
class FormScreenBase(CliveScreen, Contextual[ContextT]): class FormScreenBase(CliveScreen, Contextual[FormContextT]):
def __init__(self, owner: Form[ContextT]) -> None: def __init__(self, owner: Form[FormContextT]) -> None:
self._owner = owner self._owner = owner
super().__init__() super().__init__()
@property @property
def context(self) -> ContextT: def context(self) -> FormContextT:
return self._owner.context return self._owner.context
class FormScreen(FormScreenBase[ContextT], ABC): class FormScreen(FormScreenBase[FormContextT], ABC):
BINDINGS = [ BINDINGS = [
Binding("escape", "previous_screen", "Previous screen", show=False), Binding("escape", "previous_screen", "Previous screen", show=False),
Binding(NEXT_SCREEN_BINDING_KEY, "next_screen", "Next screen"), Binding(NEXT_SCREEN_BINDING_KEY, "next_screen", "Next screen"),
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment