1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-03-12 14:16:06 +00:00

feat(eckhart): prompt backup flow

This commit is contained in:
Lukas Bielesch 2025-02-26 12:17:30 +01:00 committed by obrusvit
parent ff6efc5334
commit e05f3c2ab7
8 changed files with 170 additions and 8 deletions

View File

@ -90,6 +90,7 @@ static void _librust_qstrs(void) {
MP_QSTR_backup__it_should_be_backed_up_now; MP_QSTR_backup__it_should_be_backed_up_now;
MP_QSTR_backup__new_wallet_created; MP_QSTR_backup__new_wallet_created;
MP_QSTR_backup__new_wallet_successfully_created; MP_QSTR_backup__new_wallet_successfully_created;
MP_QSTR_backup__not_recommend;
MP_QSTR_backup__recover_anytime; MP_QSTR_backup__recover_anytime;
MP_QSTR_backup__title_backup_completed; MP_QSTR_backup__title_backup_completed;
MP_QSTR_backup__title_backup_wallet; MP_QSTR_backup__title_backup_wallet;
@ -775,6 +776,7 @@ static void _librust_qstrs(void) {
MP_QSTR_words__not_recommended; MP_QSTR_words__not_recommended;
MP_QSTR_words__operation_cancelled; MP_QSTR_words__operation_cancelled;
MP_QSTR_words__outputs; MP_QSTR_words__outputs;
MP_QSTR_words__pay_attention;
MP_QSTR_words__please_check_again; MP_QSTR_words__please_check_again;
MP_QSTR_words__please_try_again; MP_QSTR_words__please_try_again;
MP_QSTR_words__really_wanna; MP_QSTR_words__really_wanna;

View File

@ -29,7 +29,7 @@ pub enum TranslatedString {
auto_lock__change_template = 15, // "Auto-lock Trezor after {0} of inactivity?" auto_lock__change_template = 15, // "Auto-lock Trezor after {0} of inactivity?"
auto_lock__title = 16, // "Auto-lock delay" auto_lock__title = 16, // "Auto-lock delay"
backup__can_back_up_anytime = 17, // "You can back up your Trezor once, at any time." 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__it_should_be_backed_up_now = 19, // "It should be backed up now!"
backup__new_wallet_created = 20, // "Wallet created.\n" backup__new_wallet_created = 20, // "Wallet created.\n"
backup__new_wallet_successfully_created = 21, // "Wallet created successfully." backup__new_wallet_successfully_created = 21, // "Wallet created successfully."
@ -1249,7 +1249,7 @@ pub enum TranslatedString {
instructions__hold_to_confirm = 855, // "Hold to confirm" instructions__hold_to_confirm = 855, // "Hold to confirm"
words__important = 856, // "Important" words__important = 856, // "Important"
reset__words_written_down_template = 857, // "I wrote down all {0} words in order." 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." reset__check_backup_instructions = 859, // "Let's do a quick check of your backup."
words__instructions = 860, // "Instructions" words__instructions = 860, // "Instructions"
words__not_recommended = 861, // "Not recommended!" words__not_recommended = 861, // "Not recommended!"
@ -1405,6 +1405,8 @@ pub enum TranslatedString {
#[cfg(feature = "universal_fw")] #[cfg(feature = "universal_fw")]
nostr__event_kind_template = 992, // "Event kind: {0}" nostr__event_kind_template = 992, // "Event kind: {0}"
reset__share_words_first = 993, // "Write down the first word from the backup." reset__share_words_first = 993, // "Write down the first word from the backup."
backup__not_recommend = 994, // "We don't recommend to skip wallet backup creation."
words__pay_attention = 995, // "Pay attention"
} }
impl TranslatedString { impl TranslatedString {
@ -1430,7 +1432,14 @@ impl TranslatedString {
Self::auto_lock__change_template => "Auto-lock Trezor after {0} of inactivity?", Self::auto_lock__change_template => "Auto-lock Trezor after {0} of inactivity?",
Self::auto_lock__title => "Auto-lock delay", Self::auto_lock__title => "Auto-lock delay",
Self::backup__can_back_up_anytime => "You can back up your Trezor once, at any time.", Self::backup__can_back_up_anytime => "You can back up your Trezor once, at any time.",
#[cfg(feature = "layout_bolt")]
Self::backup__it_should_be_backed_up => "You should back up your new wallet right now.", Self::backup__it_should_be_backed_up => "You should back up your new wallet right now.",
#[cfg(feature = "layout_caesar")]
Self::backup__it_should_be_backed_up => "You should back up your new wallet right now.",
#[cfg(feature = "layout_delizia")]
Self::backup__it_should_be_backed_up => "You should back up your new wallet right now.",
#[cfg(feature = "layout_eckhart")]
Self::backup__it_should_be_backed_up => "Back up your new wallet now.",
Self::backup__it_should_be_backed_up_now => "It should be backed up now!", Self::backup__it_should_be_backed_up_now => "It should be backed up now!",
Self::backup__new_wallet_created => "Wallet created.\n", Self::backup__new_wallet_created => "Wallet created.\n",
Self::backup__new_wallet_successfully_created => "Wallet created successfully.", Self::backup__new_wallet_successfully_created => "Wallet created successfully.",
@ -2671,7 +2680,14 @@ impl TranslatedString {
Self::instructions__hold_to_confirm => "Hold to confirm", Self::instructions__hold_to_confirm => "Hold to confirm",
Self::words__important => "Important", Self::words__important => "Important",
Self::reset__words_written_down_template => "I wrote down all {0} words in order.", Self::reset__words_written_down_template => "I wrote down all {0} words in order.",
#[cfg(feature = "layout_bolt")]
Self::backup__create_backup_to_prevent_loss => "Create a backup to avoid losing access to your funds", Self::backup__create_backup_to_prevent_loss => "Create a backup to avoid losing access to your funds",
#[cfg(feature = "layout_caesar")]
Self::backup__create_backup_to_prevent_loss => "Create a backup to avoid losing access to your funds",
#[cfg(feature = "layout_delizia")]
Self::backup__create_backup_to_prevent_loss => "Create a backup to avoid losing access to your funds",
#[cfg(feature = "layout_eckhart")]
Self::backup__create_backup_to_prevent_loss => "Create a wallet backup to avoid losing access to your funds.",
Self::reset__check_backup_instructions => "Let's do a quick check of your backup.", Self::reset__check_backup_instructions => "Let's do a quick check of your backup.",
Self::words__instructions => "Instructions", Self::words__instructions => "Instructions",
Self::words__not_recommended => "Not recommended!", Self::words__not_recommended => "Not recommended!",
@ -2841,6 +2857,8 @@ impl TranslatedString {
#[cfg(feature = "universal_fw")] #[cfg(feature = "universal_fw")]
Self::nostr__event_kind_template => "Event kind: {0}", Self::nostr__event_kind_template => "Event kind: {0}",
Self::reset__share_words_first => "Write down the first word from the backup.", Self::reset__share_words_first => "Write down the first word from the backup.",
Self::backup__not_recommend => "We don't recommend to skip wallet backup creation.",
Self::words__pay_attention => "Pay attention",
} }
} }
@ -4241,6 +4259,8 @@ impl TranslatedString {
#[cfg(feature = "universal_fw")] #[cfg(feature = "universal_fw")]
Qstr::MP_QSTR_nostr__event_kind_template => Some(Self::nostr__event_kind_template), Qstr::MP_QSTR_nostr__event_kind_template => Some(Self::nostr__event_kind_template),
Qstr::MP_QSTR_reset__share_words_first => Some(Self::reset__share_words_first), Qstr::MP_QSTR_reset__share_words_first => Some(Self::reset__share_words_first),
Qstr::MP_QSTR_backup__not_recommend => Some(Self::backup__not_recommend),
Qstr::MP_QSTR_words__pay_attention => Some(Self::words__pay_attention),
_ => None, _ => None,
} }
} }

View File

@ -1,7 +1,9 @@
pub mod confirm_reset; pub mod confirm_reset;
pub mod prompt_backup;
pub mod request_passphrase; pub mod request_passphrase;
pub mod show_share_words; pub mod show_share_words;
pub use confirm_reset::new_confirm_reset; pub use confirm_reset::new_confirm_reset;
pub use prompt_backup::PromptBackup;
pub use request_passphrase::RequestPassphrase; pub use request_passphrase::RequestPassphrase;
pub use show_share_words::new_show_share_words_flow; pub use show_share_words::new_show_share_words_flow;

View File

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

View File

@ -351,7 +351,8 @@ impl FirmwareUI for UIEckhart {
} }
fn prompt_backup() -> Result<impl LayoutMaybeTrace, Error> { fn prompt_backup() -> Result<impl LayoutMaybeTrace, Error> {
Err::<RootComponent<Empty, ModelUI>, Error>(Error::ValueError(c"not implemented")) let flow = flow::prompt_backup::new_prompt_backup()?;
Ok(flow)
} }
fn request_bip39( fn request_bip39(
@ -575,8 +576,6 @@ impl FirmwareUI for UIEckhart {
Ok(layout) 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( fn show_progress(
description: TString<'static>, description: TString<'static>,
_indeterminate: bool, _indeterminate: bool,

View File

@ -35,6 +35,7 @@ class TR:
backup__it_should_be_backed_up_now: str = "It should be backed up now!" 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_created: str = "Wallet created.\n"
backup__new_wallet_successfully_created: str = "Wallet created successfully." 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__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_completed: str = "Wallet backup completed"
backup__title_backup_wallet: str = "Back up wallet" backup__title_backup_wallet: str = "Back up wallet"
@ -963,6 +964,7 @@ class TR:
words__not_recommended: str = "Not recommended!" words__not_recommended: str = "Not recommended!"
words__operation_cancelled: str = "Operation cancelled" words__operation_cancelled: str = "Operation cancelled"
words__outputs: str = "outputs" words__outputs: str = "outputs"
words__pay_attention: str = "Pay attention"
words__please_check_again: str = "Please check again" words__please_check_again: str = "Please check again"
words__please_try_again: str = "Please try again" words__please_try_again: str = "Please try again"
words__really_wanna: str = "Do you really want to" words__really_wanna: str = "Do you really want to"

View File

@ -30,10 +30,21 @@
"auto_lock__title": "Auto-lock delay", "auto_lock__title": "Auto-lock delay",
"auto_lock__turned_on": "Auto-lock turned on", "auto_lock__turned_on": "Auto-lock turned on",
"backup__can_back_up_anytime": "You can back up your Trezor once, at any time.", "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_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__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__it_should_be_backed_up_now": "It should be backed up now!",
"backup__new_wallet_created": "Wallet created.\n", "backup__new_wallet_created": "Wallet created.\n",
"backup__new_wallet_successfully_created": "Wallet created successfully.", "backup__new_wallet_successfully_created": "Wallet created successfully.",
@ -978,6 +989,7 @@
"words__good_to_know": "Good to know", "words__good_to_know": "Good to know",
"words__important": "Important", "words__important": "Important",
"words__instructions": "Instructions", "words__instructions": "Instructions",
"words__pay_attention": "Pay attention",
"words__keep_it_safe": "Keep it safe!", "words__keep_it_safe": "Keep it safe!",
"words__know_what_your_doing": "Continue only if you know what you are doing!", "words__know_what_your_doing": "Continue only if you know what you are doing!",
"words__my_trezor": "My Trezor", "words__my_trezor": "My Trezor",

View File

@ -992,5 +992,7 @@
"990": "sign_message__confirm_without_review", "990": "sign_message__confirm_without_review",
"991": "instructions__tap_to_continue", "991": "instructions__tap_to_continue",
"992": "nostr__event_kind_template", "992": "nostr__event_kind_template",
"993": "reset__share_words_first" "993": "reset__share_words_first",
"994": "backup__not_recommend",
"995": "words__pay_attention"
} }