mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-01-18 03:10:58 +00:00
feat(core/ui): T3T1 backup checklist
Also add subtitle to ShareWords. [no changelog]
This commit is contained in:
parent
43eeccac59
commit
27d733f89d
@ -498,6 +498,7 @@ static void _librust_qstrs(void) {
|
||||
MP_QSTR_reset__share_completed_template;
|
||||
MP_QSTR_reset__share_words_title;
|
||||
MP_QSTR_reset__slip39_checklist_num_groups;
|
||||
MP_QSTR_reset__slip39_checklist_num_groups_x_template;
|
||||
MP_QSTR_reset__slip39_checklist_num_shares;
|
||||
MP_QSTR_reset__slip39_checklist_num_shares_x_template;
|
||||
MP_QSTR_reset__slip39_checklist_set_num_groups;
|
||||
|
@ -1307,11 +1307,11 @@ pub enum TranslatedString {
|
||||
reset__incorrect_word_selected = 907, // "Incorrect word selected"
|
||||
reset__more_at = 908, // "More at"
|
||||
reset__num_of_shares_how_many = 909, // "How many wallet backup shares do you want to create?"
|
||||
reset__num_of_shares_long_info = 910, // "Each recovery share is a sequence of 20 words. Store each wordlist in a separate, safe location or share with trusted individuals. Collect as needed to recover your wallet."
|
||||
reset__num_of_shares_long_info = 910, // "Each backup share is a sequence of 20 words. Store each wordlist in a separate, safe location or share with trusted individuals. Collect as needed to recover your wallet."
|
||||
reset__select_threshold = 911, // "Select the minimum shares required to recover your wallet."
|
||||
reset__share_completed_template = 912, // "Share #{0} completed"
|
||||
reset__slip39_checklist_num_shares_x_template = 913, // "Number of shares"
|
||||
reset__slip39_checklist_threshold_x_template = 914, // "Recovery threshold:"
|
||||
reset__slip39_checklist_num_shares_x_template = 913, // "Number of shares: {0}"
|
||||
reset__slip39_checklist_threshold_x_template = 914, // "Recovery threshold: {0}"
|
||||
send__transaction_signed = 915, // "Transaction signed"
|
||||
tutorial__continue = 916, // "Continue tutorial"
|
||||
tutorial__exit = 917, // "Exit tutorial"
|
||||
@ -1328,6 +1328,7 @@ pub enum TranslatedString {
|
||||
words__operation_cancelled = 928, // "Operation cancelled"
|
||||
words__settings = 929, // "Settings"
|
||||
words__try_again = 930, // "Try again."
|
||||
reset__slip39_checklist_num_groups_x_template = 931, // "Number of groups: {0}"
|
||||
}
|
||||
|
||||
impl TranslatedString {
|
||||
@ -2630,11 +2631,11 @@ impl TranslatedString {
|
||||
Self::reset__incorrect_word_selected => "Incorrect word selected",
|
||||
Self::reset__more_at => "More at",
|
||||
Self::reset__num_of_shares_how_many => "How many wallet backup shares do you want to create?",
|
||||
Self::reset__num_of_shares_long_info => "Each recovery share is a sequence of 20 words. Store each wordlist in a separate, safe location or share with trusted individuals. Collect as needed to recover your wallet.",
|
||||
Self::reset__num_of_shares_long_info => "Each backup share is a sequence of 20 words. Store each wordlist in a separate, safe location or share with trusted individuals. Collect as needed to recover your wallet.",
|
||||
Self::reset__select_threshold => "Select the minimum shares required to recover your wallet.",
|
||||
Self::reset__share_completed_template => "Share #{0} completed",
|
||||
Self::reset__slip39_checklist_num_shares_x_template => "Number of shares",
|
||||
Self::reset__slip39_checklist_threshold_x_template => "Recovery threshold:",
|
||||
Self::reset__slip39_checklist_num_shares_x_template => "Number of shares: {0}",
|
||||
Self::reset__slip39_checklist_threshold_x_template => "Recovery threshold: {0}",
|
||||
Self::send__transaction_signed => "Transaction signed",
|
||||
Self::tutorial__continue => "Continue tutorial",
|
||||
Self::tutorial__exit => "Exit tutorial",
|
||||
@ -2651,6 +2652,7 @@ impl TranslatedString {
|
||||
Self::words__operation_cancelled => "Operation cancelled",
|
||||
Self::words__settings => "Settings",
|
||||
Self::words__try_again => "Try again.",
|
||||
Self::reset__slip39_checklist_num_groups_x_template => "Number of groups: {0}",
|
||||
}
|
||||
}
|
||||
|
||||
@ -3975,6 +3977,7 @@ impl TranslatedString {
|
||||
Qstr::MP_QSTR_words__operation_cancelled => Some(Self::words__operation_cancelled),
|
||||
Qstr::MP_QSTR_words__settings => Some(Self::words__settings),
|
||||
Qstr::MP_QSTR_words__try_again => Some(Self::words__try_again),
|
||||
Qstr::MP_QSTR_reset__slip39_checklist_num_groups_x_template => Some(Self::reset__slip39_checklist_num_groups_x_template),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use crate::{
|
||||
strutil::TString,
|
||||
ui::{
|
||||
component::{Component, Event, EventCtx, Never, Paginate},
|
||||
display::toif::Icon,
|
||||
display::{toif::Icon, Color, Font},
|
||||
geometry::{
|
||||
Alignment, Alignment2D, Dimensions, Insets, LinearPlacement, Offset, Point, Rect,
|
||||
},
|
||||
@ -14,6 +14,7 @@ use crate::{
|
||||
};
|
||||
|
||||
use super::layout::{LayoutFit, TextLayout, TextStyle};
|
||||
use heapless::String;
|
||||
|
||||
/// Used as an upper bound of number of different styles we may render on single
|
||||
/// page.
|
||||
@ -557,6 +558,8 @@ pub struct Checklist<T> {
|
||||
current: usize,
|
||||
icon_current: Icon,
|
||||
icon_done: Icon,
|
||||
icon_done_color: Option<Color>,
|
||||
show_numerals: bool,
|
||||
/// How wide will the left icon column be
|
||||
check_width: i16,
|
||||
/// Offset of the icon representing DONE
|
||||
@ -565,7 +568,10 @@ pub struct Checklist<T> {
|
||||
current_offset: Offset,
|
||||
}
|
||||
|
||||
impl<T> Checklist<T> {
|
||||
impl<'a, T> Checklist<T>
|
||||
where
|
||||
T: ParagraphSource<'a>,
|
||||
{
|
||||
pub fn from_paragraphs(
|
||||
icon_current: Icon,
|
||||
icon_done: Icon,
|
||||
@ -578,6 +584,8 @@ impl<T> Checklist<T> {
|
||||
current,
|
||||
icon_current,
|
||||
icon_done,
|
||||
icon_done_color: None,
|
||||
show_numerals: false,
|
||||
check_width: 0,
|
||||
done_offset: Offset::zero(),
|
||||
current_offset: Offset::zero(),
|
||||
@ -599,6 +607,38 @@ impl<T> Checklist<T> {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_icon_done_color(mut self, col: Color) -> Self {
|
||||
self.icon_done_color = Some(col);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_numerals(mut self, show_numerals: bool) -> Self {
|
||||
self.show_numerals = show_numerals;
|
||||
self
|
||||
}
|
||||
|
||||
fn render_left_column<'s>(&self, target: &mut impl Renderer<'s>) {
|
||||
let current_visible = self.current.saturating_sub(self.paragraphs.offset.par);
|
||||
for (i, layout) in self.paragraphs.visible.iter().enumerate() {
|
||||
let l = &layout.layout(&self.paragraphs.source);
|
||||
let base = Point::new(self.area.x0, l.bounds.y0);
|
||||
if i < current_visible {
|
||||
// finished tasks - labeled with icon "done"
|
||||
let color = self.icon_done_color.unwrap_or(l.style.text_color);
|
||||
self.render_icon(base + self.done_offset, self.icon_done, color, target)
|
||||
} else {
|
||||
// current and future tasks - ordinal numbers or icon on current task
|
||||
if self.show_numerals {
|
||||
let num_offset = Offset::y(Font::NORMAL.visible_text_height("1"));
|
||||
self.render_numeral(base + num_offset, i, l.style.text_color, target);
|
||||
} else if i == current_visible {
|
||||
let color = l.style.text_color;
|
||||
self.render_icon(base + self.current_offset, self.icon_current, color, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn paint_icon(&self, layout: &TextLayout, icon: Icon, offset: Offset) {
|
||||
let top_left = Point::new(self.area.x0, layout.bounds.y0);
|
||||
icon.draw(
|
||||
@ -609,16 +649,29 @@ impl<T> Checklist<T> {
|
||||
);
|
||||
}
|
||||
|
||||
fn render_icon<'s>(
|
||||
fn render_numeral<'s>(
|
||||
&self,
|
||||
layout: &TextLayout,
|
||||
icon: Icon,
|
||||
offset: Offset,
|
||||
base_point: Point,
|
||||
n: usize,
|
||||
color: Color,
|
||||
target: &mut impl Renderer<'s>,
|
||||
) {
|
||||
let top_left = Point::new(self.area.x0, layout.bounds.y0);
|
||||
shape::ToifImage::new(top_left + offset, icon.toif)
|
||||
.with_fg(layout.style.text_color)
|
||||
let numeral = build_string!(10, inttostr!(n as u8 + 1), ".");
|
||||
shape::Text::new(base_point, numeral.as_str())
|
||||
.with_font(Font::NORMAL)
|
||||
.with_fg(color)
|
||||
.render(target);
|
||||
}
|
||||
|
||||
fn render_icon<'s>(
|
||||
&self,
|
||||
base_point: Point,
|
||||
icon: Icon,
|
||||
color: Color,
|
||||
target: &mut impl Renderer<'s>,
|
||||
) {
|
||||
shape::ToifImage::new(base_point, icon.toif)
|
||||
.with_fg(color)
|
||||
.render(target);
|
||||
}
|
||||
}
|
||||
@ -662,24 +715,7 @@ where
|
||||
|
||||
fn render<'s>(&self, target: &mut impl Renderer<'s>) {
|
||||
self.paragraphs.render(target);
|
||||
|
||||
let current_visible = self.current.saturating_sub(self.paragraphs.offset.par);
|
||||
for layout in self.paragraphs.visible.iter().take(current_visible) {
|
||||
self.render_icon(
|
||||
&layout.layout(&self.paragraphs.source),
|
||||
self.icon_done,
|
||||
self.done_offset,
|
||||
target,
|
||||
);
|
||||
}
|
||||
if let Some(layout) = self.paragraphs.visible.iter().nth(current_visible) {
|
||||
self.render_icon(
|
||||
&layout.layout(&self.paragraphs.source),
|
||||
self.icon_current,
|
||||
self.current_offset,
|
||||
target,
|
||||
);
|
||||
}
|
||||
self.render_left_column(target);
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_bounds")]
|
||||
|
@ -74,6 +74,7 @@ pub extern "C" fn new_show_share_words(n_args: usize, args: *const Obj, kwargs:
|
||||
impl ShowShareWords {
|
||||
fn new_obj(_args: &[Obj], kwargs: &Map) -> Result<Obj, error::Error> {
|
||||
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||
let subtitle: TString = kwargs.get(Qstr::MP_QSTR_subtitle)?.try_into()?;
|
||||
let share_words_obj: Obj = kwargs.get(Qstr::MP_QSTR_words)?;
|
||||
let share_words_vec: Vec<TString, 33> = util::iter_into_vec(share_words_obj)?;
|
||||
let text_info: TString = kwargs.get(Qstr::MP_QSTR_text_info)?.try_into()?;
|
||||
@ -90,8 +91,9 @@ impl ShowShareWords {
|
||||
.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(|_| None);
|
||||
let content_words = Frame::left_aligned(title, ShareWords::new(share_words_vec))
|
||||
.with_subtitle(subtitle)
|
||||
.map(|_| None);
|
||||
|
||||
let content_confirm =
|
||||
Frame::left_aligned(text_confirm, PromptScreen::new_hold_to_confirm())
|
||||
|
@ -1165,7 +1165,7 @@ extern "C" fn new_select_word(n_args: usize, args: *const Obj, kwargs: *mut Map)
|
||||
extern "C" fn new_show_checklist(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 button: TString = kwargs.get(Qstr::MP_QSTR_button)?.try_into()?;
|
||||
let _button: TString = kwargs.get(Qstr::MP_QSTR_button)?.try_into()?;
|
||||
let active: usize = kwargs.get(Qstr::MP_QSTR_active)?.try_into()?;
|
||||
let items: Obj = kwargs.get(Qstr::MP_QSTR_items)?;
|
||||
|
||||
@ -1180,25 +1180,22 @@ extern "C" fn new_show_checklist(n_args: usize, args: *const Obj, kwargs: *mut M
|
||||
paragraphs.add(Paragraph::new(style, text));
|
||||
}
|
||||
|
||||
let obj = LayoutObj::new(Frame::left_aligned(
|
||||
title,
|
||||
Dialog::new(
|
||||
Checklist::from_paragraphs(
|
||||
theme::ICON_LIST_CURRENT,
|
||||
theme::ICON_LIST_CHECK,
|
||||
active,
|
||||
paragraphs
|
||||
.into_paragraphs()
|
||||
.with_spacing(theme::CHECKLIST_SPACING),
|
||||
)
|
||||
.with_check_width(theme::CHECKLIST_CHECK_WIDTH)
|
||||
.with_current_offset(theme::CHECKLIST_CURRENT_OFFSET)
|
||||
.with_done_offset(theme::CHECKLIST_DONE_OFFSET),
|
||||
theme::button_bar(Button::with_text(button).map(|msg| {
|
||||
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelConfirmMsg::Confirmed)
|
||||
})),
|
||||
),
|
||||
))?;
|
||||
let checklist_content = SwipeUpScreen::new(
|
||||
Checklist::from_paragraphs(
|
||||
theme::ICON_CHEVRON_RIGHT,
|
||||
theme::ICON_BULLET_CHECKMARK,
|
||||
active,
|
||||
paragraphs
|
||||
.into_paragraphs()
|
||||
.with_spacing(theme::CHECKLIST_SPACING),
|
||||
)
|
||||
.with_check_width(theme::CHECKLIST_CHECK_WIDTH)
|
||||
.with_icon_done_color(theme::GREEN),
|
||||
);
|
||||
let obj = LayoutObj::new(
|
||||
Frame::left_aligned(title, checklist_content)
|
||||
.with_footer(TR::instructions__swipe_up.into(), None),
|
||||
)?;
|
||||
Ok(obj.into())
|
||||
};
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
@ -1812,6 +1809,7 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
||||
/// def flow_show_share_words(
|
||||
/// *,
|
||||
/// title: str,
|
||||
/// subtitle: str,
|
||||
/// words: Iterable[str],
|
||||
/// text_info: str,
|
||||
/// text_confirm: str,
|
||||
|
@ -161,10 +161,6 @@ include_icon!(ICON_CLICK, "model_tt/res/finger24.toif");
|
||||
include_icon!(ICON_CORNER_CANCEL, "model_tt/res/x32.toif");
|
||||
include_icon!(ICON_CORNER_INFO, "model_tt/res/info32.toif");
|
||||
|
||||
// Checklist symbols.
|
||||
include_icon!(ICON_LIST_CURRENT, "model_tt/res/arrow-right16.toif");
|
||||
include_icon!(ICON_LIST_CHECK, "model_tt/res/check16.toif");
|
||||
|
||||
// Homescreen notifications.
|
||||
include_icon!(ICON_WARN, "model_tt/res/warning16.toif");
|
||||
include_icon!(ICON_WARNING40, "model_tt/res/warning40.toif");
|
||||
@ -689,23 +685,23 @@ pub const fn button_counter() -> ButtonStyleSheet {
|
||||
ButtonStyleSheet {
|
||||
normal: &ButtonStyle {
|
||||
font: Font::DEMIBOLD,
|
||||
text_color: FG,
|
||||
button_color: GREY_DARK,
|
||||
icon_color: GREY_LIGHT,
|
||||
text_color: GREY,
|
||||
button_color: GREY_EXTRA_DARK,
|
||||
icon_color: GREY,
|
||||
background_color: BG,
|
||||
},
|
||||
active: &ButtonStyle {
|
||||
font: Font::DEMIBOLD,
|
||||
text_color: FG,
|
||||
button_color: GREY_MEDIUM,
|
||||
icon_color: GREY_LIGHT,
|
||||
text_color: BG,
|
||||
button_color: GREY_LIGHT,
|
||||
icon_color: BG,
|
||||
background_color: BG,
|
||||
},
|
||||
disabled: &ButtonStyle {
|
||||
font: Font::DEMIBOLD,
|
||||
text_color: GREY_LIGHT,
|
||||
button_color: GREY_DARK,
|
||||
icon_color: GREY_LIGHT,
|
||||
text_color: GREY_DARK,
|
||||
button_color: BG,
|
||||
icon_color: GREY_DARK,
|
||||
background_color: BG,
|
||||
},
|
||||
}
|
||||
@ -797,12 +793,10 @@ pub fn textstyle_number(num: i32) -> &'static TextStyle {
|
||||
|
||||
pub const TEXT_NORMAL_OFF_WHITE: TextStyle =
|
||||
TextStyle::new(Font::NORMAL, OFF_WHITE, BG, GREY_LIGHT, GREY_LIGHT);
|
||||
pub const TEXT_CHECKLIST_DEFAULT: TextStyle =
|
||||
TextStyle::new(Font::NORMAL, GREY_LIGHT, BG, GREY_LIGHT, GREY_LIGHT);
|
||||
pub const TEXT_CHECKLIST_DEFAULT: TextStyle = TextStyle::new(Font::SUB, GREY, BG, GREY, GREY);
|
||||
pub const TEXT_CHECKLIST_SELECTED: TextStyle =
|
||||
TextStyle::new(Font::NORMAL, FG, BG, GREY_LIGHT, GREY_LIGHT);
|
||||
pub const TEXT_CHECKLIST_DONE: TextStyle =
|
||||
TextStyle::new(Font::NORMAL, GREEN_DARK, BG, GREY_LIGHT, GREY_LIGHT);
|
||||
TextStyle::new(Font::NORMAL, GREY_LIGHT, BG, GREY_LIGHT, GREY_LIGHT);
|
||||
pub const TEXT_CHECKLIST_DONE: TextStyle = TextStyle::new(Font::SUB, GREY, BG, GREY, GREY);
|
||||
|
||||
/// Spacing between components (e.g. header and main content) and offsets from
|
||||
/// the side of the screen. Generally applied everywhere except the top side of
|
||||
@ -814,10 +808,11 @@ pub const BUTTON_HEIGHT: i16 = 62;
|
||||
pub const BUTTON_WIDTH: i16 = 78;
|
||||
pub const BUTTON_SPACING: i16 = SPACING;
|
||||
pub const KEYBOARD_SPACING: i16 = BUTTON_SPACING;
|
||||
pub const CHECKLIST_SPACING: i16 = 10;
|
||||
pub const CHECKLIST_SPACING: i16 = 12;
|
||||
pub const RECOVERY_SPACING: i16 = 18;
|
||||
pub const CORNER_BUTTON_SIDE: i16 = 44;
|
||||
pub const CORNER_BUTTON_SPACING: i16 = BUTTON_SPACING;
|
||||
pub const COUNTER_BUTTON_HEIGHT: i16 = 60;
|
||||
pub const INFO_BUTTON_HEIGHT: i16 = 44;
|
||||
pub const PIN_BUTTON_HEIGHT: i16 = 52;
|
||||
pub const MNEMONIC_BUTTON_HEIGHT: i16 = 62;
|
||||
@ -828,9 +823,7 @@ pub const RESULT_FOOTER_HEIGHT: i16 = 62;
|
||||
pub const DETAILS_SPACING: i16 = 8;
|
||||
|
||||
// checklist settings
|
||||
pub const CHECKLIST_CHECK_WIDTH: i16 = 16;
|
||||
pub const CHECKLIST_DONE_OFFSET: Offset = Offset::new(-2, 6);
|
||||
pub const CHECKLIST_CURRENT_OFFSET: Offset = Offset::new(2, 3);
|
||||
pub const CHECKLIST_CHECK_WIDTH: i16 = 32; // icon width (20px) + padding (12px)
|
||||
|
||||
pub const fn button_bar<T>(inner: T) -> FixedHeightBar<T> {
|
||||
FixedHeightBar::bottom(inner, BUTTON_HEIGHT)
|
||||
|
@ -396,6 +396,7 @@ def flow_prompt_backup() -> LayoutObj[UiResult]
|
||||
def flow_show_share_words(
|
||||
*,
|
||||
title: str,
|
||||
subtitle: str,
|
||||
words: Iterable[str],
|
||||
text_info: str,
|
||||
text_confirm: str,
|
||||
@ -404,18 +405,6 @@ def flow_show_share_words(
|
||||
confirmation."""
|
||||
|
||||
|
||||
# rust/src/ui/model_mercury/layout.rs
|
||||
def request_number(
|
||||
*,
|
||||
title: str,
|
||||
count: int,
|
||||
min_count: int,
|
||||
max_count: int,
|
||||
description: Callable[[int], str] | None = None,
|
||||
) -> LayoutObj[tuple[UiResult, int]]:
|
||||
"""Number input with + and - buttons, description, and info button."""
|
||||
|
||||
|
||||
# rust/src/ui/model_mercury/layout.rs
|
||||
def flow_request_number(
|
||||
*,
|
||||
|
@ -627,7 +627,7 @@ class TR:
|
||||
reset__num_of_shares_advanced_info_template: str = "Each recovery share is a sequence of 20 words. Next you will choose the threshold number of shares needed to form Group {0}."
|
||||
reset__num_of_shares_basic_info: str = "Each recovery share is a sequence of 20 words. Next you will choose how many shares you need to recover your wallet."
|
||||
reset__num_of_shares_how_many: str = "How many wallet backup shares do you want to create?"
|
||||
reset__num_of_shares_long_info: str = "Each recovery share is a sequence of 20 words. Store each wordlist in a separate, safe location or share with trusted individuals. Collect as needed to recover your wallet."
|
||||
reset__num_of_shares_long_info: str = "Each backup share is a sequence of 20 words. Store each wordlist in a separate, safe location or share with trusted individuals. Collect as needed to recover your wallet."
|
||||
reset__num_shares_for_group_template: str = "The required number of shares to form Group {0}."
|
||||
reset__number_of_shares_info: str = "= total number of unique word lists used for wallet backup."
|
||||
reset__one_share: str = "1 share"
|
||||
@ -644,14 +644,15 @@ class TR:
|
||||
reset__share_completed_template: str = "Share #{0} completed"
|
||||
reset__share_words_title: str = "Standard backup"
|
||||
reset__slip39_checklist_num_groups: str = "Number of groups"
|
||||
reset__slip39_checklist_num_groups_x_template: str = "Number of groups: {0}"
|
||||
reset__slip39_checklist_num_shares: str = "Number of shares"
|
||||
reset__slip39_checklist_num_shares_x_template: str = "Number of shares"
|
||||
reset__slip39_checklist_num_shares_x_template: str = "Number of shares: {0}"
|
||||
reset__slip39_checklist_set_num_groups: str = "Set number of groups"
|
||||
reset__slip39_checklist_set_num_shares: str = "Set number of shares"
|
||||
reset__slip39_checklist_set_sizes: str = "Set sizes and thresholds"
|
||||
reset__slip39_checklist_set_sizes_longer: str = "Set size and threshold for each group"
|
||||
reset__slip39_checklist_set_threshold: str = "Set threshold"
|
||||
reset__slip39_checklist_threshold_x_template: str = "Recovery threshold:"
|
||||
reset__slip39_checklist_threshold_x_template: str = "Recovery threshold: {0}"
|
||||
reset__slip39_checklist_title: str = "Backup checklist"
|
||||
reset__slip39_checklist_write_down: str = "Write down and check all shares"
|
||||
reset__slip39_checklist_write_down_recovery: str = "Write down & check all wallet backup shares"
|
||||
|
@ -138,7 +138,7 @@ async def _backup_slip39_basic(
|
||||
share_count = await layout.slip39_prompt_number_of_shares()
|
||||
|
||||
# get threshold
|
||||
await layout.slip39_show_checklist(1, advanced=False)
|
||||
await layout.slip39_show_checklist(1, advanced=False, count=share_count)
|
||||
share_threshold = await layout.slip39_prompt_threshold(share_count)
|
||||
|
||||
mnemonics = _get_slip39_mnemonics(
|
||||
@ -149,7 +149,9 @@ async def _backup_slip39_basic(
|
||||
)
|
||||
|
||||
# show and confirm individual shares
|
||||
await layout.slip39_show_checklist(2, advanced=False)
|
||||
await layout.slip39_show_checklist(
|
||||
2, advanced=False, count=share_count, threshold=share_threshold
|
||||
)
|
||||
await layout.slip39_basic_show_and_confirm_shares(mnemonics[0])
|
||||
|
||||
|
||||
|
@ -23,12 +23,13 @@ async def show_share_words(
|
||||
group_index: int | None = None,
|
||||
) -> None:
|
||||
|
||||
title = TR.reset__recovery_wallet_backup_title
|
||||
if share_index is None:
|
||||
title = TR.reset__recovery_wallet_backup_title
|
||||
subtitle = ""
|
||||
elif group_index is None:
|
||||
title = TR.reset__recovery_share_title_template.format(share_index + 1)
|
||||
subtitle = TR.reset__recovery_share_title_template.format(share_index + 1)
|
||||
else:
|
||||
title = TR.reset__group_share_title_template.format(
|
||||
subtitle = TR.reset__group_share_title_template.format(
|
||||
group_index + 1, share_index + 1
|
||||
)
|
||||
words_count = len(share_words)
|
||||
@ -39,6 +40,7 @@ async def show_share_words(
|
||||
RustLayout(
|
||||
trezorui2.flow_show_share_words(
|
||||
title=title,
|
||||
subtitle=subtitle,
|
||||
words=share_words,
|
||||
text_info=text_info,
|
||||
text_confirm=text_confirm,
|
||||
@ -90,29 +92,17 @@ async def select_word(
|
||||
return words[result]
|
||||
|
||||
|
||||
async def slip39_show_checklist(step: int, backup_type: BackupType) -> None:
|
||||
from trezor.enums import BackupType
|
||||
|
||||
assert backup_type in (BackupType.Slip39_Basic, BackupType.Slip39_Advanced)
|
||||
|
||||
items = (
|
||||
(
|
||||
TR.reset__slip39_checklist_set_num_shares,
|
||||
TR.reset__slip39_checklist_set_threshold,
|
||||
TR.reset__slip39_checklist_write_down_recovery,
|
||||
)
|
||||
if backup_type == BackupType.Slip39_Basic
|
||||
else (
|
||||
TR.reset__slip39_checklist_set_num_groups,
|
||||
TR.reset__slip39_checklist_set_num_shares,
|
||||
TR.reset__slip39_checklist_set_sizes_longer,
|
||||
)
|
||||
)
|
||||
|
||||
async def slip39_show_checklist(
|
||||
step: int,
|
||||
backup_type: BackupType,
|
||||
count: int | None = None,
|
||||
threshold: int | None = None,
|
||||
) -> None:
|
||||
items = _slip_39_checklist_items(step, backup_type, count, threshold)
|
||||
result = await interact(
|
||||
RustLayout(
|
||||
trezorui2.show_checklist(
|
||||
title=TR.reset__slip39_checklist_title,
|
||||
title=TR.reset__title_shamir_backup,
|
||||
button=TR.buttons__continue,
|
||||
active=step,
|
||||
items=items,
|
||||
@ -125,6 +115,44 @@ async def slip39_show_checklist(step: int, backup_type: BackupType) -> None:
|
||||
raise ActionCancelled
|
||||
|
||||
|
||||
def _slip_39_checklist_items(
|
||||
step: int,
|
||||
backup_type: BackupType,
|
||||
count: int | None = None,
|
||||
threshold: int | None = None,
|
||||
):
|
||||
from trezor.enums import BackupType
|
||||
|
||||
assert backup_type in (BackupType.Slip39_Basic, BackupType.Slip39_Advanced)
|
||||
|
||||
if backup_type == BackupType.Slip39_Basic:
|
||||
entry_1 = (
|
||||
TR.reset__slip39_checklist_num_shares_x_template.format(count)
|
||||
if count
|
||||
else TR.reset__slip39_checklist_set_num_shares
|
||||
)
|
||||
entry_2 = (
|
||||
TR.reset__slip39_checklist_threshold_x_template.format(threshold)
|
||||
if threshold
|
||||
else TR.reset__slip39_checklist_set_threshold
|
||||
)
|
||||
entry_3 = TR.reset__slip39_checklist_write_down_recovery
|
||||
return (entry_1, entry_2, entry_3)
|
||||
else:
|
||||
entry_1 = (
|
||||
TR.reset__slip39_checklist_num_groups_x_template.format(count)
|
||||
if count
|
||||
else TR.reset__slip39_checklist_set_num_groups
|
||||
)
|
||||
entry_2 = (
|
||||
TR.reset__slip39_checklist_threshold_x_template.format(threshold)
|
||||
if threshold
|
||||
else TR.reset__slip39_checklist_set_threshold
|
||||
)
|
||||
entry_3 = TR.reset__slip39_checklist_set_sizes_longer
|
||||
return (entry_1, entry_2, entry_3)
|
||||
|
||||
|
||||
async def _prompt_number(
|
||||
title: str,
|
||||
description: Callable[[int], str],
|
||||
@ -149,7 +177,6 @@ async def _prompt_number(
|
||||
)
|
||||
|
||||
if __debug__:
|
||||
# TODO: is this still relevant?
|
||||
if not isinstance(result, tuple):
|
||||
# DebugLink currently can't send number of shares and it doesn't
|
||||
# change the counter either so just use the initial value.
|
||||
@ -173,12 +200,7 @@ async def slip39_prompt_threshold(
|
||||
|
||||
def description(count: int) -> str:
|
||||
if group_id is None:
|
||||
if count == 1:
|
||||
return TR.reset__you_need_one_share
|
||||
elif count == max_count:
|
||||
return TR.reset__need_all_share_template.format(count)
|
||||
else:
|
||||
return TR.reset__need_any_share_template.format(count)
|
||||
return TR.reset__select_threshold
|
||||
else:
|
||||
return TR.reset__num_shares_for_group_template.format(group_id + 1)
|
||||
|
||||
@ -186,6 +208,8 @@ async def slip39_prompt_threshold(
|
||||
# TODO: this is madness...
|
||||
text = TR.reset__the_threshold_sets_the_number_of_shares
|
||||
if group_id is None:
|
||||
# FIXME: need to propagate the argument in rust, temporary hack to show plausible value
|
||||
count = num_of_shares - 1
|
||||
text += TR.reset__needed_to_recover_your_wallet
|
||||
text += TR.reset__set_it_to_count_template.format(count)
|
||||
if num_of_shares == 1:
|
||||
@ -225,17 +249,14 @@ async def slip39_prompt_number_of_shares(group_id: int | None = None) -> int:
|
||||
|
||||
def description(i: int):
|
||||
if group_id is None:
|
||||
if i == 1:
|
||||
return TR.reset__only_one_share_will_be_created
|
||||
else:
|
||||
return TR.reset__num_of_shares_how_many
|
||||
return TR.reset__num_of_shares_how_many
|
||||
else:
|
||||
return TR.reset__total_number_of_shares_in_group_template.format(
|
||||
group_id + 1
|
||||
)
|
||||
|
||||
if group_id is None:
|
||||
info = TR.reset__num_of_shares_basic_info
|
||||
info = TR.reset__num_of_shares_long_info
|
||||
else:
|
||||
info = TR.reset__num_of_shares_advanced_info_template.format(group_id + 1)
|
||||
|
||||
|
@ -99,7 +99,12 @@ async def select_word(
|
||||
return words[result]
|
||||
|
||||
|
||||
async def slip39_show_checklist(step: int, advanced: bool) -> None:
|
||||
async def slip39_show_checklist(
|
||||
step: int,
|
||||
advanced: bool,
|
||||
count: int | None = None,
|
||||
threshold: int | None = None,
|
||||
) -> None:
|
||||
items = (
|
||||
(
|
||||
TR.reset__slip39_checklist_num_shares,
|
||||
|
@ -103,7 +103,12 @@ async def select_word(
|
||||
return words[result]
|
||||
|
||||
|
||||
async def slip39_show_checklist(step: int, advanced: bool) -> None:
|
||||
async def slip39_show_checklist(
|
||||
step: int,
|
||||
advanced: bool,
|
||||
count: int | None = None,
|
||||
threshold: int | None = None,
|
||||
) -> None:
|
||||
items = (
|
||||
(
|
||||
TR.reset__slip39_checklist_set_num_shares,
|
||||
|
@ -629,7 +629,7 @@
|
||||
"reset__num_of_shares_how_many": "How many wallet backup shares do you want to create?",
|
||||
"reset__num_of_shares_advanced_info_template": "Each recovery share is a sequence of 20 words. Next you will choose the threshold number of shares needed to form Group {0}.",
|
||||
"reset__num_of_shares_basic_info": "Each recovery share is a sequence of 20 words. Next you will choose how many shares you need to recover your wallet.",
|
||||
"reset__num_of_shares_long_info": "Each recovery share is a sequence of 20 words. Store each wordlist in a separate, safe location or share with trusted individuals. Collect as needed to recover your wallet.",
|
||||
"reset__num_of_shares_long_info": "Each backup share is a sequence of 20 words. Store each wordlist in a separate, safe location or share with trusted individuals. Collect as needed to recover your wallet.",
|
||||
"reset__num_shares_for_group_template": "The required number of shares to form Group {0}.",
|
||||
"reset__number_of_shares_info": "= total number of unique word lists used for wallet backup.",
|
||||
"reset__one_share": "1 share",
|
||||
@ -647,13 +647,14 @@
|
||||
"reset__share_words_title": "Standard backup",
|
||||
"reset__slip39_checklist_num_groups": "Number of groups",
|
||||
"reset__slip39_checklist_num_shares": "Number of shares",
|
||||
"reset__slip39_checklist_num_shares_x_template": "Number of shares",
|
||||
"reset__slip39_checklist_num_shares_x_template": "Number of shares: {0}",
|
||||
"reset__slip39_checklist_num_groups_x_template": "Number of groups: {0}",
|
||||
"reset__slip39_checklist_set_num_groups": "Set number of groups",
|
||||
"reset__slip39_checklist_set_num_shares": "Set number of shares",
|
||||
"reset__slip39_checklist_set_sizes": "Set sizes and thresholds",
|
||||
"reset__slip39_checklist_set_sizes_longer": "Set size and threshold for each group",
|
||||
"reset__slip39_checklist_set_threshold": "Set threshold",
|
||||
"reset__slip39_checklist_threshold_x_template": "Recovery threshold:",
|
||||
"reset__slip39_checklist_threshold_x_template": "Recovery threshold: {0}",
|
||||
"reset__slip39_checklist_title": "Backup checklist",
|
||||
"reset__slip39_checklist_write_down": "Write down and check all shares",
|
||||
"reset__slip39_checklist_write_down_recovery": "Write down & check all wallet backup shares",
|
||||
|
@ -929,5 +929,6 @@
|
||||
"927": "words__good_to_know",
|
||||
"928": "words__operation_cancelled",
|
||||
"929": "words__settings",
|
||||
"930": "words__try_again"
|
||||
"930": "words__try_again",
|
||||
"931": "reset__slip39_checklist_num_groups_x_template"
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
{
|
||||
"current": {
|
||||
"merkle_root": "070867d6d288bb46d1eb69dd95bc6d7b6fc09a3f299c75e997d756e7915860d6",
|
||||
"datetime": "2024-05-22T11:43:31.930638",
|
||||
"commit": "6bd6027a57b814483947f98aeb118a15f846e3bb"
|
||||
"merkle_root": "e79fdd3c9052dfd140aef2b4800b6b0b8000ae99822cf3e8be083da0dc2b376c",
|
||||
"datetime": "2024-05-26T15:18:17.124044",
|
||||
"commit": "3e9598245d57044418f4eeb5ce5bc792f20587c3"
|
||||
},
|
||||
"history": [
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user