mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-01-18 11:21:11 +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_completed_template;
|
||||||
MP_QSTR_reset__share_words_title;
|
MP_QSTR_reset__share_words_title;
|
||||||
MP_QSTR_reset__slip39_checklist_num_groups;
|
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;
|
||||||
MP_QSTR_reset__slip39_checklist_num_shares_x_template;
|
MP_QSTR_reset__slip39_checklist_num_shares_x_template;
|
||||||
MP_QSTR_reset__slip39_checklist_set_num_groups;
|
MP_QSTR_reset__slip39_checklist_set_num_groups;
|
||||||
|
@ -1307,11 +1307,11 @@ pub enum TranslatedString {
|
|||||||
reset__incorrect_word_selected = 907, // "Incorrect word selected"
|
reset__incorrect_word_selected = 907, // "Incorrect word selected"
|
||||||
reset__more_at = 908, // "More at"
|
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_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__select_threshold = 911, // "Select the minimum shares required to recover your wallet."
|
||||||
reset__share_completed_template = 912, // "Share #{0} completed"
|
reset__share_completed_template = 912, // "Share #{0} completed"
|
||||||
reset__slip39_checklist_num_shares_x_template = 913, // "Number of shares"
|
reset__slip39_checklist_num_shares_x_template = 913, // "Number of shares: {0}"
|
||||||
reset__slip39_checklist_threshold_x_template = 914, // "Recovery threshold:"
|
reset__slip39_checklist_threshold_x_template = 914, // "Recovery threshold: {0}"
|
||||||
send__transaction_signed = 915, // "Transaction signed"
|
send__transaction_signed = 915, // "Transaction signed"
|
||||||
tutorial__continue = 916, // "Continue tutorial"
|
tutorial__continue = 916, // "Continue tutorial"
|
||||||
tutorial__exit = 917, // "Exit tutorial"
|
tutorial__exit = 917, // "Exit tutorial"
|
||||||
@ -1328,6 +1328,7 @@ pub enum TranslatedString {
|
|||||||
words__operation_cancelled = 928, // "Operation cancelled"
|
words__operation_cancelled = 928, // "Operation cancelled"
|
||||||
words__settings = 929, // "Settings"
|
words__settings = 929, // "Settings"
|
||||||
words__try_again = 930, // "Try again."
|
words__try_again = 930, // "Try again."
|
||||||
|
reset__slip39_checklist_num_groups_x_template = 931, // "Number of groups: {0}"
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TranslatedString {
|
impl TranslatedString {
|
||||||
@ -2630,11 +2631,11 @@ impl TranslatedString {
|
|||||||
Self::reset__incorrect_word_selected => "Incorrect word selected",
|
Self::reset__incorrect_word_selected => "Incorrect word selected",
|
||||||
Self::reset__more_at => "More at",
|
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_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__select_threshold => "Select the minimum shares required to recover your wallet.",
|
||||||
Self::reset__share_completed_template => "Share #{0} completed",
|
Self::reset__share_completed_template => "Share #{0} completed",
|
||||||
Self::reset__slip39_checklist_num_shares_x_template => "Number of shares",
|
Self::reset__slip39_checklist_num_shares_x_template => "Number of shares: {0}",
|
||||||
Self::reset__slip39_checklist_threshold_x_template => "Recovery threshold:",
|
Self::reset__slip39_checklist_threshold_x_template => "Recovery threshold: {0}",
|
||||||
Self::send__transaction_signed => "Transaction signed",
|
Self::send__transaction_signed => "Transaction signed",
|
||||||
Self::tutorial__continue => "Continue tutorial",
|
Self::tutorial__continue => "Continue tutorial",
|
||||||
Self::tutorial__exit => "Exit tutorial",
|
Self::tutorial__exit => "Exit tutorial",
|
||||||
@ -2651,6 +2652,7 @@ impl TranslatedString {
|
|||||||
Self::words__operation_cancelled => "Operation cancelled",
|
Self::words__operation_cancelled => "Operation cancelled",
|
||||||
Self::words__settings => "Settings",
|
Self::words__settings => "Settings",
|
||||||
Self::words__try_again => "Try again.",
|
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__operation_cancelled => Some(Self::words__operation_cancelled),
|
||||||
Qstr::MP_QSTR_words__settings => Some(Self::words__settings),
|
Qstr::MP_QSTR_words__settings => Some(Self::words__settings),
|
||||||
Qstr::MP_QSTR_words__try_again => Some(Self::words__try_again),
|
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,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ use crate::{
|
|||||||
strutil::TString,
|
strutil::TString,
|
||||||
ui::{
|
ui::{
|
||||||
component::{Component, Event, EventCtx, Never, Paginate},
|
component::{Component, Event, EventCtx, Never, Paginate},
|
||||||
display::toif::Icon,
|
display::{toif::Icon, Color, Font},
|
||||||
geometry::{
|
geometry::{
|
||||||
Alignment, Alignment2D, Dimensions, Insets, LinearPlacement, Offset, Point, Rect,
|
Alignment, Alignment2D, Dimensions, Insets, LinearPlacement, Offset, Point, Rect,
|
||||||
},
|
},
|
||||||
@ -14,6 +14,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::layout::{LayoutFit, TextLayout, TextStyle};
|
use super::layout::{LayoutFit, TextLayout, TextStyle};
|
||||||
|
use heapless::String;
|
||||||
|
|
||||||
/// Used as an upper bound of number of different styles we may render on single
|
/// Used as an upper bound of number of different styles we may render on single
|
||||||
/// page.
|
/// page.
|
||||||
@ -557,6 +558,8 @@ pub struct Checklist<T> {
|
|||||||
current: usize,
|
current: usize,
|
||||||
icon_current: Icon,
|
icon_current: Icon,
|
||||||
icon_done: Icon,
|
icon_done: Icon,
|
||||||
|
icon_done_color: Option<Color>,
|
||||||
|
show_numerals: bool,
|
||||||
/// How wide will the left icon column be
|
/// How wide will the left icon column be
|
||||||
check_width: i16,
|
check_width: i16,
|
||||||
/// Offset of the icon representing DONE
|
/// Offset of the icon representing DONE
|
||||||
@ -565,7 +568,10 @@ pub struct Checklist<T> {
|
|||||||
current_offset: Offset,
|
current_offset: Offset,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Checklist<T> {
|
impl<'a, T> Checklist<T>
|
||||||
|
where
|
||||||
|
T: ParagraphSource<'a>,
|
||||||
|
{
|
||||||
pub fn from_paragraphs(
|
pub fn from_paragraphs(
|
||||||
icon_current: Icon,
|
icon_current: Icon,
|
||||||
icon_done: Icon,
|
icon_done: Icon,
|
||||||
@ -578,6 +584,8 @@ impl<T> Checklist<T> {
|
|||||||
current,
|
current,
|
||||||
icon_current,
|
icon_current,
|
||||||
icon_done,
|
icon_done,
|
||||||
|
icon_done_color: None,
|
||||||
|
show_numerals: false,
|
||||||
check_width: 0,
|
check_width: 0,
|
||||||
done_offset: Offset::zero(),
|
done_offset: Offset::zero(),
|
||||||
current_offset: Offset::zero(),
|
current_offset: Offset::zero(),
|
||||||
@ -599,6 +607,38 @@ impl<T> Checklist<T> {
|
|||||||
self
|
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) {
|
fn paint_icon(&self, layout: &TextLayout, icon: Icon, offset: Offset) {
|
||||||
let top_left = Point::new(self.area.x0, layout.bounds.y0);
|
let top_left = Point::new(self.area.x0, layout.bounds.y0);
|
||||||
icon.draw(
|
icon.draw(
|
||||||
@ -609,16 +649,29 @@ impl<T> Checklist<T> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_icon<'s>(
|
fn render_numeral<'s>(
|
||||||
&self,
|
&self,
|
||||||
layout: &TextLayout,
|
base_point: Point,
|
||||||
icon: Icon,
|
n: usize,
|
||||||
offset: Offset,
|
color: Color,
|
||||||
target: &mut impl Renderer<'s>,
|
target: &mut impl Renderer<'s>,
|
||||||
) {
|
) {
|
||||||
let top_left = Point::new(self.area.x0, layout.bounds.y0);
|
let numeral = build_string!(10, inttostr!(n as u8 + 1), ".");
|
||||||
shape::ToifImage::new(top_left + offset, icon.toif)
|
shape::Text::new(base_point, numeral.as_str())
|
||||||
.with_fg(layout.style.text_color)
|
.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);
|
.render(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -662,24 +715,7 @@ where
|
|||||||
|
|
||||||
fn render<'s>(&self, target: &mut impl Renderer<'s>) {
|
fn render<'s>(&self, target: &mut impl Renderer<'s>) {
|
||||||
self.paragraphs.render(target);
|
self.paragraphs.render(target);
|
||||||
|
self.render_left_column(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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ui_bounds")]
|
#[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 {
|
impl ShowShareWords {
|
||||||
fn new_obj(_args: &[Obj], kwargs: &Map) -> Result<Obj, error::Error> {
|
fn new_obj(_args: &[Obj], kwargs: &Map) -> Result<Obj, error::Error> {
|
||||||
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
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_obj: Obj = kwargs.get(Qstr::MP_QSTR_words)?;
|
||||||
let share_words_vec: Vec<TString, 33> = util::iter_into_vec(share_words_obj)?;
|
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()?;
|
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)
|
.with_footer(TR::instructions__swipe_up.into(), None)
|
||||||
.map(|msg| matches!(msg, FrameMsg::Content(_)).then_some(FlowMsg::Confirmed));
|
.map(|msg| matches!(msg, FrameMsg::Content(_)).then_some(FlowMsg::Confirmed));
|
||||||
|
|
||||||
let content_words =
|
let content_words = Frame::left_aligned(title, ShareWords::new(share_words_vec))
|
||||||
Frame::left_aligned(title, ShareWords::new(share_words_vec)).map(|_| None);
|
.with_subtitle(subtitle)
|
||||||
|
.map(|_| None);
|
||||||
|
|
||||||
let content_confirm =
|
let content_confirm =
|
||||||
Frame::left_aligned(text_confirm, PromptScreen::new_hold_to_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 {
|
extern "C" fn new_show_checklist(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||||
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
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 active: usize = kwargs.get(Qstr::MP_QSTR_active)?.try_into()?;
|
||||||
let items: Obj = kwargs.get(Qstr::MP_QSTR_items)?;
|
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));
|
paragraphs.add(Paragraph::new(style, text));
|
||||||
}
|
}
|
||||||
|
|
||||||
let obj = LayoutObj::new(Frame::left_aligned(
|
let checklist_content = SwipeUpScreen::new(
|
||||||
title,
|
Checklist::from_paragraphs(
|
||||||
Dialog::new(
|
theme::ICON_CHEVRON_RIGHT,
|
||||||
Checklist::from_paragraphs(
|
theme::ICON_BULLET_CHECKMARK,
|
||||||
theme::ICON_LIST_CURRENT,
|
active,
|
||||||
theme::ICON_LIST_CHECK,
|
paragraphs
|
||||||
active,
|
.into_paragraphs()
|
||||||
paragraphs
|
.with_spacing(theme::CHECKLIST_SPACING),
|
||||||
.into_paragraphs()
|
)
|
||||||
.with_spacing(theme::CHECKLIST_SPACING),
|
.with_check_width(theme::CHECKLIST_CHECK_WIDTH)
|
||||||
)
|
.with_icon_done_color(theme::GREEN),
|
||||||
.with_check_width(theme::CHECKLIST_CHECK_WIDTH)
|
);
|
||||||
.with_current_offset(theme::CHECKLIST_CURRENT_OFFSET)
|
let obj = LayoutObj::new(
|
||||||
.with_done_offset(theme::CHECKLIST_DONE_OFFSET),
|
Frame::left_aligned(title, checklist_content)
|
||||||
theme::button_bar(Button::with_text(button).map(|msg| {
|
.with_footer(TR::instructions__swipe_up.into(), None),
|
||||||
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelConfirmMsg::Confirmed)
|
)?;
|
||||||
})),
|
|
||||||
),
|
|
||||||
))?;
|
|
||||||
Ok(obj.into())
|
Ok(obj.into())
|
||||||
};
|
};
|
||||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
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(
|
/// def flow_show_share_words(
|
||||||
/// *,
|
/// *,
|
||||||
/// title: str,
|
/// title: str,
|
||||||
|
/// subtitle: str,
|
||||||
/// words: Iterable[str],
|
/// words: Iterable[str],
|
||||||
/// text_info: str,
|
/// text_info: str,
|
||||||
/// text_confirm: 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_CANCEL, "model_tt/res/x32.toif");
|
||||||
include_icon!(ICON_CORNER_INFO, "model_tt/res/info32.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.
|
// Homescreen notifications.
|
||||||
include_icon!(ICON_WARN, "model_tt/res/warning16.toif");
|
include_icon!(ICON_WARN, "model_tt/res/warning16.toif");
|
||||||
include_icon!(ICON_WARNING40, "model_tt/res/warning40.toif");
|
include_icon!(ICON_WARNING40, "model_tt/res/warning40.toif");
|
||||||
@ -689,23 +685,23 @@ pub const fn button_counter() -> ButtonStyleSheet {
|
|||||||
ButtonStyleSheet {
|
ButtonStyleSheet {
|
||||||
normal: &ButtonStyle {
|
normal: &ButtonStyle {
|
||||||
font: Font::DEMIBOLD,
|
font: Font::DEMIBOLD,
|
||||||
text_color: FG,
|
text_color: GREY,
|
||||||
button_color: GREY_DARK,
|
button_color: GREY_EXTRA_DARK,
|
||||||
icon_color: GREY_LIGHT,
|
icon_color: GREY,
|
||||||
background_color: BG,
|
background_color: BG,
|
||||||
},
|
},
|
||||||
active: &ButtonStyle {
|
active: &ButtonStyle {
|
||||||
font: Font::DEMIBOLD,
|
font: Font::DEMIBOLD,
|
||||||
text_color: FG,
|
text_color: BG,
|
||||||
button_color: GREY_MEDIUM,
|
button_color: GREY_LIGHT,
|
||||||
icon_color: GREY_LIGHT,
|
icon_color: BG,
|
||||||
background_color: BG,
|
background_color: BG,
|
||||||
},
|
},
|
||||||
disabled: &ButtonStyle {
|
disabled: &ButtonStyle {
|
||||||
font: Font::DEMIBOLD,
|
font: Font::DEMIBOLD,
|
||||||
text_color: GREY_LIGHT,
|
text_color: GREY_DARK,
|
||||||
button_color: GREY_DARK,
|
button_color: BG,
|
||||||
icon_color: GREY_LIGHT,
|
icon_color: GREY_DARK,
|
||||||
background_color: BG,
|
background_color: BG,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -797,12 +793,10 @@ pub fn textstyle_number(num: i32) -> &'static TextStyle {
|
|||||||
|
|
||||||
pub const TEXT_NORMAL_OFF_WHITE: TextStyle =
|
pub const TEXT_NORMAL_OFF_WHITE: TextStyle =
|
||||||
TextStyle::new(Font::NORMAL, OFF_WHITE, BG, GREY_LIGHT, GREY_LIGHT);
|
TextStyle::new(Font::NORMAL, OFF_WHITE, BG, GREY_LIGHT, GREY_LIGHT);
|
||||||
pub const TEXT_CHECKLIST_DEFAULT: TextStyle =
|
pub const TEXT_CHECKLIST_DEFAULT: TextStyle = TextStyle::new(Font::SUB, GREY, BG, GREY, GREY);
|
||||||
TextStyle::new(Font::NORMAL, GREY_LIGHT, BG, GREY_LIGHT, GREY_LIGHT);
|
|
||||||
pub const TEXT_CHECKLIST_SELECTED: TextStyle =
|
pub const TEXT_CHECKLIST_SELECTED: TextStyle =
|
||||||
TextStyle::new(Font::NORMAL, FG, BG, GREY_LIGHT, GREY_LIGHT);
|
TextStyle::new(Font::NORMAL, GREY_LIGHT, BG, GREY_LIGHT, GREY_LIGHT);
|
||||||
pub const TEXT_CHECKLIST_DONE: TextStyle =
|
pub const TEXT_CHECKLIST_DONE: TextStyle = TextStyle::new(Font::SUB, GREY, BG, GREY, GREY);
|
||||||
TextStyle::new(Font::NORMAL, GREEN_DARK, BG, GREY_LIGHT, GREY_LIGHT);
|
|
||||||
|
|
||||||
/// Spacing between components (e.g. header and main content) and offsets from
|
/// 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
|
/// 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_WIDTH: i16 = 78;
|
||||||
pub const BUTTON_SPACING: i16 = SPACING;
|
pub const BUTTON_SPACING: i16 = SPACING;
|
||||||
pub const KEYBOARD_SPACING: i16 = BUTTON_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 RECOVERY_SPACING: i16 = 18;
|
||||||
pub const CORNER_BUTTON_SIDE: i16 = 44;
|
pub const CORNER_BUTTON_SIDE: i16 = 44;
|
||||||
pub const CORNER_BUTTON_SPACING: i16 = BUTTON_SPACING;
|
pub const CORNER_BUTTON_SPACING: i16 = BUTTON_SPACING;
|
||||||
|
pub const COUNTER_BUTTON_HEIGHT: i16 = 60;
|
||||||
pub const INFO_BUTTON_HEIGHT: i16 = 44;
|
pub const INFO_BUTTON_HEIGHT: i16 = 44;
|
||||||
pub const PIN_BUTTON_HEIGHT: i16 = 52;
|
pub const PIN_BUTTON_HEIGHT: i16 = 52;
|
||||||
pub const MNEMONIC_BUTTON_HEIGHT: i16 = 62;
|
pub const MNEMONIC_BUTTON_HEIGHT: i16 = 62;
|
||||||
@ -828,9 +823,7 @@ pub const RESULT_FOOTER_HEIGHT: i16 = 62;
|
|||||||
pub const DETAILS_SPACING: i16 = 8;
|
pub const DETAILS_SPACING: i16 = 8;
|
||||||
|
|
||||||
// checklist settings
|
// checklist settings
|
||||||
pub const CHECKLIST_CHECK_WIDTH: i16 = 16;
|
pub const CHECKLIST_CHECK_WIDTH: i16 = 32; // icon width (20px) + padding (12px)
|
||||||
pub const CHECKLIST_DONE_OFFSET: Offset = Offset::new(-2, 6);
|
|
||||||
pub const CHECKLIST_CURRENT_OFFSET: Offset = Offset::new(2, 3);
|
|
||||||
|
|
||||||
pub const fn button_bar<T>(inner: T) -> FixedHeightBar<T> {
|
pub const fn button_bar<T>(inner: T) -> FixedHeightBar<T> {
|
||||||
FixedHeightBar::bottom(inner, BUTTON_HEIGHT)
|
FixedHeightBar::bottom(inner, BUTTON_HEIGHT)
|
||||||
|
@ -396,6 +396,7 @@ def flow_prompt_backup() -> LayoutObj[UiResult]
|
|||||||
def flow_show_share_words(
|
def flow_show_share_words(
|
||||||
*,
|
*,
|
||||||
title: str,
|
title: str,
|
||||||
|
subtitle: str,
|
||||||
words: Iterable[str],
|
words: Iterable[str],
|
||||||
text_info: str,
|
text_info: str,
|
||||||
text_confirm: str,
|
text_confirm: str,
|
||||||
@ -404,18 +405,6 @@ def flow_show_share_words(
|
|||||||
confirmation."""
|
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
|
# rust/src/ui/model_mercury/layout.rs
|
||||||
def flow_request_number(
|
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_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_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_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__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__number_of_shares_info: str = "= total number of unique word lists used for wallet backup."
|
||||||
reset__one_share: str = "1 share"
|
reset__one_share: str = "1 share"
|
||||||
@ -644,14 +644,15 @@ class TR:
|
|||||||
reset__share_completed_template: str = "Share #{0} completed"
|
reset__share_completed_template: str = "Share #{0} completed"
|
||||||
reset__share_words_title: str = "Standard backup"
|
reset__share_words_title: str = "Standard backup"
|
||||||
reset__slip39_checklist_num_groups: str = "Number of groups"
|
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: 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_groups: str = "Set number of groups"
|
||||||
reset__slip39_checklist_set_num_shares: str = "Set number of shares"
|
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: str = "Set sizes and thresholds"
|
||||||
reset__slip39_checklist_set_sizes_longer: str = "Set size and threshold for each group"
|
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_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_title: str = "Backup checklist"
|
||||||
reset__slip39_checklist_write_down: str = "Write down and check all shares"
|
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"
|
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()
|
share_count = await layout.slip39_prompt_number_of_shares()
|
||||||
|
|
||||||
# get threshold
|
# 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)
|
share_threshold = await layout.slip39_prompt_threshold(share_count)
|
||||||
|
|
||||||
mnemonics = _get_slip39_mnemonics(
|
mnemonics = _get_slip39_mnemonics(
|
||||||
@ -149,7 +149,9 @@ async def _backup_slip39_basic(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# show and confirm individual shares
|
# 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])
|
await layout.slip39_basic_show_and_confirm_shares(mnemonics[0])
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,12 +23,13 @@ async def show_share_words(
|
|||||||
group_index: int | None = None,
|
group_index: int | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
||||||
|
title = TR.reset__recovery_wallet_backup_title
|
||||||
if share_index is None:
|
if share_index is None:
|
||||||
title = TR.reset__recovery_wallet_backup_title
|
subtitle = ""
|
||||||
elif group_index is None:
|
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:
|
else:
|
||||||
title = TR.reset__group_share_title_template.format(
|
subtitle = TR.reset__group_share_title_template.format(
|
||||||
group_index + 1, share_index + 1
|
group_index + 1, share_index + 1
|
||||||
)
|
)
|
||||||
words_count = len(share_words)
|
words_count = len(share_words)
|
||||||
@ -39,6 +40,7 @@ async def show_share_words(
|
|||||||
RustLayout(
|
RustLayout(
|
||||||
trezorui2.flow_show_share_words(
|
trezorui2.flow_show_share_words(
|
||||||
title=title,
|
title=title,
|
||||||
|
subtitle=subtitle,
|
||||||
words=share_words,
|
words=share_words,
|
||||||
text_info=text_info,
|
text_info=text_info,
|
||||||
text_confirm=text_confirm,
|
text_confirm=text_confirm,
|
||||||
@ -90,29 +92,17 @@ async def select_word(
|
|||||||
return words[result]
|
return words[result]
|
||||||
|
|
||||||
|
|
||||||
async def slip39_show_checklist(step: int, backup_type: BackupType) -> None:
|
async def slip39_show_checklist(
|
||||||
from trezor.enums import BackupType
|
step: int,
|
||||||
|
backup_type: BackupType,
|
||||||
assert backup_type in (BackupType.Slip39_Basic, BackupType.Slip39_Advanced)
|
count: int | None = None,
|
||||||
|
threshold: int | None = None,
|
||||||
items = (
|
) -> None:
|
||||||
(
|
items = _slip_39_checklist_items(step, backup_type, count, threshold)
|
||||||
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,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
result = await interact(
|
result = await interact(
|
||||||
RustLayout(
|
RustLayout(
|
||||||
trezorui2.show_checklist(
|
trezorui2.show_checklist(
|
||||||
title=TR.reset__slip39_checklist_title,
|
title=TR.reset__title_shamir_backup,
|
||||||
button=TR.buttons__continue,
|
button=TR.buttons__continue,
|
||||||
active=step,
|
active=step,
|
||||||
items=items,
|
items=items,
|
||||||
@ -125,6 +115,44 @@ async def slip39_show_checklist(step: int, backup_type: BackupType) -> None:
|
|||||||
raise ActionCancelled
|
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(
|
async def _prompt_number(
|
||||||
title: str,
|
title: str,
|
||||||
description: Callable[[int], str],
|
description: Callable[[int], str],
|
||||||
@ -149,7 +177,6 @@ async def _prompt_number(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if __debug__:
|
if __debug__:
|
||||||
# TODO: is this still relevant?
|
|
||||||
if not isinstance(result, tuple):
|
if not isinstance(result, tuple):
|
||||||
# DebugLink currently can't send number of shares and it doesn't
|
# DebugLink currently can't send number of shares and it doesn't
|
||||||
# change the counter either so just use the initial value.
|
# change the counter either so just use the initial value.
|
||||||
@ -173,12 +200,7 @@ async def slip39_prompt_threshold(
|
|||||||
|
|
||||||
def description(count: int) -> str:
|
def description(count: int) -> str:
|
||||||
if group_id is None:
|
if group_id is None:
|
||||||
if count == 1:
|
return TR.reset__select_threshold
|
||||||
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)
|
|
||||||
else:
|
else:
|
||||||
return TR.reset__num_shares_for_group_template.format(group_id + 1)
|
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...
|
# TODO: this is madness...
|
||||||
text = TR.reset__the_threshold_sets_the_number_of_shares
|
text = TR.reset__the_threshold_sets_the_number_of_shares
|
||||||
if group_id is None:
|
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__needed_to_recover_your_wallet
|
||||||
text += TR.reset__set_it_to_count_template.format(count)
|
text += TR.reset__set_it_to_count_template.format(count)
|
||||||
if num_of_shares == 1:
|
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):
|
def description(i: int):
|
||||||
if group_id is None:
|
if group_id is None:
|
||||||
if i == 1:
|
return TR.reset__num_of_shares_how_many
|
||||||
return TR.reset__only_one_share_will_be_created
|
|
||||||
else:
|
|
||||||
return TR.reset__num_of_shares_how_many
|
|
||||||
else:
|
else:
|
||||||
return TR.reset__total_number_of_shares_in_group_template.format(
|
return TR.reset__total_number_of_shares_in_group_template.format(
|
||||||
group_id + 1
|
group_id + 1
|
||||||
)
|
)
|
||||||
|
|
||||||
if group_id is None:
|
if group_id is None:
|
||||||
info = TR.reset__num_of_shares_basic_info
|
info = TR.reset__num_of_shares_long_info
|
||||||
else:
|
else:
|
||||||
info = TR.reset__num_of_shares_advanced_info_template.format(group_id + 1)
|
info = TR.reset__num_of_shares_advanced_info_template.format(group_id + 1)
|
||||||
|
|
||||||
|
@ -99,7 +99,12 @@ async def select_word(
|
|||||||
return words[result]
|
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 = (
|
items = (
|
||||||
(
|
(
|
||||||
TR.reset__slip39_checklist_num_shares,
|
TR.reset__slip39_checklist_num_shares,
|
||||||
|
@ -103,7 +103,12 @@ async def select_word(
|
|||||||
return words[result]
|
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 = (
|
items = (
|
||||||
(
|
(
|
||||||
TR.reset__slip39_checklist_set_num_shares,
|
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_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_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_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__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__number_of_shares_info": "= total number of unique word lists used for wallet backup.",
|
||||||
"reset__one_share": "1 share",
|
"reset__one_share": "1 share",
|
||||||
@ -647,13 +647,14 @@
|
|||||||
"reset__share_words_title": "Standard backup",
|
"reset__share_words_title": "Standard backup",
|
||||||
"reset__slip39_checklist_num_groups": "Number of groups",
|
"reset__slip39_checklist_num_groups": "Number of groups",
|
||||||
"reset__slip39_checklist_num_shares": "Number of shares",
|
"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_groups": "Set number of groups",
|
||||||
"reset__slip39_checklist_set_num_shares": "Set number of shares",
|
"reset__slip39_checklist_set_num_shares": "Set number of shares",
|
||||||
"reset__slip39_checklist_set_sizes": "Set sizes and thresholds",
|
"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_sizes_longer": "Set size and threshold for each group",
|
||||||
"reset__slip39_checklist_set_threshold": "Set threshold",
|
"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_title": "Backup checklist",
|
||||||
"reset__slip39_checklist_write_down": "Write down and check all shares",
|
"reset__slip39_checklist_write_down": "Write down and check all shares",
|
||||||
"reset__slip39_checklist_write_down_recovery": "Write down & check all wallet backup shares",
|
"reset__slip39_checklist_write_down_recovery": "Write down & check all wallet backup shares",
|
||||||
|
@ -929,5 +929,6 @@
|
|||||||
"927": "words__good_to_know",
|
"927": "words__good_to_know",
|
||||||
"928": "words__operation_cancelled",
|
"928": "words__operation_cancelled",
|
||||||
"929": "words__settings",
|
"929": "words__settings",
|
||||||
"930": "words__try_again"
|
"930": "words__try_again",
|
||||||
|
"931": "reset__slip39_checklist_num_groups_x_template"
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"current": {
|
"current": {
|
||||||
"merkle_root": "070867d6d288bb46d1eb69dd95bc6d7b6fc09a3f299c75e997d756e7915860d6",
|
"merkle_root": "e79fdd3c9052dfd140aef2b4800b6b0b8000ae99822cf3e8be083da0dc2b376c",
|
||||||
"datetime": "2024-05-22T11:43:31.930638",
|
"datetime": "2024-05-26T15:18:17.124044",
|
||||||
"commit": "6bd6027a57b814483947f98aeb118a15f846e3bb"
|
"commit": "3e9598245d57044418f4eeb5ce5bc792f20587c3"
|
||||||
},
|
},
|
||||||
"history": [
|
"history": [
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user