from typing import TYPE_CHECKING from trezor import io, log, loop, ui, wire, workflow from trezor.enums import ButtonRequestType import trezorui2 from ..components.common.confirm import is_confirmed from .common import interact if TYPE_CHECKING: from typing import Any, NoReturn, Type ExceptionType = BaseException | Type[BaseException] class _RustLayout(ui.Layout): # pylint: disable=super-init-not-called def __init__(self, layout: Any): self.layout = layout self.timer = loop.Timer() def set_timer(self, token: int, deadline: int) -> None: self.timer.schedule(deadline, token) def create_tasks(self) -> tuple[loop.Task, ...]: return self.handle_timers(), self.handle_input_and_rendering() def handle_input_and_rendering(self) -> loop.Task: # type: ignore [awaitable-is-generator] button = loop.wait(io.BUTTON) ui.display.clear() self.layout.attach_timer_fn(self.set_timer) self.layout.paint() while True: # Using `yield` instead of `await` to avoid allocations. event, button_num = yield button workflow.idle_timer.touch() msg = None if event in (io.BUTTON_PRESSED, io.BUTTON_RELEASED): msg = self.layout.button_event(event, button_num) self.layout.paint() if msg is not None: raise ui.Result(msg) def handle_timers(self) -> loop.Task: # type: ignore [awaitable-is-generator] while True: # Using `yield` instead of `await` to avoid allocations. token = yield self.timer msg = self.layout.timer(token) self.layout.paint() if msg is not None: raise ui.Result(msg) async def confirm_action( ctx: wire.GenericContext, br_type: str, title: str, action: str | None = None, description: str | None = None, description_param: str | None = None, description_param_font: int = ui.BOLD, verb: str | bytes | None = "OK", verb_cancel: str | bytes | None = "cancel", hold: bool = False, reverse: bool = False, exc: ExceptionType = wire.ActionCancelled, br_code: ButtonRequestType = ButtonRequestType.Other, ) -> None: if isinstance(verb, bytes) or isinstance(verb_cancel, bytes): raise NotImplementedError if description is not None and description_param is not None: if description_param_font != ui.BOLD: log.error(__name__, "confirm_action description_param_font not implemented") description = description.format(description_param) if hold: log.error(__name__, "confirm_action hold not implemented") result = await interact( ctx, _RustLayout( trezorui2.confirm_action( title=title.upper(), action=action, description=description, verb=verb, verb_cancel=verb_cancel, hold=hold, reverse=reverse, ) ), br_type, br_code, ) if not is_confirmed(result): raise exc async def confirm_text( ctx: wire.GenericContext, br_type: str, title: str, data: str, description: str | None = None, br_code: ButtonRequestType = ButtonRequestType.Other, ) -> None: result = await interact( ctx, _RustLayout( trezorui2.confirm_text( title=title.upper(), data=data, description=description, ) ), br_type, br_code, ) if not is_confirmed(result): raise wire.ActionCancelled async def show_error_and_raise( ctx: wire.GenericContext, br_type: str, content: str, subheader: str | None = None, button: str = "Close", exc: ExceptionType = wire.ActionCancelled, ) -> NoReturn: raise NotImplementedError async def show_popup( title: str, description: str, subtitle: str | None = None, description_param: str = "", timeout_ms: int = 3000, ) -> None: raise NotImplementedError