archinstall/archinstall/lib/profile/profile_menu.py

250 lines
7.2 KiB
Python

from __future__ import annotations
from typing import TYPE_CHECKING, Any, override
from archinstall.default_profiles.profile import GreeterType, Profile
from archinstall.tui import Alignment, FrameProperties, MenuItem, MenuItemGroup, Orientation, ResultType, SelectMenu
from ..hardware import GfxDriver
from ..interactions.system_conf import select_driver
from ..menu import AbstractSubMenu
from .profile_model import ProfileConfiguration
if TYPE_CHECKING:
from collections.abc import Callable
from archinstall.lib.translationhandler import DeferredTranslation
_: Callable[[str], DeferredTranslation]
class ProfileMenu(AbstractSubMenu):
def __init__(
self,
preset: ProfileConfiguration | None = None
):
if preset:
self._preset = preset
else:
self._preset = ProfileConfiguration()
self._data_store: dict[str, Any] = {}
menu_optioons = self._define_menu_options()
self._item_group = MenuItemGroup(menu_optioons, checkmarks=True)
super().__init__(self._item_group, data_store=self._data_store, allow_reset=True)
def _define_menu_options(self) -> list[MenuItem]:
return [
MenuItem(
text=str(_('Type')),
action=lambda x: self._select_profile(x),
value=self._preset.profile,
preview_action=self._preview_profile,
key='profile'
),
MenuItem(
text=str(_('Graphics driver')),
action=lambda x: self._select_gfx_driver(x),
value=self._preset.gfx_driver if self._preset.profile and self._preset.profile.is_graphic_driver_supported() else None,
preview_action=self._prev_gfx,
enabled=self._preset.profile.is_graphic_driver_supported() if self._preset.profile else False,
dependencies=['profile'],
key='gfx_driver',
),
MenuItem(
text=str(_('Greeter')),
action=lambda x: select_greeter(preset=x),
value=self._preset.greeter if self._preset.profile and self._preset.profile.is_greeter_supported() else None,
enabled=self._preset.profile.is_graphic_driver_supported() if self._preset.profile else False,
preview_action=self._prev_greeter,
dependencies=['profile'],
key='greeter',
)
]
@override
def run(self) -> ProfileConfiguration | None:
super().run()
if self._data_store.get('profile', None):
return ProfileConfiguration(
self._data_store.get('profile', None),
self._data_store.get('gfx_driver', None),
self._data_store.get('greeter', None),
)
return None
def _select_profile(self, preset: Profile | None) -> Profile | None:
profile = select_profile(preset)
if profile is not None:
if not profile.is_graphic_driver_supported():
self._item_group.find_by_key('gfx_driver').enabled = False
self._item_group.find_by_key('gfx_driver').value = None
else:
self._item_group.find_by_key('gfx_driver').enabled = True
self._item_group.find_by_key('gfx_driver').value = GfxDriver.AllOpenSource
if not profile.is_greeter_supported():
self._item_group.find_by_key('greeter').enabled = False
self._item_group.find_by_key('greeter').value = None
else:
self._item_group.find_by_key('greeter').enabled = True
self._item_group.find_by_key('greeter').value = profile.default_greeter_type
else:
self._item_group.find_by_key('gfx_driver').value = None
self._item_group.find_by_key('greeter').value = None
return profile
def _select_gfx_driver(self, preset: GfxDriver | None = None) -> GfxDriver | None:
driver = preset
profile: Profile | None = self._item_group.find_by_key('profile').value
if profile:
if profile.is_graphic_driver_supported():
driver = select_driver(preset=preset)
if driver and 'Sway' in profile.current_selection_names():
if driver.is_nvidia():
header = str(_('The proprietary Nvidia driver is not supported by Sway.')) + '\n'
header += str(_('It is likely that you will run into issues, are you okay with that?')) + '\n'
group = MenuItemGroup.yes_no()
group.focus_item = MenuItem.no()
group.default_item = MenuItem.no()
result = SelectMenu(
group,
header=header,
allow_skip=False,
columns=2,
orientation=Orientation.HORIZONTAL,
alignment=Alignment.CENTER
).run()
if result.item() == MenuItem.no():
return preset
return driver
def _prev_gfx(self, item: MenuItem) -> str | None:
if item.value:
driver = item.get_value().value
packages = item.get_value().packages_text()
return f'Driver: {driver}\n{packages}'
return None
def _prev_greeter(self, item: MenuItem) -> str | None:
if item.value:
return f'{_("Greeter")}: {item.value.value}'
return None
def _preview_profile(self, item: MenuItem) -> str | None:
profile: Profile | None = item.value
text = ''
if profile:
if (sub_profiles := profile.current_selection) is not None:
text += str(_('Selected profiles: '))
text += ', '.join([p.name for p in sub_profiles]) + '\n'
if packages := profile.packages_text(include_sub_packages=True):
text += f'{packages}'
if text:
return text
return None
def select_greeter(
profile: Profile | None = None,
preset: GreeterType | None = None
) -> GreeterType | None:
if not profile or profile.is_greeter_supported():
items = [MenuItem(greeter.value, value=greeter) for greeter in GreeterType]
group = MenuItemGroup(items, sort_items=True)
default: GreeterType | None = None
if preset is not None:
default = preset
elif profile is not None:
default_greeter = profile.default_greeter_type
default = default_greeter if default_greeter else None
group.set_default_by_value(default)
result = SelectMenu(
group,
allow_skip=True,
frame=FrameProperties.min(str(_('Greeter'))),
alignment=Alignment.CENTER
).run()
match result.type_:
case ResultType.Skip:
return preset
case ResultType.Selection:
return result.get_value()
case ResultType.Reset:
raise ValueError('Unhandled result type')
return None
def select_profile(
current_profile: Profile | None = None,
header: str | None = None,
allow_reset: bool = True,
) -> Profile | None:
from archinstall.lib.profile.profiles_handler import profile_handler
top_level_profiles = profile_handler.get_top_level_profiles()
if header is None:
header = str(_('This is a list of pre-programmed default_profiles')) + '\n'
items = [MenuItem(p.name, value=p) for p in top_level_profiles]
group = MenuItemGroup(items, sort_items=True)
group.set_selected_by_value(current_profile)
result = SelectMenu(
group,
header=header,
allow_reset=allow_reset,
allow_skip=True,
alignment=Alignment.CENTER,
frame=FrameProperties.min(str(_('Main profile')))
).run()
match result.type_:
case ResultType.Reset:
return None
case ResultType.Skip:
return current_profile
case ResultType.Selection:
profile_selection: Profile = result.get_value()
select_result = profile_selection.do_on_select()
if not select_result:
return None
# we're going to reset the currently selected profile(s) to avoid
# any stale data laying around
match select_result:
case select_result.NewSelection:
profile_handler.reset_top_level_profiles(exclude=[profile_selection])
current_profile = profile_selection
case select_result.ResetCurrent:
profile_handler.reset_top_level_profiles()
current_profile = None
case select_result.SameSelection:
pass
return current_profile
return None