From 8d08341adc6ebf702ac058010b5598153fcb411b Mon Sep 17 00:00:00 2001 From: obrusvit Date: Thu, 21 Nov 2024 12:52:04 +0100 Subject: [PATCH] refactor(core): move confirm_blob - model_t `ConfirmBlobParams` copied for now and the return type of `into_layout` changed to `Result>` --- core/embed/rust/librust_qstr.h | 1 + core/embed/rust/src/ui/api/firmware_upy.rs | 79 ++++++++++ .../embed/rust/src/ui/model_mercury/layout.rs | 87 ----------- .../src/ui/model_mercury/ui_features_fw.rs | 46 +++++- core/embed/rust/src/ui/model_tr/layout.rs | 69 --------- .../rust/src/ui/model_tr/ui_features_fw.rs | 45 +++++- core/embed/rust/src/ui/model_tt/layout.rs | 58 -------- .../rust/src/ui/model_tt/ui_features_fw.rs | 136 +++++++++++++++++- core/embed/rust/src/ui/ui_features_fw.rs | 17 +++ core/mocks/generated/trezorui2.pyi | 63 -------- core/mocks/generated/trezorui_api.pyi | 21 +++ .../src/trezor/ui/layouts/mercury/__init__.py | 10 +- core/src/trezor/ui/layouts/tr/__init__.py | 8 +- core/src/trezor/ui/layouts/tt/__init__.py | 6 +- 14 files changed, 354 insertions(+), 292 deletions(-) diff --git a/core/embed/rust/librust_qstr.h b/core/embed/rust/librust_qstr.h index 901e37fa92..393d2ceada 100644 --- a/core/embed/rust/librust_qstr.h +++ b/core/embed/rust/librust_qstr.h @@ -280,6 +280,7 @@ static void _librust_qstrs(void) { MP_QSTR_icon_name; MP_QSTR_image; MP_QSTR_indeterminate; + MP_QSTR_info; MP_QSTR_info_button; MP_QSTR_init; MP_QSTR_inputs__back; diff --git a/core/embed/rust/src/ui/api/firmware_upy.rs b/core/embed/rust/src/ui/api/firmware_upy.rs index 20abf14858..f97d0e7fcd 100644 --- a/core/embed/rust/src/ui/api/firmware_upy.rs +++ b/core/embed/rust/src/ui/api/firmware_upy.rs @@ -85,6 +85,65 @@ 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_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()?; + 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 text_mono: bool = kwargs.get_or(Qstr::MP_QSTR_text_mono, true)?; + let extra: Option = kwargs + .get(Qstr::MP_QSTR_extra) + .unwrap_or_else(|_| Obj::const_none()) + .try_into_option()?; + let subtitle: Option = kwargs + .get(Qstr::MP_QSTR_subtitle) + .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 verb_cancel: Option = kwargs + .get(Qstr::MP_QSTR_verb_cancel) + .unwrap_or_else(|_| Obj::const_none()) + .try_into_option()?; + let verb_info: Option = kwargs + .get(Qstr::MP_QSTR_verb_info) + .unwrap_or_else(|_| Obj::const_none()) + .try_into_option()?; + let info: bool = kwargs.get_or(Qstr::MP_QSTR_info, false)?; // FIXME: mercury has true + let hold: bool = kwargs.get_or(Qstr::MP_QSTR_hold, false)?; + let chunkify: bool = kwargs.get_or(Qstr::MP_QSTR_chunkify, false)?; + let prompt_screen: bool = kwargs.get_or(Qstr::MP_QSTR_prompt_screen, true)?; + let page_limit: Option = kwargs + .get(Qstr::MP_QSTR_page_limit) + .unwrap_or_else(|_| Obj::const_none()) + .try_into_option()?; + + let layout_obj = ModelUI::confirm_blob( + title, + data, + description, + text_mono, + extra, + subtitle, + verb, + verb_cancel, + verb_info, + info, + hold, + chunkify, + prompt_screen, + page_limit, + )?; + Ok(layout_obj.into()) + }; + unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } +} + extern "C" fn new_confirm_coinjoin(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { let block = move |_args: &[Obj], kwargs: &Map| { let max_rounds: TString = kwargs.get(Qstr::MP_QSTR_max_rounds)?.try_into()?; @@ -763,6 +822,26 @@ 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_blob( + /// *, + /// title: str, + /// data: str | bytes, + /// description: str | None, + /// text_mono: bool = True, + /// extra: str | None = None, + /// subtitle: str | None = None, + /// verb: str | None = None, + /// verb_cancel: str | None = None, + /// verb_info: str | None = None, + /// info: bool = True, + /// hold: bool = False, + /// chunkify: bool = False, + /// prompt_screen: bool = False, + /// page_limit: int | None = None, + /// ) -> LayoutObj[UiResult]: + /// """Confirm byte sequence data.""" + Qstr::MP_QSTR_confirm_blob => obj_fn_kw!(0, new_confirm_blob).as_obj(), + /// def confirm_coinjoin( /// *, /// max_rounds: str, diff --git a/core/embed/rust/src/ui/model_mercury/layout.rs b/core/embed/rust/src/ui/model_mercury/layout.rs index 025e8647ea..47d6cd270c 100644 --- a/core/embed/rust/src/ui/model_mercury/layout.rs +++ b/core/embed/rust/src/ui/model_mercury/layout.rs @@ -257,73 +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_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()?; - 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 text_mono: bool = kwargs.get_or(Qstr::MP_QSTR_text_mono, true)?; - let extra: Option = kwargs - .get(Qstr::MP_QSTR_extra) - .unwrap_or_else(|_| Obj::const_none()) - .try_into_option()?; - let subtitle: Option = kwargs - .get(Qstr::MP_QSTR_subtitle) - .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 verb_cancel: Option = kwargs - .get(Qstr::MP_QSTR_verb_cancel) - .unwrap_or_else(|_| Obj::const_none()) - .try_into_option()?; - let verb_info: Option = kwargs - .get(Qstr::MP_QSTR_verb_info) - .unwrap_or_else(|_| Obj::const_none()) - .try_into_option()?; - let info: bool = kwargs.get_or(Qstr::MP_QSTR_info, true)?; - let hold: bool = kwargs.get_or(Qstr::MP_QSTR_hold, false)?; - let chunkify: bool = kwargs.get_or(Qstr::MP_QSTR_chunkify, false)?; - let prompt_screen: bool = kwargs.get_or(Qstr::MP_QSTR_prompt_screen, true)?; - let page_limit: Option = kwargs - .get(Qstr::MP_QSTR_page_limit) - .unwrap_or_else(|_| Obj::const_none()) - .try_into_option()?; - - let (description, description_font) = if page_limit == Some(1) { - ( - Some(TR::instructions__view_all_data.into()), - &theme::TEXT_SUB_GREEN_LIME, - ) - } else { - (description, &theme::TEXT_NORMAL) - }; - - ConfirmBlobParams::new(title, data, description) - .with_description_font(description_font) - .with_text_mono(text_mono) - .with_subtitle(subtitle) - .with_verb(verb) - .with_verb_cancel(verb_cancel) - .with_verb_info(verb_info) - .with_extra(extra) - .with_info_button(info) - .with_chunkify(chunkify) - .with_page_limit(page_limit) - .with_prompt(prompt_screen) - .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_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()?; @@ -728,26 +661,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_blob( - /// *, - /// title: str, - /// data: str | bytes, - /// description: str | None, - /// text_mono: bool = True, - /// extra: str | None = None, - /// subtitle: str | None = None, - /// verb: str | None = None, - /// verb_cancel: str | None = None, - /// verb_info: str | None = None, - /// info: bool = True, - /// hold: bool = False, - /// chunkify: bool = False, - /// prompt_screen: bool = False, - /// page_limit: int | None = None, - /// ) -> LayoutObj[UiResult]: - /// """Confirm byte sequence data.""" - Qstr::MP_QSTR_confirm_blob => obj_fn_kw!(0, new_confirm_blob).as_obj(), - /// def confirm_address( /// *, /// 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 f36bfb5118..0fd372a552 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 @@ -35,7 +35,8 @@ use super::{ SwipeContent, SwipeUpScreen, VerticalMenu, }, flow::{ - self, confirm_with_info, new_confirm_action_simple, ConfirmActionMenu, ConfirmActionStrings, + self, confirm_with_info, new_confirm_action_simple, ConfirmActionMenu, + ConfirmActionStrings, ConfirmBlobParams, }, theme, ModelMercuryFeatures, }; @@ -68,6 +69,49 @@ impl UIFeaturesFirmware for ModelMercuryFeatures { Ok(flow) } + fn confirm_blob( + title: TString<'static>, + data: Obj, + description: Option>, + text_mono: bool, + extra: Option>, + subtitle: Option>, + verb: Option>, + verb_cancel: Option>, + verb_info: Option>, + info: bool, + hold: bool, + chunkify: bool, + prompt_screen: bool, + page_limit: Option, + ) -> Result, Error> { + let (description, description_font) = if page_limit == Some(1) { + ( + Some(TR::instructions__view_all_data.into()), + &theme::TEXT_SUB_GREEN_LIME, + ) + } else { + (description, &theme::TEXT_NORMAL) + }; + + ConfirmBlobParams::new(title, data, description) + .with_description_font(description_font) + .with_text_mono(text_mono) + .with_subtitle(subtitle) + .with_verb(verb) + .with_verb_cancel(verb_cancel) + .with_verb_info(verb_info) + .with_extra(extra) + .with_info_button(info) + .with_chunkify(chunkify) + .with_page_limit(page_limit) + .with_prompt(prompt_screen) + .with_hold(hold) + .into_flow() + .and_then(LayoutObj::new_root) + .map(Into::into) + } + fn confirm_homescreen( title: TString<'static>, image: BinaryData<'static>, diff --git a/core/embed/rust/src/ui/model_tr/layout.rs b/core/embed/rust/src/ui/model_tr/layout.rs index 3ef8ac4913..d8cf9496a4 100644 --- a/core/embed/rust/src/ui/model_tr/layout.rs +++ b/core/embed/rust/src/ui/model_tr/layout.rs @@ -270,55 +270,6 @@ fn content_in_button_page( Ok(obj.into()) } -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()?; - let data: Obj = kwargs.get(Qstr::MP_QSTR_data)?; - let description: Option = - kwargs.get(Qstr::MP_QSTR_description)?.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 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 style = if chunkify { - // Chunkifying the address into smaller pieces when requested - &theme::TEXT_MONO_ADDRESS_CHUNKS - } else { - &theme::TEXT_MONO_DATA - }; - - let paragraphs = ConfirmBlob { - description: description.unwrap_or("".into()), - extra: extra.unwrap_or("".into()), - data: data.try_into()?, - description_font: &theme::TEXT_BOLD, - extra_font: &theme::TEXT_NORMAL, - data_font: style, - } - .into_paragraphs(); - - content_in_button_page( - title, - paragraphs, - verb.unwrap_or(TR::buttons__confirm.into()), - verb_cancel, - hold, - ) - }; - 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()?; @@ -811,26 +762,6 @@ pub static mp_module_trezorui2: Module = obj_module! { /// Qstr::MP_QSTR___name__ => Qstr::MP_QSTR_trezorui2.to_obj(), - /// def confirm_blob( - /// *, - /// title: str, - /// data: str | bytes, - /// description: str | None, - /// text_mono: bool = True, - /// extra: str | None = None, - /// subtitle: str | None = None, - /// verb: str = "CONFIRM", - /// verb_cancel: str | None = None, - /// verb_info: str | None = None, - /// info: bool = True, - /// hold: bool = False, - /// chunkify: bool = False, - /// prompt_screen: bool = False, - /// page_limit: int | None = None, - /// ) -> LayoutObj[UiResult]: - /// """Confirm byte sequence data.""" - Qstr::MP_QSTR_confirm_blob => obj_fn_kw!(0, new_confirm_blob).as_obj(), - /// def confirm_address( /// *, /// title: 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 6e0a6b13cb..2684fdf060 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 @@ -23,7 +23,7 @@ use crate::{ geometry, layout::{ obj::{LayoutMaybeTrace, LayoutObj, RootComponent}, - util::RecoveryType, + util::{ConfirmBlob, RecoveryType}, }, model_tr::{ component::{ButtonActions, ButtonLayout, Page}, @@ -83,6 +83,49 @@ impl UIFeaturesFirmware for ModelTRFeatures { ) } + fn confirm_blob( + title: TString<'static>, + data: Obj, + description: Option>, + _text_mono: bool, + extra: Option>, + _subtitle: Option>, + verb: Option>, + verb_cancel: Option>, + _verb_info: Option>, + _info: bool, + hold: bool, + chunkify: bool, + _prompt_screen: bool, + _page_limit: Option, + ) -> Result, Error> { + let style = if chunkify { + // Chunkifying the address into smaller pieces when requested + &theme::TEXT_MONO_ADDRESS_CHUNKS + } else { + &theme::TEXT_MONO_DATA + }; + + let paragraphs = ConfirmBlob { + description: description.unwrap_or("".into()), + extra: extra.unwrap_or("".into()), + data: data.try_into()?, + description_font: &theme::TEXT_BOLD, + extra_font: &theme::TEXT_NORMAL, + data_font: style, + } + .into_paragraphs(); + + let layout = content_in_button_page( + title, + paragraphs, + verb.unwrap_or(TR::buttons__confirm.into()), + verb_cancel, + hold, + )?; + LayoutObj::new_root(layout) + } + fn confirm_homescreen( title: TString<'static>, image: BinaryData<'static>, diff --git a/core/embed/rust/src/ui/model_tt/layout.rs b/core/embed/rust/src/ui/model_tt/layout.rs index 9eff10fa6a..1a125b6af7 100644 --- a/core/embed/rust/src/ui/model_tt/layout.rs +++ b/core/embed/rust/src/ui/model_tt/layout.rs @@ -461,44 +461,6 @@ impl ConfirmBlobParams { } } -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()?; - let data: Obj = kwargs.get(Qstr::MP_QSTR_data)?; - let description: Option = - kwargs.get(Qstr::MP_QSTR_description)?.try_into_option()?; - let text_mono: bool = kwargs.get_or(Qstr::MP_QSTR_text_mono, true)?; - 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 verb_cancel: Option = kwargs - .get(Qstr::MP_QSTR_verb_cancel) - .unwrap_or_else(|_| Obj::const_none()) - .try_into_option()?; - let info: bool = kwargs.get_or(Qstr::MP_QSTR_info, false)?; - let hold: bool = kwargs.get_or(Qstr::MP_QSTR_hold, false)?; - let chunkify: bool = kwargs.get_or(Qstr::MP_QSTR_chunkify, false)?; - let page_limit: Option = kwargs - .get(Qstr::MP_QSTR_page_limit) - .unwrap_or_else(|_| Obj::const_none()) - .try_into_option()?; - - ConfirmBlobParams::new(title, data, description, verb, verb_cancel, hold) - .with_text_mono(text_mono) - .with_extra(extra) - .with_chunkify(chunkify) - .with_info_button(info) - .with_page_limit(page_limit) - .into_layout() - }; - 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()?; @@ -709,26 +671,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_blob( - /// *, - /// title: str, - /// data: str | bytes, - /// description: str | None, - /// text_mono: bool = True, - /// extra: str | None = None, - /// subtitle: str | None = None, - /// verb: str | None = None, - /// verb_cancel: str | None = None, - /// verb_info: str | None = None, - /// info: bool = True, - /// hold: bool = False, - /// chunkify: bool = False, - /// prompt_screen: bool = False, - /// page_limit: int | None = None, - /// ) -> LayoutObj[UiResult]: - /// """Confirm byte sequence data.""" - Qstr::MP_QSTR_confirm_blob => obj_fn_kw!(0, new_confirm_blob).as_obj(), - /// def confirm_address( /// *, /// 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 2c22472427..ff8e8517f8 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::RecoveryType, + util::{ConfirmBlob, RecoveryType}, }, ui_features_fw::UIFeaturesFirmware, }, @@ -80,6 +80,31 @@ impl UIFeaturesFirmware for ModelTTFeatures { Ok(layout) } + fn confirm_blob( + title: TString<'static>, + data: Obj, + description: Option>, + text_mono: bool, + extra: Option>, + _subtitle: Option>, + verb: Option>, + verb_cancel: Option>, + _verb_info: Option>, + info: bool, + hold: bool, + chunkify: bool, + _prompt_screen: bool, + page_limit: Option, + ) -> Result, Error> { + ConfirmBlobParams::new(title, data, description, verb, verb_cancel, hold) + .with_text_mono(text_mono) + .with_extra(extra) + .with_chunkify(chunkify) + .with_info_button(info) + .with_page_limit(page_limit) + .into_layout() + } + fn confirm_homescreen( title: TString<'static>, mut image: BinaryData<'static>, @@ -923,3 +948,112 @@ fn new_show_modal( Ok(obj) } + +// TODO: move to some util.rs? +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, Error> { + 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(); + } + LayoutObj::new(frame) + } +} diff --git a/core/embed/rust/src/ui/ui_features_fw.rs b/core/embed/rust/src/ui/ui_features_fw.rs index f5c41ed57b..6086e1f4da 100644 --- a/core/embed/rust/src/ui/ui_features_fw.rs +++ b/core/embed/rust/src/ui/ui_features_fw.rs @@ -26,6 +26,23 @@ pub trait UIFeaturesFirmware { prompt_title: Option>, ) -> Result; + fn confirm_blob( + title: TString<'static>, + data: Obj, // TODO: replace Obj + description: Option>, + text_mono: bool, + extra: Option>, + subtitle: Option>, + verb: Option>, + verb_cancel: Option>, + verb_info: Option>, + info: bool, + hold: bool, + chunkify: bool, + prompt_screen: bool, + page_limit: Option, + ) -> Result, Error>; // TODO: return LayoutMaybeTrace + fn confirm_homescreen( title: TString<'static>, image: BinaryData<'static>, diff --git a/core/mocks/generated/trezorui2.pyi b/core/mocks/generated/trezorui2.pyi index a30bd4599d..2b53713141 100644 --- a/core/mocks/generated/trezorui2.pyi +++ b/core/mocks/generated/trezorui2.pyi @@ -14,27 +14,6 @@ def confirm_emphasized( the first component is a bool indicating whether this part is emphasized.""" -# rust/src/ui/model_mercury/layout.rs -def confirm_blob( - *, - title: str, - data: str | bytes, - description: str | None, - text_mono: bool = True, - extra: str | None = None, - subtitle: str | None = None, - verb: str | None = None, - verb_cancel: str | None = None, - verb_info: str | None = None, - info: bool = True, - hold: bool = False, - chunkify: bool = False, - prompt_screen: bool = False, - page_limit: int | None = None, -) -> LayoutObj[UiResult]: - """Confirm byte sequence data.""" - - # rust/src/ui/model_mercury/layout.rs def confirm_address( *, @@ -186,27 +165,6 @@ from trezor import utils from trezorui_api import * -# rust/src/ui/model_tr/layout.rs -def confirm_blob( - *, - title: str, - data: str | bytes, - description: str | None, - text_mono: bool = True, - extra: str | None = None, - subtitle: str | None = None, - verb: str = "CONFIRM", - verb_cancel: str | None = None, - verb_info: str | None = None, - info: bool = True, - hold: bool = False, - chunkify: bool = False, - prompt_screen: bool = False, - page_limit: int | None = None, -) -> LayoutObj[UiResult]: - """Confirm byte sequence data.""" - - # rust/src/ui/model_tr/layout.rs def confirm_address( *, @@ -351,27 +309,6 @@ def confirm_emphasized( the first component is a bool indicating whether this part is emphasized.""" -# rust/src/ui/model_tt/layout.rs -def confirm_blob( - *, - title: str, - data: str | bytes, - description: str | None, - text_mono: bool = True, - extra: str | None = None, - subtitle: str | None = None, - verb: str | None = None, - verb_cancel: str | None = None, - verb_info: str | None = None, - info: bool = True, - hold: bool = False, - chunkify: bool = False, - prompt_screen: bool = False, - page_limit: int | None = None, -) -> LayoutObj[UiResult]: - """Confirm byte sequence data.""" - - # rust/src/ui/model_tt/layout.rs def confirm_address( *, diff --git a/core/mocks/generated/trezorui_api.pyi b/core/mocks/generated/trezorui_api.pyi index 1c3c64ff69..a1a94cde77 100644 --- a/core/mocks/generated/trezorui_api.pyi +++ b/core/mocks/generated/trezorui_api.pyi @@ -96,6 +96,27 @@ def confirm_action( """Confirm action.""" +# rust/src/ui/api/firmware_upy.rs +def confirm_blob( + *, + title: str, + data: str | bytes, + description: str | None, + text_mono: bool = True, + extra: str | None = None, + subtitle: str | None = None, + verb: str | None = None, + verb_cancel: str | None = None, + verb_info: str | None = None, + info: bool = True, + hold: bool = False, + chunkify: bool = False, + prompt_screen: bool = False, + page_limit: int | None = None, +) -> LayoutObj[UiResult]: + """Confirm byte sequence data.""" + + # rust/src/ui/api/firmware_upy.rs def confirm_coinjoin( *, diff --git a/core/src/trezor/ui/layouts/mercury/__init__.py b/core/src/trezor/ui/layouts/mercury/__init__.py index acf40acccc..767913899a 100644 --- a/core/src/trezor/ui/layouts/mercury/__init__.py +++ b/core/src/trezor/ui/layouts/mercury/__init__.py @@ -467,7 +467,7 @@ def confirm_blob( prompt_screen: bool = True, ) -> Awaitable[None]: if ask_pagination: - main_layout = trezorui2.confirm_blob( + main_layout = trezorui_api.confirm_blob( title=title, data=data, description=None, @@ -481,7 +481,7 @@ def confirm_blob( prompt_screen=False, page_limit=1, ) - info_layout = trezorui2.confirm_blob( + info_layout = trezorui_api.confirm_blob( title=title, data=data, description=None, @@ -502,7 +502,7 @@ def confirm_blob( info_layout_can_confirm=True, ) else: - layout = trezorui2.confirm_blob( + layout = trezorui_api.confirm_blob( title=title, data=data, description=description, @@ -909,7 +909,7 @@ async def confirm_modify_output( amount_change: str, amount_new: str, ) -> None: - address_layout = trezorui2.confirm_blob( + address_layout = trezorui_api.confirm_blob( title=TR.modify_amount__title, data=address, verb=TR.buttons__continue, @@ -1031,7 +1031,7 @@ async def confirm_signverify( horizontal=True, ) - message_layout = trezorui2.confirm_blob( + message_layout = trezorui_api.confirm_blob( title=TR.sign_message__confirm_message, description=None, data=message, diff --git a/core/src/trezor/ui/layouts/tr/__init__.py b/core/src/trezor/ui/layouts/tr/__init__.py index 0159b290c3..32aaa6204f 100644 --- a/core/src/trezor/ui/layouts/tr/__init__.py +++ b/core/src/trezor/ui/layouts/tr/__init__.py @@ -561,7 +561,7 @@ def confirm_blob( prompt_screen: bool = True, ) -> Awaitable[None]: verb = verb or TR.buttons__confirm # def_arg - layout = trezorui2.confirm_blob( + layout = trezorui_api.confirm_blob( title=title, description=description, data=data, @@ -748,7 +748,7 @@ async def confirm_value( elif result is INFO: info_title, info_value = info_items_list[0] await interact( - trezorui2.confirm_blob( + trezorui_api.confirm_blob( title=info_title, data=info_value, description=description, @@ -993,7 +993,7 @@ async def confirm_modify_output( amount_change: str, amount_new: str, ) -> None: - address_layout = trezorui2.confirm_blob( + address_layout = trezorui_api.confirm_blob( title=TR.modify_amount__title, data=address, verb=TR.buttons__continue, @@ -1095,7 +1095,7 @@ async def confirm_signverify( ) try: await raise_if_not_confirmed( - trezorui2.confirm_blob( + trezorui_api.confirm_blob( title=TR.sign_message__confirm_message, description=None, data=message, diff --git a/core/src/trezor/ui/layouts/tt/__init__.py b/core/src/trezor/ui/layouts/tt/__init__.py index 80de346c4d..5d09856b5f 100644 --- a/core/src/trezor/ui/layouts/tt/__init__.py +++ b/core/src/trezor/ui/layouts/tt/__init__.py @@ -560,7 +560,7 @@ def confirm_blob( prompt_screen: bool = True, ) -> Awaitable[None]: verb = verb or TR.buttons__confirm # def_arg - layout = trezorui2.confirm_blob( + layout = trezorui_api.confirm_blob( title=title, description=description, text_mono=text_mono, @@ -957,7 +957,7 @@ async def confirm_modify_output( while True: # if the user cancels here, raise ActionCancelled (by default) await interact( - trezorui2.confirm_blob( + trezorui_api.confirm_blob( title="MODIFY AMOUNT", data=address, verb="CONTINUE", @@ -1076,7 +1076,7 @@ async def confirm_signverify( horizontal=True, ) - message_layout = trezorui2.confirm_blob( + message_layout = trezorui_api.confirm_blob( title=TR.sign_message__confirm_message, description=None, data=message,