archinstall/archinstall/lib/menu/helpers.py

255 lines
6.5 KiB
Python

from collections.abc import Awaitable, Callable
from typing import Any, Literal, override
from textual.validation import ValidationResult, Validator
from archinstall.lib.translationhandler import tr
from archinstall.tui.ui.components import InputScreen, LoadingScreen, NotifyScreen, OptionListScreen, SelectListScreen, TableSelectionScreen
from archinstall.tui.ui.menu_item import MenuItemGroup
from archinstall.tui.ui.result import Result, ResultType
class Selection[ValueT]:
def __init__(
self,
group: MenuItemGroup,
header: str | None = None,
title: str | None = None,
allow_skip: bool = True,
allow_reset: bool = False,
preview_location: Literal['right', 'bottom'] | None = None,
multi: bool = False,
enable_filter: bool = False,
):
self._header = header
self._title = title
self._group: MenuItemGroup = group
self._allow_skip = allow_skip
self._allow_reset = allow_reset
self._preview_location = preview_location
self._multi = multi
self._enable_filter = enable_filter
async def show(self) -> Result[ValueT]:
if self._multi:
result = await SelectListScreen[ValueT](
self._group,
header=self._header,
allow_skip=self._allow_skip,
allow_reset=self._allow_reset,
preview_location=self._preview_location,
enable_filter=self._enable_filter,
).run()
else:
result = await OptionListScreen[ValueT](
self._group,
header=self._header,
title=self._title,
allow_skip=self._allow_skip,
allow_reset=self._allow_reset,
preview_location=self._preview_location,
enable_filter=self._enable_filter,
).run()
if result.type_ == ResultType.Reset:
confirmed = await _confirm_reset()
if confirmed.get_value() is False:
return await self.show()
return result
class Confirmation:
def __init__(
self,
header: str,
group: MenuItemGroup | None = None,
allow_skip: bool = True,
allow_reset: bool = False,
preset: bool = False,
preview_location: Literal['bottom'] | None = None,
preview_header: str | None = None,
):
self._header = header
self._allow_skip = allow_skip
self._allow_reset = allow_reset
self._preset = preset
self._preview_location = preview_location
self._preview_header = preview_header
if not group:
self._group = MenuItemGroup.yes_no()
self._group.set_focus_by_value(preset)
else:
self._group = group
async def show(self) -> Result[bool]:
result = await OptionListScreen[bool](
self._group,
header=self._header,
allow_skip=self._allow_skip,
allow_reset=self._allow_reset,
preview_location=self._preview_location,
enable_filter=False,
).run()
if result.type_ == ResultType.Reset:
confirmed = await _confirm_reset()
if confirmed.get_value() is False:
return await self.show()
return result
class Notify:
def __init__(self, header: str):
self._header = header
async def show(self) -> Result[bool]:
_ = await NotifyScreen(header=self._header).run()
return Result.true()
class GenericValidator(Validator):
def __init__(self, validator_callback: Callable[[str], str | None]) -> None:
super().__init__()
self._validator_callback = validator_callback
@override
def validate(self, value: str) -> ValidationResult:
result = self._validator_callback(value)
if result is not None:
return self.failure(result)
return self.success()
class Input:
def __init__(
self,
header: str | None = None,
placeholder: str | None = None,
password: bool = False,
default_value: str | None = None,
allow_skip: bool = True,
allow_reset: bool = False,
validator_callback: Callable[[str], str | None] | None = None,
):
self._header = header
self._placeholder = placeholder
self._password = password
self._default_value = default_value
self._allow_skip = allow_skip
self._allow_reset = allow_reset
self._validator_callback = validator_callback
async def show(self) -> Result[str]:
validator = GenericValidator(self._validator_callback) if self._validator_callback else None
result = await InputScreen(
header=self._header,
placeholder=self._placeholder,
password=self._password,
default_value=self._default_value,
allow_skip=self._allow_skip,
allow_reset=self._allow_reset,
validator=validator,
).run()
if result.type_ == ResultType.Reset:
confirmed = await _confirm_reset()
if confirmed.get_value() is False:
return await self.show()
return result
class Loading[ValueT]:
def __init__(
self,
header: str | None = None,
timer: int = 3,
data_callback: Callable[[], Any] | None = None,
):
self._header = header
self._timer = timer
self._data_callback = data_callback
async def show(self) -> Result[ValueT]:
if self._data_callback:
result = await LoadingScreen[ValueT](
header=self._header,
data_callback=self._data_callback,
).run()
return result
else:
_ = await LoadingScreen(
timer=self._timer,
header=self._header,
).run()
return Result.true()
class Table[ValueT]:
def __init__(
self,
header: str | None = None,
group: MenuItemGroup | None = None,
group_callback: Callable[[], Awaitable[MenuItemGroup]] | None = None,
presets: list[ValueT] | None = None,
allow_reset: bool = False,
allow_skip: bool = False,
loading_header: str | None = None,
multi: bool = False,
preview_location: Literal['bottom'] | None = None,
preview_header: str | None = None,
):
self._header = header
self._group = group
self._data_callback = group_callback
self._loading_header = loading_header
self._allow_skip = allow_skip
self._allow_reset = allow_reset
self._multi = multi
self._presets = presets
self._preview_location = preview_location
self._preview_header = preview_header
if self._group is None and self._data_callback is None:
raise ValueError('Either data or data_callback must be provided')
async def show(self) -> Result[ValueT]:
result = await TableSelectionScreen[ValueT](
header=self._header,
group=self._group,
group_callback=self._data_callback,
allow_skip=self._allow_skip,
allow_reset=self._allow_reset,
loading_header=self._loading_header,
multi=self._multi,
preview_location=self._preview_location,
preview_header=self._preview_header,
).run()
if result.type_ == ResultType.Reset:
confirmed = await _confirm_reset()
if confirmed.get_value() is False:
return await self.show()
return result
async def _confirm_reset() -> Result[bool]:
return await OptionListScreen[bool](
MenuItemGroup.yes_no(),
header=tr('Are you sure you want to reset this setting?'),
allow_skip=False,
allow_reset=False,
).run()