diff --git a/core/embed/rust/src/ui/api/firmware_upy.rs b/core/embed/rust/src/ui/api/firmware_upy.rs index 51e22d9ee9..4f2d5e34aa 100644 --- a/core/embed/rust/src/ui/api/firmware_upy.rs +++ b/core/embed/rust/src/ui/api/firmware_upy.rs @@ -233,6 +233,18 @@ extern "C" fn new_confirm_modify_output(n_args: usize, args: *const Obj, kwargs: unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } +extern "C" fn new_confirm_properties(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { + let block = move |_args: &[Obj], kwargs: &Map| { + let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; + let items: Obj = kwargs.get(Qstr::MP_QSTR_items)?; + let hold: bool = kwargs.get_or(Qstr::MP_QSTR_hold, false)?; + + let layout = ModelUI::confirm_properties(title, items, hold)?; + Ok(LayoutObj::new_root(layout)?.into()) + }; + unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } +} + extern "C" fn new_confirm_reset_device(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { let block = move |_args: &[Obj], kwargs: &Map| { let recovery: bool = kwargs.get(Qstr::MP_QSTR_recovery)?.try_into()?; @@ -937,6 +949,16 @@ pub static mp_module_trezorui_api: Module = obj_module! { /// """Decrease or increase output amount.""" Qstr::MP_QSTR_confirm_modify_output => obj_fn_kw!(0, new_confirm_modify_output).as_obj(), + /// def confirm_properties( + /// *, + /// title: str, + /// items: list[tuple[str | None, str | bytes | None, bool]], + /// hold: bool = False, + /// ) -> LayoutObj[UiResult]: + /// """Confirm list of key-value pairs. The third component in the tuple should be True if + /// the value is to be rendered as binary with monospace font, False otherwise.""" + Qstr::MP_QSTR_confirm_properties => obj_fn_kw!(0, new_confirm_properties).as_obj(), + /// def confirm_reset_device(recovery: bool) -> LayoutObj[UiResult]: /// """Confirm TOS before creating wallet creation or wallet recovery.""" Qstr::MP_QSTR_confirm_reset_device => obj_fn_kw!(0, new_confirm_reset_device).as_obj(), diff --git a/core/embed/rust/src/ui/model_mercury/layout.rs b/core/embed/rust/src/ui/model_mercury/layout.rs index c3f44e83f5..74ceb3f1fb 100644 --- a/core/embed/rust/src/ui/model_mercury/layout.rs +++ b/core/embed/rust/src/ui/model_mercury/layout.rs @@ -296,32 +296,6 @@ extern "C" fn new_confirm_address(n_args: usize, args: *const Obj, kwargs: *mut unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } -extern "C" fn new_confirm_properties(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { - let block = move |_args: &[Obj], kwargs: &Map| { - let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; - let hold: bool = kwargs.get_or(Qstr::MP_QSTR_hold, false)?; - let items: Obj = kwargs.get(Qstr::MP_QSTR_items)?; - - let paragraphs = PropsList::new( - items, - &theme::TEXT_NORMAL, - &theme::TEXT_MONO, - &theme::TEXT_MONO, - )?; - - new_confirm_action_simple( - paragraphs.into_paragraphs(), - ConfirmActionMenu::new(None, false, None), - ConfirmActionStrings::new(title, None, None, hold.then_some(title)), - hold, - None, - ) - .and_then(LayoutObj::new_root) - .map(Into::into) - }; - unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } -} - extern "C" fn new_confirm_set_new_pin(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { let block = move |_args: &[Obj], kwargs: &Map| { let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; @@ -637,16 +611,6 @@ pub static mp_module_trezorui2: Module = obj_module! { /// and allows left swipe which does the same thing as the button.""" Qstr::MP_QSTR_confirm_address => obj_fn_kw!(0, new_confirm_address).as_obj(), - /// def confirm_properties( - /// *, - /// title: str, - /// items: list[tuple[str | None, str | bytes | None, bool]], - /// hold: bool = False, - /// ) -> LayoutObj[UiResult]: - /// """Confirm list of key-value pairs. The third component in the tuple should be True if - /// the value is to be rendered as binary with monospace font, False otherwise.""" - Qstr::MP_QSTR_confirm_properties => obj_fn_kw!(0, new_confirm_properties).as_obj(), - // TODO: supply more arguments for Wipe code setting when figma done /// def flow_confirm_set_new_pin( /// *, diff --git a/core/embed/rust/src/ui/model_mercury/ui_features_fw.rs b/core/embed/rust/src/ui/model_mercury/ui_features_fw.rs index 08cda289b2..1e03392be1 100644 --- a/core/embed/rust/src/ui/model_mercury/ui_features_fw.rs +++ b/core/embed/rust/src/ui/model_mercury/ui_features_fw.rs @@ -22,7 +22,7 @@ use crate::{ geometry::{self, Direction}, layout::{ obj::{LayoutMaybeTrace, LayoutObj, RootComponent}, - util::RecoveryType, + util::{PropsList, RecoveryType}, }, ui_features_fw::UIFeaturesFirmware, }, @@ -274,6 +274,28 @@ impl UIFeaturesFirmware for ModelMercuryFeatures { Ok(flow) } + fn confirm_properties( + title: TString<'static>, + items: Obj, + hold: bool, + ) -> Result { + let paragraphs = PropsList::new( + items, + &theme::TEXT_NORMAL, + &theme::TEXT_MONO, + &theme::TEXT_MONO, + )?; + + let flow = flow::new_confirm_action_simple( + paragraphs.into_paragraphs(), + ConfirmActionMenu::new(None, false, None), + ConfirmActionStrings::new(title, None, None, hold.then_some(title)), + hold, + None, + )?; + Ok(flow) + } + fn confirm_value( title: TString<'static>, value: Obj, diff --git a/core/embed/rust/src/ui/model_tr/layout.rs b/core/embed/rust/src/ui/model_tr/layout.rs index 33d85083fa..a247efea3b 100644 --- a/core/embed/rust/src/ui/model_tr/layout.rs +++ b/core/embed/rust/src/ui/model_tr/layout.rs @@ -270,59 +270,6 @@ fn content_in_button_page( Ok(obj.into()) } -extern "C" fn new_confirm_properties(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { - let block = move |_args: &[Obj], kwargs: &Map| { - let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; - let hold: bool = kwargs.get_or(Qstr::MP_QSTR_hold, false)?; - let items: Obj = kwargs.get(Qstr::MP_QSTR_items)?; - - let mut paragraphs = ParagraphVecLong::new(); - - for para in IterBuf::new().try_iterate(items)? { - let [key, value, is_data]: [Obj; 3] = util::iter_into_array(para)?; - let key = key.try_into_option::()?; - let value = value.try_into_option::()?; - let is_data: bool = is_data.try_into()?; - - if let Some(key) = key { - if value.is_some() { - // Decreasing the margin between key and value (default is 5 px, we use 2 px) - // (this enables 4 lines - 2 key:value pairs - on the same screen) - paragraphs.add( - Paragraph::new(&theme::TEXT_BOLD, key) - .no_break() - .with_bottom_padding(2), - ); - } else { - paragraphs.add(Paragraph::new(&theme::TEXT_BOLD, key)); - } - } - if let Some(value) = value { - let style = if is_data { - &theme::TEXT_MONO_DATA - } else { - &theme::TEXT_MONO - }; - paragraphs.add(Paragraph::new(style, value)); - } - } - let button_text = if hold { - TR::buttons__hold_to_confirm.into() - } else { - TR::buttons__confirm.into() - }; - - content_in_button_page( - title, - paragraphs.into_paragraphs(), - button_text, - Some("".into()), - hold, - ) - }; - unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } -} - extern "C" fn new_confirm_backup(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { let block = move |_args: &[Obj], _kwargs: &Map| { let get_page = move |page_index| match page_index { @@ -746,18 +693,6 @@ pub static mp_module_trezorui2: Module = obj_module! { /// """Confirm address.""" Qstr::MP_QSTR_confirm_address => obj_fn_kw!(0, new_confirm_address).as_obj(), - - /// def confirm_properties( - /// *, - /// title: str, - /// items: list[tuple[str | None, str | bytes | None, bool]], - /// hold: bool = False, - /// ) -> LayoutObj[UiResult]: - /// """Confirm list of key-value pairs. The third component in the tuple should be True if - /// the value is to be rendered as binary with monospace font, False otherwise. - /// This only concerns the text style, you need to decode the value to UTF-8 in python.""" - Qstr::MP_QSTR_confirm_properties => obj_fn_kw!(0, new_confirm_properties).as_obj(), - /// def confirm_backup() -> LayoutObj[UiResult]: /// """Strongly recommend user to do backup.""" Qstr::MP_QSTR_confirm_backup => obj_fn_kw!(0, new_confirm_backup).as_obj(), diff --git a/core/embed/rust/src/ui/model_tr/ui_features_fw.rs b/core/embed/rust/src/ui/model_tr/ui_features_fw.rs index 2a7f67fa76..cb4300890b 100644 --- a/core/embed/rust/src/ui/model_tr/ui_features_fw.rs +++ b/core/embed/rust/src/ui/model_tr/ui_features_fw.rs @@ -311,6 +311,56 @@ impl UIFeaturesFirmware for ModelTRFeatures { ) } + fn confirm_properties( + title: TString<'static>, + items: Obj, + hold: bool, + ) -> Result { + let mut paragraphs = ParagraphVecLong::new(); + + for para in IterBuf::new().try_iterate(items)? { + let [key, value, is_data]: [Obj; 3] = util::iter_into_array(para)?; + let key = key.try_into_option::()?; + let value = value.try_into_option::()?; + let is_data: bool = is_data.try_into()?; + + if let Some(key) = key { + if value.is_some() { + // Decreasing the margin between key and value (default is 5 px, we use 2 px) + // (this enables 4 lines - 2 key:value pairs - on the same screen) + paragraphs.add( + Paragraph::new(&theme::TEXT_BOLD, key) + .no_break() + .with_bottom_padding(2), + ); + } else { + paragraphs.add(Paragraph::new(&theme::TEXT_BOLD, key)); + } + } + if let Some(value) = value { + let style = if is_data { + &theme::TEXT_MONO_DATA + } else { + &theme::TEXT_MONO + }; + paragraphs.add(Paragraph::new(style, value)); + } + } + let button_text = if hold { + TR::buttons__hold_to_confirm.into() + } else { + TR::buttons__confirm.into() + }; + + content_in_button_page( + title, + paragraphs.into_paragraphs(), + button_text, + Some("".into()), + hold, + ) + } + fn confirm_reset_device(recovery: bool) -> Result { let (title, button) = if recovery { ( diff --git a/core/embed/rust/src/ui/model_tt/layout.rs b/core/embed/rust/src/ui/model_tt/layout.rs index a422595056..abb023c6d1 100644 --- a/core/embed/rust/src/ui/model_tt/layout.rs +++ b/core/embed/rust/src/ui/model_tt/layout.rs @@ -394,30 +394,6 @@ extern "C" fn new_confirm_address(n_args: usize, args: *const Obj, kwargs: *mut unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } -extern "C" fn new_confirm_properties(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { - let block = move |_args: &[Obj], kwargs: &Map| { - let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; - let hold: bool = kwargs.get_or(Qstr::MP_QSTR_hold, false)?; - let items: Obj = kwargs.get(Qstr::MP_QSTR_items)?; - - let paragraphs = PropsList::new( - items, - &theme::TEXT_NORMAL, - &theme::TEXT_MONO, - &theme::TEXT_MONO, - )?; - let page = if hold { - ButtonPage::new(paragraphs.into_paragraphs(), theme::BG).with_hold()? - } else { - ButtonPage::new(paragraphs.into_paragraphs(), theme::BG) - .with_cancel_confirm(None, Some(TR::buttons__confirm.into())) - }; - let obj = LayoutObj::new(Frame::left_aligned(theme::label_title(), title, page))?; - Ok(obj.into()) - }; - unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } -} - extern "C" fn new_show_address_details(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { let block = move |_args: &[Obj], kwargs: &Map| { let qr_title: TString<'static> = kwargs.get(Qstr::MP_QSTR_qr_title)?.try_into()?; @@ -544,16 +520,6 @@ pub static mp_module_trezorui2: Module = obj_module! { /// and allows left swipe which does the same thing as the button.""" Qstr::MP_QSTR_confirm_address => obj_fn_kw!(0, new_confirm_address).as_obj(), - /// def confirm_properties( - /// *, - /// title: str, - /// items: list[tuple[str | None, str | bytes | None, bool]], - /// hold: bool = False, - /// ) -> LayoutObj[UiResult]: - /// """Confirm list of key-value pairs. The third component in the tuple should be True if - /// the value is to be rendered as binary with monospace font, False otherwise.""" - Qstr::MP_QSTR_confirm_properties => obj_fn_kw!(0, new_confirm_properties).as_obj(), - /// def show_address_details( /// *, /// qr_title: str, diff --git a/core/embed/rust/src/ui/model_tt/ui_features_fw.rs b/core/embed/rust/src/ui/model_tt/ui_features_fw.rs index 7a5c003212..7a68216066 100644 --- a/core/embed/rust/src/ui/model_tt/ui_features_fw.rs +++ b/core/embed/rust/src/ui/model_tt/ui_features_fw.rs @@ -22,7 +22,7 @@ use crate::{ geometry, layout::{ obj::{LayoutMaybeTrace, LayoutObj, RootComponent}, - util::{ConfirmBlob, RecoveryType}, + util::{ConfirmBlob, PropsList, RecoveryType}, }, ui_features_fw::UIFeaturesFirmware, }, @@ -270,6 +270,27 @@ impl UIFeaturesFirmware for ModelTTFeatures { Ok(layout) } + fn confirm_properties( + title: TString<'static>, + items: Obj, + hold: bool, + ) -> Result { + let paragraphs = PropsList::new( + items, + &theme::TEXT_NORMAL, + &theme::TEXT_MONO, + &theme::TEXT_MONO, + )?; + let page = if hold { + ButtonPage::new(paragraphs.into_paragraphs(), theme::BG).with_hold()? + } else { + ButtonPage::new(paragraphs.into_paragraphs(), theme::BG) + .with_cancel_confirm(None, Some(TR::buttons__confirm.into())) + }; + let layout = RootComponent::new(Frame::left_aligned(theme::label_title(), title, page)); + Ok(layout) + } + fn confirm_reset_device(recovery: bool) -> Result { let (title, button) = if recovery { ( diff --git a/core/embed/rust/src/ui/ui_features_fw.rs b/core/embed/rust/src/ui/ui_features_fw.rs index 1f0c91a572..6eb59e7071 100644 --- a/core/embed/rust/src/ui/ui_features_fw.rs +++ b/core/embed/rust/src/ui/ui_features_fw.rs @@ -79,6 +79,12 @@ pub trait UIFeaturesFirmware { amount_new: TString<'static>, ) -> Result; + fn confirm_properties( + title: TString<'static>, + items: Obj, // TODO: replace Obj` + hold: bool, + ) -> Result; + fn confirm_reset_device(recovery: bool) -> Result; fn confirm_value( diff --git a/core/mocks/generated/trezorui2.pyi b/core/mocks/generated/trezorui2.pyi index 90bf513ade..8596d96c92 100644 --- a/core/mocks/generated/trezorui2.pyi +++ b/core/mocks/generated/trezorui2.pyi @@ -28,17 +28,6 @@ def confirm_address( and allows left swipe which does the same thing as the button.""" -# rust/src/ui/model_mercury/layout.rs -def confirm_properties( - *, - title: str, - items: list[tuple[str | None, str | bytes | None, bool]], - hold: bool = False, -) -> LayoutObj[UiResult]: - """Confirm list of key-value pairs. The third component in the tuple should be True if - the value is to be rendered as binary with monospace font, False otherwise.""" - - # rust/src/ui/model_mercury/layout.rs def flow_confirm_set_new_pin( *, @@ -161,18 +150,6 @@ def confirm_address( """Confirm address.""" -# rust/src/ui/model_tr/layout.rs -def confirm_properties( - *, - title: str, - items: list[tuple[str | None, str | bytes | None, bool]], - hold: bool = False, -) -> LayoutObj[UiResult]: - """Confirm list of key-value pairs. The third component in the tuple should be True if - the value is to be rendered as binary with monospace font, False otherwise. - This only concerns the text style, you need to decode the value to UTF-8 in python.""" - - # rust/src/ui/model_tr/layout.rs def confirm_backup() -> LayoutObj[UiResult]: """Strongly recommend user to do backup.""" @@ -294,17 +271,6 @@ def confirm_address( and allows left swipe which does the same thing as the button.""" -# rust/src/ui/model_tt/layout.rs -def confirm_properties( - *, - title: str, - items: list[tuple[str | None, str | bytes | None, bool]], - hold: bool = False, -) -> LayoutObj[UiResult]: - """Confirm list of key-value pairs. The third component in the tuple should be True if - the value is to be rendered as binary with monospace font, False otherwise.""" - - # rust/src/ui/model_tt/layout.rs def show_address_details( *, diff --git a/core/mocks/generated/trezorui_api.pyi b/core/mocks/generated/trezorui_api.pyi index a291e04ce8..5160e201c5 100644 --- a/core/mocks/generated/trezorui_api.pyi +++ b/core/mocks/generated/trezorui_api.pyi @@ -179,6 +179,17 @@ def confirm_modify_output( """Decrease or increase output amount.""" +# rust/src/ui/api/firmware_upy.rs +def confirm_properties( + *, + title: str, + items: list[tuple[str | None, str | bytes | None, bool]], + hold: bool = False, +) -> LayoutObj[UiResult]: + """Confirm list of key-value pairs. The third component in the tuple should be True if + the value is to be rendered as binary with monospace font, False otherwise.""" + + # rust/src/ui/api/firmware_upy.rs def confirm_reset_device(recovery: bool) -> LayoutObj[UiResult]: """Confirm TOS before creating wallet creation or wallet recovery.""" diff --git a/core/src/trezor/ui/layouts/mercury/__init__.py b/core/src/trezor/ui/layouts/mercury/__init__.py index d454c36f87..096c448021 100644 --- a/core/src/trezor/ui/layouts/mercury/__init__.py +++ b/core/src/trezor/ui/layouts/mercury/__init__.py @@ -636,7 +636,7 @@ def confirm_properties( items = [(prop[0], prop[1], isinstance(prop[1], bytes)) for prop in props] return raise_if_not_confirmed( - trezorui2.confirm_properties( + trezorui_api.confirm_properties( title=title, items=items, hold=hold, diff --git a/core/src/trezor/ui/layouts/tr/__init__.py b/core/src/trezor/ui/layouts/tr/__init__.py index 5f283ef55e..ea053a70f2 100644 --- a/core/src/trezor/ui/layouts/tr/__init__.py +++ b/core/src/trezor/ui/layouts/tr/__init__.py @@ -684,7 +684,7 @@ def confirm_properties( return (key, value, bool(is_data)) return raise_if_not_confirmed( - trezorui2.confirm_properties( + trezorui_api.confirm_properties( title=title, items=map(handle_bytes, props), # type: ignore [cannot be assigned to parameter "items"] hold=hold, diff --git a/core/src/trezor/ui/layouts/tt/__init__.py b/core/src/trezor/ui/layouts/tt/__init__.py index bf94e24f96..8a63dd14ad 100644 --- a/core/src/trezor/ui/layouts/tt/__init__.py +++ b/core/src/trezor/ui/layouts/tt/__init__.py @@ -693,7 +693,7 @@ def confirm_properties( items = [(prop[0], prop[1], isinstance(prop[1], bytes)) for prop in props] return raise_if_not_confirmed( - trezorui2.confirm_properties( + trezorui_api.confirm_properties( title=title, items=items, hold=hold,