diff --git a/core/embed/projects/firmware/mpconfigport.h b/core/embed/projects/firmware/mpconfigport.h index 0df34659e5..913f44ca39 100644 --- a/core/embed/projects/firmware/mpconfigport.h +++ b/core/embed/projects/firmware/mpconfigport.h @@ -165,6 +165,7 @@ #define MICROPY_PY_TREZORPROTO (1) #define MICROPY_PY_TREZORTRANSLATE (1) #define MICROPY_PY_TREZORUI2 (1) +#define MICROPY_PY_TREZORUI_API (1) #ifdef SYSTEM_VIEW #define MP_PLAT_PRINT_STRN(str, len) segger_print(str, len) diff --git a/core/embed/projects/unix/mpconfigport.h b/core/embed/projects/unix/mpconfigport.h index 2cc4b7d9e7..2d6e0db741 100644 --- a/core/embed/projects/unix/mpconfigport.h +++ b/core/embed/projects/unix/mpconfigport.h @@ -214,6 +214,7 @@ extern const struct _mp_print_t mp_stderr_print; #define MICROPY_PY_TREZORPROTO (1) #define MICROPY_PY_TREZORTRANSLATE (1) #define MICROPY_PY_TREZORUI2 (1) +#define MICROPY_PY_TREZORUI_API (1) #define MP_STATE_PORT MP_STATE_VM diff --git a/core/embed/rust/librust.h b/core/embed/rust/librust.h index 590840067b..d6432e7803 100644 --- a/core/embed/rust/librust.h +++ b/core/embed/rust/librust.h @@ -9,6 +9,7 @@ mp_obj_t protobuf_debug_msg_def_type(); extern mp_obj_module_t mp_module_trezorproto; extern mp_obj_module_t mp_module_trezorui2; +extern mp_obj_module_t mp_module_trezorui_api; extern mp_obj_module_t mp_module_trezortranslate; #ifdef TREZOR_EMULATOR diff --git a/core/embed/rust/librust_qstr.h b/core/embed/rust/librust_qstr.h index 2d3a3f54d7..c93786615d 100644 --- a/core/embed/rust/librust_qstr.h +++ b/core/embed/rust/librust_qstr.h @@ -701,6 +701,7 @@ static void _librust_qstrs(void) { MP_QSTR_trace; MP_QSTR_trezorproto; MP_QSTR_trezorui2; + MP_QSTR_trezorui_api; MP_QSTR_tutorial; MP_QSTR_tutorial__continue; MP_QSTR_tutorial__did_you_know; diff --git a/core/embed/rust/src/ui/api/firmware_upy.rs b/core/embed/rust/src/ui/api/firmware_upy.rs new file mode 100644 index 0000000000..c253a23786 --- /dev/null +++ b/core/embed/rust/src/ui/api/firmware_upy.rs @@ -0,0 +1,133 @@ +use crate::micropython::map::Map; +use crate::ui::layout::obj::ATTACH_TYPE_OBJ; +use crate::ui::layout::base::LAYOUT_STATE; +use crate::ui::backlight::BACKLIGHT_LEVELS_OBJ; +use crate::{ + micropython::{macros::obj_module, module::Module, qstr::Qstr}, + ui::layout::result::{CANCELLED, CONFIRMED, INFO}, +}; + +#[no_mangle] +pub static mp_module_trezorui_api: Module = obj_module! { + /// from trezor import utils + /// + /// T = TypeVar("T") + /// + /// class LayoutObj(Generic[T]): + /// """Representation of a Rust-based layout object. + /// see `trezor::ui::layout::obj::LayoutObj`. + /// """ + /// + /// def attach_timer_fn(self, fn: Callable[[int, int], None], attach_type: AttachType | None) -> LayoutState | None: + /// """Attach a timer setter function. + /// + /// The layout object can call the timer setter with two arguments, + /// `token` and `duration_ms`. When `duration_ms` elapses, the layout object + /// expects a callback to `self.timer(token)`. + /// """ + /// + /// if utils.USE_TOUCH: + /// def touch_event(self, event: int, x: int, y: int) -> LayoutState | None: + /// """Receive a touch event `event` at coordinates `x`, `y`.""" + /// + /// if utils.USE_BUTTON: + /// def button_event(self, event: int, button: int) -> LayoutState | None: + /// """Receive a button event `event` for button `button`.""" + /// + /// def progress_event(self, value: int, description: str) -> LayoutState | None: + /// """Receive a progress event.""" + /// + /// def usb_event(self, connected: bool) -> LayoutState | None: + /// """Receive a USB connect/disconnect event.""" + /// + /// def timer(self, token: int) -> LayoutState | None: + /// """Callback for the timer set by `attach_timer_fn`. + /// + /// This function should be called by the executor after the corresponding + /// duration elapses. + /// """ + /// + /// def paint(self) -> bool: + /// """Paint the layout object on screen. + /// + /// Will only paint updated parts of the layout as required. + /// Returns True if any painting actually happened. + /// """ + /// + /// def request_complete_repaint(self) -> None: + /// """Request a complete repaint of the screen. + /// + /// Does not repaint the screen, a subsequent call to `paint()` is required. + /// """ + /// + /// if __debug__: + /// def trace(self, tracer: Callable[[str], None]) -> None: + /// """Generate a JSON trace of the layout object. + /// + /// The JSON can be emitted as a sequence of calls to `tracer`, each of + /// which is not necessarily a valid JSON chunk. The caller must + /// reassemble the chunks to get a sensible result. + /// """ + /// + /// def bounds(self) -> None: + /// """Paint bounds of individual components on screen.""" + /// + /// def page_count(self) -> int: + /// """Return the number of pages in the layout object.""" + /// + /// def button_request(self) -> tuple[int, str] | None: + /// """Return (code, type) of button request made during the last event or timer pass.""" + /// + /// def get_transition_out(self) -> AttachType: + /// """Return the transition type.""" + /// + /// def return_value(self) -> T: + /// """Retrieve the return value of the layout object.""" + /// + /// def __del__(self) -> None: + /// """Calls drop on contents of the root component.""" + /// + /// class UiResult: + /// """Result of a UI operation.""" + /// pass + /// + /// mock:global + Qstr::MP_QSTR___name__ => Qstr::MP_QSTR_trezorui_api.to_obj(), + + /// CONFIRMED: UiResult + Qstr::MP_QSTR_CONFIRMED => CONFIRMED.as_obj(), + + /// CANCELLED: UiResult + Qstr::MP_QSTR_CANCELLED => CANCELLED.as_obj(), + + /// INFO: UiResult + Qstr::MP_QSTR_INFO => INFO.as_obj(), + + /// class BacklightLevels: + /// """Backlight levels. Values dynamically update based on user settings.""" + /// MAX: ClassVar[int] + /// NORMAL: ClassVar[int] + /// LOW: ClassVar[int] + /// DIM: ClassVar[int] + /// NONE: ClassVar[int] + /// + /// mock:global + Qstr::MP_QSTR_BacklightLevels => BACKLIGHT_LEVELS_OBJ.as_obj(), + + /// class AttachType: + /// INITIAL: ClassVar[int] + /// RESUME: ClassVar[int] + /// SWIPE_UP: ClassVar[int] + /// SWIPE_DOWN: ClassVar[int] + /// SWIPE_LEFT: ClassVar[int] + /// SWIPE_RIGHT: ClassVar[int] + Qstr::MP_QSTR_AttachType => ATTACH_TYPE_OBJ.as_obj(), + + /// class LayoutState: + /// """Layout state.""" + /// INITIAL: "ClassVar[LayoutState]" + /// ATTACHED: "ClassVar[LayoutState]" + /// TRANSITIONING: "ClassVar[LayoutState]" + /// DONE: "ClassVar[LayoutState]" + Qstr::MP_QSTR_LayoutState => LAYOUT_STATE.as_obj(), +}; diff --git a/core/embed/rust/src/ui/api/mod.rs b/core/embed/rust/src/ui/api/mod.rs index 52ae91db0b..8569a55b7e 100644 --- a/core/embed/rust/src/ui/api/mod.rs +++ b/core/embed/rust/src/ui/api/mod.rs @@ -2,3 +2,6 @@ pub mod common_c; #[cfg(feature = "bootloader")] pub mod bootloader_c; + +#[cfg(feature = "micropython")] +pub mod firmware_upy; diff --git a/core/embed/rust/src/ui/mod.rs b/core/embed/rust/src/ui/mod.rs index 89e0ec2a76..e64bb0eef8 100644 --- a/core/embed/rust/src/ui/mod.rs +++ b/core/embed/rust/src/ui/mod.rs @@ -24,5 +24,7 @@ pub mod model_tr; #[cfg(feature = "model_tt")] pub mod model_tt; pub mod ui_features; +#[cfg(feature = "micropython")] +pub mod ui_features_fw; pub use ui_features::UIFeaturesCommon; diff --git a/core/embed/rust/src/ui/model_mercury/layout.rs b/core/embed/rust/src/ui/model_mercury/layout.rs index 65358ce6c0..fb5e082b78 100644 --- a/core/embed/rust/src/ui/model_mercury/layout.rs +++ b/core/embed/rust/src/ui/model_mercury/layout.rs @@ -1508,16 +1508,10 @@ extern "C" fn new_warning_hi_prio(n_args: usize, args: *const Obj, kwargs: *mut #[no_mangle] pub static mp_module_trezorui2: Module = obj_module! { /// from trezor import utils + /// from trezorui_api import * + /// Qstr::MP_QSTR___name__ => Qstr::MP_QSTR_trezorui2.to_obj(), - /// CONFIRMED: UiResult - Qstr::MP_QSTR_CONFIRMED => CONFIRMED.as_obj(), - - /// CANCELLED: UiResult - Qstr::MP_QSTR_CANCELLED => CANCELLED.as_obj(), - - /// INFO: UiResult - Qstr::MP_QSTR_INFO => INFO.as_obj(), /// def disable_animation(disable: bool) -> None: /// """Disable animations, debug builds only.""" @@ -2021,33 +2015,5 @@ pub static mp_module_trezorui2: Module = obj_module! { /// cancel_text: str | None = None, /// ) -> LayoutObj[UiResult]: /// """Total summary and hold to confirm.""" - Qstr::MP_QSTR_flow_confirm_summary => obj_fn_kw!(0, new_confirm_summary).as_obj(), - - /// class BacklightLevels: - /// """Backlight levels. Values dynamically update based on user settings.""" - /// MAX: ClassVar[int] - /// NORMAL: ClassVar[int] - /// LOW: ClassVar[int] - /// DIM: ClassVar[int] - /// NONE: ClassVar[int] - /// - /// mock:global - Qstr::MP_QSTR_BacklightLevels => BACKLIGHT_LEVELS_OBJ.as_obj(), - - /// class AttachType: - /// INITIAL: ClassVar[int] - /// RESUME: ClassVar[int] - /// SWIPE_UP: ClassVar[int] - /// SWIPE_DOWN: ClassVar[int] - /// SWIPE_LEFT: ClassVar[int] - /// SWIPE_RIGHT: ClassVar[int] - Qstr::MP_QSTR_AttachType => ATTACH_TYPE_OBJ.as_obj(), - - /// class LayoutState: - /// """Layout state.""" - /// INITIAL: "ClassVar[LayoutState]" - /// ATTACHED: "ClassVar[LayoutState]" - /// TRANSITIONING: "ClassVar[LayoutState]" - /// DONE: "ClassVar[LayoutState]" - Qstr::MP_QSTR_LayoutState => LAYOUT_STATE.as_obj(), + Qstr::MP_QSTR_flow_confirm_summary => obj_fn_kw!(0, flow::new_confirm_summary).as_obj(), }; diff --git a/core/embed/rust/src/ui/model_mercury/mod.rs b/core/embed/rust/src/ui/model_mercury/mod.rs index 85dde610d0..79ee10cc90 100644 --- a/core/embed/rust/src/ui/model_mercury/mod.rs +++ b/core/embed/rust/src/ui/model_mercury/mod.rs @@ -13,6 +13,8 @@ pub mod flow; #[cfg(feature = "micropython")] pub mod layout; pub mod screens; +#[cfg(feature = "micropython")] +pub mod ui_features_fw; pub struct ModelMercuryFeatures; diff --git a/core/embed/rust/src/ui/model_tr/layout.rs b/core/embed/rust/src/ui/model_tr/layout.rs index 248eb5b418..91f58bc98c 100644 --- a/core/embed/rust/src/ui/model_tr/layout.rs +++ b/core/embed/rust/src/ui/model_tr/layout.rs @@ -30,7 +30,6 @@ use crate::{ translations::TR, trezorhal::model, ui::{ - backlight::BACKLIGHT_LEVELS_OBJ, component::{ base::Component, connect::Connect, @@ -47,8 +46,7 @@ use crate::{ }, geometry, layout::{ - base::LAYOUT_STATE, - obj::{ComponentMsgObj, LayoutObj, ATTACH_TYPE_OBJ}, + obj::{ComponentMsgObj, LayoutObj}, result::{CANCELLED, CONFIRMED, INFO}, util::{upy_disable_animation, ConfirmBlob, RecoveryType}, }, @@ -1651,17 +1649,11 @@ extern "C" fn new_show_wait_text(message: Obj) -> Obj { #[no_mangle] pub static mp_module_trezorui2: Module = obj_module! { + /// from trezor import utils + /// from trezorui_api import * + /// Qstr::MP_QSTR___name__ => Qstr::MP_QSTR_trezorui2.to_obj(), - /// CONFIRMED: UiResult - Qstr::MP_QSTR_CONFIRMED => CONFIRMED.as_obj(), - - /// CANCELLED: UiResult - Qstr::MP_QSTR_CANCELLED => CANCELLED.as_obj(), - - /// INFO: UiResult - Qstr::MP_QSTR_INFO => INFO.as_obj(), - /// def disable_animation(disable: bool) -> None: /// """Disable animations, debug builds only.""" Qstr::MP_QSTR_disable_animation => obj_fn_1!(upy_disable_animation).as_obj(), @@ -2082,32 +2074,4 @@ pub static mp_module_trezorui2: Module = obj_module! { /// def show_wait_text(message: str, /) -> None: /// """Show single-line text in the middle of the screen.""" Qstr::MP_QSTR_show_wait_text => obj_fn_1!(new_show_wait_text).as_obj(), - - /// class BacklightLevels: - /// """Backlight levels. Values dynamically update based on user settings.""" - /// MAX: ClassVar[int] - /// NORMAL: ClassVar[int] - /// LOW: ClassVar[int] - /// DIM: ClassVar[int] - /// NONE: ClassVar[int] - /// - /// mock:global - Qstr::MP_QSTR_BacklightLevels => BACKLIGHT_LEVELS_OBJ.as_obj(), - - /// class AttachType: - /// INITIAL: ClassVar[int] - /// RESUME: ClassVar[int] - /// SWIPE_UP: ClassVar[int] - /// SWIPE_DOWN: ClassVar[int] - /// SWIPE_LEFT: ClassVar[int] - /// SWIPE_RIGHT: ClassVar[int] - Qstr::MP_QSTR_AttachType => ATTACH_TYPE_OBJ.as_obj(), - - /// class LayoutState: - /// """Layout state.""" - /// INITIAL: "ClassVar[LayoutState]" - /// ATTACHED: "ClassVar[LayoutState]" - /// TRANSITIONING: "ClassVar[LayoutState]" - /// DONE: "ClassVar[LayoutState]" - Qstr::MP_QSTR_LayoutState => LAYOUT_STATE.as_obj(), }; diff --git a/core/embed/rust/src/ui/model_tt/layout.rs b/core/embed/rust/src/ui/model_tt/layout.rs index f37952700f..b0d034faa3 100644 --- a/core/embed/rust/src/ui/model_tt/layout.rs +++ b/core/embed/rust/src/ui/model_tt/layout.rs @@ -30,7 +30,6 @@ use crate::{ translations::TR, trezorhal::model, ui::{ - backlight::BACKLIGHT_LEVELS_OBJ, component::{ base::ComponentExt, connect::Connect, @@ -50,8 +49,7 @@ use crate::{ }, geometry, layout::{ - base::LAYOUT_STATE, - obj::{ComponentMsgObj, LayoutObj, ATTACH_TYPE_OBJ}, + obj::{ComponentMsgObj, LayoutObj}, result::{CANCELLED, CONFIRMED, INFO}, util::{upy_disable_animation, ConfirmBlob, PropsList, RecoveryType}, }, @@ -1653,98 +1651,8 @@ extern "C" fn new_show_wait_text(message: Obj) -> Obj { #[no_mangle] pub static mp_module_trezorui2: Module = obj_module! { /// from trezor import utils + /// from trezorui_api import * /// - /// T = TypeVar("T") - /// - /// class LayoutObj(Generic[T]): - /// """Representation of a Rust-based layout object. - /// see `trezor::ui::layout::obj::LayoutObj`. - /// """ - /// - /// def attach_timer_fn(self, fn: Callable[[int, int], None], attach_type: AttachType | None) -> LayoutState | None: - /// """Attach a timer setter function. - /// - /// The layout object can call the timer setter with two arguments, - /// `token` and `duration_ms`. When `duration_ms` elapses, the layout object - /// expects a callback to `self.timer(token)`. - /// """ - /// - /// if utils.USE_TOUCH: - /// def touch_event(self, event: int, x: int, y: int) -> LayoutState | None: - /// """Receive a touch event `event` at coordinates `x`, `y`.""" - /// - /// if utils.USE_BUTTON: - /// def button_event(self, event: int, button: int) -> LayoutState | None: - /// """Receive a button event `event` for button `button`.""" - /// - /// def progress_event(self, value: int, description: str) -> LayoutState | None: - /// """Receive a progress event.""" - /// - /// def usb_event(self, connected: bool) -> LayoutState | None: - /// """Receive a USB connect/disconnect event.""" - /// - /// def timer(self, token: int) -> LayoutState | None: - /// """Callback for the timer set by `attach_timer_fn`. - /// - /// This function should be called by the executor after the corresponding - /// duration elapses. - /// """ - /// - /// def paint(self) -> bool: - /// """Paint the layout object on screen. - /// - /// Will only paint updated parts of the layout as required. - /// Returns True if any painting actually happened. - /// """ - /// - /// def request_complete_repaint(self) -> None: - /// """Request a complete repaint of the screen. - /// - /// Does not repaint the screen, a subsequent call to `paint()` is required. - /// """ - /// - /// if __debug__: - /// def trace(self, tracer: Callable[[str], None]) -> None: - /// """Generate a JSON trace of the layout object. - /// - /// The JSON can be emitted as a sequence of calls to `tracer`, each of - /// which is not necessarily a valid JSON chunk. The caller must - /// reassemble the chunks to get a sensible result. - /// """ - /// - /// def bounds(self) -> None: - /// """Paint bounds of individual components on screen.""" - /// - /// def page_count(self) -> int: - /// """Return the number of pages in the layout object.""" - /// - /// def button_request(self) -> tuple[int, str] | None: - /// """Return (code, type) of button request made during the last event or timer pass.""" - /// - /// def get_transition_out(self) -> AttachType: - /// """Return the transition type.""" - /// - /// def return_value(self) -> T: - /// """Retrieve the return value of the layout object.""" - /// - /// def __del__(self) -> None: - /// """Calls drop on contents of the root component.""" - /// - /// class UiResult: - /// """Result of an UI operation.""" - /// pass - /// - /// mock:global - Qstr::MP_QSTR___name__ => Qstr::MP_QSTR_trezorui2.to_obj(), - - /// CONFIRMED: UiResult - Qstr::MP_QSTR_CONFIRMED => CONFIRMED.as_obj(), - - /// CANCELLED: UiResult - Qstr::MP_QSTR_CANCELLED => CANCELLED.as_obj(), - - /// INFO: UiResult - Qstr::MP_QSTR_INFO => INFO.as_obj(), /// def disable_animation(disable: bool) -> None: /// """Disable animations, debug builds only.""" @@ -2182,34 +2090,6 @@ pub static mp_module_trezorui2: Module = obj_module! { /// def show_wait_text(message: str, /) -> LayoutObj[None]: /// """Show single-line text in the middle of the screen.""" Qstr::MP_QSTR_show_wait_text => obj_fn_1!(new_show_wait_text).as_obj(), - - /// class BacklightLevels: - /// """Backlight levels. Values dynamically update based on user settings.""" - /// MAX: ClassVar[int] - /// NORMAL: ClassVar[int] - /// LOW: ClassVar[int] - /// DIM: ClassVar[int] - /// NONE: ClassVar[int] - /// - /// mock:global - Qstr::MP_QSTR_BacklightLevels => BACKLIGHT_LEVELS_OBJ.as_obj(), - - /// class AttachType: - /// INITIAL: ClassVar[int] - /// RESUME: ClassVar[int] - /// SWIPE_UP: ClassVar[int] - /// SWIPE_DOWN: ClassVar[int] - /// SWIPE_LEFT: ClassVar[int] - /// SWIPE_RIGHT: ClassVar[int] - Qstr::MP_QSTR_AttachType => ATTACH_TYPE_OBJ.as_obj(), - - /// class LayoutState: - /// """Layout state.""" - /// INITIAL: "ClassVar[LayoutState]" - /// ATTACHED: "ClassVar[LayoutState]" - /// TRANSITIONING: "ClassVar[LayoutState]" - /// DONE: "ClassVar[LayoutState]" - Qstr::MP_QSTR_LayoutState => LAYOUT_STATE.as_obj(), }; #[cfg(test)] diff --git a/core/embed/upymod/rustmods.c b/core/embed/upymod/rustmods.c index 2673bceb55..fa3d34575a 100644 --- a/core/embed/upymod/rustmods.c +++ b/core/embed/upymod/rustmods.c @@ -25,6 +25,10 @@ MP_REGISTER_MODULE(MP_QSTR_trezorui2, mp_module_trezorui2); #endif +#if MICROPY_PY_TREZORUI_API +MP_REGISTER_MODULE(MP_QSTR_trezorui_api, mp_module_trezorui_api); +#endif + #if MICROPY_PY_TREZORPROTO MP_REGISTER_MODULE(MP_QSTR_trezorproto, mp_module_trezorproto); #endif diff --git a/core/mocks/generated/trezorui2.pyi b/core/mocks/generated/trezorui2.pyi index e7fa414d73..6765d58f2d 100644 --- a/core/mocks/generated/trezorui2.pyi +++ b/core/mocks/generated/trezorui2.pyi @@ -1,8 +1,6 @@ from typing import * from trezor import utils -CONFIRMED: UiResult -CANCELLED: UiResult -INFO: UiResult +from trezorui_api import * # rust/src/ui/model_mercury/layout.rs @@ -554,38 +552,8 @@ def flow_confirm_summary( cancel_text: str | None = None, ) -> LayoutObj[UiResult]: """Total summary and hold to confirm.""" - - -# rust/src/ui/model_mercury/layout.rs -class BacklightLevels: - """Backlight levels. Values dynamically update based on user settings.""" - MAX: ClassVar[int] - NORMAL: ClassVar[int] - LOW: ClassVar[int] - DIM: ClassVar[int] - NONE: ClassVar[int] - - -# rust/src/ui/model_mercury/layout.rs -class AttachType: - INITIAL: ClassVar[int] - RESUME: ClassVar[int] - SWIPE_UP: ClassVar[int] - SWIPE_DOWN: ClassVar[int] - SWIPE_LEFT: ClassVar[int] - SWIPE_RIGHT: ClassVar[int] - - -# rust/src/ui/model_mercury/layout.rs -class LayoutState: - """Layout state.""" - INITIAL: "ClassVar[LayoutState]" - ATTACHED: "ClassVar[LayoutState]" - TRANSITIONING: "ClassVar[LayoutState]" - DONE: "ClassVar[LayoutState]" -CONFIRMED: UiResult -CANCELLED: UiResult -INFO: UiResult +from trezor import utils +from trezorui_api import * # rust/src/ui/model_tr/layout.rs @@ -1050,102 +1018,8 @@ def confirm_firmware_update( # rust/src/ui/model_tr/layout.rs def show_wait_text(message: str, /) -> None: """Show single-line text in the middle of the screen.""" - - -# rust/src/ui/model_tr/layout.rs -class BacklightLevels: - """Backlight levels. Values dynamically update based on user settings.""" - MAX: ClassVar[int] - NORMAL: ClassVar[int] - LOW: ClassVar[int] - DIM: ClassVar[int] - NONE: ClassVar[int] - - -# rust/src/ui/model_tr/layout.rs -class AttachType: - INITIAL: ClassVar[int] - RESUME: ClassVar[int] - SWIPE_UP: ClassVar[int] - SWIPE_DOWN: ClassVar[int] - SWIPE_LEFT: ClassVar[int] - SWIPE_RIGHT: ClassVar[int] - - -# rust/src/ui/model_tr/layout.rs -class LayoutState: - """Layout state.""" - INITIAL: "ClassVar[LayoutState]" - ATTACHED: "ClassVar[LayoutState]" - TRANSITIONING: "ClassVar[LayoutState]" - DONE: "ClassVar[LayoutState]" from trezor import utils -T = TypeVar("T") - - -# rust/src/ui/model_tt/layout.rs -class LayoutObj(Generic[T]): - """Representation of a Rust-based layout object. - see `trezor::ui::layout::obj::LayoutObj`. - """ - def attach_timer_fn(self, fn: Callable[[int, int], None], attach_type: AttachType | None) -> LayoutState | None: - """Attach a timer setter function. - The layout object can call the timer setter with two arguments, - `token` and `duration_ms`. When `duration_ms` elapses, the layout object - expects a callback to `self.timer(token)`. - """ - if utils.USE_TOUCH: - def touch_event(self, event: int, x: int, y: int) -> LayoutState | None: - """Receive a touch event `event` at coordinates `x`, `y`.""" - if utils.USE_BUTTON: - def button_event(self, event: int, button: int) -> LayoutState | None: - """Receive a button event `event` for button `button`.""" - def progress_event(self, value: int, description: str) -> LayoutState | None: - """Receive a progress event.""" - def usb_event(self, connected: bool) -> LayoutState | None: - """Receive a USB connect/disconnect event.""" - def timer(self, token: int) -> LayoutState | None: - """Callback for the timer set by `attach_timer_fn`. - This function should be called by the executor after the corresponding - duration elapses. - """ - def paint(self) -> bool: - """Paint the layout object on screen. - Will only paint updated parts of the layout as required. - Returns True if any painting actually happened. - """ - def request_complete_repaint(self) -> None: - """Request a complete repaint of the screen. - Does not repaint the screen, a subsequent call to `paint()` is required. - """ - if __debug__: - def trace(self, tracer: Callable[[str], None]) -> None: - """Generate a JSON trace of the layout object. - The JSON can be emitted as a sequence of calls to `tracer`, each of - which is not necessarily a valid JSON chunk. The caller must - reassemble the chunks to get a sensible result. - """ - def bounds(self) -> None: - """Paint bounds of individual components on screen.""" - def page_count(self) -> int: - """Return the number of pages in the layout object.""" - def button_request(self) -> tuple[int, str] | None: - """Return (code, type) of button request made during the last event or timer pass.""" - def get_transition_out(self) -> AttachType: - """Return the transition type.""" - def return_value(self) -> T: - """Retrieve the return value of the layout object.""" - def __del__(self) -> None: - """Calls drop on contents of the root component.""" - - -# rust/src/ui/model_tt/layout.rs -class UiResult: - """Result of an UI operation.""" - pass -CONFIRMED: UiResult -CANCELLED: UiResult -INFO: UiResult +from trezorui_api import * # rust/src/ui/model_tt/layout.rs @@ -1626,32 +1500,3 @@ def confirm_firmware_update( # rust/src/ui/model_tt/layout.rs def show_wait_text(message: str, /) -> LayoutObj[None]: """Show single-line text in the middle of the screen.""" - - -# rust/src/ui/model_tt/layout.rs -class BacklightLevels: - """Backlight levels. Values dynamically update based on user settings.""" - MAX: ClassVar[int] - NORMAL: ClassVar[int] - LOW: ClassVar[int] - DIM: ClassVar[int] - NONE: ClassVar[int] - - -# rust/src/ui/model_tt/layout.rs -class AttachType: - INITIAL: ClassVar[int] - RESUME: ClassVar[int] - SWIPE_UP: ClassVar[int] - SWIPE_DOWN: ClassVar[int] - SWIPE_LEFT: ClassVar[int] - SWIPE_RIGHT: ClassVar[int] - - -# rust/src/ui/model_tt/layout.rs -class LayoutState: - """Layout state.""" - INITIAL: "ClassVar[LayoutState]" - ATTACHED: "ClassVar[LayoutState]" - TRANSITIONING: "ClassVar[LayoutState]" - DONE: "ClassVar[LayoutState]" diff --git a/core/mocks/generated/trezorui_api.pyi b/core/mocks/generated/trezorui_api.pyi new file mode 100644 index 0000000000..aac8e6b8ac --- /dev/null +++ b/core/mocks/generated/trezorui_api.pyi @@ -0,0 +1,97 @@ +from typing import * +from trezor import utils +T = TypeVar("T") + + +# rust/src/ui/api/firmware_upy.rs +class LayoutObj(Generic[T]): + """Representation of a Rust-based layout object. + see `trezor::ui::layout::obj::LayoutObj`. + """ + def attach_timer_fn(self, fn: Callable[[int, int], None], attach_type: AttachType | None) -> LayoutState | None: + """Attach a timer setter function. + The layout object can call the timer setter with two arguments, + `token` and `duration_ms`. When `duration_ms` elapses, the layout object + expects a callback to `self.timer(token)`. + """ + if utils.USE_TOUCH: + def touch_event(self, event: int, x: int, y: int) -> LayoutState | None: + """Receive a touch event `event` at coordinates `x`, `y`.""" + if utils.USE_BUTTON: + def button_event(self, event: int, button: int) -> LayoutState | None: + """Receive a button event `event` for button `button`.""" + def progress_event(self, value: int, description: str) -> LayoutState | None: + """Receive a progress event.""" + def usb_event(self, connected: bool) -> LayoutState | None: + """Receive a USB connect/disconnect event.""" + def timer(self, token: int) -> LayoutState | None: + """Callback for the timer set by `attach_timer_fn`. + This function should be called by the executor after the corresponding + duration elapses. + """ + def paint(self) -> bool: + """Paint the layout object on screen. + Will only paint updated parts of the layout as required. + Returns True if any painting actually happened. + """ + def request_complete_repaint(self) -> None: + """Request a complete repaint of the screen. + Does not repaint the screen, a subsequent call to `paint()` is required. + """ + if __debug__: + def trace(self, tracer: Callable[[str], None]) -> None: + """Generate a JSON trace of the layout object. + The JSON can be emitted as a sequence of calls to `tracer`, each of + which is not necessarily a valid JSON chunk. The caller must + reassemble the chunks to get a sensible result. + """ + def bounds(self) -> None: + """Paint bounds of individual components on screen.""" + def page_count(self) -> int: + """Return the number of pages in the layout object.""" + def button_request(self) -> tuple[int, str] | None: + """Return (code, type) of button request made during the last event or timer pass.""" + def get_transition_out(self) -> AttachType: + """Return the transition type.""" + def return_value(self) -> T: + """Retrieve the return value of the layout object.""" + def __del__(self) -> None: + """Calls drop on contents of the root component.""" + + +# rust/src/ui/api/firmware_upy.rs +class UiResult: + """Result of a UI operation.""" + pass +CONFIRMED: UiResult +CANCELLED: UiResult +INFO: UiResult + + +# rust/src/ui/api/firmware_upy.rs +class BacklightLevels: + """Backlight levels. Values dynamically update based on user settings.""" + MAX: ClassVar[int] + NORMAL: ClassVar[int] + LOW: ClassVar[int] + DIM: ClassVar[int] + NONE: ClassVar[int] + + +# rust/src/ui/api/firmware_upy.rs +class AttachType: + INITIAL: ClassVar[int] + RESUME: ClassVar[int] + SWIPE_UP: ClassVar[int] + SWIPE_DOWN: ClassVar[int] + SWIPE_LEFT: ClassVar[int] + SWIPE_RIGHT: ClassVar[int] + + +# rust/src/ui/api/firmware_upy.rs +class LayoutState: + """Layout state.""" + INITIAL: "ClassVar[LayoutState]" + ATTACHED: "ClassVar[LayoutState]" + TRANSITIONING: "ClassVar[LayoutState]" + DONE: "ClassVar[LayoutState]" diff --git a/core/src/apps/debug/__init__.py b/core/src/apps/debug/__init__.py index 41c65eb85b..353e1eabad 100644 --- a/core/src/apps/debug/__init__.py +++ b/core/src/apps/debug/__init__.py @@ -8,7 +8,7 @@ if __debug__: from micropython import const from typing import TYPE_CHECKING - import trezorui2 + import trezorui_api from storage import debug as storage from trezor import io, log, loop, ui, utils, wire, workflow from trezor.enums import DebugWaitType, MessageType @@ -195,11 +195,11 @@ if __debug__: assert isinstance(ui.CURRENT_LAYOUT, ui.Layout) if button == DebugButton.NO: - ui.CURRENT_LAYOUT._emit_message(trezorui2.CANCELLED) + ui.CURRENT_LAYOUT._emit_message(trezorui_api.CANCELLED) elif button == DebugButton.YES: - ui.CURRENT_LAYOUT._emit_message(trezorui2.CONFIRMED) + ui.CURRENT_LAYOUT._emit_message(trezorui_api.CONFIRMED) elif button == DebugButton.INFO: - ui.CURRENT_LAYOUT._emit_message(trezorui2.INFO) + ui.CURRENT_LAYOUT._emit_message(trezorui_api.INFO) else: raise RuntimeError("Invalid DebugButton") diff --git a/core/src/trezor/ui/__init__.py b/core/src/trezor/ui/__init__.py index a0ad35a338..91e8e71c4d 100644 --- a/core/src/trezor/ui/__init__.py +++ b/core/src/trezor/ui/__init__.py @@ -8,12 +8,12 @@ import trezorui2 from trezor import io, log, loop, utils, wire, workflow from trezor.messages import ButtonAck, ButtonRequest from trezor.wire import context -from trezorui2 import BacklightLevels, LayoutState +from trezorui_api import BacklightLevels, LayoutState if TYPE_CHECKING: from typing import Any, Callable, Generator, Generic, Iterator, TypeVar - from trezorui2 import AttachType, LayoutObj, UiResult # noqa: F401 + from trezorui_api import AttachType, LayoutObj, UiResult # noqa: F401 T = TypeVar("T", covariant=True) diff --git a/core/src/trezor/ui/layouts/common.py b/core/src/trezor/ui/layouts/common.py index 52d92c5c7f..e3d30dbb49 100644 --- a/core/src/trezor/ui/layouts/common.py +++ b/core/src/trezor/ui/layouts/common.py @@ -1,6 +1,7 @@ from typing import TYPE_CHECKING import trezorui2 +import trezorui_api from trezor import ui, utils, workflow from trezor.enums import ButtonRequestType from trezor.messages import ButtonAck, ButtonRequest @@ -52,7 +53,7 @@ async def interact( # wait for the layout result result = await layout.get_result() # raise an exception if the user cancelled the action - if raise_on_cancel is not None and result is trezorui2.CANCELLED: + if raise_on_cancel is not None and result is trezorui_api.CANCELLED: raise raise_on_cancel return result @@ -93,13 +94,13 @@ async def with_info( first_br = next_br - if result is trezorui2.CONFIRMED: + if result is trezorui_api.CONFIRMED: return - elif result is trezorui2.INFO: + elif result is trezorui_api.INFO: info_result = await interact( info_layout, next_br, br_code, raise_on_cancel=None ) - if info_layout_can_confirm and info_result is trezorui2.CONFIRMED: + if info_layout_can_confirm and info_result is trezorui_api.CONFIRMED: return else: # no matter what the info layout returns, we always go back to the main layout @@ -108,7 +109,7 @@ async def with_info( raise RuntimeError # unexpected result -def draw_simple(layout: trezorui2.LayoutObj[Any]) -> None: +def draw_simple(layout: trezorui_api.LayoutObj[Any]) -> None: # Simple drawing not supported for layouts that set timers. def dummy_set_timer(token: int, duration: int) -> None: raise RuntimeError diff --git a/core/src/trezor/ui/layouts/homescreen.py b/core/src/trezor/ui/layouts/homescreen.py index 0fe5d2e1cf..99ea69454d 100644 --- a/core/src/trezor/ui/layouts/homescreen.py +++ b/core/src/trezor/ui/layouts/homescreen.py @@ -2,6 +2,7 @@ from typing import TYPE_CHECKING import storage.cache as storage_cache import trezorui2 +import trezorui_api from trezor import TR, ui if TYPE_CHECKING: @@ -126,7 +127,7 @@ class Busyscreen(HomescreenBase): # Handle timeout. result = await super().get_result() - assert result == trezorui2.CANCELLED + assert result == trezorui_api.CANCELLED storage_cache.delete(storage_cache.APP_COMMON_BUSY_DEADLINE_MS) set_homescreen() return result diff --git a/core/src/trezor/ui/layouts/mercury/__init__.py b/core/src/trezor/ui/layouts/mercury/__init__.py index b03947c419..983cd156b5 100644 --- a/core/src/trezor/ui/layouts/mercury/__init__.py +++ b/core/src/trezor/ui/layouts/mercury/__init__.py @@ -1,6 +1,7 @@ from typing import TYPE_CHECKING import trezorui2 +import trezorui_api from trezor import TR, ui, utils from trezor.enums import ButtonRequestType from trezor.wire import ActionCancelled @@ -17,9 +18,9 @@ if TYPE_CHECKING: BR_CODE_OTHER = ButtonRequestType.Other # global_import_cache -CONFIRMED = trezorui2.CONFIRMED -CANCELLED = trezorui2.CANCELLED -INFO = trezorui2.INFO +CONFIRMED = trezorui_api.CONFIRMED +CANCELLED = trezorui_api.CANCELLED +INFO = trezorui_api.INFO def confirm_action( diff --git a/core/src/trezor/ui/layouts/mercury/fido.py b/core/src/trezor/ui/layouts/mercury/fido.py index 53ee827485..6ab7aa784a 100644 --- a/core/src/trezor/ui/layouts/mercury/fido.py +++ b/core/src/trezor/ui/layouts/mercury/fido.py @@ -1,4 +1,5 @@ import trezorui2 +import trezorui_api from trezor import ui from trezor.enums import ButtonRequestType @@ -20,7 +21,7 @@ async def confirm_fido( ) result = await interact(confirm, "confirm_fido", ButtonRequestType.Other) - if __debug__ and result is trezorui2.CONFIRMED: + if __debug__ and result is trezorui_api.CONFIRMED: # debuglink will directly inject a CONFIRMED message which we need to handle # by playing back a click to the Rust layout and getting out the selected number # that way @@ -51,4 +52,4 @@ async def confirm_fido_reset() -> bool: prompt_screen=True, ) ) - return (await confirm.get_result()) is trezorui2.CONFIRMED + return (await confirm.get_result()) is trezorui_api.CONFIRMED diff --git a/core/src/trezor/ui/layouts/mercury/recovery.py b/core/src/trezor/ui/layouts/mercury/recovery.py index e809799887..8f0b9c244b 100644 --- a/core/src/trezor/ui/layouts/mercury/recovery.py +++ b/core/src/trezor/ui/layouts/mercury/recovery.py @@ -1,15 +1,16 @@ from typing import TYPE_CHECKING import trezorui2 +import trezorui_api from trezor import TR from trezor.enums import ButtonRequestType, RecoveryType from ..common import interact from . import raise_if_not_confirmed -CONFIRMED = trezorui2.CONFIRMED # global_import_cache -CANCELLED = trezorui2.CANCELLED # global_import_cache -INFO = trezorui2.INFO # global_import_cache +CONFIRMED = trezorui_api.CONFIRMED # global_import_cache +CANCELLED = trezorui_api.CANCELLED # global_import_cache +INFO = trezorui_api.INFO # global_import_cache if TYPE_CHECKING: from apps.management.recovery_device.layout import RemainingSharesInfo diff --git a/core/src/trezor/ui/layouts/mercury/reset.py b/core/src/trezor/ui/layouts/mercury/reset.py index 17399228f7..48ec5352d9 100644 --- a/core/src/trezor/ui/layouts/mercury/reset.py +++ b/core/src/trezor/ui/layouts/mercury/reset.py @@ -1,6 +1,7 @@ from typing import Awaitable, Callable, Sequence import trezorui2 +import trezorui_api from trezor import TR, ui from trezor.enums import ButtonRequestType from trezor.wire import ActionCancelled @@ -8,7 +9,7 @@ from trezor.wire import ActionCancelled from ..common import interact from . import raise_if_not_confirmed, show_success -CONFIRMED = trezorui2.CONFIRMED # global_import_cache +CONFIRMED = trezorui_api.CONFIRMED # global_import_cache def show_share_words( @@ -172,7 +173,7 @@ async def _prompt_number( # so use the initial one return count - if result is not trezorui2.CANCELLED: + if result is not trezorui_api.CANCELLED: assert isinstance(result, int) return result else: diff --git a/core/src/trezor/ui/layouts/tr/__init__.py b/core/src/trezor/ui/layouts/tr/__init__.py index 2346a1e348..622c744782 100644 --- a/core/src/trezor/ui/layouts/tr/__init__.py +++ b/core/src/trezor/ui/layouts/tr/__init__.py @@ -1,6 +1,7 @@ from typing import TYPE_CHECKING import trezorui2 +import trezorui_api from trezor import TR, ui, utils from trezor.enums import ButtonRequestType from trezor.wire import ActionCancelled @@ -13,9 +14,9 @@ if TYPE_CHECKING: from ..common import ExceptionType, PropertyType -CONFIRMED = trezorui2.CONFIRMED -CANCELLED = trezorui2.CANCELLED -INFO = trezorui2.INFO +CONFIRMED = trezorui_api.CONFIRMED +CANCELLED = trezorui_api.CANCELLED +INFO = trezorui_api.INFO BR_CODE_OTHER = ButtonRequestType.Other # global_import_cache @@ -1128,7 +1129,7 @@ def error_popup( *, button: str = "", timeout_ms: int = 0, -) -> trezorui2.LayoutObj[trezorui2.UiResult]: +) -> trezorui_api.LayoutObj[trezorui_api.UiResult]: if button: raise NotImplementedError("Button not implemented") diff --git a/core/src/trezor/ui/layouts/tr/fido.py b/core/src/trezor/ui/layouts/tr/fido.py index 7fd6c9786b..4aaaad634d 100644 --- a/core/src/trezor/ui/layouts/tr/fido.py +++ b/core/src/trezor/ui/layouts/tr/fido.py @@ -1,4 +1,5 @@ import trezorui2 +import trezorui_api from trezor import ui from trezor.enums import ButtonRequestType @@ -24,7 +25,7 @@ async def confirm_fido( # For the usage in device tests, assuming CONFIRMED (sent by debuglink) # is choosing the first credential. - if __debug__ and result is trezorui2.CONFIRMED: + if __debug__ and result is trezorui_api.CONFIRMED: return 0 raise RuntimeError # should not get here, cancellation is handled by `interact` @@ -40,4 +41,4 @@ async def confirm_fido_reset() -> bool: verb_cancel="", verb=TR.buttons__confirm, ) - return (await ui.Layout(confirm).get_result()) is trezorui2.CONFIRMED + return (await ui.Layout(confirm).get_result()) is trezorui_api.CONFIRMED diff --git a/core/src/trezor/ui/layouts/tr/recovery.py b/core/src/trezor/ui/layouts/tr/recovery.py index 84bdf6fc19..82786672c0 100644 --- a/core/src/trezor/ui/layouts/tr/recovery.py +++ b/core/src/trezor/ui/layouts/tr/recovery.py @@ -1,6 +1,7 @@ from typing import TYPE_CHECKING import trezorui2 +import trezorui_api from trezor import TR, ui from trezor.enums import ButtonRequestType, RecoveryType @@ -137,7 +138,7 @@ async def continue_recovery( ButtonRequestType.RecoveryHomepage, raise_on_cancel=None, ) - if result is trezorui2.CONFIRMED: + if result is trezorui_api.CONFIRMED: return True try: diff --git a/core/src/trezor/ui/layouts/tr/reset.py b/core/src/trezor/ui/layouts/tr/reset.py index 326f703752..787940b817 100644 --- a/core/src/trezor/ui/layouts/tr/reset.py +++ b/core/src/trezor/ui/layouts/tr/reset.py @@ -3,11 +3,12 @@ from typing import TYPE_CHECKING import trezorui2 from trezor import TR from trezor.enums import ButtonRequestType +import trezorui_api from ..common import interact, raise_if_not_confirmed from . import confirm_action, show_success, show_warning -CONFIRMED = trezorui2.CONFIRMED # global_import_cache +CONFIRMED = trezorui_api.CONFIRMED # global_import_cache if TYPE_CHECKING: from typing import Awaitable, Sequence @@ -268,7 +269,7 @@ def show_intro_backup(single_share: bool, num_of_words: int | None) -> Awaitable ) -def show_warning_backup() -> Awaitable[trezorui2.UiResult]: +def show_warning_backup() -> Awaitable[trezorui_api.UiResult]: return show_warning( "backup_warning", TR.words__title_remember, @@ -295,7 +296,7 @@ def show_reset_warning( subheader: str | None = None, button: str | None = None, br_code: ButtonRequestType = ButtonRequestType.Warning, -) -> Awaitable[trezorui2.UiResult]: +) -> Awaitable[trezorui_api.UiResult]: button = button or TR.buttons__try_again # def_arg return show_warning( diff --git a/core/src/trezor/ui/layouts/tt/__init__.py b/core/src/trezor/ui/layouts/tt/__init__.py index 3440445523..67dc1776b6 100644 --- a/core/src/trezor/ui/layouts/tt/__init__.py +++ b/core/src/trezor/ui/layouts/tt/__init__.py @@ -1,6 +1,7 @@ from typing import TYPE_CHECKING import trezorui2 +import trezorui_api from trezor import TR, ui, utils from trezor.enums import ButtonRequestType from trezor.wire import ActionCancelled @@ -15,9 +16,9 @@ if TYPE_CHECKING: BR_CODE_OTHER = ButtonRequestType.Other # global_import_cache -CONFIRMED = trezorui2.CONFIRMED -CANCELLED = trezorui2.CANCELLED -INFO = trezorui2.INFO +CONFIRMED = trezorui_api.CONFIRMED +CANCELLED = trezorui_api.CANCELLED +INFO = trezorui_api.INFO def confirm_action( diff --git a/core/src/trezor/ui/layouts/tt/fido.py b/core/src/trezor/ui/layouts/tt/fido.py index 05b733af38..76d071ab69 100644 --- a/core/src/trezor/ui/layouts/tt/fido.py +++ b/core/src/trezor/ui/layouts/tt/fido.py @@ -1,4 +1,5 @@ import trezorui2 +import trezorui_api from trezor import ui from trezor.enums import ButtonRequestType @@ -20,7 +21,7 @@ async def confirm_fido( ) result = await interact(confirm, "confirm_fido", ButtonRequestType.Other) - if __debug__ and result is trezorui2.CONFIRMED: + if __debug__ and result is trezorui_api.CONFIRMED: # debuglink will directly inject a CONFIRMED message which we need to handle # by playing back a click to the Rust layout and getting out the selected number # that way @@ -32,7 +33,7 @@ async def confirm_fido( msg = confirm.touch_event(io.TOUCH_END, 220, 220) if confirm.paint(): ui.refresh() - assert msg is trezorui2.LayoutState.DONE + assert msg is trezorui_api.LayoutState.DONE retval = confirm.return_value() assert isinstance(retval, int) return retval @@ -59,4 +60,4 @@ async def confirm_fido_reset() -> bool: reverse=True, ) ) - return (await confirm.get_result()) is trezorui2.CONFIRMED + return (await confirm.get_result()) is trezorui_api.CONFIRMED diff --git a/core/src/trezor/ui/layouts/tt/recovery.py b/core/src/trezor/ui/layouts/tt/recovery.py index b751039dfb..7de8e3be45 100644 --- a/core/src/trezor/ui/layouts/tt/recovery.py +++ b/core/src/trezor/ui/layouts/tt/recovery.py @@ -1,6 +1,7 @@ from typing import TYPE_CHECKING import trezorui2 +import trezorui_api from trezor import TR, ui from trezor.enums import ButtonRequestType @@ -54,7 +55,7 @@ def show_remaining_shares( groups: set[tuple[str, ...]], shares_remaining: list[int], group_threshold: int, -) -> Awaitable[trezorui2.UiResult]: +) -> Awaitable[trezorui_api.UiResult]: from trezor import strings from trezor.crypto.slip39 import MAX_SHARE_COUNT @@ -161,9 +162,9 @@ async def continue_recovery( raise_on_cancel=None, ) - if result is trezorui2.CONFIRMED: + if result is trezorui_api.CONFIRMED: return True - elif result is trezorui2.INFO and remaining_shares_info is not None: + elif result is trezorui_api.INFO and remaining_shares_info is not None: await show_remaining_shares(*remaining_shares_info) else: try: diff --git a/core/src/trezor/ui/layouts/tt/reset.py b/core/src/trezor/ui/layouts/tt/reset.py index 39132a5bd2..b3b380c0d2 100644 --- a/core/src/trezor/ui/layouts/tt/reset.py +++ b/core/src/trezor/ui/layouts/tt/reset.py @@ -1,12 +1,13 @@ from typing import Awaitable, Callable, Sequence import trezorui2 +import trezorui_api from trezor import TR from trezor.enums import ButtonRequestType from ..common import interact, raise_if_not_confirmed -CONFIRMED = trezorui2.CONFIRMED # global_import_cache +CONFIRMED = trezorui_api.CONFIRMED # global_import_cache def _split_share_into_pages(share_words: Sequence[str], per_page: int = 4) -> list[str]: @@ -323,7 +324,7 @@ def show_intro_backup(single_share: bool, num_of_words: int | None) -> Awaitable ) -def show_warning_backup() -> Awaitable[trezorui2.UiResult]: +def show_warning_backup() -> Awaitable[trezorui_api.UiResult]: return interact( trezorui2.show_info( title=TR.reset__never_make_digital_copy, @@ -351,7 +352,7 @@ def show_reset_warning( subheader: str | None = None, button: str | None = None, br_code: ButtonRequestType = ButtonRequestType.Warning, -) -> Awaitable[trezorui2.UiResult]: +) -> Awaitable[trezorui_api.UiResult]: button = button or TR.buttons__try_again # def_arg return interact( trezorui2.show_warning(