diff --git a/core/embed/rust/src/ui/api/firmware_upy.rs b/core/embed/rust/src/ui/api/firmware_upy.rs index 75a4d6e00c..775e061181 100644 --- a/core/embed/rust/src/ui/api/firmware_upy.rs +++ b/core/embed/rust/src/ui/api/firmware_upy.rs @@ -178,6 +178,21 @@ extern "C" fn new_confirm_coinjoin(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_emphasized(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 verb: Option = kwargs + .get(Qstr::MP_QSTR_verb) + .unwrap_or_else(|_| Obj::const_none()) + .try_into_option()?; + + let layout = ModelUI::confirm_emphasized(title, items, verb)?; + Ok(LayoutObj::new_root(layout)?.into()) + }; + unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } +} + extern "C" fn new_confirm_fido(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()?; @@ -962,6 +977,16 @@ pub static mp_module_trezorui_api: Module = obj_module! { /// """Confirm coinjoin authorization.""" Qstr::MP_QSTR_confirm_coinjoin => obj_fn_kw!(0, new_confirm_coinjoin).as_obj(), + /// def confirm_emphasized( + /// *, + /// title: str, + /// items: Iterable[str | tuple[bool, str]], + /// verb: str | None = None, + /// ) -> LayoutObj[UiResult]: + /// """Confirm formatted text that has been pre-split in python. For tuples + /// 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_fido( /// *, /// 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 502361f215..899817c41b 100644 --- a/core/embed/rust/src/ui/model_mercury/layout.rs +++ b/core/embed/rust/src/ui/model_mercury/layout.rs @@ -226,41 +226,6 @@ where } } -extern "C" fn new_confirm_emphasized(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 mut ops = OpTextLayout::new(theme::TEXT_NORMAL); - for item in IterBuf::new().try_iterate(items)? { - if item.is_str() { - ops = ops.text_normal(TString::try_from(item)?) - } else { - let [emphasis, text]: [Obj; 2] = util::iter_into_array(item)?; - let text: TString = text.try_into()?; - if emphasis.try_into()? { - ops = ops.text_demibold(text); - } else { - ops = ops.text_normal(text); - } - } - } - - new_confirm_action_simple( - FormattedText::new(ops).vertically_centered(), - ConfirmActionExtra::Menu(ConfirmActionMenuStrings::new()), - ConfirmActionStrings::new(title, None, None, Some(title)), - false, - None, - 0, - false, - ) - .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_blob_intro(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()?; @@ -558,16 +523,6 @@ pub static mp_module_trezorui2: Module = obj_module! { /// Qstr::MP_QSTR___name__ => Qstr::MP_QSTR_trezorui2.to_obj(), - /// def confirm_emphasized( - /// *, - /// title: str, - /// items: Iterable[str | tuple[bool, str]], - /// verb: str | None = None, - /// ) -> LayoutObj[UiResult]: - /// """Confirm formatted text that has been pre-split in python. For tuples - /// 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_intro( /// *, /// 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 329391002b..79fb08cb78 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 @@ -11,13 +11,14 @@ use crate::{ connect::Connect, swipe_detect::SwipeSettings, text::{ + op::OpTextLayout, paragraphs::{ Checklist, Paragraph, ParagraphSource, ParagraphVecLong, ParagraphVecShort, Paragraphs, VecExt, }, TextStyle, }, - Border, CachedJpeg, ComponentExt, Empty, Never, Timeout, + Border, CachedJpeg, ComponentExt, Empty, FormattedText, Never, Timeout, }, geometry::{self, Direction}, layout::{ @@ -205,6 +206,38 @@ impl UIFeaturesFirmware for ModelMercuryFeatures { Ok(flow) } + fn confirm_emphasized( + title: TString<'static>, + items: Obj, + verb: Option>, + ) -> Result { + let mut ops = OpTextLayout::new(theme::TEXT_NORMAL); + for item in IterBuf::new().try_iterate(items)? { + if item.is_str() { + ops = ops.text_normal(TString::try_from(item)?) + } else { + let [emphasis, text]: [Obj; 2] = util::iter_into_array(item)?; + let text: TString = text.try_into()?; + if emphasis.try_into()? { + ops = ops.text_demibold(text); + } else { + ops = ops.text_normal(text); + } + } + } + + let flow = flow::new_confirm_action_simple( + FormattedText::new(ops).vertically_centered(), + ConfirmActionExtra::Menu(ConfirmActionMenuStrings::new()), + ConfirmActionStrings::new(title, None, None, Some(title)), + false, + None, + 0, + false, + )?; + Ok(flow) + } + fn confirm_fido( title: TString<'static>, app_name: TString<'static>, 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 b664722b79..944a982b6d 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 @@ -190,6 +190,16 @@ impl UIFeaturesFirmware for ModelTRFeatures { ) } + fn confirm_emphasized( + _title: TString<'static>, + _items: Obj, + _verb: Option>, + ) -> Result { + Err::, Error>(Error::ValueError( + c"confirm_emphasized not implemented", + )) + } + fn confirm_fido( title: TString<'static>, app_name: 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 9a7a92b0a4..a3bb33888f 100644 --- a/core/embed/rust/src/ui/model_tt/layout.rs +++ b/core/embed/rust/src/ui/model_tt/layout.rs @@ -317,41 +317,6 @@ impl ComponentMsgObj for super::component::bl_confirm::Confirm<'_> { } } -extern "C" fn new_confirm_emphasized(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 verb: Option = kwargs - .get(Qstr::MP_QSTR_verb) - .unwrap_or_else(|_| Obj::const_none()) - .try_into_option()?; - - let items: Obj = kwargs.get(Qstr::MP_QSTR_items)?; - let mut ops = OpTextLayout::new(theme::TEXT_NORMAL); - for item in IterBuf::new().try_iterate(items)? { - if item.is_str() { - ops = ops.text_normal(TString::try_from(item)?) - } else { - let [emphasis, text]: [Obj; 2] = util::iter_into_array(item)?; - let text: TString = text.try_into()?; - if emphasis.try_into()? { - ops = ops.text_demibold(text); - } else { - ops = ops.text_normal(text); - } - } - } - - let obj = LayoutObj::new(Frame::left_aligned( - theme::label_title(), - title, - ButtonPage::new(FormattedText::new(ops).vertically_centered(), theme::BG) - .with_cancel_confirm(None, verb), - ))?; - 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()?; @@ -421,16 +386,6 @@ pub static mp_module_trezorui2: Module = obj_module! { /// from trezorui_api import * /// - /// def confirm_emphasized( - /// *, - /// title: str, - /// items: Iterable[str | tuple[bool, str]], - /// verb: str | None = None, - /// ) -> LayoutObj[UiResult]: - /// """Confirm formatted text that has been pre-split in python. For tuples - /// 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 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 aaed6ad8db..9e878d255c 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 @@ -11,13 +11,14 @@ use crate::{ connect::Connect, image::BlendedImage, text::{ + op::OpTextLayout, paragraphs::{ Checklist, Paragraph, ParagraphSource, ParagraphVecLong, ParagraphVecShort, Paragraphs, VecExt, }, TextStyle, }, - Border, ComponentExt, Empty, Jpeg, Label, Never, Timeout, + Border, ComponentExt, Empty, FormattedText, Jpeg, Label, Never, Timeout, }, geometry, layout::{ @@ -186,6 +187,35 @@ impl UIFeaturesFirmware for ModelTTFeatures { Ok(layout) } + fn confirm_emphasized( + title: TString<'static>, + items: Obj, + verb: Option>, + ) -> Result { + let mut ops = OpTextLayout::new(theme::TEXT_NORMAL); + for item in IterBuf::new().try_iterate(items)? { + if item.is_str() { + ops = ops.text_normal(TString::try_from(item)?) + } else { + let [emphasis, text]: [Obj; 2] = util::iter_into_array(item)?; + let text: TString = text.try_into()?; + if emphasis.try_into()? { + ops = ops.text_demibold(text); + } else { + ops = ops.text_normal(text); + } + } + } + + let layout = RootComponent::new(Frame::left_aligned( + theme::label_title(), + title, + ButtonPage::new(FormattedText::new(ops).vertically_centered(), theme::BG) + .with_cancel_confirm(None, verb), + )); + Ok(layout) + } + fn confirm_fido( title: TString<'static>, app_name: 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 0f1316a901..89ca18d1c6 100644 --- a/core/embed/rust/src/ui/ui_features_fw.rs +++ b/core/embed/rust/src/ui/ui_features_fw.rs @@ -63,6 +63,12 @@ pub trait UIFeaturesFirmware { max_feerate: TString<'static>, ) -> Result; + fn confirm_emphasized( + title: TString<'static>, + items: Obj, // TODO: replace Obj + verb: Option>, + ) -> Result; + fn confirm_fido( title: TString<'static>, app_name: TString<'static>, diff --git a/core/mocks/generated/trezorui2.pyi b/core/mocks/generated/trezorui2.pyi index 8187ddaab5..486da68ec7 100644 --- a/core/mocks/generated/trezorui2.pyi +++ b/core/mocks/generated/trezorui2.pyi @@ -3,16 +3,6 @@ from trezor import utils from trezorui_api import * -# rust/src/ui/model_mercury/layout.rs -def confirm_emphasized( - *, - title: str, - items: Iterable[str | tuple[bool, str]], - verb: str | None = None, -) -> LayoutObj[UiResult]: - """Confirm formatted text that has been pre-split in python. For tuples - the first component is a bool indicating whether this part is emphasized.""" - # rust/src/ui/model_mercury/layout.rs def confirm_blob_intro( *, @@ -201,17 +191,6 @@ from trezor import utils from trezorui_api import * -# rust/src/ui/model_tt/layout.rs -def confirm_emphasized( - *, - title: str, - items: Iterable[str | tuple[bool, str]], - verb: str | None = None, -) -> LayoutObj[UiResult]: - """Confirm formatted text that has been pre-split in python. For tuples - the first component is a bool indicating whether this part is emphasized.""" - - # 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 cdb44db2e8..b2f264a55c 100644 --- a/core/mocks/generated/trezorui_api.pyi +++ b/core/mocks/generated/trezorui_api.pyi @@ -140,6 +140,17 @@ def confirm_coinjoin( """Confirm coinjoin authorization.""" +# rust/src/ui/api/firmware_upy.rs +def confirm_emphasized( + *, + title: str, + items: Iterable[str | tuple[bool, str]], + verb: str | None = None, +) -> LayoutObj[UiResult]: + """Confirm formatted text that has been pre-split in python. For tuples + the first component is a bool indicating whether this part is emphasized.""" + + # rust/src/ui/api/firmware_upy.rs def confirm_fido( *, diff --git a/core/src/trezor/ui/layouts/mercury/__init__.py b/core/src/trezor/ui/layouts/mercury/__init__.py index a75f62fd3e..27cb231940 100644 --- a/core/src/trezor/ui/layouts/mercury/__init__.py +++ b/core/src/trezor/ui/layouts/mercury/__init__.py @@ -74,12 +74,11 @@ def confirm_single( # Placeholders are coming from translations in form of {0} template_str = "{0}" - if template_str not in description: - template_str = "{}" + assert template_str in description begin, _separator, end = description.partition(template_str) return raise_if_not_confirmed( - trezorui2.confirm_emphasized( + trezorui_api.confirm_emphasized( title=title, items=(begin, (True, description_param), end), verb=verb, diff --git a/core/src/trezor/ui/layouts/tt/__init__.py b/core/src/trezor/ui/layouts/tt/__init__.py index 6579013441..50988fffa9 100644 --- a/core/src/trezor/ui/layouts/tt/__init__.py +++ b/core/src/trezor/ui/layouts/tt/__init__.py @@ -74,7 +74,7 @@ def confirm_single( begin, _separator, end = description.partition(template_str) return raise_if_not_confirmed( - trezorui2.confirm_emphasized( + trezorui_api.confirm_emphasized( title=title, items=(begin, (True, description_param), end), verb=verb, @@ -1229,7 +1229,7 @@ def confirm_set_new_pin( br_code: ButtonRequestType = BR_CODE_OTHER, ) -> Awaitable[None]: return raise_if_not_confirmed( - trezorui2.confirm_emphasized( + trezorui_api.confirm_emphasized( title=title, items=( (True, description + "\n\n"),