1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-23 14:58:09 +00:00

refactor(core/mercury): unify confirm TOS

[no changelog]
This commit is contained in:
obrusvit 2024-07-22 17:07:34 +02:00 committed by Vít Obrusník
parent f41176af02
commit 008490bf4b
8 changed files with 181 additions and 256 deletions

View File

@ -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;

View File

@ -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<Obj, error::Error> {
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())
}

View File

@ -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<Obj, error::Error> {
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())
}
}

View File

@ -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<Obj, error::Error> {
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())
}
}

View File

@ -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;

View File

@ -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(

View File

@ -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

View File

@ -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: