mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-08-04 04:48:48 +00:00
WIP - some feedback from product
This commit is contained in:
parent
cf538e5789
commit
aa4c3551d4
Binary file not shown.
Before Width: | Height: | Size: 135 B After Width: | Height: | Size: 134 B |
@ -10,11 +10,23 @@ pub fn shuffle<T>(slice: &mut [T]) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a random number in the range [min, max].
|
||||
pub fn uniform_between(min: u32, max: u32) -> u32 {
|
||||
assert!(max > min);
|
||||
uniform(max - min + 1) + min
|
||||
}
|
||||
|
||||
/// Returns a random number in the range [min, max] except one `except` number.
|
||||
pub fn uniform_between_except(min: u32, max: u32, except: u32) -> u32 {
|
||||
// Generate uniform_between as long as it is not except
|
||||
loop {
|
||||
let rand = uniform_between(min, max);
|
||||
if rand != except {
|
||||
return rand;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@ -27,4 +39,11 @@ mod tests {
|
||||
assert!((256..=512).contains(&uniform_between(256, 512)));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uniform_between_except_test() {
|
||||
for _ in 0..10 {
|
||||
assert!(uniform_between_except(10, 12, 11) != 11);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -545,6 +545,15 @@ impl ButtonLayout {
|
||||
)
|
||||
}
|
||||
|
||||
/// Left text and right arrow.
|
||||
pub fn text_none_arrow(text: StrBuffer) -> Self {
|
||||
Self::new(
|
||||
Some(ButtonDetails::text(text)),
|
||||
None,
|
||||
Some(ButtonDetails::right_arrow_icon()),
|
||||
)
|
||||
}
|
||||
|
||||
/// Only right text.
|
||||
pub fn none_none_text(text: StrBuffer) -> Self {
|
||||
Self::new(None, None, Some(ButtonDetails::text(text)))
|
||||
|
@ -36,13 +36,10 @@ where
|
||||
}
|
||||
|
||||
/// Aligning the title to the center, instead of the left.
|
||||
/// Also disabling scrollbar in the positive case, as they are not
|
||||
/// compatible.
|
||||
pub fn with_title_center(mut self, title_centered: bool) -> Self {
|
||||
self.title_centered = title_centered;
|
||||
if title_centered {
|
||||
self.account_for_scrollbar = false;
|
||||
}
|
||||
/// Also disabling scrollbar, as they are not compatible.
|
||||
pub fn with_title_centered(mut self) -> Self {
|
||||
self.title_centered = true;
|
||||
self.account_for_scrollbar = false;
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,17 @@ impl ChoiceItem {
|
||||
self
|
||||
}
|
||||
|
||||
/// Getting the offset of the icon to center it vertically.
|
||||
/// Depending on its size and used font.
|
||||
fn icon_vertical_offset(&self) -> Offset {
|
||||
if let Some(icon) = self.icon {
|
||||
let height_diff = self.font.text_height() - icon.height();
|
||||
Offset::y(-height_diff / 2)
|
||||
} else {
|
||||
Offset::zero()
|
||||
}
|
||||
}
|
||||
|
||||
/// Getting the text width in pixels.
|
||||
pub fn text_width(&self) -> i16 {
|
||||
self.font.text_width(&self.text)
|
||||
@ -88,7 +99,11 @@ impl ChoiceItem {
|
||||
/// Showing only the icon, if available, otherwise the text.
|
||||
pub fn render_left(&self, area: Rect) {
|
||||
if let Some(icon) = self.icon {
|
||||
icon.draw_bottom_right(area.bottom_right(), theme::FG, theme::BG);
|
||||
icon.draw_bottom_right(
|
||||
area.bottom_right() + self.icon_vertical_offset(),
|
||||
theme::FG,
|
||||
theme::BG,
|
||||
);
|
||||
} else {
|
||||
display_right(area.bottom_right(), &self.text, self.font);
|
||||
}
|
||||
@ -98,7 +113,11 @@ impl ChoiceItem {
|
||||
/// Showing only the icon, if available, otherwise the text.
|
||||
pub fn render_right(&self, area: Rect) {
|
||||
if let Some(icon) = self.icon {
|
||||
icon.draw_bottom_left(area.bottom_left(), theme::FG, theme::BG);
|
||||
icon.draw_bottom_left(
|
||||
area.bottom_left() + self.icon_vertical_offset(),
|
||||
theme::FG,
|
||||
theme::BG,
|
||||
);
|
||||
} else {
|
||||
display(area.bottom_left(), &self.text, self.font);
|
||||
}
|
||||
@ -135,7 +154,7 @@ impl Choice for ChoiceItem {
|
||||
if let Some(icon) = self.icon {
|
||||
let fg_color = if inverse { theme::BG } else { theme::FG };
|
||||
let bg_color = if inverse { theme::FG } else { theme::BG };
|
||||
icon.draw_bottom_left(baseline, fg_color, bg_color);
|
||||
icon.draw_bottom_left(baseline + self.icon_vertical_offset(), fg_color, bg_color);
|
||||
baseline = baseline + Offset::x(icon.width() + 2);
|
||||
}
|
||||
if inverse {
|
||||
|
@ -193,10 +193,12 @@ impl Component for PinEntry {
|
||||
_ => {
|
||||
if !self.is_full() {
|
||||
self.append_new_digit(ctx, page_counter);
|
||||
// Choosing any random digit to be shown next
|
||||
let new_page_counter = random::uniform_between(
|
||||
// Choosing random digit to be shown next, but different
|
||||
// from the current choice.
|
||||
let new_page_counter = random::uniform_between_except(
|
||||
NUMBER_START_INDEX as u32,
|
||||
(CHOICE_LENGTH - 1) as u32,
|
||||
page_counter as u32,
|
||||
);
|
||||
self.choice_page
|
||||
.set_page_counter(ctx, new_page_counter as u8);
|
||||
|
@ -75,6 +75,13 @@ impl<const N: usize> SimpleChoice<N> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Show choices even when they do not fit entirely.
|
||||
pub fn with_show_incomplete(mut self) -> Self {
|
||||
self.choice_page = self.choice_page.with_incomplete(true);
|
||||
self
|
||||
}
|
||||
|
||||
/// Returning chosen page index instead of the string result.
|
||||
pub fn with_return_index(mut self) -> Self {
|
||||
self.return_index = true;
|
||||
self
|
||||
|
@ -149,8 +149,6 @@ impl Loader {
|
||||
// NOTE: need to calculate this in `i32`, it would overflow using `i16`
|
||||
let invert_from = ((self.area.width() as i32 + 1) * done) / (display::LOADER_MAX as i32);
|
||||
|
||||
// TODO: the text should be moved one pixel to the top so it is centered in the
|
||||
// loader
|
||||
display::bar_with_text_and_fill(
|
||||
self.area,
|
||||
Some(&self.text_overlay),
|
||||
@ -167,7 +165,8 @@ impl Component for Loader {
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.area = bounds;
|
||||
let baseline = bounds.bottom_center() + Offset::new(1, -1);
|
||||
// Centering the text in the loader rectangle.
|
||||
let baseline = bounds.bottom_center() + Offset::new(1, -2);
|
||||
self.text_overlay.place(baseline);
|
||||
self.area
|
||||
}
|
||||
|
@ -414,7 +414,7 @@ extern "C" fn new_show_receive_address(n_args: usize, args: *const Obj, kwargs:
|
||||
.text_bold("ADDRESS MISMATCH?".into())
|
||||
.newline()
|
||||
.newline_half()
|
||||
.text_mono("Please contact Trezor support on trezor.io/support".into())
|
||||
.text_mono("Please contact Trezor support at trezor.io/support".into())
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
@ -565,7 +565,7 @@ extern "C" fn tutorial(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj
|
||||
tutorial_screen(
|
||||
"HELLO".into(),
|
||||
"Welcome to Trezor.\nPress right to continue.".into(),
|
||||
ButtonLayout::cancel_none_arrow(),
|
||||
ButtonLayout::text_none_arrow("SKIP".into()),
|
||||
ButtonActions::last_none_next(),
|
||||
)
|
||||
},
|
||||
@ -609,7 +609,7 @@ extern "C" fn tutorial(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj
|
||||
Font::MONO,
|
||||
)
|
||||
.newline()
|
||||
.text_mono("Tutorial finished.".into())
|
||||
.text_mono("Tutorial complete.".into())
|
||||
.newline()
|
||||
.newline()
|
||||
.alignment(Alignment::Center)
|
||||
@ -655,10 +655,9 @@ extern "C" fn new_request_number(n_args: usize, args: *const Obj, kwargs: *mut M
|
||||
let max_count: u32 = kwargs.get(Qstr::MP_QSTR_max_count)?.try_into()?;
|
||||
let count: u32 = kwargs.get(Qstr::MP_QSTR_count)?.try_into()?;
|
||||
|
||||
let obj = LayoutObj::new(Frame::new(
|
||||
title,
|
||||
NumberInput::new(min_count, max_count, count),
|
||||
))?;
|
||||
let obj = LayoutObj::new(
|
||||
Frame::new(title, NumberInput::new(min_count, max_count, count)).with_title_centered(),
|
||||
)?;
|
||||
Ok(obj.into())
|
||||
};
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
@ -736,10 +735,10 @@ extern "C" fn new_select_word(n_args: usize, args: *const Obj, kwargs: *mut Map)
|
||||
Frame::new(
|
||||
title,
|
||||
SimpleChoice::new(words, false)
|
||||
.with_only_one_item()
|
||||
.with_show_incomplete()
|
||||
.with_return_index(),
|
||||
)
|
||||
.with_title_center(true),
|
||||
.with_title_centered(),
|
||||
)?;
|
||||
Ok(obj.into())
|
||||
};
|
||||
@ -756,7 +755,9 @@ extern "C" fn new_select_word_count(n_args: usize, args: *const Obj, kwargs: *mu
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
let obj = LayoutObj::new(Frame::new(title, SimpleChoice::new(choices, false)))?;
|
||||
let obj = LayoutObj::new(
|
||||
Frame::new(title, SimpleChoice::new(choices, false)).with_title_centered(),
|
||||
)?;
|
||||
Ok(obj.into())
|
||||
};
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
@ -767,7 +768,7 @@ extern "C" fn new_request_bip39(n_args: usize, args: *const Obj, kwargs: *mut Ma
|
||||
let prompt: StrBuffer = kwargs.get(Qstr::MP_QSTR_prompt)?.try_into()?;
|
||||
|
||||
let obj = LayoutObj::new(
|
||||
Frame::new(prompt, WordlistEntry::new(WordlistType::Bip39)).with_title_center(true),
|
||||
Frame::new(prompt, WordlistEntry::new(WordlistType::Bip39)).with_title_centered(),
|
||||
)?;
|
||||
Ok(obj.into())
|
||||
};
|
||||
@ -779,7 +780,7 @@ extern "C" fn new_request_slip39(n_args: usize, args: *const Obj, kwargs: *mut M
|
||||
let prompt: StrBuffer = kwargs.get(Qstr::MP_QSTR_prompt)?.try_into()?;
|
||||
|
||||
let obj = LayoutObj::new(
|
||||
Frame::new(prompt, WordlistEntry::new(WordlistType::Slip39)).with_title_center(true),
|
||||
Frame::new(prompt, WordlistEntry::new(WordlistType::Slip39)).with_title_centered(),
|
||||
)?;
|
||||
Ok(obj.into())
|
||||
};
|
||||
|
Binary file not shown.
@ -48,7 +48,7 @@ pub const ICON_CANCEL: IconAndName = IconAndName::new(
|
||||
"cancel",
|
||||
); // 8*8
|
||||
pub const ICON_DELETE: IconAndName =
|
||||
IconAndName::new(include_res!("model_tr/res/delete.toif"), "delete"); // 12*8
|
||||
IconAndName::new(include_res!("model_tr/res/delete.toif"), "delete"); // 10*7
|
||||
pub const ICON_EYE: IconAndName =
|
||||
IconAndName::new(include_res!("model_tr/res/eye_round.toif"), "eye"); // 12*7
|
||||
pub const ICON_LOCK: IconAndName = IconAndName::new(include_res!("model_tr/res/lock.toif"), "lock"); // 10*10
|
||||
|
@ -9,6 +9,7 @@ from trezor.enums import (
|
||||
)
|
||||
from trezor.strings import format_amount
|
||||
from trezor.ui import layouts
|
||||
from trezor.ui.layouts import confirm_metadata, confirm_properties
|
||||
|
||||
from apps.common.paths import address_n_to_str
|
||||
|
||||
@ -21,9 +22,6 @@ from .helpers.utils import (
|
||||
format_stake_pool_id,
|
||||
)
|
||||
|
||||
confirm_metadata = layouts.confirm_metadata # global_import_cache
|
||||
confirm_properties = layouts.confirm_properties # global_import_cache
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Literal
|
||||
|
||||
|
@ -121,7 +121,7 @@ async def error_pin_invalid(ctx: Context) -> NoReturn:
|
||||
await show_error_and_raise(
|
||||
ctx,
|
||||
"warning_wrong_pin",
|
||||
"The PIN you entered is invalid.",
|
||||
"PIN you have entered is not valid.",
|
||||
"Wrong PIN", # header
|
||||
exc=wire.PinInvalid,
|
||||
)
|
||||
|
@ -28,7 +28,11 @@ async def change_pin(ctx: Context, msg: ChangePin) -> Success:
|
||||
await _require_confirm_change_pin(ctx, msg)
|
||||
|
||||
# get old pin
|
||||
curpin, salt = await request_pin_and_sd_salt(ctx, "Enter old PIN")
|
||||
if msg.remove:
|
||||
prompt = "Enter PIN"
|
||||
else:
|
||||
prompt = "Enter old PIN"
|
||||
curpin, salt = await request_pin_and_sd_salt(ctx, prompt)
|
||||
|
||||
# if changing pin, pre-check the entered pin before getting new pin
|
||||
if curpin and not msg.remove:
|
||||
|
@ -90,7 +90,7 @@ def _require_confirm_action(
|
||||
title,
|
||||
"enable wipe code?",
|
||||
[
|
||||
"Wipe code will\nbe used to delete this device.",
|
||||
"Wipe code can be used to erase all data from this device.",
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -65,7 +65,9 @@ async def _continue_recovery_process(ctx: GenericContext) -> Success:
|
||||
if is_first_step:
|
||||
# If we are starting recovery, ask for word count first...
|
||||
# _request_word_count
|
||||
await layout.homescreen_dialog(ctx, "Select", "Select number of words")
|
||||
await layout.homescreen_dialog(
|
||||
ctx, "Select", "First select the number of words in your recovery seed"
|
||||
)
|
||||
# ask for the number of words
|
||||
word_count = await layout.request_word_count(ctx, dry_run)
|
||||
# ...and only then show the starting screen with word count.
|
||||
@ -158,7 +160,7 @@ async def _finish_recovery(
|
||||
storage_recovery.end_progress()
|
||||
|
||||
await show_success(
|
||||
ctx, "success_recovery", "You have successfully recovered your wallet."
|
||||
ctx, "success_recovery", "You have finished recovering your wallet."
|
||||
)
|
||||
return Success(message="Device recovered")
|
||||
|
||||
@ -196,7 +198,7 @@ async def _request_share_first_screen(ctx: GenericContext, word_count: int) -> N
|
||||
)
|
||||
else: # BIP-39
|
||||
await layout.homescreen_dialog(
|
||||
ctx, "Enter seed", "Enter recovery seed", f"({word_count} words)"
|
||||
ctx, "Enter seed", "Now enter your recovery seed", f"({word_count} words)"
|
||||
)
|
||||
|
||||
|
||||
|
@ -52,7 +52,7 @@ async def request_mnemonic(
|
||||
ctx,
|
||||
"request_word",
|
||||
"WORD ENTERING",
|
||||
description="You'll only have to select first 2-3 letters.",
|
||||
description="You'll only have to select the first 2-3 letters.",
|
||||
verb="CONTINUE",
|
||||
verb_cancel=None,
|
||||
br_code=ButtonRequestType.MnemonicInput,
|
||||
@ -103,14 +103,7 @@ async def show_dry_run_result(
|
||||
from trezor.ui.layouts import show_success
|
||||
|
||||
if result:
|
||||
if is_slip39:
|
||||
text = text_r(
|
||||
"The entered recovery\nshares are valid and\nmatch what is currently\nin the device."
|
||||
)
|
||||
else:
|
||||
text = text_r(
|
||||
"The entered recovery\nseed is valid and\nmatches the one\nin the device."
|
||||
)
|
||||
text = "You have finished verifying your recovery seed"
|
||||
await show_success(ctx, "success_dry_recovery", text, button="Continue")
|
||||
else:
|
||||
if is_slip39:
|
||||
|
@ -12,8 +12,6 @@ from trezor.ui.layouts.reset import ( # noqa: F401
|
||||
slip39_show_checklist,
|
||||
)
|
||||
|
||||
from .. import text_r
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Sequence
|
||||
from trezor.wire import GenericContext
|
||||
@ -170,8 +168,9 @@ async def show_backup_warning(ctx: GenericContext, slip39: bool = False) -> None
|
||||
|
||||
|
||||
async def show_backup_success(ctx: GenericContext) -> None:
|
||||
text = text_r("Use your backup\nwhen you need to\nrecover your wallet.")
|
||||
await show_success(ctx, "success_backup", text, "Your backup is done.")
|
||||
from trezor.ui.layouts.reset import show_success_backup
|
||||
|
||||
await show_success_backup(ctx)
|
||||
|
||||
|
||||
# BIP39
|
||||
|
@ -24,11 +24,20 @@ async def cipher_key_value(ctx: Context, msg: CipherKeyValue) -> CipheredKeyValu
|
||||
encrypt = msg.encrypt
|
||||
decrypt = not msg.encrypt
|
||||
if (encrypt and msg.ask_on_encrypt) or (decrypt and msg.ask_on_decrypt):
|
||||
if encrypt:
|
||||
title = "Encrypt value"
|
||||
# Special case for Trezor Suite, which asks for setting up labels
|
||||
if msg.key == "Enable labeling?":
|
||||
title = "SUITE LABELING"
|
||||
verb = "ENABLE"
|
||||
else:
|
||||
title = "Decrypt value"
|
||||
await confirm_action(ctx, "cipher_key_value", title, description=msg.key)
|
||||
if encrypt:
|
||||
title = "Encrypt value"
|
||||
else:
|
||||
title = "Decrypt value"
|
||||
verb = "CONFIRM"
|
||||
|
||||
await confirm_action(
|
||||
ctx, "cipher_key_value", title, description=msg.key, verb=verb
|
||||
)
|
||||
|
||||
node = keychain.derive(msg.address_n)
|
||||
|
||||
|
@ -510,6 +510,7 @@ async def confirm_action(
|
||||
hold: bool = False,
|
||||
hold_danger: bool = False,
|
||||
reverse: bool = False,
|
||||
uppercase_title: bool = True,
|
||||
exc: ExceptionType = ActionCancelled,
|
||||
br_code: ButtonRequestType = BR_TYPE_OTHER,
|
||||
) -> None:
|
||||
@ -535,7 +536,7 @@ async def confirm_action(
|
||||
ctx,
|
||||
RustLayout(
|
||||
trezorui2.confirm_action(
|
||||
title=title.upper(),
|
||||
title=title.upper() if uppercase_title else title,
|
||||
action=action,
|
||||
description=description,
|
||||
verb=verb,
|
||||
@ -566,15 +567,12 @@ async def confirm_reset_device(
|
||||
if show_tutorial:
|
||||
await tutorial(ctx)
|
||||
|
||||
to_show = "By continuing you agree to our terms and conditions.\nMore info at trezor.io/tos."
|
||||
if not recovery:
|
||||
to_show += "\nUse you backup to recover your wallet."
|
||||
|
||||
return await _placeholder_confirm(
|
||||
ctx,
|
||||
"recover_device" if recovery else "setup_device",
|
||||
"WALLET RECOVERY" if recovery else "WALLET BACKUP",
|
||||
description=to_show,
|
||||
"WALLET RECOVERY" if recovery else "WALLET CREATION",
|
||||
description="By continuing you agree to Trezor Company terms and conditions.\n\rMore info at trezor.io/tos",
|
||||
verb="RECOVER WALLET" if recovery else "CREATE WALLET",
|
||||
br_code=ButtonRequestType.ProtectCall
|
||||
if recovery
|
||||
else ButtonRequestType.ResetDevice,
|
||||
@ -587,14 +585,14 @@ async def confirm_backup(ctx: GenericContext) -> bool:
|
||||
ctx,
|
||||
"backup_device",
|
||||
"SUCCESS",
|
||||
"New wallet created successfully!\nYou should back up your new wallet right now.",
|
||||
description="New wallet has been created.\nIt should be backed up now!",
|
||||
verb="BACK UP",
|
||||
verb_cancel="SKIP",
|
||||
br_code=ButtonRequestType.ResetDevice,
|
||||
):
|
||||
return True
|
||||
|
||||
confirmed = await get_bool(
|
||||
return await get_bool(
|
||||
ctx,
|
||||
"backup_device",
|
||||
"WARNING",
|
||||
@ -604,7 +602,6 @@ async def confirm_backup(ctx: GenericContext) -> bool:
|
||||
verb_cancel="SKIP",
|
||||
br_code=ButtonRequestType.ResetDevice,
|
||||
)
|
||||
return confirmed
|
||||
|
||||
|
||||
async def confirm_path_warning(
|
||||
@ -771,10 +768,25 @@ def show_success(
|
||||
subheader: str | None = None,
|
||||
button: str = "Continue",
|
||||
) -> Awaitable[None]:
|
||||
title = "Success"
|
||||
|
||||
# In case only subheader is supplied, showing it
|
||||
# in regular font, not bold.
|
||||
if not content and subheader:
|
||||
content = subheader
|
||||
subheader = None
|
||||
|
||||
# Special case for Shamir backup - to show everything just on one page
|
||||
# in regular font.
|
||||
if "Continue with" in content:
|
||||
content = f"{subheader}\n{content}"
|
||||
subheader = None
|
||||
title = ""
|
||||
|
||||
return _show_modal(
|
||||
ctx,
|
||||
br_type,
|
||||
"Success",
|
||||
title,
|
||||
subheader,
|
||||
content,
|
||||
button_confirm=button,
|
||||
@ -1192,7 +1204,7 @@ async def show_popup(
|
||||
def request_passphrase_on_host() -> None:
|
||||
draw_simple(
|
||||
trezorui2.show_info(
|
||||
title="",
|
||||
title="HIDDEN WALLET",
|
||||
description="Please type your passphrase on the connected host.",
|
||||
)
|
||||
)
|
||||
@ -1226,7 +1238,9 @@ async def request_pin_on_device(
|
||||
) -> str:
|
||||
from trezor import wire
|
||||
|
||||
if attempts_remaining is None:
|
||||
# Not showing the prompt in case user did not enter it badly yet
|
||||
# (has full 16 attempts left)
|
||||
if attempts_remaining is None or attempts_remaining == 16:
|
||||
subprompt = ""
|
||||
elif attempts_remaining == 1:
|
||||
subprompt = "Last attempt"
|
||||
@ -1260,7 +1274,7 @@ async def confirm_reenter_pin(
|
||||
ctx,
|
||||
br_type,
|
||||
"CHECK PIN",
|
||||
"Please re-enter to confirm.",
|
||||
description="Please re-enter PIN to confirm.",
|
||||
verb="BEGIN",
|
||||
br_code=br_code,
|
||||
)
|
||||
@ -1294,7 +1308,7 @@ async def confirm_pin_action(
|
||||
ctx,
|
||||
br_type,
|
||||
title,
|
||||
f"{description} {action}",
|
||||
description=f"{description} {action}",
|
||||
br_code=br_code,
|
||||
)
|
||||
|
||||
@ -1317,21 +1331,22 @@ async def confirm_set_new_pin(
|
||||
br_code=br_code,
|
||||
)
|
||||
|
||||
# TODO: this is a hack to put the next info on new screen in case of wipe code
|
||||
# TODO: there should be a possibility to give a list of strings and each of them
|
||||
# would be rendered on a new screen
|
||||
if len(information) == 1:
|
||||
information.append("\n")
|
||||
if "wipe_code" in br_type:
|
||||
title = "WIPE CODE INFO"
|
||||
verb = "HODL TO BEGIN" # Easter egg from @Hannsek
|
||||
else:
|
||||
title = "PIN INFORMATION"
|
||||
information.append(
|
||||
"Position of individual numbers will change between entries for enhanced security."
|
||||
)
|
||||
verb = "HOLD TO BEGIN"
|
||||
|
||||
information.append(
|
||||
"Position of individual numbers will change between entries for more security."
|
||||
)
|
||||
return await confirm_action(
|
||||
ctx,
|
||||
br_type,
|
||||
title="",
|
||||
title=title,
|
||||
description="\n".join(information),
|
||||
verb="HOLD TO BEGIN",
|
||||
verb=verb,
|
||||
hold=True,
|
||||
br_code=br_code,
|
||||
)
|
||||
|
@ -79,7 +79,7 @@ async def continue_recovery(
|
||||
if dry_run:
|
||||
title = "SEED CHECK"
|
||||
else:
|
||||
title = "RECOVERY MODE"
|
||||
title = "WALLET RECOVERY"
|
||||
|
||||
return await get_bool(
|
||||
ctx,
|
||||
|
@ -47,18 +47,18 @@ async def show_share_words(
|
||||
)
|
||||
|
||||
if share_index is None:
|
||||
check_title = "CHECK SEED"
|
||||
check_title = "CHECK BACKUP"
|
||||
elif group_index is None:
|
||||
check_title = f"CHECK SHARE #{share_index + 1}"
|
||||
else:
|
||||
check_title = f"CHECK G{group_index + 1} - SHARE {share_index + 1}"
|
||||
check_title = f"GROUP {group_index + 1} - SHARE {share_index + 1}"
|
||||
|
||||
if await get_bool(
|
||||
ctx,
|
||||
"backup_words",
|
||||
check_title,
|
||||
None,
|
||||
"Select correct words in correct positions.",
|
||||
"Select correct word for each position.",
|
||||
verb_cancel="SEE AGAIN",
|
||||
verb="BEGIN",
|
||||
br_code=ButtonRequestType.ResetDevice,
|
||||
@ -84,7 +84,7 @@ async def select_word(
|
||||
RustLayout(
|
||||
trezorui2.select_word( # type: ignore [Argument missing for parameter "description"]
|
||||
title=f"SELECT {format_ordinal(checked_index + 1).upper()} WORD",
|
||||
words=(words[0].upper(), words[1].upper(), words[2].upper()),
|
||||
words=(words[0].lower(), words[1].lower(), words[2].lower()),
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -165,10 +165,11 @@ async def slip39_prompt_threshold(
|
||||
await confirm_action(
|
||||
ctx,
|
||||
"slip39_prompt_threshold",
|
||||
"Set threshold",
|
||||
"Threshold",
|
||||
description="= number of shares needed for recovery",
|
||||
verb="BEGIN",
|
||||
verb_cancel=None,
|
||||
uppercase_title=False,
|
||||
)
|
||||
|
||||
count = num_of_shares // 2 + 1
|
||||
@ -199,9 +200,10 @@ async def slip39_prompt_number_of_shares(
|
||||
ctx,
|
||||
"slip39_shares",
|
||||
"Number of shares",
|
||||
description="= total number of unique word lists used for wallet backup.",
|
||||
description="= total number of unique word lists used for wallet backup",
|
||||
verb="BEGIN",
|
||||
verb_cancel=None,
|
||||
uppercase_title=False,
|
||||
)
|
||||
|
||||
count = 5
|
||||
@ -256,21 +258,26 @@ async def slip39_advanced_prompt_group_threshold(
|
||||
|
||||
|
||||
async def show_warning_backup(ctx: GenericContext, slip39: bool) -> None:
|
||||
if slip39:
|
||||
description = (
|
||||
"Never make a digital copy of your shares and never upload them online."
|
||||
)
|
||||
else:
|
||||
description = (
|
||||
"Never make a digital copy of your seed and never upload it online."
|
||||
)
|
||||
|
||||
await confirm_action(
|
||||
ctx,
|
||||
"backup_warning",
|
||||
"Caution",
|
||||
description=description,
|
||||
verb="I understand",
|
||||
verb_cancel=None,
|
||||
"SHAMIR BACKUP" if slip39 else "WALLET BACKUP",
|
||||
description="You can use your backup to recover your wallet at any time.",
|
||||
verb="HOLD TO BEGIN",
|
||||
hold=True,
|
||||
br_code=ButtonRequestType.ResetDevice,
|
||||
)
|
||||
|
||||
|
||||
async def show_success_backup(ctx: GenericContext) -> None:
|
||||
from . import confirm_action
|
||||
|
||||
await confirm_action(
|
||||
ctx,
|
||||
"success_backup",
|
||||
"BACKUP IS DONE",
|
||||
description="Keep it safe!",
|
||||
verb="CONTINUE",
|
||||
verb_cancel=None,
|
||||
br_code=ButtonRequestType.Success,
|
||||
)
|
||||
|
@ -331,3 +331,10 @@ async def show_warning_backup(ctx: GenericContext, slip39: bool) -> None:
|
||||
)
|
||||
if result != CONFIRMED:
|
||||
raise ActionCancelled
|
||||
|
||||
|
||||
async def show_success_backup(ctx: GenericContext) -> None:
|
||||
from . import show_success
|
||||
|
||||
text = "Use your backup when you need to recover your wallet."
|
||||
await show_success(ctx, "success_backup", text, "Your backup is done.")
|
||||
|
@ -992,6 +992,7 @@ static secbool decrypt_dek(const uint8_t *kek, const uint8_t *keiv) {
|
||||
static void ensure_not_wipe_code(const uint8_t *pin, size_t pin_len) {
|
||||
if (sectrue != is_not_wipe_code(pin, pin_len)) {
|
||||
storage_wipe();
|
||||
// TODO: need to account for smaller model R - smaller font and different copy
|
||||
error_shutdown("You have entered the", "wipe code. All private",
|
||||
"data has been erased.", NULL);
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ def select_number_of_words(
|
||||
layout = debug.read_layout()
|
||||
|
||||
# select number of words
|
||||
assert "Select number of words" in layout.get_content()
|
||||
assert "select the number of words" in layout.get_content()
|
||||
layout = debug.click(buttons.OK, wait=True)
|
||||
if legacy_ui:
|
||||
assert layout.text == "WordSelector"
|
||||
|
@ -131,7 +131,7 @@ def test_dryrun_locks_at_number_of_words(device_handler: "BackgroundDeviceHandle
|
||||
layout = debug.click(buttons.OK, wait=True)
|
||||
assert layout.text == "< PinKeyboard >"
|
||||
layout = debug.input(PIN4, wait=True)
|
||||
assert "Select number of words " in layout.get_content()
|
||||
assert "select the number of words " in layout.get_content()
|
||||
|
||||
# wait for autolock to trigger
|
||||
time.sleep(10.1)
|
||||
@ -146,7 +146,7 @@ def test_dryrun_locks_at_number_of_words(device_handler: "BackgroundDeviceHandle
|
||||
layout = debug.input(PIN4, wait=True)
|
||||
|
||||
# we are back at homescreen
|
||||
assert "Select number of words" in layout.get_content()
|
||||
assert "select the number of words" in layout.get_content()
|
||||
|
||||
|
||||
@pytest.mark.setup_client(pin=PIN4)
|
||||
|
@ -58,7 +58,7 @@ def do_recover_core(client: Client, mnemonic: List[str], **kwargs: Any):
|
||||
client.debug.click(buttons.OK)
|
||||
|
||||
yield
|
||||
assert "Select number of words" in layout().get_content()
|
||||
assert "select the number of words" in layout().get_content()
|
||||
client.debug.click(buttons.OK)
|
||||
|
||||
yield
|
||||
@ -70,7 +70,7 @@ def do_recover_core(client: Client, mnemonic: List[str], **kwargs: Any):
|
||||
client.debug.click(buttons.grid34(index % 3, index // 3))
|
||||
|
||||
yield
|
||||
assert "Enter recovery seed" in layout().get_content()
|
||||
assert "enter your recovery seed" in layout().get_content()
|
||||
client.debug.click(buttons.OK)
|
||||
|
||||
yield
|
||||
@ -97,7 +97,7 @@ def do_recover_r(client: Client, mnemonic: List[str], **kwargs: Any):
|
||||
client.debug.press_right()
|
||||
|
||||
yield
|
||||
assert "Select number of words" in layout().text
|
||||
assert "select the number of words" in layout().text
|
||||
client.debug.press_yes()
|
||||
|
||||
yield
|
||||
@ -110,7 +110,7 @@ def do_recover_r(client: Client, mnemonic: List[str], **kwargs: Any):
|
||||
client.debug.input(str(len(mnemonic)))
|
||||
|
||||
yield
|
||||
assert "Enter recovery seed" in layout().text
|
||||
assert "enter your recovery seed" in layout().text
|
||||
client.debug.press_yes()
|
||||
|
||||
yield
|
||||
@ -173,7 +173,7 @@ def test_invalid_seed_core(client: Client):
|
||||
client.debug.click(buttons.OK)
|
||||
|
||||
yield
|
||||
assert "Select number of words" in layout().get_content()
|
||||
assert "select the number of words" in layout().get_content()
|
||||
client.debug.click(buttons.OK)
|
||||
|
||||
yield
|
||||
@ -182,7 +182,7 @@ def test_invalid_seed_core(client: Client):
|
||||
client.debug.click(buttons.grid34(0, 2))
|
||||
|
||||
yield
|
||||
assert "Enter recovery seed" in layout().get_content()
|
||||
assert "enter your recovery seed" in layout().get_content()
|
||||
client.debug.click(buttons.OK)
|
||||
|
||||
yield
|
||||
@ -197,7 +197,7 @@ def test_invalid_seed_core(client: Client):
|
||||
|
||||
yield
|
||||
# retry screen
|
||||
assert "Select number of words" in layout().get_content()
|
||||
assert "select the number of words" in layout().get_content()
|
||||
client.debug.click(buttons.CANCEL)
|
||||
|
||||
yield
|
||||
@ -210,7 +210,7 @@ def test_invalid_seed_core(client: Client):
|
||||
client.debug.press_right()
|
||||
|
||||
yield
|
||||
assert "Select number of words" in layout().text
|
||||
assert "select the number of words" in layout().text
|
||||
client.debug.press_yes()
|
||||
|
||||
yield
|
||||
@ -220,7 +220,7 @@ def test_invalid_seed_core(client: Client):
|
||||
client.debug.press_middle()
|
||||
|
||||
yield
|
||||
assert "Enter recovery seed" in layout().text
|
||||
assert "enter your recovery seed" in layout().text
|
||||
client.debug.press_yes()
|
||||
|
||||
yield
|
||||
@ -239,7 +239,7 @@ def test_invalid_seed_core(client: Client):
|
||||
|
||||
yield
|
||||
# retry screen
|
||||
assert "Select number of words" in layout().text
|
||||
assert "select the number of words" in layout().text
|
||||
client.debug.press_left()
|
||||
|
||||
yield
|
||||
|
@ -43,7 +43,7 @@ def test_tt_pin_passphrase(client: Client):
|
||||
client.debug.input("654")
|
||||
|
||||
yield
|
||||
assert "Select number of words" in layout().get_content()
|
||||
assert "select the number of words" in layout().get_content()
|
||||
client.debug.press_yes()
|
||||
|
||||
yield
|
||||
@ -51,7 +51,7 @@ def test_tt_pin_passphrase(client: Client):
|
||||
client.debug.input(str(len(mnemonic)))
|
||||
|
||||
yield
|
||||
assert "Enter recovery seed" in layout().get_content()
|
||||
assert "enter your recovery seed" in layout().get_content()
|
||||
client.debug.press_yes()
|
||||
|
||||
yield
|
||||
@ -75,7 +75,7 @@ def test_tt_pin_passphrase(client: Client):
|
||||
client.debug.input("654")
|
||||
|
||||
yield
|
||||
assert "re-enter to confirm" in layout().text
|
||||
assert "re-enter PIN to confirm" in layout().text
|
||||
client.debug.press_right()
|
||||
|
||||
yield
|
||||
@ -83,7 +83,7 @@ def test_tt_pin_passphrase(client: Client):
|
||||
client.debug.input("654")
|
||||
|
||||
yield
|
||||
assert "Select number of words" in layout().text
|
||||
assert "select the number of words" in layout().text
|
||||
client.debug.press_yes()
|
||||
|
||||
yield
|
||||
@ -92,7 +92,7 @@ def test_tt_pin_passphrase(client: Client):
|
||||
client.debug.input(str(len(mnemonic)))
|
||||
|
||||
yield
|
||||
assert "Enter recovery seed" in layout().text
|
||||
assert "enter your recovery seed" in layout().text
|
||||
client.debug.press_yes()
|
||||
|
||||
yield
|
||||
@ -105,7 +105,7 @@ def test_tt_pin_passphrase(client: Client):
|
||||
client.debug.input(word)
|
||||
|
||||
yield
|
||||
assert "You have successfully recovered your wallet." in layout().text
|
||||
assert "You have finished recovering your wallet." in layout().text
|
||||
client.debug.press_yes()
|
||||
|
||||
with client:
|
||||
@ -141,7 +141,7 @@ def test_tt_nopin_nopassphrase(client: Client):
|
||||
client.debug.press_yes()
|
||||
|
||||
yield
|
||||
assert "Select number of words" in layout().get_content()
|
||||
assert "select the number of words" in layout().get_content()
|
||||
client.debug.press_yes()
|
||||
|
||||
yield
|
||||
@ -149,7 +149,7 @@ def test_tt_nopin_nopassphrase(client: Client):
|
||||
client.debug.input(str(len(mnemonic)))
|
||||
|
||||
yield
|
||||
assert "Enter recovery seed" in layout().get_content()
|
||||
assert "enter your recovery seed" in layout().get_content()
|
||||
client.debug.press_yes()
|
||||
|
||||
yield
|
||||
@ -169,7 +169,7 @@ def test_tt_nopin_nopassphrase(client: Client):
|
||||
client.debug.press_yes()
|
||||
|
||||
yield
|
||||
assert "Select number of words" in layout().text
|
||||
assert "select the number of words" in layout().text
|
||||
client.debug.press_yes()
|
||||
|
||||
yield
|
||||
@ -178,7 +178,7 @@ def test_tt_nopin_nopassphrase(client: Client):
|
||||
client.debug.input(str(len(mnemonic)))
|
||||
|
||||
yield
|
||||
assert "Enter recovery seed" in layout().text
|
||||
assert "enter your recovery seed" in layout().text
|
||||
client.debug.press_yes()
|
||||
|
||||
yield
|
||||
@ -191,7 +191,7 @@ def test_tt_nopin_nopassphrase(client: Client):
|
||||
client.debug.input(word)
|
||||
|
||||
yield
|
||||
assert "You have successfully recovered your wallet." in layout().text
|
||||
assert "You have finished recovering your wallet." in layout().text
|
||||
client.debug.press_yes()
|
||||
|
||||
with client:
|
||||
|
@ -53,7 +53,7 @@ def test_abort(emulator: Emulator):
|
||||
assert layout.get_title() == "RECOVERY MODE"
|
||||
|
||||
layout = debug.click(buttons.OK, wait=True)
|
||||
assert "Select number of words" in layout.text
|
||||
assert "select the number of words" in layout.text
|
||||
|
||||
device_handler.restart(emulator)
|
||||
debug = device_handler.debuglink()
|
||||
@ -63,7 +63,7 @@ def test_abort(emulator: Emulator):
|
||||
|
||||
# no waiting for layout because layout doesn't change
|
||||
layout = debug.read_layout()
|
||||
assert "Select number of words" in layout.text
|
||||
assert "select the number of words" in layout.text
|
||||
layout = debug.click(buttons.CANCEL, wait=True)
|
||||
|
||||
assert layout.get_title() == "ABORT RECOVERY"
|
||||
|
Loading…
Reference in New Issue
Block a user