diff --git a/core/embed/rust/librust_qstr.h b/core/embed/rust/librust_qstr.h index 081cb3fa23..225c165646 100644 --- a/core/embed/rust/librust_qstr.h +++ b/core/embed/rust/librust_qstr.h @@ -54,6 +54,7 @@ static void _librust_qstrs(void) { MP_QSTR_auto_lock__change_template; MP_QSTR_auto_lock__title; MP_QSTR_backup__can_back_up_anytime; + MP_QSTR_backup__create_backup_to_prevent_loss; MP_QSTR_backup__it_should_be_backed_up; MP_QSTR_backup__it_should_be_backed_up_now; MP_QSTR_backup__new_wallet_created; @@ -150,10 +151,8 @@ static void _librust_qstrs(void) { MP_QSTR_confirm_action; MP_QSTR_confirm_address; MP_QSTR_confirm_backup; - MP_QSTR_confirm_backup_written_down; MP_QSTR_confirm_blob; MP_QSTR_confirm_coinjoin; - MP_QSTR_confirm_create_wallet; MP_QSTR_confirm_emphasized; MP_QSTR_confirm_fido; MP_QSTR_confirm_firmware_update; @@ -175,7 +174,6 @@ static void _librust_qstrs(void) { MP_QSTR_confirm_value; MP_QSTR_confirm_with_info; MP_QSTR_count; - MP_QSTR_create_backup_flow; MP_QSTR_data; MP_QSTR_data_hash; MP_QSTR_data_len; @@ -207,7 +205,11 @@ static void _librust_qstrs(void) { MP_QSTR_fingerprint; MP_QSTR_firmware_update__title; MP_QSTR_firmware_update__title_fingerprint; + MP_QSTR_flow_confirm_reset_create; + MP_QSTR_flow_confirm_reset_recover; MP_QSTR_flow_get_address; + MP_QSTR_flow_prompt_backup; + MP_QSTR_flow_show_share_words; MP_QSTR_get_language; MP_QSTR_hold; MP_QSTR_hold_danger; @@ -399,6 +401,7 @@ static void _librust_qstrs(void) { MP_QSTR_reset__button_create; MP_QSTR_reset__button_recover; MP_QSTR_reset__by_continuing; + MP_QSTR_reset__check_backup_instructions; MP_QSTR_reset__check_backup_title; MP_QSTR_reset__check_group_share_title_template; MP_QSTR_reset__check_share_title_template; @@ -462,6 +465,7 @@ static void _librust_qstrs(void) { MP_QSTR_reset__tos_link; MP_QSTR_reset__total_number_of_shares_in_group_template; MP_QSTR_reset__use_your_backup; + MP_QSTR_reset__words_written_down_template; MP_QSTR_reset__write_down_words_template; MP_QSTR_reset__wrong_word_selected; MP_QSTR_reset__you_need_one_share; @@ -553,6 +557,8 @@ static void _librust_qstrs(void) { MP_QSTR_storage_msg__wrong_pin; MP_QSTR_subprompt; MP_QSTR_subtitle; + MP_QSTR_text_confirm; + MP_QSTR_text_info; MP_QSTR_text_mono; MP_QSTR_time_ms; MP_QSTR_timer; @@ -626,10 +632,12 @@ static void _librust_qstrs(void) { MP_QSTR_words__fee; MP_QSTR_words__from; MP_QSTR_words__important; + MP_QSTR_words__instructions; MP_QSTR_words__keep_it_safe; MP_QSTR_words__know_what_your_doing; MP_QSTR_words__my_trezor; MP_QSTR_words__no; + MP_QSTR_words__not_recommended; MP_QSTR_words__outputs; MP_QSTR_words__please_check_again; MP_QSTR_words__please_try_again; diff --git a/core/embed/rust/src/translations/generated/translated_string.rs b/core/embed/rust/src/translations/generated/translated_string.rs index 44acb3d31a..fb704f8d98 100644 --- a/core/embed/rust/src/translations/generated/translated_string.rs +++ b/core/embed/rust/src/translations/generated/translated_string.rs @@ -1255,6 +1255,11 @@ pub enum TranslatedString { instructions__tap_to_confirm = 854, // "Tap to confirm" instructions__hold_to_confirm = 855, // "Hold to confirm" words__important = 856, // "Important" + reset__words_written_down_template = 857, // "I wrote down all {0} words in order." + backup__create_backup_to_prevent_loss = 858, // "Create a backup to avoid losing access to your funds" + reset__check_backup_instructions = 859, // "Let's do a quick check of your backup." + words__instructions = 860, // "Instructions" + words__not_recommended = 861, // "Not recommended!" } impl TranslatedString { @@ -2505,6 +2510,11 @@ impl TranslatedString { Self::instructions__tap_to_confirm => "Tap to confirm", Self::instructions__hold_to_confirm => "Hold to confirm", Self::words__important => "Important", + Self::reset__words_written_down_template => "I wrote down all {0} words in order.", + Self::backup__create_backup_to_prevent_loss => "Create a backup to avoid losing access to your funds", + Self::reset__check_backup_instructions => "Let's do a quick check of your backup.", + Self::words__instructions => "Instructions", + Self::words__not_recommended => "Not recommended!", } } @@ -3756,6 +3766,11 @@ impl TranslatedString { Qstr::MP_QSTR_instructions__tap_to_confirm => Some(Self::instructions__tap_to_confirm), Qstr::MP_QSTR_instructions__hold_to_confirm => Some(Self::instructions__hold_to_confirm), Qstr::MP_QSTR_words__important => Some(Self::words__important), + Qstr::MP_QSTR_reset__words_written_down_template => Some(Self::reset__words_written_down_template), + Qstr::MP_QSTR_backup__create_backup_to_prevent_loss => Some(Self::backup__create_backup_to_prevent_loss), + Qstr::MP_QSTR_reset__check_backup_instructions => Some(Self::reset__check_backup_instructions), + Qstr::MP_QSTR_words__instructions => Some(Self::words__instructions), + Qstr::MP_QSTR_words__not_recommended => Some(Self::words__not_recommended), _ => None, } } diff --git a/core/embed/rust/src/ui/model_mercury/component/frame.rs b/core/embed/rust/src/ui/model_mercury/component/frame.rs index 0da98964fb..499b0407c1 100644 --- a/core/embed/rust/src/ui/model_mercury/component/frame.rs +++ b/core/embed/rust/src/ui/model_mercury/component/frame.rs @@ -72,7 +72,7 @@ where } pub fn with_subtitle(mut self, subtitle: TString<'static>) -> Self { - let style = theme::TEXT_SUB_GREY_LIGHT; + let style = theme::TEXT_SUB_GREY; self.title = Child::new(self.title.into_inner().top_aligned()); self.subtitle = Some(Child::new(Label::new( subtitle, diff --git a/core/embed/rust/src/ui/model_mercury/component/mod.rs b/core/embed/rust/src/ui/model_mercury/component/mod.rs index 43d1f4c436..ce87cba00c 100644 --- a/core/embed/rust/src/ui/model_mercury/component/mod.rs +++ b/core/embed/rust/src/ui/model_mercury/component/mod.rs @@ -65,7 +65,7 @@ pub use prompt_screen::PromptScreen; pub use result::{ResultFooter, ResultScreen, ResultStyle}; pub use scroll::ScrollBar; #[cfg(feature = "translations")] -pub use share_words::ShareWords; +pub use share_words::{ShareWords, ShareWordsMsg}; pub use simple_page::SimplePage; pub use status_screen::StatusScreen; pub use swipe::{Swipe, SwipeDirection}; diff --git a/core/embed/rust/src/ui/model_mercury/component/share_words.rs b/core/embed/rust/src/ui/model_mercury/component/share_words.rs index aa888fce60..8ffcceb37f 100644 --- a/core/embed/rust/src/ui/model_mercury/component/share_words.rs +++ b/core/embed/rust/src/ui/model_mercury/component/share_words.rs @@ -3,8 +3,9 @@ use crate::{ strutil::TString, translations::TR, ui::{ - component::{Component, Event, EventCtx, PageMsg, Paginate}, + component::{Component, Event, EventCtx, Paginate}, constant::SPACING, + flow::Swipable, geometry::{Alignment, Alignment2D, Insets, Offset, Rect}, model_mercury::component::{Footer, Swipe, SwipeDirection}, shape, @@ -30,6 +31,11 @@ pub struct ShareWords<'a> { footer: Footer<'static>, } +pub enum ShareWordsMsg { + GoPrevScreen, + WordsSeen, +} + impl<'a> ShareWords<'a> { const AREA_WORD_HEIGHT: i16 = 91; @@ -44,13 +50,17 @@ impl<'a> ShareWords<'a> { } } + fn is_first_page(&self) -> bool { + self.page_index == 0 + } + fn is_final_page(&self) -> bool { self.page_index == self.share_words.len() - 1 } } impl<'a> Component for ShareWords<'a> { - type Msg = PageMsg<()>; + type Msg = ShareWordsMsg; fn place(&mut self, bounds: Rect) -> Rect { self.area = bounds; @@ -72,17 +82,20 @@ impl<'a> Component for ShareWords<'a> { } fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { - ctx.set_page_count(self.share_words.len()); + // ctx.set_page_count(self.share_words.len()); let swipe = self.swipe.event(ctx, event); match swipe { Some(SwipeDirection::Up) => { if self.is_final_page() { - return Some(PageMsg::Confirmed); + return Some(ShareWordsMsg::WordsSeen); } self.change_page(self.page_index + 1); ctx.request_paint(); } Some(SwipeDirection::Down) => { + if self.is_first_page() { + return Some(ShareWordsMsg::GoPrevScreen); + } self.change_page(self.page_index.saturating_sub(1)); ctx.request_paint(); } @@ -136,6 +149,8 @@ impl<'a> Component for ShareWords<'a> { fn bounds(&self, _sink: &mut dyn FnMut(Rect)) {} } +impl<'a> Swipable for ShareWords<'a> {} + impl<'a> Paginate for ShareWords<'a> { fn page_count(&mut self) -> usize { self.share_words.len() diff --git a/core/embed/rust/src/ui/model_mercury/flow/confirm_reset_device.rs b/core/embed/rust/src/ui/model_mercury/flow/confirm_reset_create.rs similarity index 68% rename from core/embed/rust/src/ui/model_mercury/flow/confirm_reset_device.rs rename to core/embed/rust/src/ui/model_mercury/flow/confirm_reset_create.rs index 751123e80b..c59d46b5c9 100644 --- a/core/embed/rust/src/ui/model_mercury/flow/confirm_reset_device.rs +++ b/core/embed/rust/src/ui/model_mercury/flow/confirm_reset_create.rs @@ -18,34 +18,43 @@ use super::super::{ }; #[derive(Copy, Clone, PartialEq, Eq, ToPrimitive)] -pub enum ConfirmResetDevice { +pub enum ConfirmResetCreate { Intro, Menu, + Confirm, } -impl FlowState for ConfirmResetDevice { +impl FlowState for ConfirmResetCreate { fn handle_swipe(&self, direction: SwipeDirection) -> Decision { match (self, direction) { - (ConfirmResetDevice::Intro, SwipeDirection::Left) => { - Decision::Goto(ConfirmResetDevice::Menu, direction) + (ConfirmResetCreate::Intro, SwipeDirection::Left) => { + Decision::Goto(ConfirmResetCreate::Menu, direction) } - (ConfirmResetDevice::Menu, SwipeDirection::Right) => { - Decision::Goto(ConfirmResetDevice::Intro, direction) + (ConfirmResetCreate::Menu, SwipeDirection::Right) => { + Decision::Goto(ConfirmResetCreate::Intro, direction) + } + (ConfirmResetCreate::Intro, SwipeDirection::Up) => { + Decision::Goto(ConfirmResetCreate::Confirm, direction) + } + (ConfirmResetCreate::Confirm, SwipeDirection::Down) => { + Decision::Goto(ConfirmResetCreate::Intro, direction) } - (ConfirmResetDevice::Intro, SwipeDirection::Up) => Decision::Return(FlowMsg::Confirmed), _ => Decision::Nothing, } } fn handle_event(&self, msg: FlowMsg) -> Decision { match (self, msg) { - (ConfirmResetDevice::Intro, FlowMsg::Info) => { - Decision::Goto(ConfirmResetDevice::Menu, SwipeDirection::Left) + (ConfirmResetCreate::Intro, FlowMsg::Info) => { + Decision::Goto(ConfirmResetCreate::Menu, SwipeDirection::Left) } - (ConfirmResetDevice::Menu, FlowMsg::Cancelled) => { - Decision::Goto(ConfirmResetDevice::Intro, SwipeDirection::Right) + (ConfirmResetCreate::Menu, FlowMsg::Cancelled) => { + Decision::Goto(ConfirmResetCreate::Intro, SwipeDirection::Right) + } + (ConfirmResetCreate::Menu, FlowMsg::Choice(0)) => Decision::Return(FlowMsg::Cancelled), + (ConfirmResetCreate::Confirm, FlowMsg::Confirmed) => { + Decision::Return(FlowMsg::Confirmed) } - (ConfirmResetDevice::Menu, FlowMsg::Choice(0)) => Decision::Return(FlowMsg::Cancelled), _ => Decision::Nothing, } } @@ -56,17 +65,17 @@ use crate::{ ui::layout::obj::LayoutObj, }; -pub extern "C" fn new_confirm_reset_device( +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, ConfirmResetDevice::new) } + unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, ConfirmResetCreate::new) } } -impl ConfirmResetDevice { +impl ConfirmResetCreate { fn new(_args: &[Obj], kwargs: &Map) -> Result { - let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; + 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), @@ -81,7 +90,7 @@ impl ConfirmResetDevice { let content_menu = Frame::left_aligned( "".into(), - VerticalMenu::empty().danger(theme::ICON_CANCEL, "Cancel".into()), + VerticalMenu::empty().danger(theme::ICON_CANCEL, "Cancel".into()), // TODO: use TR ) .with_cancel_button() .map(|msg| match msg { @@ -100,14 +109,11 @@ impl ConfirmResetDevice { }); let store = flow_store() - // Intro, .add(content_intro)? - // Context Menu, .add(content_menu)? - // Confirm prompt .add(content_confirm)?; - let res = SwipeFlow::new(ConfirmResetDevice::Intro, store)?; + let res = SwipeFlow::new(ConfirmResetCreate::Intro, store)?; 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 new file mode 100644 index 0000000000..54dc32a8e4 --- /dev/null +++ b/core/embed/rust/src/ui/model_mercury/flow/confirm_reset_recover.rs @@ -0,0 +1,115 @@ +use crate::{ + error, + translations::TR, + ui::{ + component::{ + text::paragraphs::{Paragraph, Paragraphs}, + ComponentExt, SwipeDirection, + }, + flow::{base::Decision, flow_store, FlowMsg, FlowState, FlowStore, SwipeFlow, SwipePage}, + }, +}; + +use super::super::{ + component::{Frame, FrameMsg, PromptScreen, VerticalMenu, VerticalMenuChoiceMsg}, + theme, +}; + +#[derive(Copy, Clone, PartialEq, Eq, ToPrimitive)] +pub enum ConfirmResetRecover { + Intro, + Menu, +} + +impl FlowState for ConfirmResetRecover { + fn handle_swipe(&self, direction: SwipeDirection) -> Decision { + match (self, direction) { + (ConfirmResetRecover::Intro, SwipeDirection::Left) => { + Decision::Goto(ConfirmResetRecover::Menu, direction) + } + (ConfirmResetRecover::Menu, SwipeDirection::Right) => { + Decision::Goto(ConfirmResetRecover::Intro, direction) + } + (ConfirmResetRecover::Intro, SwipeDirection::Up) => { + Decision::Return(FlowMsg::Confirmed) + } + _ => Decision::Nothing, + } + } + + fn handle_event(&self, msg: FlowMsg) -> Decision { + match (self, msg) { + (ConfirmResetRecover::Intro, FlowMsg::Info) => { + Decision::Goto(ConfirmResetRecover::Menu, SwipeDirection::Left) + } + (ConfirmResetRecover::Menu, FlowMsg::Cancelled) => { + Decision::Goto(ConfirmResetRecover::Intro, SwipeDirection::Right) + } + (ConfirmResetRecover::Menu, FlowMsg::Choice(0)) => Decision::Return(FlowMsg::Cancelled), + _ => Decision::Nothing, + } + } +} + +use crate::{ + micropython::{map::Map, obj::Obj, util}, + ui::layout::obj::LayoutObj, +}; + +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) } +} + +impl ConfirmResetRecover { + fn new(_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(), + SwipePage::vertical(paragraphs), + ) + .with_menu_button() + .with_footer(TR::instructions__swipe_up.into(), None) + .map(|msg| matches!(msg, FrameMsg::Button(_)).then_some(FlowMsg::Info)); + + let content_menu = Frame::left_aligned( + "".into(), + VerticalMenu::empty().danger( + theme::ICON_CANCEL, + TR::recovery__title_cancel_recovery.into(), + ), + ) + .with_cancel_button() + .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(), + PromptScreen::new_hold_to_confirm(), + ) + .with_footer(TR::instructions__hold_to_confirm.into(), None) + .map(|msg| match msg { + FrameMsg::Content(()) => Some(FlowMsg::Confirmed), + _ => Some(FlowMsg::Cancelled), + }); + + let store = flow_store() + .add(content_intro)? + .add(content_menu)? + .add(content_confirm)?; + + let res = SwipeFlow::new(ConfirmResetRecover::Intro, store)?; + 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 555d3bc63e..c9a14f6e58 100644 --- a/core/embed/rust/src/ui/model_mercury/flow/mod.rs +++ b/core/embed/rust/src/ui/model_mercury/flow/mod.rs @@ -1,7 +1,11 @@ -pub mod confirm_reset_device; -pub mod create_backup; +pub mod confirm_reset_create; +pub mod confirm_reset_recover; pub mod get_address; +pub mod prompt_backup; +pub mod show_share_words; -pub use confirm_reset_device::ConfirmResetDevice; -pub use create_backup::CreateBackup; +pub use confirm_reset_create::ConfirmResetCreate; +pub use confirm_reset_recover::ConfirmResetRecover; pub use get_address::GetAddress; +pub use prompt_backup::PromptBackup; +pub use show_share_words::ShowShareWords; diff --git a/core/embed/rust/src/ui/model_mercury/flow/create_backup.rs b/core/embed/rust/src/ui/model_mercury/flow/prompt_backup.rs similarity index 67% rename from core/embed/rust/src/ui/model_mercury/flow/create_backup.rs rename to core/embed/rust/src/ui/model_mercury/flow/prompt_backup.rs index e15201deb8..e7ceeba10e 100644 --- a/core/embed/rust/src/ui/model_mercury/flow/create_backup.rs +++ b/core/embed/rust/src/ui/model_mercury/flow/prompt_backup.rs @@ -19,48 +19,48 @@ use super::super::{ }; #[derive(Copy, Clone, PartialEq, Eq, ToPrimitive)] -pub enum CreateBackup { +pub enum PromptBackup { Intro, Menu, SkipBackupIntro, SkipBackupConfirm, } -impl FlowState for CreateBackup { +impl FlowState for PromptBackup { fn handle_swipe(&self, direction: SwipeDirection) -> Decision { match (self, direction) { - (CreateBackup::Intro, SwipeDirection::Left) => { - Decision::Goto(CreateBackup::Menu, direction) + (PromptBackup::Intro, SwipeDirection::Left) => { + Decision::Goto(PromptBackup::Menu, direction) } - (CreateBackup::SkipBackupIntro, SwipeDirection::Up) => { - Decision::Goto(CreateBackup::SkipBackupConfirm, direction) + (PromptBackup::SkipBackupIntro, SwipeDirection::Up) => { + Decision::Goto(PromptBackup::SkipBackupConfirm, direction) } - (CreateBackup::SkipBackupConfirm, SwipeDirection::Down) => { - Decision::Goto(CreateBackup::SkipBackupIntro, direction) + (PromptBackup::SkipBackupConfirm, SwipeDirection::Down) => { + Decision::Goto(PromptBackup::SkipBackupIntro, direction) } - (CreateBackup::Intro, SwipeDirection::Up) => Decision::Return(FlowMsg::Confirmed), + (PromptBackup::Intro, SwipeDirection::Up) => Decision::Return(FlowMsg::Confirmed), _ => Decision::Nothing, } } fn handle_event(&self, msg: FlowMsg) -> Decision { match (self, msg) { - (CreateBackup::Intro, FlowMsg::Info) => { - Decision::Goto(CreateBackup::Menu, SwipeDirection::Left) + (PromptBackup::Intro, FlowMsg::Info) => { + Decision::Goto(PromptBackup::Menu, SwipeDirection::Left) } - (CreateBackup::Menu, FlowMsg::Choice(0)) => { - Decision::Goto(CreateBackup::SkipBackupIntro, SwipeDirection::Left) + (PromptBackup::Menu, FlowMsg::Choice(0)) => { + Decision::Goto(PromptBackup::SkipBackupIntro, SwipeDirection::Left) } - (CreateBackup::Menu, FlowMsg::Cancelled) => { - Decision::Goto(CreateBackup::Intro, SwipeDirection::Right) + (PromptBackup::Menu, FlowMsg::Cancelled) => { + Decision::Goto(PromptBackup::Intro, SwipeDirection::Right) } - (CreateBackup::SkipBackupIntro, FlowMsg::Cancelled) => { - Decision::Goto(CreateBackup::Menu, SwipeDirection::Right) + (PromptBackup::SkipBackupIntro, FlowMsg::Cancelled) => { + Decision::Goto(PromptBackup::Menu, SwipeDirection::Right) } - (CreateBackup::SkipBackupConfirm, FlowMsg::Cancelled) => { - Decision::Goto(CreateBackup::SkipBackupIntro, SwipeDirection::Right) + (PromptBackup::SkipBackupConfirm, FlowMsg::Cancelled) => { + Decision::Goto(PromptBackup::SkipBackupIntro, SwipeDirection::Right) } - (CreateBackup::SkipBackupConfirm, FlowMsg::Confirmed) => { + (PromptBackup::SkipBackupConfirm, FlowMsg::Confirmed) => { Decision::Return(FlowMsg::Cancelled) } _ => Decision::Nothing, @@ -73,16 +73,18 @@ use crate::{ ui::layout::obj::LayoutObj, }; -pub extern "C" fn new_create_backup(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { - unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, CreateBackup::new) } +pub extern "C" fn new_prompt_backup(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { + unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, PromptBackup::new) } } -impl CreateBackup { +impl PromptBackup { fn new(_args: &[Obj], _kwargs: &Map) -> Result { let title: TString = TR::backup__title_backup_wallet.into(); let par_array: [Paragraph<'static>; 1] = [Paragraph::new( &theme::TEXT_MAIN_GREY_LIGHT, - TString::from_str("Your wallet backup contains X words in a specific order."), + // FIXME: should be "contains X words" but the mnemonic/shares are not yet generated at + // this point. We might need to merge the PromptBackup and ShowShareWords flows + TString::from_str("Your wallet backup contains words in a specific order."), )]; let paragraphs = Paragraphs::new(par_array); let content_intro = Frame::left_aligned(title, SwipePage::vertical(paragraphs)) @@ -94,7 +96,7 @@ impl CreateBackup { let content_menu = Frame::left_aligned( "".into(), - VerticalMenu::empty().danger(theme::ICON_CANCEL, "Skip backup".into()), + VerticalMenu::empty().danger(theme::ICON_CANCEL, TR::backup__title_skip.into()), ) .with_cancel_button() .map(|msg| match msg { @@ -104,10 +106,10 @@ impl CreateBackup { }); let par_array_skip_intro: [Paragraph<'static>; 2] = [ - Paragraph::new(&theme::TEXT_WARNING, TString::from_str("Not recommended!")), + Paragraph::new(&theme::TEXT_WARNING, TR::words__not_recommended), Paragraph::new( &theme::TEXT_MAIN_GREY_LIGHT, - TString::from_str("Create a backup to avoid losing access to your funds"), + TR::backup__create_backup_to_prevent_loss, ), ]; let paragraphs_skip_intro = Paragraphs::new(par_array_skip_intro); @@ -141,7 +143,7 @@ impl CreateBackup { .add(content_menu)? .add(content_skip_intro)? .add(content_skip_confirm)?; - let res = SwipeFlow::new(CreateBackup::Intro, store)?; + let res = SwipeFlow::new(PromptBackup::Intro, store)?; Ok(LayoutObj::new(res)?.into()) } } diff --git a/core/embed/rust/src/ui/model_mercury/flow/show_share_words.rs b/core/embed/rust/src/ui/model_mercury/flow/show_share_words.rs new file mode 100644 index 0000000000..8b88ffbe22 --- /dev/null +++ b/core/embed/rust/src/ui/model_mercury/flow/show_share_words.rs @@ -0,0 +1,120 @@ +use crate::{ + error, + micropython::{map::Map, obj::Obj, qstr::Qstr, util}, + strutil::TString, + translations::TR, + ui::{ + component::{ + text::paragraphs::{Paragraph, Paragraphs}, + ComponentExt, + }, + flow::{ + base::Decision, flow_store, FlowMsg, FlowState, FlowStore, IgnoreSwipe, SwipeFlow, + SwipePage, + }, + layout::obj::LayoutObj, + }, +}; +use heapless::Vec; + +use super::super::{ + component::{Frame, FrameMsg, PromptScreen, ShareWords, ShareWordsMsg, SwipeDirection}, + theme, +}; + +#[derive(Copy, Clone, PartialEq, Eq, ToPrimitive)] +pub enum ShowShareWords { + // TODO: potentially also add there the 'never put anywhere digital' warning? + Instruction, + Words, + Confirm, + CheckBackupIntro, +} + +impl FlowState for ShowShareWords { + fn handle_swipe(&self, direction: SwipeDirection) -> Decision { + match (self, direction) { + (ShowShareWords::Instruction, SwipeDirection::Up) => { + Decision::Goto(ShowShareWords::Words, direction) + } + (ShowShareWords::Confirm, SwipeDirection::Down) => { + Decision::Goto(ShowShareWords::Words, direction) + } + (ShowShareWords::CheckBackupIntro, SwipeDirection::Up) => { + Decision::Return(FlowMsg::Confirmed) + } + _ => Decision::Nothing, + } + } + + fn handle_event(&self, msg: FlowMsg) -> Decision { + match (self, msg) { + (ShowShareWords::Words, FlowMsg::Cancelled) => { + Decision::Goto(ShowShareWords::Instruction, SwipeDirection::Down) + } + (ShowShareWords::Words, FlowMsg::Confirmed) => { + Decision::Goto(ShowShareWords::Confirm, SwipeDirection::Up) + } + (ShowShareWords::Confirm, FlowMsg::Confirmed) => { + Decision::Goto(ShowShareWords::CheckBackupIntro, SwipeDirection::Up) + } + _ => Decision::Nothing, + } + } +} + +pub extern "C" fn new_show_share_words(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { + unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, ShowShareWords::new) } +} + +impl ShowShareWords { + fn new(_args: &[Obj], kwargs: &Map) -> Result { + let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; + let share_words_obj: Obj = kwargs.get(Qstr::MP_QSTR_words)?; + let share_words_vec: Vec = util::iter_into_vec(share_words_obj)?; + let text_info: TString = kwargs.get(Qstr::MP_QSTR_text_info)?.try_into()?; + let text_confirm: TString = kwargs.get(Qstr::MP_QSTR_text_confirm)?.try_into()?; + + let content_instruction = Frame::left_aligned( + title, + SwipePage::vertical(Paragraphs::new(Paragraph::new( + &theme::TEXT_MAIN_GREY_LIGHT, + text_info, + ))), + ) + .with_subtitle(TR::words__instructions.into()) + .with_footer(TR::instructions__swipe_up.into(), None) + .map(|msg| matches!(msg, FrameMsg::Content(_)).then_some(FlowMsg::Confirmed)); + + let content_words = + Frame::left_aligned(title, ShareWords::new(share_words_vec)).map(|msg| match msg { + FrameMsg::Content(ShareWordsMsg::GoPrevScreen) => Some(FlowMsg::Cancelled), + FrameMsg::Content(ShareWordsMsg::WordsSeen) => Some(FlowMsg::Confirmed), + _ => None, + }); + + let content_confirm = + Frame::left_aligned(text_confirm, PromptScreen::new_hold_to_confirm()) + .with_footer(TR::instructions__hold_to_confirm.into(), None) + .map(|_| Some(FlowMsg::Confirmed)); + + let content_check_backup_intro = Frame::left_aligned( + TR::reset__check_backup_title.into(), + SwipePage::vertical(Paragraphs::new(Paragraph::new( + &theme::TEXT_MAIN_GREY_LIGHT, + TR::reset__check_backup_instructions, + ))), + ) + .with_subtitle(TR::words__instructions.into()) + .with_footer(TR::instructions__swipe_up.into(), None) + .map(|_| Some(FlowMsg::Confirmed)); + + let store = flow_store() + .add(content_instruction)? + .add(content_words)? + .add(content_confirm)? + .add(content_check_backup_intro)?; + let res = SwipeFlow::new(ShowShareWords::Instruction, store)?; + Ok(LayoutObj::new(res)?.into()) + } +} diff --git a/core/embed/rust/src/ui/model_mercury/layout.rs b/core/embed/rust/src/ui/model_mercury/layout.rs index ba436433e9..14c3a4a081 100644 --- a/core/embed/rust/src/ui/model_mercury/layout.rs +++ b/core/embed/rust/src/ui/model_mercury/layout.rs @@ -46,8 +46,8 @@ use super::{ FidoMsg, Frame, FrameMsg, Homescreen, HomescreenMsg, IconDialog, Lockscreen, MnemonicInput, MnemonicKeyboard, MnemonicKeyboardMsg, NumberInputDialog, NumberInputDialogMsg, PassphraseKeyboard, PassphraseKeyboardMsg, PinKeyboard, PinKeyboardMsg, Progress, - PromptScreen, SelectWordCount, SelectWordCountMsg, ShareWords, SimplePage, Slip39Input, - StatusScreen, SwipeUpScreen, SwipeUpScreenMsg, VerticalMenu, VerticalMenuChoiceMsg, + PromptScreen, SelectWordCount, SelectWordCountMsg, SimplePage, Slip39Input, StatusScreen, + SwipeUpScreen, SwipeUpScreenMsg, VerticalMenu, VerticalMenuChoiceMsg, }, flow, theme, }; @@ -183,15 +183,6 @@ where } } -impl ComponentMsgObj for ShareWords<'_> { - fn msg_try_into_obj(&self, msg: Self::Msg) -> Result { - match msg { - PageMsg::Confirmed => Ok(CONFIRMED.as_obj()), - _ => Err(Error::TypeError), - } - } -} - impl ComponentMsgObj for SelectWordCount { fn msg_try_into_obj(&self, msg: Self::Msg) -> Result { match msg { @@ -767,18 +758,6 @@ extern "C" fn new_show_info_with_cancel(n_args: usize, args: *const Obj, kwargs: unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } -extern "C" fn new_confirm_create_wallet(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { - let block = move |_args: &[Obj], _kwargs: &Map| { - let content = PromptScreen::new_hold_to_confirm(); - let obj = LayoutObj::new( - Frame::left_aligned(TR::reset__title_create_wallet.into(), content) - .with_footer(TR::instructions__hold_to_confirm.into(), None), - )?; - Ok(obj.into()) - }; - unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } -} - extern "C" fn new_confirm_value(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()?; @@ -1316,37 +1295,6 @@ extern "C" fn new_select_word(n_args: usize, args: *const Obj, kwargs: *mut Map) unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } -extern "C" fn new_show_share_words(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 share_words_obj: Obj = kwargs.get(Qstr::MP_QSTR_pages)?; - let share_words_vec: Vec = util::iter_into_vec(share_words_obj)?; - - let share_words = ShareWords::new(share_words_vec); - let frame_with_share_words = Frame::left_aligned(title, share_words); - let obj = LayoutObj::new(frame_with_share_words)?; - Ok(obj.into()) - }; - unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } -} - -extern "C" fn new_confirm_backup_written_down( - n_args: usize, - args: *const Obj, - kwargs: *mut Map, -) -> Obj { - let block = move |_args: &[Obj], _kwargs: &Map| { - let content = PromptScreen::new_hold_to_confirm(); - // TODO: use TR - let frame_with_hold_to_confirm = - Frame::left_aligned("I wrote down all words in order.".into(), content) - .with_footer(TR::instructions__hold_to_confirm.into(), None); - let obj = LayoutObj::new(frame_with_hold_to_confirm)?; - Ok(obj.into()) - }; - unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } -} - extern "C" fn new_request_number(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()?; @@ -1436,7 +1384,7 @@ extern "C" fn new_confirm_recovery(n_args: usize, args: *const Obj, kwargs: *mut let obj = LayoutObj::new( Frame::left_aligned(notification, content) .with_footer(TR::instructions__swipe_up.into(), None) - .with_subtitle("Instructions".into()), // FIXME: use TR + .with_subtitle(TR::words__instructions.into()), )?; Ok(obj.into()) }; @@ -1797,17 +1745,13 @@ 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 confirm_reset_device( - /// *, - /// title: str, - /// button: str, - /// ) -> LayoutObj[UiResult]: - /// """Confirm TOS before device setup.""" - Qstr::MP_QSTR_confirm_reset_device => obj_fn_kw!(0, flow::confirm_reset_device::new_confirm_reset_device).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 confirm_create_wallet() -> LayoutObj[UiResult]: - /// """Confirm creating wallet""" - Qstr::MP_QSTR_confirm_create_wallet => obj_fn_kw!(0, new_confirm_create_wallet).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 show_address_details( /// *, @@ -2024,23 +1968,20 @@ pub static mp_module_trezorui2: Module = obj_module! { /// iterable must be of exact size. Returns index in range `0..3`.""" Qstr::MP_QSTR_select_word => obj_fn_kw!(0, new_select_word).as_obj(), - // TODO: This is just POC - /// def create_backup_flow() -> LayoutObj[UiResult] - /// """Start create backup or skip flow.""" - Qstr::MP_QSTR_create_backup_flow => obj_fn_kw!(0, flow::create_backup::new_create_backup).as_obj(), + /// def flow_prompt_backup() -> LayoutObj[UiResult] + /// """Prompt a user to create backup with an option to skip.""" + Qstr::MP_QSTR_flow_prompt_backup => obj_fn_kw!(0, flow::prompt_backup::new_prompt_backup).as_obj(), - /// def show_share_words( + /// def flow_show_share_words( /// *, /// title: str, - /// pages: Iterable[str], + /// words: Iterable[str], + /// text_info: str, + /// text_confirm: str, /// ) -> LayoutObj[UiResult]: - /// """Show mnemonic for backup.""" - Qstr::MP_QSTR_show_share_words => obj_fn_kw!(0, new_show_share_words).as_obj(), - - // TODO: This is just POC - /// def confirm_backup_written_down() -> LayoutObj[UiResult] - /// """Confirm with the user that backup words are written down.""" - Qstr::MP_QSTR_confirm_backup_written_down => obj_fn_kw!(0, new_confirm_backup_written_down).as_obj(), + /// """Show wallet backup words preceded by an instruction screen and followed by + /// confirmation.""" + Qstr::MP_QSTR_flow_show_share_words => obj_fn_kw!(0, flow::show_share_words::new_show_share_words).as_obj(), /// def request_number( /// *, diff --git a/core/mocks/generated/trezorui2.pyi b/core/mocks/generated/trezorui2.pyi index d53028d3c5..34658d8417 100644 --- a/core/mocks/generated/trezorui2.pyi +++ b/core/mocks/generated/trezorui2.pyi @@ -146,17 +146,13 @@ def confirm_properties( # rust/src/ui/model_mercury/layout.rs -def confirm_reset_device( - *, - title: str, - button: str, -) -> LayoutObj[UiResult]: - """Confirm TOS before device setup.""" +def flow_confirm_reset_recover() -> LayoutObj[UiResult]: + """Confirm TOS before recovery process.""" # rust/src/ui/model_mercury/layout.rs -def confirm_create_wallet() -> LayoutObj[UiResult]: - """Confirm creating wallet""" +def flow_confirm_reset_create() -> LayoutObj[UiResult]: + """Confirm TOS before creating a wallet and have a user hold to confirm creation.""" # rust/src/ui/model_mercury/layout.rs @@ -395,22 +391,20 @@ def select_word( # rust/src/ui/model_mercury/layout.rs -def create_backup_flow() -> LayoutObj[UiResult] -"""Start create backup or skip flow.""" +def flow_prompt_backup() -> LayoutObj[UiResult] +"""Prompt a user to create backup with an option to skip.""" # rust/src/ui/model_mercury/layout.rs -def show_share_words( +def flow_show_share_words( *, title: str, - pages: Iterable[str], + words: Iterable[str], + text_info: str, + text_confirm: str, ) -> LayoutObj[UiResult]: - """Show mnemonic for backup.""" - - -# rust/src/ui/model_mercury/layout.rs -def confirm_backup_written_down() -> LayoutObj[UiResult] -"""Confirm with the user that backup words are written down.""" + """Show wallet backup words preceded by an instruction screen and followed by + confirmation.""" # rust/src/ui/model_mercury/layout.rs diff --git a/core/mocks/trezortranslate_keys.pyi b/core/mocks/trezortranslate_keys.pyi index ee0fc0c0c9..117056ca29 100644 --- a/core/mocks/trezortranslate_keys.pyi +++ b/core/mocks/trezortranslate_keys.pyi @@ -20,6 +20,7 @@ class TR: auto_lock__change_template: str = "Auto-lock your Trezor after {0} of inactivity?" auto_lock__title: str = "Auto-lock delay" backup__can_back_up_anytime: str = "You can back up your Trezor once, at any time." + backup__create_backup_to_prevent_loss: str = "Create a backup to avoid losing access to your funds" backup__it_should_be_backed_up: str = "You should back up your new wallet right now." backup__it_should_be_backed_up_now: str = "It should be backed up now!" backup__new_wallet_created: str = "New wallet created.\n" @@ -560,6 +561,7 @@ class TR: reset__button_create: str = "Create wallet" reset__button_recover: str = "Recover wallet" reset__by_continuing: str = "By continuing you agree to Trezor Company's terms and conditions." + reset__check_backup_instructions: str = "Let's do a quick check of your backup." reset__check_backup_title: str = "Check backup" reset__check_group_share_title_template: str = "Check g{0} - share {1}" reset__check_share_title_template: str = "Check share #{0}" @@ -622,6 +624,7 @@ class TR: reset__tos_link: str = "trezor.io/tos" reset__total_number_of_shares_in_group_template: str = "Set the total number of shares in Group {0}." reset__use_your_backup: str = "Use your backup when you need to recover your wallet." + reset__words_written_down_template: str = "I wrote down all {0} words in order." reset__write_down_words_template: str = "Write down all {0} words in order." reset__wrong_word_selected: str = "Wrong word selected!" reset__you_need_one_share: str = "For recovery you need 1 share." @@ -834,10 +837,12 @@ class TR: words__fee: str = "Fee" words__from: str = "from" words__important: str = "Important" + words__instructions: str = "Instructions" words__keep_it_safe: str = "Keep it safe!" words__know_what_your_doing: str = "Continue only if you know what you are doing!" words__my_trezor: str = "My Trezor" words__no: str = "No" + words__not_recommended: str = "Not recommended!" words__outputs: str = "outputs" words__please_check_again: str = "Please check again" words__please_try_again: str = "Please try again" diff --git a/core/src/trezor/ui/layouts/mercury/__init__.py b/core/src/trezor/ui/layouts/mercury/__init__.py index d33eda0cf1..f1a3d1cc46 100644 --- a/core/src/trezor/ui/layouts/mercury/__init__.py +++ b/core/src/trezor/ui/layouts/mercury/__init__.py @@ -322,33 +322,19 @@ async def confirm_single( ) -async def confirm_reset_device(title: str, recovery: bool = False) -> None: +async def confirm_reset_device(_title: str, recovery: bool = False) -> None: if recovery: await raise_if_not_confirmed( interact( - RustLayout( - trezorui2.confirm_reset_device( - title=title, - button="", # not used - ) - ), + RustLayout(trezorui2.flow_confirm_reset_recover()), "recover_device", ButtonRequestType.ProtectCall, ) ) else: - # creating wallet shows TOS first and then an extra screen confirms - await raise_if_not_confirmed( - RustLayout( - trezorui2.confirm_reset_device( - title=title, - button="", # not used - ) - ), - ) await raise_if_not_confirmed( interact( - RustLayout(trezorui2.confirm_create_wallet()), + RustLayout(trezorui2.flow_confirm_reset_create()), "setup_device", ButtonRequestType.ResetDevice, ) @@ -356,7 +342,7 @@ async def confirm_reset_device(title: str, recovery: bool = False) -> None: async def prompt_backup() -> bool: - # result = await interact(RustLayout(trezorui2.)) + # TODO: should we move this to `flow_prompt_backup`? await interact( RustLayout(trezorui2.show_success(title=TR.backup__new_wallet_created)), "backup_device", @@ -364,8 +350,7 @@ async def prompt_backup() -> bool: ) result = await interact( - # TODO: this is just POC - RustLayout(trezorui2.create_backup_flow()), + RustLayout(trezorui2.flow_prompt_backup()), "backup_device", ButtonRequestType.ResetDevice, ) diff --git a/core/src/trezor/ui/layouts/mercury/reset.py b/core/src/trezor/ui/layouts/mercury/reset.py index a6025edc22..19dd964f8f 100644 --- a/core/src/trezor/ui/layouts/mercury/reset.py +++ b/core/src/trezor/ui/layouts/mercury/reset.py @@ -23,7 +23,9 @@ async def show_share_words( share_index: int | None = None, group_index: int | None = None, ) -> None: + if share_index is None: + # FIXME use TR.reset__recovery_wallet_backup_title after #3710 merged title = TR.reset__recovery_seed_title elif group_index is None: title = TR.reset__recovery_share_title_template.format(share_index + 1) @@ -31,28 +33,23 @@ async def show_share_words( title = TR.reset__group_share_title_template.format( group_index + 1, share_index + 1 ) - - await RustLayout( - trezorui2.show_share_words( - title=title, - pages=share_words, - ), - ) + words_count = len(share_words) + text_info = TR.reset__write_down_words_template.format(words_count) + text_confirm = TR.reset__words_written_down_template.format(words_count) result = await interact( RustLayout( - trezorui2.confirm_backup_written_down(), + trezorui2.flow_show_share_words( + title=title, + words=share_words, + text_info=text_info, + text_confirm=text_confirm, + ) ), "backup_words", ButtonRequestType.ResetDevice, ) - result = await RustLayout( - trezorui2.show_info( - title="Check wallet backup", - description="Let's do a quick check of your backup.", - ) - ) if result != CONFIRMED: raise ActionCancelled @@ -317,12 +314,6 @@ async def show_warning_backup(slip39: bool) -> None: "backup_warning", ButtonRequestType.ResetDevice, ) - result = await RustLayout( - trezorui2.show_info( - title="Wallet backup", - description="Write the following words in order on your wallet backup card.", - ) - ) if result != CONFIRMED: raise ActionCancelled diff --git a/core/translations/en.json b/core/translations/en.json index 720415ac12..cd3723fba5 100644 --- a/core/translations/en.json +++ b/core/translations/en.json @@ -22,6 +22,7 @@ "auto_lock__change_template": "Auto-lock your Trezor after {0} of inactivity?", "auto_lock__title": "Auto-lock delay", "backup__can_back_up_anytime": "You can back up your Trezor once, at any time.", + "backup__create_backup_to_prevent_loss": "Create a backup to avoid losing access to your funds", "backup__it_should_be_backed_up": "You should back up your new wallet right now.", "backup__it_should_be_backed_up_now": "It should be backed up now!", "backup__new_wallet_created": "New wallet created.\n", @@ -566,6 +567,7 @@ "reset__check_group_share_title_template": "Check g{0} - share {1}", "reset__check_wallet_backup_title": "Check wallet backup", "reset__check_share_title_template": "Check share #{0}", + "reset__check_backup_instructions": "Let's do a quick check of your backup.", "reset__continue_with_next_share": "Continue with the next share.", "reset__continue_with_share_template": "Continue with share #{0}.", "reset__create_x_of_y_multi_share_backup_template": "Do you want to create a {0} of {1} multi-share backup?", @@ -624,6 +626,7 @@ "reset__tos_link": "trezor.io/tos", "reset__total_number_of_shares_in_group_template": "Set the total number of shares in Group {0}.", "reset__use_your_backup": "Use your backup when you need to recover your wallet.", + "reset__words_written_down_template": "I wrote down all {0} words in order.", "reset__write_down_words_template": "Write down all {0} words in order.", "reset__wrong_word_selected": "Wrong word selected!", "reset__you_need_one_share": "For recovery you need 1 share.", @@ -836,10 +839,12 @@ "words__fee": "Fee", "words__from": "from", "words__important": "Important", + "words__instructions": "Instructions", "words__keep_it_safe": "Keep it safe!", "words__know_what_your_doing": "Continue only if you know what you are doing!", "words__my_trezor": "My Trezor", "words__no": "No", + "words__not_recommended": "Not recommended!", "words__outputs": "outputs", "words__please_check_again": "Please check again", "words__please_try_again": "Please try again", diff --git a/core/translations/order.json b/core/translations/order.json index 49b154e5f0..95885a2668 100644 --- a/core/translations/order.json +++ b/core/translations/order.json @@ -855,5 +855,10 @@ "853": "instructions__swipe_up", "854": "instructions__tap_to_confirm", "855": "instructions__hold_to_confirm", - "856": "words__important" + "856": "words__important", + "857": "reset__words_written_down_template", + "858": "backup__create_backup_to_prevent_loss", + "859": "reset__check_backup_instructions", + "860": "words__instructions", + "861": "words__not_recommended" } diff --git a/core/translations/signatures.json b/core/translations/signatures.json index 394ade0b70..84db9e0693 100644 --- a/core/translations/signatures.json +++ b/core/translations/signatures.json @@ -1,8 +1,8 @@ { "current": { - "merkle_root": "04a116dbd20d79235dd81e26fa428eb7c5f4971e76f08a47cde1ec98c959e586", - "datetime": "2024-05-17T10:12:24.161735", - "commit": "aea8bdbe8f9cc2fe629e624a06f4f1b1af6e0a8f" + "merkle_root": "5261bdad43d4e3cda9263ec6ce080218a0d897e02307ca8cafa2525d6a8d3d6b", + "datetime": "2024-05-17T10:18:14.246905", + "commit": "58db509b926fd99b3a36eb3bd550945bf1a139c4" }, "history": [ { diff --git a/tests/common.py b/tests/common.py index 1725b41ef1..35d6905c8a 100644 --- a/tests/common.py +++ b/tests/common.py @@ -256,7 +256,7 @@ def read_mnemonic_from_screen_mercury( debug.wait_layout() - for i in range(br.pages): + for _ in range(br.pages): words = debug.wait_layout().seed_words() mnemonic.extend(words) debug.swipe_up()