diff --git a/core/embed/rust/librust_qstr.h b/core/embed/rust/librust_qstr.h index 79dfa086ad..fcc0c675b5 100644 --- a/core/embed/rust/librust_qstr.h +++ b/core/embed/rust/librust_qstr.h @@ -105,6 +105,7 @@ static void _librust_qstrs(void) { MP_QSTR_backup__it_should_be_backed_up_now; MP_QSTR_backup__new_wallet_created; MP_QSTR_backup__new_wallet_successfully_created; + MP_QSTR_backup__not_recommend; MP_QSTR_backup__recover_anytime; MP_QSTR_backup__title_backup_completed; MP_QSTR_backup__title_backup_wallet; @@ -806,6 +807,7 @@ static void _librust_qstrs(void) { MP_QSTR_words__not_recommended; MP_QSTR_words__operation_cancelled; MP_QSTR_words__outputs; + MP_QSTR_words__pay_attention; MP_QSTR_words__please_check_again; MP_QSTR_words__please_try_again; MP_QSTR_words__really_wanna; diff --git a/core/embed/rust/src/translations/generated/translated_string.rs b/core/embed/rust/src/translations/generated/translated_string.rs index 952e557ec9..821dcf9018 100644 --- a/core/embed/rust/src/translations/generated/translated_string.rs +++ b/core/embed/rust/src/translations/generated/translated_string.rs @@ -29,7 +29,7 @@ pub enum TranslatedString { auto_lock__change_template = 15, // "Auto-lock Trezor after {0} of inactivity?" auto_lock__title = 16, // "Auto-lock delay" backup__can_back_up_anytime = 17, // "You can back up your Trezor once, at any time." - backup__it_should_be_backed_up = 18, // "You should back up your new wallet right now." + backup__it_should_be_backed_up = 18, // {"Bolt": "You should back up your new wallet right now.", "Caesar": "You should back up your new wallet right now.", "Delizia": "You should back up your new wallet right now.", "Eckhart": "Back up your new wallet now."} backup__it_should_be_backed_up_now = 19, // "It should be backed up now!" backup__new_wallet_created = 20, // "Wallet created.\n" backup__new_wallet_successfully_created = 21, // "Wallet created successfully." @@ -1227,7 +1227,7 @@ pub enum TranslatedString { 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" + backup__create_backup_to_prevent_loss = 858, // {"Bolt": "Create a backup to avoid losing access to your funds", "Caesar": "Create a backup to avoid losing access to your funds", "Delizia": "Create a backup to avoid losing access to your funds", "Eckhart": "Create a wallet 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!" diff --git a/core/embed/rust/src/ui/layout_eckhart/flow/mod.rs b/core/embed/rust/src/ui/layout_eckhart/flow/mod.rs index a83f738009..5835ae7e81 100644 --- a/core/embed/rust/src/ui/layout_eckhart/flow/mod.rs +++ b/core/embed/rust/src/ui/layout_eckhart/flow/mod.rs @@ -1,7 +1,9 @@ pub mod confirm_reset; +pub mod prompt_backup; pub mod request_passphrase; pub mod show_share_words; pub use confirm_reset::new_confirm_reset; +pub use prompt_backup::PromptBackup; pub use request_passphrase::RequestPassphrase; pub use show_share_words::new_show_share_words_flow; diff --git a/core/embed/rust/src/ui/layout_eckhart/flow/prompt_backup.rs b/core/embed/rust/src/ui/layout_eckhart/flow/prompt_backup.rs new file mode 100644 index 0000000000..302b6210ad --- /dev/null +++ b/core/embed/rust/src/ui/layout_eckhart/flow/prompt_backup.rs @@ -0,0 +1,123 @@ +use crate::{ + error, + strutil::TString, + translations::TR, + ui::{ + component::{ + text::paragraphs::{Paragraph, ParagraphSource, Paragraphs}, + ComponentExt, + }, + flow::{ + base::{Decision, DecisionBuilder as _}, + FlowController, FlowMsg, SwipeFlow, + }, + geometry::{Alignment, Direction, LinearPlacement, Offset}, + }, +}; + +use super::super::{ + component::{ + ActionBar, Button, Header, HeaderMsg, Hint, TextScreen, TextScreenMsg, VerticalMenu, + VerticalMenuScreen, VerticalMenuScreenMsg, + }, + theme, +}; + +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum PromptBackup { + Intro, + Menu, + SkipBackup, +} + +impl FlowController for PromptBackup { + #[inline] + fn index(&'static self) -> usize { + *self as usize + } + + fn handle_swipe(&'static self, direction: Direction) -> Decision { + match (self, direction) { + _ => self.do_nothing(), + } + } + + fn handle_event(&'static self, msg: FlowMsg) -> Decision { + match (self, msg) { + (Self::Intro, FlowMsg::Info) => Self::Menu.goto(), + (Self::Intro, FlowMsg::Confirmed) => self.return_msg(FlowMsg::Confirmed), + (Self::Menu, FlowMsg::Choice(0)) => Self::SkipBackup.swipe_left(), + (Self::Menu, FlowMsg::Cancelled) => Self::Intro.goto(), + (Self::SkipBackup, FlowMsg::Cancelled) => Self::Intro.goto(), + (Self::SkipBackup, FlowMsg::Confirmed) => self.return_msg(FlowMsg::Cancelled), + _ => self.do_nothing(), + } + } +} + +pub fn new_prompt_backup() -> Result { + let title: TString = TR::backup__title_create_wallet_backup.into(); + let content: TString = TR::backup__it_should_be_backed_up.into(); + + let paragraphs = Paragraphs::new(Paragraph::new(&theme::TEXT_REGULAR, content)) + .with_placement(LinearPlacement::vertical()); + + let content_intro = TextScreen::new(paragraphs) + .with_header(Header::new(title).with_menu_button()) + .with_action_bar(ActionBar::new_single(Button::with_text( + TR::buttons__continue.into(), + ))) + .map(|msg| match msg { + TextScreenMsg::Menu => Some(FlowMsg::Info), + TextScreenMsg::Confirmed => Some(FlowMsg::Confirmed), + _ => None, + }); + + let content_menu = VerticalMenuScreen::new( + VerticalMenu::empty().item( + Button::with_text(TR::backup__title_skip.into()) + .styled(theme::menu_item_title_red()) + .with_text_align(Alignment::Start) + .with_content_offset(Offset::x(12)), + ), + ) + .with_header( + Header::new(title) + .with_right_button(Button::with_icon(theme::ICON_CROSS), HeaderMsg::Cancelled), + ) + .map(|msg| match msg { + VerticalMenuScreenMsg::Selected(i) => Some(FlowMsg::Choice(i)), + VerticalMenuScreenMsg::Close => Some(FlowMsg::Cancelled), + _ => None, + }); + + let paragraphs_skip_intro = Paragraph::new( + &theme::TEXT_REGULAR, + TR::backup__create_backup_to_prevent_loss, + ) + .into_paragraphs() + .with_placement(LinearPlacement::vertical()); + + let content_skip_intro = TextScreen::new(paragraphs_skip_intro) + .with_header( + Header::new(TR::words__pay_attention.into()) + .with_icon(theme::ICON_WARNING, theme::ORANGE) + .with_text_style(theme::label_title_danger()), + ) + .with_action_bar(ActionBar::new_double( + Button::with_icon(theme::ICON_CHEVRON_LEFT), + Button::with_text(TR::buttons__skip.into()).styled(theme::button_cancel()), + )) + .with_hint(Hint::new_instruction(TR::backup__not_recommend, None)) + .map(|msg| match msg { + TextScreenMsg::Menu => Some(FlowMsg::Cancelled), + TextScreenMsg::Confirmed => Some(FlowMsg::Confirmed), + TextScreenMsg::Cancelled => Some(FlowMsg::Cancelled), + }); + + let mut res = SwipeFlow::new(&PromptBackup::Intro)?; + res.add_page(&PromptBackup::Intro, content_intro)? + .add_page(&PromptBackup::Menu, content_menu)? + .add_page(&PromptBackup::SkipBackup, content_skip_intro)?; + Ok(res) +} diff --git a/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs b/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs index a95e0678a4..06b34e6610 100644 --- a/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs +++ b/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs @@ -351,7 +351,8 @@ impl FirmwareUI for UIEckhart { } fn prompt_backup() -> Result { - Err::, Error>(Error::ValueError(c"not implemented")) + let flow = flow::prompt_backup::new_prompt_backup()?; + Ok(flow) } fn request_bip39( @@ -575,8 +576,6 @@ impl FirmwareUI for UIEckhart { Ok(layout) } - // TODO: This is a temporary implementation so the UI can be functional. - // TODO: This is a temporary implementation so the UI can be functional. fn show_progress( description: TString<'static>, _indeterminate: bool, diff --git a/core/mocks/trezortranslate_keys.pyi b/core/mocks/trezortranslate_keys.pyi index a4eb1a7e0f..9f722c5d75 100644 --- a/core/mocks/trezortranslate_keys.pyi +++ b/core/mocks/trezortranslate_keys.pyi @@ -35,6 +35,7 @@ class TR: backup__it_should_be_backed_up_now: str = "It should be backed up now!" backup__new_wallet_created: str = "Wallet created.\n" backup__new_wallet_successfully_created: str = "Wallet created successfully." + backup__not_recommend: str = "We don't recommend to skip wallet backup creation." backup__recover_anytime: str = "You can use your backup to recover your wallet at any time." backup__title_backup_completed: str = "Wallet backup completed" backup__title_backup_wallet: str = "Back up wallet" @@ -957,6 +958,7 @@ class TR: words__not_recommended: str = "Not recommended!" words__operation_cancelled: str = "Operation cancelled" words__outputs: str = "outputs" + words__pay_attention: str = "Pay attention" words__please_check_again: str = "Please check again" words__please_try_again: str = "Please try again" words__really_wanna: str = "Do you really want to" diff --git a/core/translations/en.json b/core/translations/en.json index ad3859676c..8fc1eb726d 100644 --- a/core/translations/en.json +++ b/core/translations/en.json @@ -30,10 +30,21 @@ "auto_lock__title": "Auto-lock delay", "auto_lock__turned_on": "Auto-lock turned on", "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__create_backup_to_prevent_loss": { + "Bolt": "Create a backup to avoid losing access to your funds", + "Caesar": "Create a backup to avoid losing access to your funds", + "Delizia": "Create a backup to avoid losing access to your funds", + "Eckhart": "Create a wallet backup to avoid losing access to your funds." + }, + "backup__not_recommend": "We don't recommend to skip wallet backup creation.", "backup__info_multi_share_backup": "Your wallet backup contains multiple lists of words in a specific order (shares).", "backup__info_single_share_backup": "Your wallet backup contains {0} words in a specific order.", - "backup__it_should_be_backed_up": "You should back up your new wallet right now.", + "backup__it_should_be_backed_up": { + "Bolt": "You should back up your new wallet right now.", + "Caesar": "You should back up your new wallet right now.", + "Delizia": "You should back up your new wallet right now.", + "Eckhart": "Back up your new wallet now." + }, "backup__it_should_be_backed_up_now": "It should be backed up now!", "backup__new_wallet_created": "Wallet created.\n", "backup__new_wallet_successfully_created": "Wallet created successfully.", @@ -972,6 +983,7 @@ "words__good_to_know": "Good to know", "words__important": "Important", "words__instructions": "Instructions", + "words__pay_attention": "Pay attention", "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", diff --git a/core/translations/order.json b/core/translations/order.json index 3d3d4e6383..9b13161c8b 100644 --- a/core/translations/order.json +++ b/core/translations/order.json @@ -999,5 +999,7 @@ "997": "solana__max_fees_rent", "998": "solana__max_rent_fee", "999": "solana__transaction_fee", - "1000": "reset__share_words_first" + "1000": "reset__share_words_first", + "1001": "backup__not_recommend", + "1002": "words__pay_attention" }