diff --git a/core/embed/rust/src/ui/api/firmware_upy.rs b/core/embed/rust/src/ui/api/firmware_upy.rs index 04362ab5e5..2e4e1a15b9 100644 --- a/core/embed/rust/src/ui/api/firmware_upy.rs +++ b/core/embed/rust/src/ui/api/firmware_upy.rs @@ -1,12 +1,16 @@ use crate::{ - io::BinaryData, 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, @@ -16,7 +20,7 @@ use crate::{ }, ui_features::ModelUI, ui_features_fw::UIFeaturesFirmware, - } + }, }; // free-standing functions exported to MicroPython mirror `trait diff --git a/core/embed/rust/src/ui/model_mercury/flow/confirm_homescreen.rs b/core/embed/rust/src/ui/model_mercury/flow/confirm_homescreen.rs new file mode 100644 index 0000000000..593dcb5559 --- /dev/null +++ b/core/embed/rust/src/ui/model_mercury/flow/confirm_homescreen.rs @@ -0,0 +1,106 @@ +use crate::{ + error, + strutil::TString, + translations::TR, + ui::{ + component::{swipe_detect::SwipeSettings, CachedJpeg, ComponentExt}, + flow::{ + base::{Decision, DecisionBuilder}, + FlowController, FlowMsg, SwipeFlow, + }, + geometry::Direction, + model_mercury::{ + component::{ + Frame, FrameMsg, PromptMsg, PromptScreen, SwipeContent, VerticalMenu, + VerticalMenuChoiceMsg, + }, + theme, + }, + }, +}; + +/// Flow for a setting of homescreen wallpaper showing a preview of the image, +/// menu to cancel and tap to confirm prompt. +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum ConfirmHomescreen { + Homescreen, + Menu, + Confirm, +} + +impl FlowController for ConfirmHomescreen { + #[inline] + fn index(&'static self) -> usize { + *self as usize + } + + fn handle_swipe(&'static self, direction: Direction) -> Decision { + match (self, direction) { + (Self::Homescreen, Direction::Left) => Self::Menu.swipe(direction), + (Self::Homescreen, Direction::Up) => Self::Confirm.swipe(direction), + (Self::Menu, Direction::Right) => Self::Homescreen.swipe(direction), + (Self::Confirm, Direction::Down) => Self::Homescreen.swipe(direction), + (Self::Confirm, Direction::Left) => Self::Menu.swipe(direction), + _ => self.do_nothing(), + } + } + + fn handle_event(&'static self, msg: FlowMsg) -> Decision { + match (self, msg) { + (Self::Homescreen, FlowMsg::Info) => Self::Menu.goto(), + (Self::Menu, FlowMsg::Cancelled) => Self::Homescreen.swipe_right(), + (Self::Menu, FlowMsg::Choice(0)) => self.return_msg(FlowMsg::Cancelled), + (Self::Confirm, FlowMsg::Confirmed) => self.return_msg(FlowMsg::Confirmed), + (Self::Confirm, FlowMsg::Info) => Self::Menu.goto(), + _ => self.do_nothing(), + } + } +} + +pub fn new_confirm_homescreen( + title: TString<'static>, + image: CachedJpeg, +) -> Result { + let content_homescreen = Frame::left_aligned(title, SwipeContent::new(image)) + .with_menu_button() + .with_footer( + TR::instructions__swipe_up.into(), + Some(TR::buttons__change.into()), + ) + .with_swipe(Direction::Up, SwipeSettings::default()) + .map(|msg| match msg { + FrameMsg::Button(_) => Some(FlowMsg::Info), + _ => None, + }); + + let content_menu = Frame::left_aligned( + TString::empty(), + VerticalMenu::empty().danger(theme::ICON_CANCEL, TR::buttons__cancel.into()), + ) + .with_cancel_button() + .with_swipe(Direction::Right, SwipeSettings::immediate()) + .map(|msg| match msg { + FrameMsg::Content(VerticalMenuChoiceMsg::Selected(i)) => Some(FlowMsg::Choice(i)), + FrameMsg::Button(_) => Some(FlowMsg::Cancelled), + }); + + let content_confirm = Frame::left_aligned( + TR::homescreen__title_set.into(), + SwipeContent::new(PromptScreen::new_tap_to_confirm()), + ) + .with_menu_button() + .with_footer(TR::instructions__tap_to_confirm.into(), None) + .with_swipe(Direction::Down, SwipeSettings::default()) + .with_swipe(Direction::Left, SwipeSettings::default()) + .map(|msg| match msg { + FrameMsg::Content(PromptMsg::Confirmed) => Some(FlowMsg::Confirmed), + FrameMsg::Button(_) => Some(FlowMsg::Info), + _ => None, + }); + + let res = SwipeFlow::new(&ConfirmHomescreen::Homescreen)? + .with_page(&ConfirmHomescreen::Homescreen, content_homescreen)? + .with_page(&ConfirmHomescreen::Menu, content_menu)? + .with_page(&ConfirmHomescreen::Confirm, content_confirm)?; + Ok(res) +} diff --git a/core/embed/rust/src/ui/model_mercury/flow/mod.rs b/core/embed/rust/src/ui/model_mercury/flow/mod.rs index 9a646aec3d..15e04e07d1 100644 --- a/core/embed/rust/src/ui/model_mercury/flow/mod.rs +++ b/core/embed/rust/src/ui/model_mercury/flow/mod.rs @@ -2,6 +2,7 @@ pub mod confirm_action; #[cfg(feature = "universal_fw")] pub mod confirm_fido; pub mod confirm_firmware_update; +pub mod confirm_homescreen; pub mod confirm_output; pub mod confirm_reset; pub mod confirm_set_new_pin; @@ -24,6 +25,7 @@ pub use confirm_action::{ #[cfg(feature = "universal_fw")] pub use confirm_fido::new_confirm_fido; pub use confirm_firmware_update::new_confirm_firmware_update; +pub use confirm_homescreen::new_confirm_homescreen; pub use confirm_output::new_confirm_output; pub use confirm_reset::new_confirm_reset; pub use confirm_set_new_pin::SetNewPin; 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 518d30dd06..d8d51bc463 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 @@ -68,7 +68,6 @@ impl UIFeaturesFirmware for ModelMercuryFeatures { TR::homescreen__set_default, )]) .into_paragraphs(); - let paragraphs = paragraphs; new_confirm_action_simple( paragraphs, @@ -87,16 +86,7 @@ impl UIFeaturesFirmware for ModelMercuryFeatures { 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 + flow::confirm_homescreen::new_confirm_homescreen(title, CachedJpeg::new(image, 1))? }; Ok(layout) } 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 6ec432c078..9c1e2ac4d4 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 @@ -6,7 +6,9 @@ use crate::{ translations::TR, ui::{ component::{ - image::BlendedImage, text::paragraphs::{Paragraph, ParagraphSource, ParagraphVecShort, Paragraphs, VecExt}, ComponentExt, Empty, Jpeg, Label, Timeout + image::BlendedImage, + text::paragraphs::{Paragraph, ParagraphSource, ParagraphVecShort, Paragraphs, VecExt}, + ComponentExt, Empty, Jpeg, Label, Timeout, }, layout::{ obj::{LayoutMaybeTrace, LayoutObj, RootComponent},