diff --git a/core/embed/rust/src/ui/api/firmware_upy.rs b/core/embed/rust/src/ui/api/firmware_upy.rs index f97d0e7fcd..51e22d9ee9 100644 --- a/core/embed/rust/src/ui/api/firmware_upy.rs +++ b/core/embed/rust/src/ui/api/firmware_upy.rs @@ -243,6 +243,44 @@ extern "C" fn new_confirm_reset_device(n_args: usize, args: *const Obj, kwargs: unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } +extern "C" fn new_confirm_value(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 subtitle: Option = kwargs.get(Qstr::MP_QSTR_subtitle)?.try_into_option()?; + let description: Option = + kwargs.get(Qstr::MP_QSTR_description)?.try_into_option()?; + let value: Obj = kwargs.get(Qstr::MP_QSTR_value)?; + let info_button: bool = kwargs.get_or(Qstr::MP_QSTR_info_button, false)?; + + let verb: Option = kwargs + .get(Qstr::MP_QSTR_verb) + .unwrap_or_else(|_| Obj::const_none()) + .try_into_option()?; + let verb_cancel: Option = kwargs + .get(Qstr::MP_QSTR_verb_cancel) + .unwrap_or_else(|_| Obj::const_none()) + .try_into_option()?; + let hold: bool = kwargs.get_or(Qstr::MP_QSTR_hold, false)?; + let chunkify: bool = kwargs.get_or(Qstr::MP_QSTR_chunkify, false)?; + let text_mono: bool = kwargs.get_or(Qstr::MP_QSTR_text_mono, true)?; + + let layout_obj = ModelUI::confirm_value( + title, + value, + description, + subtitle, + verb, + verb_cancel, + info_button, + hold, + chunkify, + text_mono, + )?; + Ok(layout_obj.into()) + }; + unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } +} + extern "C" fn new_confirm_with_info(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()?; @@ -903,6 +941,22 @@ pub static mp_module_trezorui_api: Module = obj_module! { /// """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(), + /// def confirm_value( + /// *, + /// title: str, + /// value: str, + /// description: str | None, + /// subtitle: str | None, + /// verb: str | None = None, + /// verb_cancel: str | None = None, + /// info_button: bool = False, + /// hold: bool = False, + /// chunkify: bool = False, + /// text_mono: bool = True, + /// ) -> LayoutObj[UiResult]: + /// """Confirm value. Merge of confirm_total and confirm_output.""" + Qstr::MP_QSTR_confirm_value => obj_fn_kw!(0, new_confirm_value).as_obj(), + /// def confirm_with_info( /// *, /// 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 47d6cd270c..c3f44e83f5 100644 --- a/core/embed/rust/src/ui/model_mercury/layout.rs +++ b/core/embed/rust/src/ui/model_mercury/layout.rs @@ -495,43 +495,6 @@ extern "C" fn new_confirm_summary(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_value(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 subtitle: Option = kwargs.get(Qstr::MP_QSTR_subtitle)?.try_into_option()?; - let description: Option = - kwargs.get(Qstr::MP_QSTR_description)?.try_into_option()?; - let value: Obj = kwargs.get(Qstr::MP_QSTR_value)?; - let info_button: bool = kwargs.get_or(Qstr::MP_QSTR_info_button, false)?; - - let verb: Option = kwargs - .get(Qstr::MP_QSTR_verb) - .unwrap_or_else(|_| Obj::const_none()) - .try_into_option()?; - let verb_cancel: Option = kwargs - .get(Qstr::MP_QSTR_verb_cancel) - .unwrap_or_else(|_| Obj::const_none()) - .try_into_option()?; - let hold: bool = kwargs.get_or(Qstr::MP_QSTR_hold, false)?; - let chunkify: bool = kwargs.get_or(Qstr::MP_QSTR_chunkify, false)?; - let text_mono: bool = kwargs.get_or(Qstr::MP_QSTR_text_mono, true)?; - - ConfirmBlobParams::new(title, value, description) - .with_subtitle(subtitle) - .with_verb(verb) - .with_verb_cancel(verb_cancel) - .with_info_button(info_button) - .with_chunkify(chunkify) - .with_text_mono(text_mono) - .with_prompt(hold) - .with_hold(hold) - .into_flow() - .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_total(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()?; @@ -693,22 +656,6 @@ pub static mp_module_trezorui2: Module = obj_module! { /// """Confirm new PIN setup with an option to cancel action.""" Qstr::MP_QSTR_flow_confirm_set_new_pin => obj_fn_kw!(0, new_confirm_set_new_pin).as_obj(), - /// def confirm_value( - /// *, - /// title: str, - /// value: str, - /// description: str | None, - /// subtitle: str | None, - /// verb: str | None = None, - /// verb_cancel: str | None = None, - /// info_button: bool = False, - /// hold: bool = False, - /// chunkify: bool = False, - /// text_mono: bool = True, - /// ) -> LayoutObj[UiResult]: - /// """Confirm value. Merge of confirm_total and confirm_output.""" - Qstr::MP_QSTR_confirm_value => obj_fn_kw!(0, new_confirm_value).as_obj(), - /// def confirm_total( /// *, /// title: str, 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 0fd372a552..08cda289b2 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 @@ -274,6 +274,32 @@ impl UIFeaturesFirmware for ModelMercuryFeatures { Ok(flow) } + fn confirm_value( + title: TString<'static>, + value: Obj, + description: Option>, + subtitle: Option>, + verb: Option>, + verb_cancel: Option>, + info_button: bool, + hold: bool, + chunkify: bool, + text_mono: bool, + ) -> Result, Error> { + ConfirmBlobParams::new(title, value, description) + .with_subtitle(subtitle) + .with_verb(verb) + .with_verb_cancel(verb_cancel) + .with_info_button(info_button) + .with_chunkify(chunkify) + .with_text_mono(text_mono) + .with_prompt(hold) + .with_hold(hold) + .into_flow() + .and_then(LayoutObj::new_root) + .map(Into::into) + } + fn confirm_with_info( title: TString<'static>, button: TString<'static>, diff --git a/core/embed/rust/src/ui/model_tr/layout.rs b/core/embed/rust/src/ui/model_tr/layout.rs index d8cf9496a4..33d85083fa 100644 --- a/core/embed/rust/src/ui/model_tr/layout.rs +++ b/core/embed/rust/src/ui/model_tr/layout.rs @@ -378,34 +378,6 @@ extern "C" fn new_show_address_details(n_args: usize, args: *const Obj, kwargs: unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } -extern "C" fn new_confirm_value(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: TString = kwargs.get(Qstr::MP_QSTR_description)?.try_into()?; - let value: TString = kwargs.get(Qstr::MP_QSTR_value)?.try_into()?; - - let verb: Option> = kwargs - .get(Qstr::MP_QSTR_verb) - .unwrap_or_else(|_| Obj::const_none()) - .try_into_option()?; - let hold: bool = kwargs.get_or(Qstr::MP_QSTR_hold, false)?; - - let paragraphs = Paragraphs::new([ - Paragraph::new(&theme::TEXT_BOLD, description), - Paragraph::new(&theme::TEXT_MONO, value), - ]); - - content_in_button_page( - title, - paragraphs, - verb.unwrap_or(TR::buttons__confirm.into()), - Some("".into()), - hold, - ) - }; - unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } -} - extern "C" fn new_confirm_joint_total(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { let block = move |_args: &[Obj], kwargs: &Map| { let spending_amount: TString = kwargs.get(Qstr::MP_QSTR_spending_amount)?.try_into()?; @@ -801,17 +773,6 @@ pub static mp_module_trezorui2: Module = obj_module! { /// """Show address details - QR code, account, path, cosigner xpubs.""" Qstr::MP_QSTR_show_address_details => obj_fn_kw!(0, new_show_address_details).as_obj(), - /// def confirm_value( - /// *, - /// title: str, - /// description: str, - /// value: str, - /// verb: str | None = None, - /// hold: bool = False, - /// ) -> LayoutObj[UiResult]: - /// """Confirm value.""" - Qstr::MP_QSTR_confirm_value => obj_fn_kw!(0, new_confirm_value).as_obj(), - /// def confirm_joint_total( /// *, /// spending_amount: str, 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 2684fdf060..2a7f67fa76 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 @@ -334,6 +334,35 @@ impl UIFeaturesFirmware for ModelTRFeatures { content_in_button_page(title, formatted, button, Some("".into()), false) } + fn confirm_value( + title: TString<'static>, + value: Obj, + description: Option>, + _subtitle: Option>, + verb: Option>, + _verb_cancel: Option>, + _info_button: bool, + hold: bool, + _chunkify: bool, + _text_mono: bool, + ) -> Result, Error> { + let value: TString = value.try_into()?; + let description = description.unwrap_or("".into()); + let paragraphs = Paragraphs::new([ + Paragraph::new(&theme::TEXT_BOLD, description), + Paragraph::new(&theme::TEXT_MONO, value), + ]); + + let layout = content_in_button_page( + title, + paragraphs, + verb.unwrap_or(TR::buttons__confirm.into()), + Some("".into()), + hold, + )?; + LayoutObj::new_root(layout) + } + fn confirm_with_info( title: TString<'static>, button: TString<'static>, diff --git a/core/embed/rust/src/ui/model_tt/layout.rs b/core/embed/rust/src/ui/model_tt/layout.rs index 1a125b6af7..a422595056 100644 --- a/core/embed/rust/src/ui/model_tt/layout.rs +++ b/core/embed/rust/src/ui/model_tt/layout.rs @@ -352,115 +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) } } -struct ConfirmBlobParams { - title: TString<'static>, - subtitle: Option>, - data: Obj, - description: Option>, - extra: Option>, - verb: Option>, - verb_cancel: Option>, - info_button: bool, - hold: bool, - chunkify: bool, - text_mono: bool, - page_limit: Option, -} - -impl ConfirmBlobParams { - fn new( - title: TString<'static>, - data: Obj, - description: Option>, - verb: Option>, - verb_cancel: Option>, - hold: bool, - ) -> Self { - Self { - title, - subtitle: None, - data, - description, - extra: None, - verb, - verb_cancel, - info_button: false, - hold, - chunkify: false, - text_mono: true, - page_limit: None, - } - } - - fn with_extra(mut self, extra: Option>) -> Self { - self.extra = extra; - self - } - - fn with_subtitle(mut self, subtitle: Option>) -> Self { - self.subtitle = subtitle; - self - } - - fn with_info_button(mut self, info_button: bool) -> Self { - self.info_button = info_button; - self - } - - fn with_chunkify(mut self, chunkify: bool) -> Self { - self.chunkify = chunkify; - self - } - - fn with_text_mono(mut self, text_mono: bool) -> Self { - self.text_mono = text_mono; - self - } - - fn with_page_limit(mut self, page_limit: Option) -> Self { - self.page_limit = page_limit; - self - } - - fn into_layout(self) -> Result { - let paragraphs = ConfirmBlob { - description: self.description.unwrap_or("".into()), - extra: self.extra.unwrap_or("".into()), - data: self.data.try_into()?, - description_font: &theme::TEXT_NORMAL, - extra_font: &theme::TEXT_DEMIBOLD, - data_font: if self.chunkify { - let data: TString = self.data.try_into()?; - theme::get_chunkified_text_style(data.len()) - } else if self.text_mono { - &theme::TEXT_MONO - } else { - &theme::TEXT_NORMAL - }, - } - .into_paragraphs(); - - let mut page = ButtonPage::new(paragraphs, theme::BG); - if let Some(verb) = self.verb { - page = page.with_cancel_confirm(self.verb_cancel, Some(verb)) - } - if self.hold { - page = page.with_hold()? - } - page = page.with_page_limit(self.page_limit); - let mut frame = Frame::left_aligned(theme::label_title(), self.title, page); - if let Some(subtitle) = self.subtitle { - frame = frame.with_subtitle(theme::label_subtitle(), subtitle); - } - - if self.info_button { - frame = frame.with_info_button(); - } - let obj = LayoutObj::new(frame)?; - Ok(obj.into()) - } -} - 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()?; @@ -559,37 +450,6 @@ extern "C" fn new_show_address_details(n_args: usize, args: *const Obj, kwargs: unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } -extern "C" fn new_confirm_value(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 subtitle: Option = kwargs.get(Qstr::MP_QSTR_subtitle)?.try_into_option()?; - let description: Option = - kwargs.get(Qstr::MP_QSTR_description)?.try_into_option()?; - let value: Obj = kwargs.get(Qstr::MP_QSTR_value)?; - let info_button: bool = kwargs.get_or(Qstr::MP_QSTR_info_button, false)?; - - let verb: Option = kwargs - .get(Qstr::MP_QSTR_verb) - .unwrap_or_else(|_| Obj::const_none()) - .try_into_option()?; - let verb_cancel: Option = kwargs - .get(Qstr::MP_QSTR_verb_cancel) - .unwrap_or_else(|_| Obj::const_none()) - .try_into_option()?; - let hold: bool = kwargs.get_or(Qstr::MP_QSTR_hold, false)?; - let chunkify: bool = kwargs.get_or(Qstr::MP_QSTR_chunkify, false)?; - let text_mono: bool = kwargs.get_or(Qstr::MP_QSTR_text_mono, true)?; - - ConfirmBlobParams::new(title, value, description, verb, verb_cancel, hold) - .with_subtitle(subtitle) - .with_info_button(info_button) - .with_chunkify(chunkify) - .with_text_mono(text_mono) - .into_layout() - }; - unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } -} - extern "C" fn new_confirm_total(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()?; @@ -707,22 +567,6 @@ pub static mp_module_trezorui2: Module = obj_module! { /// """Show address details - QR code, account, path, cosigner xpubs.""" Qstr::MP_QSTR_show_address_details => obj_fn_kw!(0, new_show_address_details).as_obj(), - /// def confirm_value( - /// *, - /// title: str, - /// value: str, - /// description: str | None, - /// subtitle: str | None, - /// verb: str | None = None, - /// verb_cancel: str | None = None, - /// info_button: bool = False, - /// hold: bool = False, - /// chunkify: bool = False, - /// text_mono: bool = True, - /// ) -> LayoutObj[UiResult]: - /// """Confirm value. Merge of confirm_total and confirm_output.""" - Qstr::MP_QSTR_confirm_value => obj_fn_kw!(0, new_confirm_value).as_obj(), - /// def confirm_total( /// *, /// 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 ff8e8517f8..7a5c003212 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 @@ -301,6 +301,26 @@ impl UIFeaturesFirmware for ModelTTFeatures { Ok(layout) } + fn confirm_value( + title: TString<'static>, + value: Obj, + description: Option>, + subtitle: Option>, + verb: Option>, + verb_cancel: Option>, + info_button: bool, + hold: bool, + chunkify: bool, + text_mono: bool, + ) -> Result, Error> { + ConfirmBlobParams::new(title, value, description, verb, verb_cancel, hold) + .with_subtitle(subtitle) + .with_info_button(info_button) + .with_chunkify(chunkify) + .with_text_mono(text_mono) + .into_layout() + } + fn confirm_with_info( title: TString<'static>, button: TString<'static>, diff --git a/core/embed/rust/src/ui/ui_features_fw.rs b/core/embed/rust/src/ui/ui_features_fw.rs index 6086e1f4da..1f0c91a572 100644 --- a/core/embed/rust/src/ui/ui_features_fw.rs +++ b/core/embed/rust/src/ui/ui_features_fw.rs @@ -81,6 +81,19 @@ pub trait UIFeaturesFirmware { fn confirm_reset_device(recovery: bool) -> Result; + fn confirm_value( + title: TString<'static>, + value: Obj, // TODO: replace Obj + description: Option>, + subtitle: Option>, + verb: Option>, + verb_cancel: Option>, + info_button: bool, + hold: bool, + chunkify: bool, + text_mono: bool, + ) -> Result, Error>; // TODO: return LayoutMaybeTrace + fn confirm_with_info( title: TString<'static>, button: TString<'static>, diff --git a/core/mocks/generated/trezorui2.pyi b/core/mocks/generated/trezorui2.pyi index 2b53713141..90bf513ade 100644 --- a/core/mocks/generated/trezorui2.pyi +++ b/core/mocks/generated/trezorui2.pyi @@ -48,23 +48,6 @@ def flow_confirm_set_new_pin( """Confirm new PIN setup with an option to cancel action.""" -# rust/src/ui/model_mercury/layout.rs -def confirm_value( - *, - title: str, - value: str, - description: str | None, - subtitle: str | None, - verb: str | None = None, - verb_cancel: str | None = None, - info_button: bool = False, - hold: bool = False, - chunkify: bool = False, - text_mono: bool = True, -) -> LayoutObj[UiResult]: - """Confirm value. Merge of confirm_total and confirm_output.""" - - # rust/src/ui/model_mercury/layout.rs def confirm_total( *, @@ -207,18 +190,6 @@ def show_address_details( """Show address details - QR code, account, path, cosigner xpubs.""" -# rust/src/ui/model_tr/layout.rs -def confirm_value( - *, - title: str, - description: str, - value: str, - verb: str | None = None, - hold: bool = False, -) -> LayoutObj[UiResult]: - """Confirm value.""" - - # rust/src/ui/model_tr/layout.rs def confirm_joint_total( *, @@ -348,23 +319,6 @@ def show_address_details( """Show address details - QR code, account, path, cosigner xpubs.""" -# rust/src/ui/model_tt/layout.rs -def confirm_value( - *, - title: str, - value: str, - description: str | None, - subtitle: str | None, - verb: str | None = None, - verb_cancel: str | None = None, - info_button: bool = False, - hold: bool = False, - chunkify: bool = False, - text_mono: bool = True, -) -> LayoutObj[UiResult]: - """Confirm value. Merge of confirm_total and confirm_output.""" - - # rust/src/ui/model_tt/layout.rs def confirm_total( *, diff --git a/core/mocks/generated/trezorui_api.pyi b/core/mocks/generated/trezorui_api.pyi index a1a94cde77..a291e04ce8 100644 --- a/core/mocks/generated/trezorui_api.pyi +++ b/core/mocks/generated/trezorui_api.pyi @@ -184,6 +184,23 @@ def confirm_reset_device(recovery: bool) -> LayoutObj[UiResult]: """Confirm TOS before creating wallet creation or wallet recovery.""" +# rust/src/ui/api/firmware_upy.rs +def confirm_value( + *, + title: str, + value: str, + description: str | None, + subtitle: str | None, + verb: str | None = None, + verb_cancel: str | None = None, + info_button: bool = False, + hold: bool = False, + chunkify: bool = False, + text_mono: bool = True, +) -> LayoutObj[UiResult]: + """Confirm value. Merge of confirm_total and confirm_output.""" + + # rust/src/ui/api/firmware_upy.rs def confirm_with_info( *, diff --git a/core/src/trezor/ui/layouts/mercury/__init__.py b/core/src/trezor/ui/layouts/mercury/__init__.py index 767913899a..d454c36f87 100644 --- a/core/src/trezor/ui/layouts/mercury/__init__.py +++ b/core/src/trezor/ui/layouts/mercury/__init__.py @@ -608,7 +608,7 @@ def confirm_value( ) return with_info( - trezorui2.confirm_value( + trezorui_api.confirm_value( title=title, subtitle=subtitle, description=description, diff --git a/core/src/trezor/ui/layouts/tr/__init__.py b/core/src/trezor/ui/layouts/tr/__init__.py index 32aaa6204f..5f283ef55e 100644 --- a/core/src/trezor/ui/layouts/tr/__init__.py +++ b/core/src/trezor/ui/layouts/tr/__init__.py @@ -713,7 +713,7 @@ async def confirm_value( if info_items is None: return await raise_if_not_confirmed( - trezorui2.confirm_value( # type: ignore [Argument missing for parameter "subtitle"] + trezorui_api.confirm_value( # type: ignore [Argument missing for parameter "subtitle"] title=title, description=description, value=value, diff --git a/core/src/trezor/ui/layouts/tt/__init__.py b/core/src/trezor/ui/layouts/tt/__init__.py index 5d09856b5f..bf94e24f96 100644 --- a/core/src/trezor/ui/layouts/tt/__init__.py +++ b/core/src/trezor/ui/layouts/tt/__init__.py @@ -404,7 +404,7 @@ async def confirm_output( while True: # if the user cancels here, raise ActionCancelled (by default) await interact( - trezorui2.confirm_value( + trezorui_api.confirm_value( title=recipient_title, subtitle=address_label, description=None, @@ -420,7 +420,7 @@ async def confirm_output( try: await interact( - trezorui2.confirm_value( + trezorui_api.confirm_value( title=amount_title, subtitle=None, description=None, @@ -666,7 +666,7 @@ def confirm_value( ) return with_info( - trezorui2.confirm_value( + trezorui_api.confirm_value( title=title, subtitle=subtitle, description=description,