155 lines
4.2 KiB
Python
155 lines
4.2 KiB
Python
import copy
|
|
from typing import TYPE_CHECKING, cast
|
|
|
|
from archinstall.lib.menu.menu_helper import MenuHelper
|
|
from archinstall.tui.curses_menu import SelectMenu
|
|
from archinstall.tui.menu_item import MenuItem, MenuItemGroup
|
|
from archinstall.tui.result import ResultType
|
|
from archinstall.tui.types import Alignment
|
|
|
|
if TYPE_CHECKING:
|
|
from collections.abc import Callable
|
|
|
|
from archinstall.lib.translationhandler import DeferredTranslation
|
|
|
|
_: Callable[[str], DeferredTranslation]
|
|
|
|
|
|
class ListManager[ValueT]:
|
|
def __init__(
|
|
self,
|
|
entries: list[ValueT],
|
|
base_actions: list[str],
|
|
sub_menu_actions: list[str],
|
|
prompt: str | None = None
|
|
):
|
|
"""
|
|
:param prompt: Text which will appear at the header
|
|
type param: string | DeferredTranslation
|
|
|
|
:param entries: list/dict of option to be shown / manipulated
|
|
type param: list
|
|
|
|
:param base_actions: list of actions that is displayed in the main list manager,
|
|
usually global actions such as 'Add...'
|
|
type param: list
|
|
|
|
:param sub_menu_actions: list of actions available for a chosen entry
|
|
type param: list
|
|
"""
|
|
self._original_data = copy.deepcopy(entries)
|
|
self._data = copy.deepcopy(entries)
|
|
|
|
self._prompt = prompt
|
|
|
|
self._separator = ''
|
|
self._confirm_action = str(_('Confirm and exit'))
|
|
self._cancel_action = str(_('Cancel'))
|
|
|
|
self._terminate_actions = [self._confirm_action, self._cancel_action]
|
|
self._base_actions = base_actions
|
|
self._sub_menu_actions = sub_menu_actions
|
|
|
|
self._last_choice: ValueT | str | None = None
|
|
|
|
@property
|
|
def last_choice(self) -> ValueT | str | None:
|
|
return self._last_choice
|
|
|
|
def is_last_choice_cancel(self) -> bool:
|
|
if self._last_choice is not None:
|
|
return self._last_choice == self._cancel_action
|
|
return False
|
|
|
|
def run(self) -> list[ValueT]:
|
|
additional_options = self._base_actions + self._terminate_actions
|
|
|
|
while True:
|
|
group = MenuHelper(
|
|
data=self._data,
|
|
additional_options=additional_options
|
|
).create_menu_group()
|
|
|
|
prompt = None
|
|
if self._prompt is not None:
|
|
prompt = f'{self._prompt}\n\n'
|
|
|
|
prompt = None
|
|
|
|
result = SelectMenu[ValueT | str](
|
|
group,
|
|
header=prompt,
|
|
search_enabled=False,
|
|
allow_skip=False,
|
|
alignment=Alignment.CENTER
|
|
).run()
|
|
|
|
match result.type_:
|
|
case ResultType.Selection:
|
|
value = result.get_value()
|
|
case _:
|
|
raise ValueError('Unhandled return type')
|
|
|
|
if value in self._base_actions:
|
|
value = cast(str, value)
|
|
self._data = self.handle_action(value, None, self._data)
|
|
elif value in self._terminate_actions:
|
|
break
|
|
else: # an entry of the existing selection was chosen
|
|
selected_entry = result.get_value()
|
|
selected_entry = cast(ValueT, selected_entry)
|
|
|
|
self._run_actions_on_entry(selected_entry)
|
|
|
|
self._last_choice = value
|
|
|
|
if result.get_value() == self._cancel_action:
|
|
return self._original_data # return the original list
|
|
else:
|
|
return self._data
|
|
|
|
def _run_actions_on_entry(self, entry: ValueT) -> None:
|
|
options = self.filter_options(entry, self._sub_menu_actions) + [self._cancel_action]
|
|
|
|
items = [MenuItem(o, value=o) for o in options]
|
|
group = MenuItemGroup(items, sort_items=False)
|
|
|
|
header = f'{self.selected_action_display(entry)}\n'
|
|
|
|
result = SelectMenu[str](
|
|
group,
|
|
header=header,
|
|
search_enabled=False,
|
|
allow_skip=False,
|
|
alignment=Alignment.CENTER
|
|
).run()
|
|
|
|
match result.type_:
|
|
case ResultType.Selection:
|
|
value = result.get_value()
|
|
case _:
|
|
raise ValueError('Unhandled return type')
|
|
|
|
if value != self._cancel_action:
|
|
self._data = self.handle_action(value, entry, self._data)
|
|
|
|
def selected_action_display(self, selection: ValueT) -> str:
|
|
"""
|
|
this will return the value to be displayed in the
|
|
"Select an action for '{}'" string
|
|
"""
|
|
raise NotImplementedError('Please implement me in the child class')
|
|
|
|
def handle_action(self, action: str, entry: ValueT | None, data: list[ValueT]) -> list[ValueT]:
|
|
"""
|
|
this function is called when a base action or
|
|
a specific action for an entry is triggered
|
|
"""
|
|
raise NotImplementedError('Please implement me in the child class')
|
|
|
|
def filter_options(self, selection: ValueT, options: list[str]) -> list[str]:
|
|
"""
|
|
filter which actions to show for an specific selection
|
|
"""
|
|
return options
|