From 008490bf4b8a04a085c59e217f743c9713727480 Mon Sep 17 00:00:00 2001 From: obrusvit Date: Mon, 22 Jul 2024 17:07:34 +0200 Subject: [PATCH] refactor(core/mercury): unify confirm TOS [no changelog] --- core/embed/rust/librust_qstr.h | 4 +- .../ui/model_mercury/flow/confirm_reset.rs | 169 ++++++++++++++++++ .../flow/confirm_reset_create.rs | 123 ------------- .../flow/confirm_reset_recover.rs | 105 ----------- .../rust/src/ui/model_mercury/flow/mod.rs | 6 +- .../embed/rust/src/ui/model_mercury/layout.rs | 10 +- core/mocks/generated/trezorui2.pyi | 9 +- .../src/trezor/ui/layouts/mercury/__init__.py | 11 +- 8 files changed, 181 insertions(+), 256 deletions(-) create mode 100644 core/embed/rust/src/ui/model_mercury/flow/confirm_reset.rs delete mode 100644 core/embed/rust/src/ui/model_mercury/flow/confirm_reset_create.rs delete mode 100644 core/embed/rust/src/ui/model_mercury/flow/confirm_reset_recover.rs diff --git a/core/embed/rust/librust_qstr.h b/core/embed/rust/librust_qstr.h index c7e919866..5c642a966 100644 --- a/core/embed/rust/librust_qstr.h +++ b/core/embed/rust/librust_qstr.h @@ -240,8 +240,7 @@ static void _librust_qstrs(void) { MP_QSTR_firmware_update__title; MP_QSTR_firmware_update__title_fingerprint; MP_QSTR_flow_confirm_output; - MP_QSTR_flow_confirm_reset_create; - MP_QSTR_flow_confirm_reset_recover; + MP_QSTR_flow_confirm_reset; MP_QSTR_flow_confirm_set_new_pin; MP_QSTR_flow_confirm_summary; MP_QSTR_flow_get_address; @@ -417,6 +416,7 @@ static void _librust_qstrs(void) { MP_QSTR_reboot_to_bootloader__restart; MP_QSTR_reboot_to_bootloader__title; MP_QSTR_reboot_to_bootloader__version_by_template; + MP_QSTR_recovery; MP_QSTR_recovery__cancel_dry_run; MP_QSTR_recovery__check_dry_run; MP_QSTR_recovery__cursor_will_change; diff --git a/core/embed/rust/src/ui/model_mercury/flow/confirm_reset.rs b/core/embed/rust/src/ui/model_mercury/flow/confirm_reset.rs new file mode 100644 index 000000000..e3ba7742b --- /dev/null +++ b/core/embed/rust/src/ui/model_mercury/flow/confirm_reset.rs @@ -0,0 +1,169 @@ +use crate::{ + error, + micropython::{map::Map, obj::Obj, qstr::Qstr, util}, + strutil::TString, + translations::TR, + ui::{ + button_request::ButtonRequestCode, + component::{ + swipe_detect::SwipeSettings, + text::paragraphs::{Paragraph, ParagraphSource, ParagraphVecShort}, + ButtonRequestExt, ComponentExt, SwipeDirection, + }, + flow::{ + base::{DecisionBuilder as _, StateChange}, + FlowMsg, FlowState, SwipeFlow, + }, + layout::obj::LayoutObj, + model_mercury::component::{PromptScreen, SwipeContent}, + }, +}; + +use super::super::{ + component::{Frame, FrameMsg, VerticalMenu, VerticalMenuChoiceMsg}, + theme, +}; + +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum ConfirmResetCreate { + Intro, + Menu, + Confirm, +} + +impl FlowState for ConfirmResetCreate { + #[inline] + fn index(&'static self) -> usize { + *self as usize + } + + fn handle_swipe(&'static self, direction: SwipeDirection) -> StateChange { + match (self, direction) { + (Self::Intro, SwipeDirection::Left) => Self::Menu.swipe(direction), + (Self::Intro, SwipeDirection::Up) => Self::Confirm.swipe(direction), + (Self::Menu, SwipeDirection::Right) => Self::Intro.swipe(direction), + (Self::Confirm, SwipeDirection::Down) => Self::Intro.swipe(direction), + (Self::Confirm, SwipeDirection::Left) => Self::Menu.swipe(direction), + _ => self.do_nothing(), + } + } + + fn handle_event(&'static self, msg: FlowMsg) -> StateChange { + match (self, msg) { + (Self::Intro, FlowMsg::Info) => Self::Menu.transit(), + (Self::Menu, FlowMsg::Cancelled) => Self::Intro.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.transit(), + _ => self.do_nothing(), + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum ConfirmResetRecover { + Intro, + Menu, +} + +impl FlowState for ConfirmResetRecover { + #[inline] + fn index(&'static self) -> usize { + *self as usize + } + + fn handle_swipe(&'static self, direction: SwipeDirection) -> StateChange { + match (self, direction) { + (Self::Intro, SwipeDirection::Left) => Self::Menu.swipe(direction), + (Self::Menu, SwipeDirection::Right) => Self::Intro.swipe(direction), + (Self::Intro, SwipeDirection::Up) => self.return_msg(FlowMsg::Confirmed), + _ => self.do_nothing(), + } + } + + fn handle_event(&'static self, msg: FlowMsg) -> StateChange { + match (self, msg) { + (Self::Intro, FlowMsg::Info) => Self::Menu.transit(), + (Self::Menu, FlowMsg::Cancelled) => Self::Intro.swipe_right(), + (Self::Menu, FlowMsg::Choice(0)) => self.return_msg(FlowMsg::Cancelled), + _ => self.do_nothing(), + } + } +} + +#[allow(clippy::not_unsafe_ptr_arg_deref)] +pub extern "C" fn new_confirm_reset(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { + unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, new_confirm_reset_obj) } +} + +fn new_confirm_reset_obj(_args: &[Obj], kwargs: &Map) -> Result { + let recovery: bool = kwargs.get_or(Qstr::MP_QSTR_recovery, false)?; + + let (title, br, cancel_btn_text) = if recovery { + ( + TR::recovery__title_recover.into(), + ButtonRequestCode::ProtectCall.with_name("recover_device"), + TR::recovery__title_cancel_recovery.into(), + ) + } else { + ( + TR::reset__title_create_wallet.into(), + ButtonRequestCode::ResetDevice.with_name("setup_device"), + // FIXME: TR::reset__cancel_create_wallet should be used but Button text on + // multiple lines not supported yet + TR::buttons__cancel.into(), + ) + }; + + let paragraphs = ParagraphVecShort::from_iter([ + Paragraph::new(&theme::TEXT_MAIN_GREY_LIGHT, TR::reset__by_continuing) + .with_bottom_padding(17), + Paragraph::new(&theme::TEXT_SUB_GREY, TR::reset__more_info_at), + Paragraph::new(&theme::TEXT_SUB_GREY_LIGHT, TR::reset__tos_link), + ]) + .into_paragraphs(); + let content_intro = Frame::left_aligned(title, SwipeContent::new(paragraphs)) + .with_menu_button() + .with_footer(TR::instructions__swipe_up.into(), None) + .with_swipe(SwipeDirection::Up, SwipeSettings::default()) + .with_swipe(SwipeDirection::Left, SwipeSettings::default()) + .map(|msg| matches!(msg, FrameMsg::Button(_)).then_some(FlowMsg::Info)) + .one_button_request(br); + + let content_menu = Frame::left_aligned( + TString::empty(), + VerticalMenu::empty().danger(theme::ICON_CANCEL, cancel_btn_text), + ) + .with_cancel_button() + .with_swipe(SwipeDirection::Right, SwipeSettings::immediate()) + .map(|msg| match msg { + FrameMsg::Content(VerticalMenuChoiceMsg::Selected(i)) => Some(FlowMsg::Choice(i)), + FrameMsg::Button(_) => Some(FlowMsg::Cancelled), + }); + + let res = if recovery { + SwipeFlow::new(&ConfirmResetRecover::Intro)? + .with_page(&ConfirmResetRecover::Intro, content_intro)? + .with_page(&ConfirmResetRecover::Menu, content_menu)? + } else { + let content_confirm = Frame::left_aligned( + TR::reset__title_create_wallet.into(), + SwipeContent::new(PromptScreen::new_hold_to_confirm()), + ) + .with_menu_button() + .with_footer(TR::instructions__hold_to_confirm.into(), None) + .with_swipe(SwipeDirection::Down, SwipeSettings::default()) + .with_swipe(SwipeDirection::Left, SwipeSettings::default()) + .map(|msg| match msg { + FrameMsg::Content(()) => Some(FlowMsg::Confirmed), + FrameMsg::Button(_) => Some(FlowMsg::Info), + }) + .one_button_request(ButtonRequestCode::ResetDevice.with_name("confirm_setup_device")); + + SwipeFlow::new(&ConfirmResetCreate::Intro)? + .with_page(&ConfirmResetCreate::Intro, content_intro)? + .with_page(&ConfirmResetCreate::Menu, content_menu)? + .with_page(&ConfirmResetCreate::Confirm, content_confirm)? + }; + Ok(LayoutObj::new(res)?.into()) +} diff --git a/core/embed/rust/src/ui/model_mercury/flow/confirm_reset_create.rs b/core/embed/rust/src/ui/model_mercury/flow/confirm_reset_create.rs deleted file mode 100644 index 5f6357298..000000000 --- a/core/embed/rust/src/ui/model_mercury/flow/confirm_reset_create.rs +++ /dev/null @@ -1,123 +0,0 @@ -use crate::{ - error, - micropython::{map::Map, obj::Obj, util}, - strutil::TString, - translations::TR, - ui::{ - button_request::ButtonRequestCode, - component::{ - swipe_detect::SwipeSettings, - text::paragraphs::{Paragraph, Paragraphs}, - ButtonRequestExt, ComponentExt, SwipeDirection, - }, - flow::{ - base::{DecisionBuilder as _, StateChange}, - FlowMsg, FlowState, SwipeFlow, - }, - layout::obj::LayoutObj, - model_mercury::component::{PromptScreen, SwipeContent}, - }, -}; - -use super::super::{ - component::{Frame, FrameMsg, VerticalMenu, VerticalMenuChoiceMsg}, - theme, -}; - -#[derive(Copy, Clone, PartialEq, Eq)] -pub enum ConfirmResetCreate { - Intro, - Menu, - Confirm, -} - -impl FlowState for ConfirmResetCreate { - #[inline] - fn index(&'static self) -> usize { - *self as usize - } - - fn handle_swipe(&'static self, direction: SwipeDirection) -> StateChange { - match (self, direction) { - (Self::Intro, SwipeDirection::Left) => Self::Menu.swipe(direction), - (Self::Intro, SwipeDirection::Up) => Self::Confirm.swipe(direction), - (Self::Menu, SwipeDirection::Right) => Self::Intro.swipe(direction), - (Self::Confirm, SwipeDirection::Down) => Self::Intro.swipe(direction), - (Self::Confirm, SwipeDirection::Left) => Self::Menu.swipe(direction), - _ => self.do_nothing(), - } - } - - fn handle_event(&'static self, msg: FlowMsg) -> StateChange { - match (self, msg) { - (Self::Intro, FlowMsg::Info) => Self::Menu.transit(), - (Self::Menu, FlowMsg::Cancelled) => Self::Intro.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.transit(), - _ => self.do_nothing(), - } - } -} - -#[allow(clippy::not_unsafe_ptr_arg_deref)] -pub extern "C" fn new_confirm_reset_create( - n_args: usize, - args: *const Obj, - kwargs: *mut Map, -) -> Obj { - unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, ConfirmResetCreate::new_obj) } -} - -impl ConfirmResetCreate { - fn new_obj(_args: &[Obj], _kwargs: &Map) -> Result { - let title: TString = TR::reset__title_create_wallet.into(); - let par_array: [Paragraph<'static>; 3] = [ - Paragraph::new(&theme::TEXT_MAIN_GREY_LIGHT, TR::reset__by_continuing) - .with_bottom_padding(17), - Paragraph::new(&theme::TEXT_SUB_GREY, TR::reset__more_info_at), - Paragraph::new(&theme::TEXT_SUB_GREY_LIGHT, TR::reset__tos_link), - ]; - let paragraphs = Paragraphs::new(par_array); - let content_intro = Frame::left_aligned(title, SwipeContent::new(paragraphs)) - .with_menu_button() - .with_footer(TR::instructions__swipe_up.into(), None) - .with_swipe(SwipeDirection::Up, SwipeSettings::default()) - .with_swipe(SwipeDirection::Left, SwipeSettings::default()) - .map(|msg| matches!(msg, FrameMsg::Button(_)).then_some(FlowMsg::Info)) - .one_button_request(ButtonRequestCode::ResetDevice.with_name("setup_device")); - - // FIXME: TR::reset__cancel_create_wallet should be used but Button text on - // multiple lines not supported yet - let content_menu = Frame::left_aligned( - "".into(), - VerticalMenu::empty().danger(theme::ICON_CANCEL, TR::buttons__cancel.into()), - ) - .with_cancel_button() - .with_swipe(SwipeDirection::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::reset__title_create_wallet.into(), - SwipeContent::new(PromptScreen::new_hold_to_confirm()), - ) - .with_menu_button() - .with_footer(TR::instructions__hold_to_confirm.into(), None) - .with_swipe(SwipeDirection::Down, SwipeSettings::default()) - .with_swipe(SwipeDirection::Left, SwipeSettings::default()) - .map(|msg| match msg { - FrameMsg::Content(()) => Some(FlowMsg::Confirmed), - FrameMsg::Button(_) => Some(FlowMsg::Info), - }) - .one_button_request(ButtonRequestCode::ResetDevice.with_name("confirm_setup_device")); - - let res = SwipeFlow::new(&ConfirmResetCreate::Intro)? - .with_page(&ConfirmResetCreate::Intro, content_intro)? - .with_page(&ConfirmResetCreate::Menu, content_menu)? - .with_page(&ConfirmResetCreate::Confirm, content_confirm)?; - Ok(LayoutObj::new(res)?.into()) - } -} diff --git a/core/embed/rust/src/ui/model_mercury/flow/confirm_reset_recover.rs b/core/embed/rust/src/ui/model_mercury/flow/confirm_reset_recover.rs deleted file mode 100644 index 13210faec..000000000 --- a/core/embed/rust/src/ui/model_mercury/flow/confirm_reset_recover.rs +++ /dev/null @@ -1,105 +0,0 @@ -use crate::{ - error, - micropython::{map::Map, obj::Obj, util}, - translations::TR, - ui::{ - button_request::ButtonRequestCode, - component::{ - swipe_detect::SwipeSettings, - text::paragraphs::{Paragraph, Paragraphs}, - ButtonRequestExt, ComponentExt, SwipeDirection, - }, - flow::{ - base::{DecisionBuilder as _, StateChange}, - FlowMsg, FlowState, SwipeFlow, - }, - layout::obj::LayoutObj, - model_mercury::component::SwipeContent, - }, -}; - -use super::super::{ - component::{Frame, FrameMsg, VerticalMenu, VerticalMenuChoiceMsg}, - theme, -}; - -#[derive(Copy, Clone, PartialEq, Eq)] -pub enum ConfirmResetRecover { - Intro, - Menu, -} - -impl FlowState for ConfirmResetRecover { - #[inline] - fn index(&'static self) -> usize { - *self as usize - } - - fn handle_swipe(&'static self, direction: SwipeDirection) -> StateChange { - match (self, direction) { - (Self::Intro, SwipeDirection::Left) => Self::Menu.swipe(direction), - (Self::Menu, SwipeDirection::Right) => Self::Intro.swipe(direction), - (Self::Intro, SwipeDirection::Up) => self.return_msg(FlowMsg::Confirmed), - _ => self.do_nothing(), - } - } - - fn handle_event(&'static self, msg: FlowMsg) -> StateChange { - match (self, msg) { - (Self::Intro, FlowMsg::Info) => Self::Menu.transit(), - (Self::Menu, FlowMsg::Cancelled) => Self::Intro.swipe_right(), - (Self::Menu, FlowMsg::Choice(0)) => self.return_msg(FlowMsg::Cancelled), - _ => self.do_nothing(), - } - } -} - -#[allow(clippy::not_unsafe_ptr_arg_deref)] -pub extern "C" fn new_confirm_reset_recover( - n_args: usize, - args: *const Obj, - kwargs: *mut Map, -) -> Obj { - unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, ConfirmResetRecover::new_obj) } -} - -impl ConfirmResetRecover { - fn new_obj(_args: &[Obj], _kwargs: &Map) -> Result { - let par_array: [Paragraph<'static>; 3] = [ - Paragraph::new(&theme::TEXT_MAIN_GREY_LIGHT, TR::reset__by_continuing) - .with_bottom_padding(17), - Paragraph::new(&theme::TEXT_SUB_GREY, TR::reset__more_info_at), - Paragraph::new(&theme::TEXT_SUB_GREY_LIGHT, TR::reset__tos_link), - ]; - let paragraphs = Paragraphs::new(par_array); - let content_intro = Frame::left_aligned( - TR::recovery__title_recover.into(), - SwipeContent::new(paragraphs), - ) - .with_menu_button() - .with_footer(TR::instructions__swipe_up.into(), None) - .with_swipe(SwipeDirection::Up, SwipeSettings::default()) - .with_swipe(SwipeDirection::Left, SwipeSettings::default()) - .map(|msg| matches!(msg, FrameMsg::Button(_)).then_some(FlowMsg::Info)) - .one_button_request(ButtonRequestCode::ProtectCall.with_name("recover_device")); - - let content_menu = Frame::left_aligned( - "".into(), - VerticalMenu::empty().danger( - theme::ICON_CANCEL, - TR::recovery__title_cancel_recovery.into(), - ), - ) - .with_cancel_button() - .with_swipe(SwipeDirection::Right, SwipeSettings::immediate()) - .map(|msg| match msg { - FrameMsg::Content(VerticalMenuChoiceMsg::Selected(i)) => Some(FlowMsg::Choice(i)), - FrameMsg::Button(_) => Some(FlowMsg::Cancelled), - }); - - let res = SwipeFlow::new(&ConfirmResetRecover::Intro)? - .with_page(&ConfirmResetRecover::Intro, content_intro)? - .with_page(&ConfirmResetRecover::Menu, content_menu)?; - Ok(LayoutObj::new(res)?.into()) - } -} 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 47c264c28..7fb877bf3 100644 --- a/core/embed/rust/src/ui/model_mercury/flow/mod.rs +++ b/core/embed/rust/src/ui/model_mercury/flow/mod.rs @@ -1,8 +1,7 @@ pub mod confirm_action; pub mod confirm_firmware_update; pub mod confirm_output; -pub mod confirm_reset_create; -pub mod confirm_reset_recover; +pub mod confirm_reset; pub mod confirm_set_new_pin; pub mod confirm_summary; pub mod get_address; @@ -18,8 +17,7 @@ mod util; pub use confirm_firmware_update::new_confirm_firmware_update; pub use confirm_output::new_confirm_output; -pub use confirm_reset_create::ConfirmResetCreate; -pub use confirm_reset_recover::ConfirmResetRecover; +pub use confirm_reset::new_confirm_reset; pub use confirm_set_new_pin::SetNewPin; pub use confirm_summary::new_confirm_summary; pub use get_address::GetAddress; diff --git a/core/embed/rust/src/ui/model_mercury/layout.rs b/core/embed/rust/src/ui/model_mercury/layout.rs index 2dd793d6b..656fc6bf6 100644 --- a/core/embed/rust/src/ui/model_mercury/layout.rs +++ b/core/embed/rust/src/ui/model_mercury/layout.rs @@ -1422,13 +1422,9 @@ pub static mp_module_trezorui2: Module = obj_module! { /// the value is to be rendered as binary with monospace font, False otherwise.""" Qstr::MP_QSTR_confirm_properties => obj_fn_kw!(0, new_confirm_properties).as_obj(), - /// def flow_confirm_reset_recover() -> LayoutObj[UiResult]: - /// """Confirm TOS before recovery process.""" - Qstr::MP_QSTR_flow_confirm_reset_recover => obj_fn_kw!(0, flow::confirm_reset_recover::new_confirm_reset_recover).as_obj(), - - /// def flow_confirm_reset_create() -> LayoutObj[UiResult]: - /// """Confirm TOS before creating a wallet and have a user hold to confirm creation.""" - Qstr::MP_QSTR_flow_confirm_reset_create => obj_fn_kw!(0, flow::confirm_reset_create::new_confirm_reset_create).as_obj(), + /// def flow_confirm_reset(recovery: bool) -> LayoutObj[UiResult]: + /// """Confirm TOS before creating wallet creation or wallet recovery.""" + Qstr::MP_QSTR_flow_confirm_reset => obj_fn_kw!(0, flow::confirm_reset::new_confirm_reset).as_obj(), // TODO: supply more arguments for Wipe code setting when figma done /// def flow_confirm_set_new_pin( diff --git a/core/mocks/generated/trezorui2.pyi b/core/mocks/generated/trezorui2.pyi index 20a9e563c..d75e2ca78 100644 --- a/core/mocks/generated/trezorui2.pyi +++ b/core/mocks/generated/trezorui2.pyi @@ -154,13 +154,8 @@ def confirm_properties( # rust/src/ui/model_mercury/layout.rs -def flow_confirm_reset_recover() -> LayoutObj[UiResult]: - """Confirm TOS before recovery process.""" - - -# rust/src/ui/model_mercury/layout.rs -def flow_confirm_reset_create() -> LayoutObj[UiResult]: - """Confirm TOS before creating a wallet and have a user hold to confirm creation.""" +def flow_confirm_reset(recovery: bool) -> LayoutObj[UiResult]: + """Confirm TOS before creating wallet creation or wallet recovery.""" # rust/src/ui/model_mercury/layout.rs diff --git a/core/src/trezor/ui/layouts/mercury/__init__.py b/core/src/trezor/ui/layouts/mercury/__init__.py index 7a519d9c2..dd92777d4 100644 --- a/core/src/trezor/ui/layouts/mercury/__init__.py +++ b/core/src/trezor/ui/layouts/mercury/__init__.py @@ -363,14 +363,9 @@ def confirm_single( def confirm_reset_device(_title: str, recovery: bool = False) -> Awaitable[None]: - if recovery: - return raise_if_not_confirmed( - RustLayout(trezorui2.flow_confirm_reset_recover()), - ) - else: - return raise_if_not_confirmed( - RustLayout(trezorui2.flow_confirm_reset_create()), - ) + return raise_if_not_confirmed( + RustLayout(trezorui2.flow_confirm_reset(recovery=recovery)) + ) async def show_wallet_created_success() -> None: