diff --git a/core/embed/rust/src/ui/api/firmware_upy.rs b/core/embed/rust/src/ui/api/firmware_upy.rs index 09d3644244..f00b2949b8 100644 --- a/core/embed/rust/src/ui/api/firmware_upy.rs +++ b/core/embed/rust/src/ui/api/firmware_upy.rs @@ -85,6 +85,30 @@ extern "C" fn new_confirm_action(n_args: usize, args: *const Obj, kwargs: *mut M unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } +extern "C" fn new_confirm_address(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 data: Obj = kwargs.get(Qstr::MP_QSTR_data)?; + let description: Option = kwargs + .get(Qstr::MP_QSTR_description) + .unwrap_or_else(|_| Obj::const_none()) + .try_into_option()?; + let extra: Option = kwargs + .get(Qstr::MP_QSTR_extra) + .unwrap_or_else(|_| Obj::const_none()) + .try_into_option()?; + let verb: Option = kwargs + .get(Qstr::MP_QSTR_verb) + .unwrap_or_else(|_| Obj::const_none()) + .try_into_option()?; + let chunkify: bool = kwargs.get_or(Qstr::MP_QSTR_chunkify, false)?; + + let layout = ModelUI::confirm_address(title, data, description, extra, verb, chunkify)?; + Ok(LayoutObj::new_root(layout)?.into()) + }; + unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } +} + extern "C" fn new_confirm_blob(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()?; @@ -886,6 +910,18 @@ pub static mp_module_trezorui_api: Module = obj_module! { /// """Confirm action.""" Qstr::MP_QSTR_confirm_action => obj_fn_kw!(0, new_confirm_action).as_obj(), + /// def confirm_address( + /// *, + /// title: str, + /// data: str | bytes, + /// description: str | None, + /// extra: str | None, + /// verb: str | None = None, + /// chunkify: bool = False, + /// ) -> LayoutObj[UiResult]: + /// """Confirm address.""" + Qstr::MP_QSTR_confirm_address => obj_fn_kw!(0, new_confirm_address).as_obj(), + /// def confirm_blob( /// *, /// title: str, diff --git a/core/embed/rust/src/ui/model_mercury/layout.rs b/core/embed/rust/src/ui/model_mercury/layout.rs index c9ecba6e1c..425a707dfd 100644 --- a/core/embed/rust/src/ui/model_mercury/layout.rs +++ b/core/embed/rust/src/ui/model_mercury/layout.rs @@ -257,45 +257,6 @@ extern "C" fn new_confirm_emphasized(n_args: usize, args: *const Obj, kwargs: *m unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } -extern "C" fn new_confirm_address(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 description: Option = - kwargs.get(Qstr::MP_QSTR_description)?.try_into_option()?; - let extra: Option = kwargs.get(Qstr::MP_QSTR_extra)?.try_into_option()?; - let data: Obj = kwargs.get(Qstr::MP_QSTR_data)?; - let chunkify: bool = kwargs.get_or(Qstr::MP_QSTR_chunkify, false)?; - - let data_style = if chunkify { - let address: TString = data.try_into()?; - theme::get_chunkified_text_style(address.len()) - } else { - &theme::TEXT_MONO - }; - - let paragraphs = ConfirmBlob { - description: description.unwrap_or("".into()), - extra: extra.unwrap_or("".into()), - data: data.try_into()?, - description_font: &theme::TEXT_NORMAL, - extra_font: &theme::TEXT_DEMIBOLD, - data_font: data_style, - } - .into_paragraphs(); - - flow::new_confirm_action_simple( - paragraphs, - ConfirmActionMenu::new(None, false, None), - ConfirmActionStrings::new(title, None, None, None), - false, - 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()?; @@ -573,19 +534,6 @@ pub static mp_module_trezorui2: Module = obj_module! { /// the first component is a bool indicating whether this part is emphasized.""" Qstr::MP_QSTR_confirm_emphasized => obj_fn_kw!(0, new_confirm_emphasized).as_obj(), - /// def confirm_address( - /// *, - /// title: str, - /// data: str | bytes, - /// description: str | None, - /// verb: str | None = "CONFIRM", - /// extra: str | None, - /// chunkify: bool = False, - /// ) -> LayoutObj[UiResult]: - /// """Confirm address. Similar to `confirm_blob` but has corner info button - /// 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(), - // 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 aa2cecfec9..5470fab258 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::{PropsList, RecoveryType}, + util::{ConfirmBlob, PropsList, RecoveryType}, }, ui_features_fw::UIFeaturesFirmware, }, @@ -69,6 +69,41 @@ impl UIFeaturesFirmware for ModelMercuryFeatures { Ok(flow) } + fn confirm_address( + title: TString<'static>, + data: Obj, + description: Option>, + extra: Option>, + _verb: Option>, + chunkify: bool, + ) -> Result { + let data_style = if chunkify { + let address: TString = data.try_into()?; + theme::get_chunkified_text_style(address.len()) + } else { + &theme::TEXT_MONO + }; + + let paragraphs = ConfirmBlob { + description: description.unwrap_or("".into()), + extra: extra.unwrap_or("".into()), + data: data.try_into()?, + description_font: &theme::TEXT_NORMAL, + extra_font: &theme::TEXT_DEMIBOLD, + data_font: data_style, + } + .into_paragraphs(); + + let flow = flow::new_confirm_action_simple( + paragraphs, + ConfirmActionMenu::new(None, false, None), + ConfirmActionStrings::new(title, None, None, None), + false, + None, + )?; + Ok(flow) + } + fn confirm_blob( title: TString<'static>, data: Obj, diff --git a/core/embed/rust/src/ui/model_tr/layout.rs b/core/embed/rust/src/ui/model_tr/layout.rs index 5f73a86cd4..a093be6b8a 100644 --- a/core/embed/rust/src/ui/model_tr/layout.rs +++ b/core/embed/rust/src/ui/model_tr/layout.rs @@ -562,37 +562,6 @@ extern "C" fn new_altcoin_tx_summary(n_args: usize, args: *const Obj, kwargs: *m unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } -extern "C" fn new_confirm_address(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 address: TString = kwargs.get(Qstr::MP_QSTR_data)?.try_into()?; - let verb: TString<'static> = - kwargs.get_or(Qstr::MP_QSTR_verb, TR::buttons__confirm.into())?; - let chunkify: bool = kwargs.get_or(Qstr::MP_QSTR_chunkify, false)?; - - let get_page = move |page_index| { - assert!(page_index == 0); - - let btn_layout = ButtonLayout::cancel_armed_info(verb); - let btn_actions = ButtonActions::cancel_confirm_info(); - let style = if chunkify { - // Chunkifying the address into smaller pieces when requested - theme::TEXT_MONO_ADDRESS_CHUNKS - } else { - theme::TEXT_MONO_DATA - }; - let ops = OpTextLayout::new(style).text_mono(address); - let formatted = FormattedText::new(ops).vertically_centered(); - Page::new(btn_layout, btn_actions, formatted).with_title(title) - }; - let pages = FlowPages::new(get_page, 1); - - let obj = LayoutObj::new(Flow::new(pages))?; - Ok(obj.into()) - }; - unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } -} - extern "C" fn new_multiple_pages_texts(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()?; @@ -655,18 +624,6 @@ pub static mp_module_trezorui2: Module = obj_module! { /// Qstr::MP_QSTR___name__ => Qstr::MP_QSTR_trezorui2.to_obj(), - /// def confirm_address( - /// *, - /// title: str, - /// data: str, - /// description: str | None, # unused on TR - /// extra: str | None, # unused on TR - /// verb: str = "CONFIRM", - /// chunkify: bool = False, - /// ) -> LayoutObj[UiResult]: - /// """Confirm address.""" - Qstr::MP_QSTR_confirm_address => obj_fn_kw!(0, new_confirm_address).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 bad81b2006..4cd3a89fd8 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 @@ -83,6 +83,38 @@ impl UIFeaturesFirmware for ModelTRFeatures { ) } + fn confirm_address( + title: TString<'static>, + data: Obj, + description: Option>, + extra: Option>, + verb: Option>, + chunkify: bool, + ) -> Result { + let verb = verb.unwrap_or(TR::buttons__confirm.into()); + let address: TString = data.try_into()?; + + let get_page = move |page_index| { + assert!(page_index == 0); + + let btn_layout = ButtonLayout::cancel_armed_info(verb); + let btn_actions = ButtonActions::cancel_confirm_info(); + let style = if chunkify { + // Chunkifying the address into smaller pieces when requested + theme::TEXT_MONO_ADDRESS_CHUNKS + } else { + theme::TEXT_MONO_DATA + }; + let ops = OpTextLayout::new(style).text_mono(address); + let formatted = FormattedText::new(ops).vertically_centered(); + Page::new(btn_layout, btn_actions, formatted).with_title(title) + }; + let pages = FlowPages::new(get_page, 1); + + let layout = RootComponent::new(Flow::new(pages)); + Ok(layout) + } + fn confirm_blob( title: TString<'static>, data: Obj, diff --git a/core/embed/rust/src/ui/model_tt/layout.rs b/core/embed/rust/src/ui/model_tt/layout.rs index 04fafed3dc..9a7a92b0a4 100644 --- a/core/embed/rust/src/ui/model_tt/layout.rs +++ b/core/embed/rust/src/ui/model_tt/layout.rs @@ -352,48 +352,6 @@ extern "C" fn new_confirm_emphasized(n_args: usize, args: *const Obj, kwargs: *m unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } -extern "C" fn new_confirm_address(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 description: Option = - kwargs.get(Qstr::MP_QSTR_description)?.try_into_option()?; - let verb: TString = kwargs.get_or(Qstr::MP_QSTR_verb, TR::buttons__confirm.into())?; - let extra: Option = kwargs.get(Qstr::MP_QSTR_extra)?.try_into_option()?; - let data: Obj = kwargs.get(Qstr::MP_QSTR_data)?; - let chunkify: bool = kwargs.get_or(Qstr::MP_QSTR_chunkify, false)?; - - let data_style = if chunkify { - let address: TString = data.try_into()?; - theme::get_chunkified_text_style(address.len()) - } else { - &theme::TEXT_MONO - }; - - let paragraphs = ConfirmBlob { - description: description.unwrap_or("".into()), - extra: extra.unwrap_or("".into()), - data: data.try_into()?, - description_font: &theme::TEXT_NORMAL, - extra_font: &theme::TEXT_DEMIBOLD, - data_font: data_style, - } - .into_paragraphs(); - - let obj = LayoutObj::new( - Frame::left_aligned( - theme::label_title(), - title, - ButtonPage::new(paragraphs, theme::BG) - .with_swipe_left() - .with_cancel_confirm(None, Some(verb)), - ) - .with_info_button(), - )?; - 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()?; @@ -473,19 +431,6 @@ pub static mp_module_trezorui2: Module = obj_module! { /// the first component is a bool indicating whether this part is emphasized.""" Qstr::MP_QSTR_confirm_emphasized => obj_fn_kw!(0, new_confirm_emphasized).as_obj(), - /// def confirm_address( - /// *, - /// title: str, - /// data: str | bytes, - /// description: str | None, - /// verb: str | None = "CONFIRM", - /// extra: str | None, - /// chunkify: bool = False, - /// ) -> LayoutObj[UiResult]: - /// """Confirm address. Similar to `confirm_blob` but has corner info button - /// 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 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 bc62f671ee..24d30a04c1 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 @@ -80,6 +80,45 @@ impl UIFeaturesFirmware for ModelTTFeatures { Ok(layout) } + fn confirm_address( + title: TString<'static>, + data: Obj, + description: Option>, + extra: Option>, + verb: Option>, + chunkify: bool, + ) -> Result { + let verb = verb.unwrap_or(TR::buttons__confirm.into()); + let data_style = if chunkify { + let address: TString = data.try_into()?; + theme::get_chunkified_text_style(address.len()) + } else { + &theme::TEXT_MONO + }; + + let paragraphs = ConfirmBlob { + description: description.unwrap_or("".into()), + extra: extra.unwrap_or("".into()), + data: data.try_into()?, + description_font: &theme::TEXT_NORMAL, + extra_font: &theme::TEXT_DEMIBOLD, + data_font: data_style, + } + .into_paragraphs(); + + let layout = RootComponent::new( + Frame::left_aligned( + theme::label_title(), + title, + ButtonPage::new(paragraphs, theme::BG) + .with_swipe_left() + .with_cancel_confirm(None, Some(verb)), + ) + .with_info_button(), + ); + Ok(layout) + } + fn confirm_blob( title: TString<'static>, data: Obj, diff --git a/core/embed/rust/src/ui/ui_features_fw.rs b/core/embed/rust/src/ui/ui_features_fw.rs index cfc67fb37d..eaed74770c 100644 --- a/core/embed/rust/src/ui/ui_features_fw.rs +++ b/core/embed/rust/src/ui/ui_features_fw.rs @@ -26,6 +26,15 @@ pub trait UIFeaturesFirmware { prompt_title: Option>, ) -> Result; + fn confirm_address( + title: TString<'static>, + data: Obj, // TODO: replace Obj + description: Option>, + extra: Option>, + verb: Option>, + chunkify: bool, + ) -> Result; + fn confirm_blob( title: TString<'static>, data: Obj, // TODO: replace Obj diff --git a/core/mocks/generated/trezorui_api.pyi b/core/mocks/generated/trezorui_api.pyi index 7cced72539..1f78db6c55 100644 --- a/core/mocks/generated/trezorui_api.pyi +++ b/core/mocks/generated/trezorui_api.pyi @@ -96,6 +96,19 @@ def confirm_action( """Confirm action.""" +# rust/src/ui/api/firmware_upy.rs +def confirm_address( + *, + title: str, + data: str | bytes, + description: str | None, + extra: str | None, + verb: str | None = None, + chunkify: bool = False, +) -> LayoutObj[UiResult]: + """Confirm address.""" + + # rust/src/ui/api/firmware_upy.rs def confirm_blob( *, diff --git a/core/src/trezor/ui/layouts/mercury/__init__.py b/core/src/trezor/ui/layouts/mercury/__init__.py index 096c448021..f7943893cb 100644 --- a/core/src/trezor/ui/layouts/mercury/__init__.py +++ b/core/src/trezor/ui/layouts/mercury/__init__.py @@ -1004,7 +1004,7 @@ async def confirm_signverify( address_title = TR.sign_message__confirm_address br_name = "sign_message" - address_layout = trezorui2.confirm_address( + address_layout = trezorui_api.confirm_address( title=address_title, data=address, description="", diff --git a/core/src/trezor/ui/layouts/tr/__init__.py b/core/src/trezor/ui/layouts/tr/__init__.py index 4e3c4b7264..e7941c0795 100644 --- a/core/src/trezor/ui/layouts/tr/__init__.py +++ b/core/src/trezor/ui/layouts/tr/__init__.py @@ -248,7 +248,7 @@ async def show_address( while True: result = await interact( - trezorui2.confirm_address( + trezorui_api.confirm_address( title=title, data=address, description="", # unused on TR diff --git a/core/src/trezor/ui/layouts/tt/__init__.py b/core/src/trezor/ui/layouts/tt/__init__.py index 257022720a..3402b283e3 100644 --- a/core/src/trezor/ui/layouts/tt/__init__.py +++ b/core/src/trezor/ui/layouts/tt/__init__.py @@ -234,7 +234,7 @@ async def show_address( while True: result = await interact( - trezorui2.confirm_address( + trezorui_api.confirm_address( title=title, data=address, description=network or "", @@ -1049,7 +1049,7 @@ async def confirm_signverify( address_title = TR.sign_message__confirm_address br_name = "sign_message" - address_layout = trezorui2.confirm_address( + address_layout = trezorui_api.confirm_address( title=address_title, data=address, description="",