diff --git a/core/embed/rust/src/ui/api/firmware_upy.rs b/core/embed/rust/src/ui/api/firmware_upy.rs index 21c44d2dac..04362ab5e5 100644 --- a/core/embed/rust/src/ui/api/firmware_upy.rs +++ b/core/embed/rust/src/ui/api/firmware_upy.rs @@ -1,15 +1,12 @@ use crate::{ - micropython::{ + io::BinaryData, micropython::{ macros::{obj_fn_1, obj_fn_kw, obj_module}, map::Map, module::Module, obj::Obj, qstr::Qstr, util, - }, - strutil::TString, - trezorhal::model, - ui::{ + }, strutil::TString, trezorhal::model, ui::{ backlight::BACKLIGHT_LEVELS_OBJ, layout::{ base::LAYOUT_STATE, @@ -19,7 +16,7 @@ use crate::{ }, ui_features::ModelUI, ui_features_fw::UIFeaturesFirmware, - }, + } }; // free-standing functions exported to MicroPython mirror `trait @@ -86,6 +83,20 @@ extern "C" fn new_confirm_firmware_update( unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } +extern "C" fn new_confirm_homescreen(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 image: Obj = kwargs.get(Qstr::MP_QSTR_image)?; + + let jpeg: BinaryData = image.try_into()?; + + let layout = ModelUI::confirm_homescreen(title, jpeg)?; + Ok(LayoutObj::new_root(layout)?.into()) + }; + + unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } +} + extern "C" fn new_request_bip39(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { let block = move |_args: &[Obj], kwargs: &Map| { let prompt: TString = kwargs.get(Qstr::MP_QSTR_prompt)?.try_into()?; @@ -352,6 +363,14 @@ pub static mp_module_trezorui_api: Module = obj_module! { /// """Ask whether to update firmware, optionally show fingerprint.""" Qstr::MP_QSTR_confirm_firmware_update => obj_fn_kw!(0, new_confirm_firmware_update).as_obj(), + /// def confirm_homescreen( + /// *, + /// title: str, + /// image: bytes, + /// ) -> LayoutObj[UiResult]: + /// """Confirm homescreen.""" + Qstr::MP_QSTR_confirm_homescreen => obj_fn_kw!(0, new_confirm_homescreen).as_obj(), + /// def request_bip39( /// *, /// prompt: str, diff --git a/core/embed/rust/src/ui/model_mercury/layout.rs b/core/embed/rust/src/ui/model_mercury/layout.rs index 566114dcc8..9499641f69 100644 --- a/core/embed/rust/src/ui/model_mercury/layout.rs +++ b/core/embed/rust/src/ui/model_mercury/layout.rs @@ -389,58 +389,6 @@ extern "C" fn new_confirm_properties(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_homescreen(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 image: Obj = kwargs.get(Qstr::MP_QSTR_image)?; - - let jpeg: BinaryData = image.try_into()?; - - let obj = if jpeg.is_empty() { - // Incoming data may be empty, meaning we should - // display default homescreen message. - let paragraphs = ParagraphVecShort::from_iter([Paragraph::new( - &theme::TEXT_DEMIBOLD, - TR::homescreen__set_default, - )]) - .into_paragraphs(); - - new_confirm_action_simple( - paragraphs, - ConfirmActionMenu::new(None, false, None), - ConfirmActionStrings::new( - TR::homescreen__settings_title.into(), - Some(TR::homescreen__settings_subtitle.into()), - None, - Some(TR::homescreen__settings_title.into()), - ), - false, - None, - ) - .and_then(LayoutObj::new_root) - .map(Into::into) - } else { - if !check_homescreen_format(jpeg) { - return Err(value_error!(c"Invalid image.")); - }; - - let obj = LayoutObj::new(SwipeUpScreen::new( - Frame::left_aligned(title, SwipeContent::new(CachedJpeg::new(jpeg, 1))) - .with_cancel_button() - .with_footer( - TR::instructions__swipe_up.into(), - Some(TR::buttons__change.into()), - ) - .with_swipe(Direction::Up, SwipeSettings::default()), - )); - Ok(obj?.into()) - }; - obj - }; - - unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } -} - extern "C" fn new_confirm_reset(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()?; @@ -1319,14 +1267,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_homescreen( - /// *, - /// title: str, - /// image: bytes, - /// ) -> LayoutObj[UiResult]: - /// """Confirm homescreen.""" - Qstr::MP_QSTR_confirm_homescreen => obj_fn_kw!(0, new_confirm_homescreen).as_obj(), - /// def confirm_blob( /// *, /// 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 7709e9f526..518d30dd06 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 @@ -1,5 +1,5 @@ use crate::{ - error::Error, + error::{value_error, Error}, io::BinaryData, micropython::gc::Gc, strutil::TString, @@ -7,7 +7,8 @@ use crate::{ ui::{ component::{ swipe_detect::SwipeSettings, - text::paragraphs::{Paragraph, Paragraphs}, + text::paragraphs::{Paragraph, ParagraphSource, ParagraphVecShort, Paragraphs}, + CachedJpeg, }, geometry::Direction, layout::{ @@ -20,10 +21,11 @@ use crate::{ use super::{ component::{ - Bip39Input, Frame, Homescreen, Lockscreen, MnemonicKeyboard, PinKeyboard, SelectWordCount, - Slip39Input, SwipeContent, SwipeUpScreen, VerticalMenu, + check_homescreen_format, Bip39Input, Frame, Homescreen, Lockscreen, MnemonicKeyboard, + PinKeyboard, SelectWordCount, Slip39Input, SwipeContent, SwipeUpScreen, VerticalMenu, }, - flow, theme, ModelMercuryFeatures, + flow::{self, new_confirm_action_simple, ConfirmActionMenu, ConfirmActionStrings}, + theme, ModelMercuryFeatures, }; impl UIFeaturesFirmware for ModelMercuryFeatures { @@ -54,6 +56,51 @@ impl UIFeaturesFirmware for ModelMercuryFeatures { Ok(flow) } + fn confirm_homescreen( + title: TString<'static>, + image: BinaryData<'static>, + ) -> Result { + let layout = if image.is_empty() { + // Incoming data may be empty, meaning we should + // display default homescreen message. + let paragraphs = ParagraphVecShort::from_iter([Paragraph::new( + &theme::TEXT_DEMIBOLD, + TR::homescreen__set_default, + )]) + .into_paragraphs(); + let paragraphs = paragraphs; + + new_confirm_action_simple( + paragraphs, + ConfirmActionMenu::new(None, false, None), + ConfirmActionStrings::new( + TR::homescreen__settings_title.into(), + Some(TR::homescreen__settings_subtitle.into()), + None, + Some(TR::homescreen__settings_title.into()), + ), + false, + None, + )? + } else { + if !check_homescreen_format(image) { + return Err(value_error!(c"Invalid image.")); + }; + + let obj = RootComponent::new(SwipeUpScreen::new( + Frame::left_aligned(title, SwipeContent::new(CachedJpeg::new(image, 1))) + .with_cancel_button() + .with_footer( + TR::instructions__swipe_up.into(), + Some(TR::buttons__change.into()), + ) + .with_swipe(Direction::Up, SwipeSettings::default()), + )); + obj + }; + Ok(layout) + } + fn confirm_firmware_update( description: TString<'static>, fingerprint: 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 b57f9bb430..1ae4070c1b 100644 --- a/core/embed/rust/src/ui/model_tr/layout.rs +++ b/core/embed/rust/src/ui/model_tr/layout.rs @@ -372,17 +372,6 @@ extern "C" fn new_confirm_properties(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_homescreen(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 image: Obj = kwargs.get(Qstr::MP_QSTR_image)?; - let obj = LayoutObj::new(ConfirmHomescreen::new(title, image.try_into()?))?; - Ok(obj.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 title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; @@ -1399,14 +1388,6 @@ pub static mp_module_trezorui2: Module = obj_module! { /// Qstr::MP_QSTR___name__ => Qstr::MP_QSTR_trezorui2.to_obj(), - /// def confirm_homescreen( - /// *, - /// title: str, - /// image: bytes, - /// ) -> object: - /// """Confirm homescreen.""" - Qstr::MP_QSTR_confirm_homescreen => obj_fn_kw!(0, new_confirm_homescreen).as_obj(), - /// def confirm_blob( /// *, /// 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 28ccca196f..a65f3e9b55 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 @@ -20,8 +20,8 @@ use crate::{ use super::{ component::{ - ButtonDetails, ButtonPage, Frame, Homescreen, Lockscreen, PassphraseEntry, PinEntry, - ScrollableFrame, SimpleChoice, WordlistEntry, WordlistType, + ButtonDetails, ButtonPage, ConfirmHomescreen, Frame, Homescreen, Lockscreen, + PassphraseEntry, PinEntry, ScrollableFrame, SimpleChoice, WordlistEntry, WordlistType, }, theme, ModelTRFeatures, }; @@ -67,6 +67,14 @@ impl UIFeaturesFirmware for ModelTRFeatures { ) } + fn confirm_homescreen( + title: TString<'static>, + image: BinaryData<'static>, + ) -> Result { + let layout = RootComponent::new(ConfirmHomescreen::new(title, image)); + Ok(layout) + } + fn confirm_firmware_update( description: TString<'static>, fingerprint: 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 e744ad2d82..10567198e1 100644 --- a/core/embed/rust/src/ui/model_tt/layout.rs +++ b/core/embed/rust/src/ui/model_tt/layout.rs @@ -565,35 +565,6 @@ extern "C" fn new_confirm_properties(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_homescreen(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 image: Obj = kwargs.get(Qstr::MP_QSTR_image)?; - - let mut jpeg: BinaryData = image.try_into()?; - - if jpeg.is_empty() { - // Incoming data may be empty, meaning we should - // display default homescreen image. - jpeg = theme::IMAGE_HOMESCREEN.into(); - } - - if !check_homescreen_format(jpeg, false) { - return Err(value_error!(c"Invalid image.")); - }; - - let buttons = Button::cancel_confirm_text(None, Some(TR::buttons__change.into())); - let obj = LayoutObj::new(Frame::centered( - theme::label_title(), - title, - Dialog::new(Jpeg::new(jpeg, 1), buttons), - ))?; - Ok(obj.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 title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; @@ -1417,14 +1388,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_homescreen( - /// *, - /// title: str, - /// image: bytes, - /// ) -> LayoutObj[UiResult]: - /// """Confirm homescreen.""" - Qstr::MP_QSTR_confirm_homescreen => obj_fn_kw!(0, new_confirm_homescreen).as_obj(), - /// def confirm_blob( /// *, /// 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 5f33e6c5fd..6ec432c078 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 @@ -1,14 +1,12 @@ use crate::{ - error::Error, + error::{value_error, Error}, io::BinaryData, micropython::gc::Gc, strutil::TString, translations::TR, ui::{ component::{ - image::BlendedImage, - text::paragraphs::{Paragraph, ParagraphSource, ParagraphVecShort, Paragraphs, VecExt}, - ComponentExt, Empty, Label, Timeout, + image::BlendedImage, text::paragraphs::{Paragraph, ParagraphSource, ParagraphVecShort, Paragraphs, VecExt}, ComponentExt, Empty, Jpeg, Label, Timeout }, layout::{ obj::{LayoutMaybeTrace, LayoutObj, RootComponent}, @@ -20,9 +18,9 @@ use crate::{ use super::{ component::{ - Bip39Input, Button, ButtonMsg, ButtonPage, ButtonStyleSheet, CancelConfirmMsg, Dialog, - Frame, Homescreen, IconDialog, Lockscreen, MnemonicKeyboard, PassphraseKeyboard, - PinKeyboard, SelectWordCount, Slip39Input, + check_homescreen_format, Bip39Input, Button, ButtonMsg, ButtonPage, ButtonStyleSheet, + CancelConfirmMsg, Dialog, Frame, Homescreen, IconDialog, Lockscreen, MnemonicKeyboard, + PassphraseKeyboard, PinKeyboard, SelectWordCount, Slip39Input, }, theme, ModelTTFeatures, }; @@ -69,6 +67,29 @@ impl UIFeaturesFirmware for ModelTTFeatures { Ok(layout) } + fn confirm_homescreen( + title: TString<'static>, + mut image: BinaryData<'static>, + ) -> Result { + if image.is_empty() { + // Incoming data may be empty, meaning we should + // display default homescreen image. + image = theme::IMAGE_HOMESCREEN.into(); + } + + if !check_homescreen_format(image, false) { + return Err(value_error!(c"Invalid image.")); + }; + + let buttons = Button::cancel_confirm_text(None, Some(TR::buttons__change.into())); + let layout = RootComponent::new(Frame::centered( + theme::label_title(), + title, + Dialog::new(Jpeg::new(image, 1), buttons), + )); + Ok(layout) + } + fn confirm_firmware_update( description: TString<'static>, fingerprint: 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 8e8d4320e8..1aa486db85 100644 --- a/core/embed/rust/src/ui/ui_features_fw.rs +++ b/core/embed/rust/src/ui/ui_features_fw.rs @@ -20,6 +20,11 @@ pub trait UIFeaturesFirmware { prompt_title: Option>, ) -> Result; + fn confirm_homescreen( + title: TString<'static>, + image: BinaryData<'static>, + ) -> Result; + fn confirm_firmware_update( description: TString<'static>, fingerprint: TString<'static>, diff --git a/core/mocks/generated/trezorui2.pyi b/core/mocks/generated/trezorui2.pyi index 3f71877c97..5c5bef1e61 100644 --- a/core/mocks/generated/trezorui2.pyi +++ b/core/mocks/generated/trezorui2.pyi @@ -14,15 +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_homescreen( - *, - title: str, - image: bytes, -) -> LayoutObj[UiResult]: - """Confirm homescreen.""" - - # rust/src/ui/model_mercury/layout.rs def confirm_blob( *, @@ -424,15 +415,6 @@ from trezor import utils from trezorui_api import * -# rust/src/ui/model_tr/layout.rs -def confirm_homescreen( - *, - title: str, - image: bytes, -) -> object: - """Confirm homescreen.""" - - # rust/src/ui/model_tr/layout.rs def confirm_blob( *, @@ -771,15 +753,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_homescreen( - *, - title: str, - image: bytes, -) -> LayoutObj[UiResult]: - """Confirm homescreen.""" - - # rust/src/ui/model_tt/layout.rs def confirm_blob( *, diff --git a/core/mocks/generated/trezorui_api.pyi b/core/mocks/generated/trezorui_api.pyi index 08e88bc2bc..30c28dbe82 100644 --- a/core/mocks/generated/trezorui_api.pyi +++ b/core/mocks/generated/trezorui_api.pyi @@ -105,6 +105,15 @@ def confirm_firmware_update( """Ask whether to update firmware, optionally show fingerprint.""" +# rust/src/ui/api/firmware_upy.rs +def confirm_homescreen( + *, + title: str, + image: bytes, +) -> LayoutObj[UiResult]: + """Confirm homescreen.""" + + # rust/src/ui/api/firmware_upy.rs def request_bip39( *, diff --git a/core/src/trezor/ui/layouts/mercury/__init__.py b/core/src/trezor/ui/layouts/mercury/__init__.py index 73b442e80b..e5a4b0ca20 100644 --- a/core/src/trezor/ui/layouts/mercury/__init__.py +++ b/core/src/trezor/ui/layouts/mercury/__init__.py @@ -149,7 +149,7 @@ def confirm_homescreen( workflow.close_others() return raise_if_not_confirmed( - trezorui2.confirm_homescreen( + trezorui_api.confirm_homescreen( title=TR.homescreen__title_set, image=image, ), diff --git a/core/src/trezor/ui/layouts/tr/__init__.py b/core/src/trezor/ui/layouts/tr/__init__.py index 4a8d51623e..e34ad068c8 100644 --- a/core/src/trezor/ui/layouts/tr/__init__.py +++ b/core/src/trezor/ui/layouts/tr/__init__.py @@ -184,7 +184,7 @@ def confirm_multisig_warning() -> Awaitable[ui.UiResult]: def confirm_homescreen(image: bytes) -> Awaitable[None]: return raise_if_not_confirmed( - trezorui2.confirm_homescreen( + trezorui_api.confirm_homescreen( title=TR.homescreen__title_set, image=image, ), diff --git a/core/src/trezor/ui/layouts/tt/__init__.py b/core/src/trezor/ui/layouts/tt/__init__.py index bcd9e7cb27..4f6c4be577 100644 --- a/core/src/trezor/ui/layouts/tt/__init__.py +++ b/core/src/trezor/ui/layouts/tt/__init__.py @@ -165,7 +165,7 @@ def confirm_multisig_warning() -> Awaitable[None]: def confirm_homescreen(image: bytes) -> Awaitable[None]: return raise_if_not_confirmed( - trezorui2.confirm_homescreen( + trezorui_api.confirm_homescreen( title=TR.homescreen__title_set, image=image, ),