1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-02-28 15:22:14 +00:00

feat(eckhart): prompt backup flow

This commit is contained in:
Lukas Bielesch 2025-02-26 12:17:30 +01:00
parent de25d208cd
commit d04174199c
9 changed files with 173 additions and 11 deletions

View File

@ -89,6 +89,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;
@ -773,6 +774,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;

View File

@ -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."
@ -1249,7 +1249,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!"
@ -1403,6 +1403,8 @@ pub enum TranslatedString {
sign_message__confirm_without_review = 990, // "Confirm without review"
instructions__tap_to_continue = 991, // "Tap to continue"
reset__share_words_first = 992, // "Write down the first word from the backup."
backup__not_recommend = 993, // "We don't recommend to skip wallet backup creation."
words__pay_attention = 994, // "Pay attention"
}
impl TranslatedString {
@ -1428,7 +1430,14 @@ impl TranslatedString {
Self::auto_lock__change_template => "Auto-lock Trezor after {0} of inactivity?",
Self::auto_lock__title => "Auto-lock delay",
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.",
#[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__new_wallet_created => "Wallet created.\n",
Self::backup__new_wallet_successfully_created => "Wallet created successfully.",
@ -2669,7 +2678,14 @@ impl TranslatedString {
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.",
#[cfg(feature = "layout_bolt")]
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::words__instructions => "Instructions",
Self::words__not_recommended => "Not recommended!",
@ -2837,6 +2853,8 @@ impl TranslatedString {
Self::sign_message__confirm_without_review => "Confirm without review",
Self::instructions__tap_to_continue => "Tap to continue",
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",
}
}
@ -4235,6 +4253,8 @@ impl TranslatedString {
Qstr::MP_QSTR_sign_message__confirm_without_review => Some(Self::sign_message__confirm_without_review),
Qstr::MP_QSTR_instructions__tap_to_continue => Some(Self::instructions__tap_to_continue),
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,
}
}

View File

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

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.swipe_right(),
(Self::SkipBackup, FlowMsg::Cancelled) => Self::Menu.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 res = SwipeFlow::new(&PromptBackup::Intro)?
.with_page(&PromptBackup::Intro, content_intro)?
.with_page(&PromptBackup::Menu, content_menu)?
.with_page(&PromptBackup::SkipBackup, content_skip_intro)?;
Ok(res)
}

View File

@ -349,7 +349,8 @@ impl FirmwareUI for UIEckhart {
}
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(
@ -565,8 +566,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,

View File

@ -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"
@ -962,6 +963,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"

View File

@ -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.",
@ -977,6 +988,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",

View File

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

View File

@ -1,8 +1,8 @@
{
"current": {
"merkle_root": "6684203c68c3a64d607c948fac5eeaa9f349f0e81cf54c8dfc662d5a8d3662e8",
"datetime": "2025-02-26T16:20:10.257648",
"commit": "1f4a43feee5e3f959d638a300b6faf2235c69a82"
"merkle_root": "4df2339f6c6499539f2be851d4a4efe197415bd041c9742e69ad619ddf5786d0",
"datetime": "2025-02-27T08:00:38.586283",
"commit": "de25d208cddda457cd7841cd2854a2a6adc69052"
},
"history": [
{