mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-07-18 04:28:18 +00:00
WIP - passphrase design by Figma
This commit is contained in:
parent
4d407edbbc
commit
c9a980203e
BIN
core/assets/model_r/back_up_arrow.png
Normal file
BIN
core/assets/model_r/back_up_arrow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 133 B |
BIN
core/assets/model_r/space.png
Normal file
BIN
core/assets/model_r/space.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 118 B |
@ -2,13 +2,12 @@ use crate::ui::{
|
|||||||
component::{text::common::TextBox, Child, Component, ComponentExt, Event, EventCtx},
|
component::{text::common::TextBox, Child, Component, ComponentExt, Event, EventCtx},
|
||||||
display::Icon,
|
display::Icon,
|
||||||
geometry::Rect,
|
geometry::Rect,
|
||||||
model_tr::theme,
|
model_tr::{component::ButtonDetails, theme},
|
||||||
util::char_to_string,
|
util::char_to_string,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::super::{
|
use super::super::{
|
||||||
ButtonDetails, ButtonLayout, ChangingTextLine, ChoiceFactory, ChoiceItem, ChoicePage,
|
ButtonLayout, ChangingTextLine, ChoiceFactory, ChoiceItem, ChoicePage, ChoicePageMsg,
|
||||||
ChoicePageMsg,
|
|
||||||
};
|
};
|
||||||
use heapless::String;
|
use heapless::String;
|
||||||
|
|
||||||
@ -18,7 +17,7 @@ pub enum PassphraseEntryMsg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Defines the choices currently available on the screen
|
/// Defines the choices currently available on the screen
|
||||||
#[derive(PartialEq, Clone)]
|
#[derive(PartialEq, Clone, Copy)]
|
||||||
enum ChoiceCategory {
|
enum ChoiceCategory {
|
||||||
Menu,
|
Menu,
|
||||||
LowercaseLetter,
|
LowercaseLetter,
|
||||||
@ -42,10 +41,25 @@ const SPECIAL_SYMBOLS: [char; 30] = [
|
|||||||
'_', '<', '>', '.', ':', '@', '/', '|', '\\', '!', '(', ')', '+', '%', '&', '-', '[', ']', '?',
|
'_', '<', '>', '.', ':', '@', '/', '|', '\\', '!', '(', ')', '+', '%', '&', '-', '[', ']', '?',
|
||||||
'{', '}', ',', '\'', '`', ';', '"', '~', '$', '^', '=',
|
'{', '}', ',', '\'', '`', ';', '"', '~', '$', '^', '=',
|
||||||
];
|
];
|
||||||
const MENU_LENGTH: usize = 6;
|
const MENU_LENGTH: usize = 8;
|
||||||
const DELETE_INDEX: usize = MENU_LENGTH - 1;
|
const SHOW_INDEX: usize = 0;
|
||||||
const SHOW_INDEX: usize = MENU_LENGTH - 2;
|
const CANCEL_DELETE_INDEX: usize = 1;
|
||||||
const MENU: [&str; MENU_LENGTH] = ["abc", "ABC", "123", "*#_", "SHOW", "DELETE"];
|
const ENTER_INDEX: usize = 2;
|
||||||
|
const LOWERCASE_INDEX: usize = 3;
|
||||||
|
const UPPERCASE_INDEX: usize = 4;
|
||||||
|
const DIGITS_INDEX: usize = 5;
|
||||||
|
const SPECIAL_INDEX: usize = 6;
|
||||||
|
const SPACE_INDEX: usize = 7;
|
||||||
|
const MENU: [&str; MENU_LENGTH] = [
|
||||||
|
"SHOW",
|
||||||
|
"CANCEL_OR_DELETE", // will be chosen dynamically
|
||||||
|
"ENTER",
|
||||||
|
"abc",
|
||||||
|
"ABC",
|
||||||
|
"123",
|
||||||
|
"#$!",
|
||||||
|
"SPACE",
|
||||||
|
];
|
||||||
|
|
||||||
/// Get a character at a specified index for a specified category.
|
/// Get a character at a specified index for a specified category.
|
||||||
fn get_char(current_category: &ChoiceCategory, index: u8) -> char {
|
fn get_char(current_category: &ChoiceCategory, index: u8) -> char {
|
||||||
@ -61,11 +75,11 @@ fn get_char(current_category: &ChoiceCategory, index: u8) -> char {
|
|||||||
|
|
||||||
/// Return category from menu based on page index.
|
/// Return category from menu based on page index.
|
||||||
fn get_category_from_menu(page_index: u8) -> ChoiceCategory {
|
fn get_category_from_menu(page_index: u8) -> ChoiceCategory {
|
||||||
match page_index {
|
match page_index as usize {
|
||||||
0 => ChoiceCategory::LowercaseLetter,
|
LOWERCASE_INDEX => ChoiceCategory::LowercaseLetter,
|
||||||
1 => ChoiceCategory::UppercaseLetter,
|
UPPERCASE_INDEX => ChoiceCategory::UppercaseLetter,
|
||||||
2 => ChoiceCategory::Digit,
|
DIGITS_INDEX => ChoiceCategory::Digit,
|
||||||
3 => ChoiceCategory::SpecialSymbol,
|
SPECIAL_INDEX => ChoiceCategory::SpecialSymbol,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -93,49 +107,68 @@ fn is_menu_choice(current_category: &ChoiceCategory, page_index: u8) -> bool {
|
|||||||
|
|
||||||
struct ChoiceFactoryPassphrase {
|
struct ChoiceFactoryPassphrase {
|
||||||
current_category: ChoiceCategory,
|
current_category: ChoiceCategory,
|
||||||
|
/// Used to either show DELETE or CANCEL
|
||||||
|
is_empty: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChoiceFactoryPassphrase {
|
impl ChoiceFactoryPassphrase {
|
||||||
fn new(current_category: ChoiceCategory) -> Self {
|
fn new(current_category: ChoiceCategory, is_empty: bool) -> Self {
|
||||||
Self { current_category }
|
Self {
|
||||||
|
current_category,
|
||||||
|
is_empty,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// MENU choices with accept and cancel hold-to-confirm side buttons.
|
/// MENU choices with accept and cancel hold-to-confirm side buttons.
|
||||||
fn get_menu_item(&self, choice_index: u8) -> ChoiceItem {
|
fn get_menu_item(&self, choice_index: u8) -> ChoiceItem {
|
||||||
let choice = MENU[choice_index as usize];
|
let choice_index = choice_index as usize;
|
||||||
|
|
||||||
|
// More options for CANCEL/DELETE button
|
||||||
|
let choice = if choice_index == CANCEL_DELETE_INDEX {
|
||||||
|
if self.is_empty {
|
||||||
|
"CANCEL"
|
||||||
|
} else {
|
||||||
|
"DELETE"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MENU[choice_index]
|
||||||
|
};
|
||||||
|
|
||||||
let mut menu_item = ChoiceItem::new(
|
let mut menu_item = ChoiceItem::new(
|
||||||
String::<50>::from(choice),
|
String::<50>::from(choice),
|
||||||
ButtonLayout::default_three_icons(),
|
ButtonLayout::default_three_icons(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Including accept button on the left and cancel on the very right.
|
// Action buttons have different middle button text
|
||||||
// TODO: could have some icons instead of the shortcut text
|
if [CANCEL_DELETE_INDEX, SHOW_INDEX, ENTER_INDEX].contains(&(choice_index as usize)) {
|
||||||
if choice_index == 0 {
|
let confirm_btn = ButtonDetails::armed_text("CONFIRM".into());
|
||||||
menu_item.set_left_btn(Some(
|
menu_item.set_middle_btn(Some(confirm_btn));
|
||||||
ButtonDetails::text("ACC".into()).with_default_duration(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if choice_index == MENU.len() as u8 - 1 {
|
|
||||||
menu_item.set_right_btn(Some(
|
|
||||||
ButtonDetails::text("CAN".into()).with_default_duration(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Including icons for some items.
|
// Including icons for some items.
|
||||||
if choice_index == DELETE_INDEX as u8 {
|
if choice_index == CANCEL_DELETE_INDEX {
|
||||||
menu_item = menu_item.with_icon(Icon::new(theme::ICON_DELETE));
|
if self.is_empty {
|
||||||
} else if choice_index == SHOW_INDEX as u8 {
|
menu_item = menu_item.with_icon(Icon::new(theme::ICON_CANCEL));
|
||||||
|
} else {
|
||||||
|
menu_item = menu_item.with_icon(Icon::new(theme::ICON_DELETE));
|
||||||
|
}
|
||||||
|
} else if choice_index == SHOW_INDEX {
|
||||||
menu_item = menu_item.with_icon(Icon::new(theme::ICON_EYE));
|
menu_item = menu_item.with_icon(Icon::new(theme::ICON_EYE));
|
||||||
|
} else if choice_index == ENTER_INDEX {
|
||||||
|
menu_item = menu_item.with_icon(Icon::new(theme::ICON_TICK));
|
||||||
|
} else if choice_index == SPACE_INDEX {
|
||||||
|
menu_item = menu_item.with_icon(Icon::new(theme::ICON_SPACE));
|
||||||
}
|
}
|
||||||
|
|
||||||
menu_item
|
menu_item
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Character choices with a MENU choice at the end (visible from start) to
|
/// Character choices with a BACK to MENU choice at the end (visible from
|
||||||
/// return back
|
/// start) to return back
|
||||||
fn get_character_item(&self, choice_index: u8) -> ChoiceItem {
|
fn get_character_item(&self, choice_index: u8) -> ChoiceItem {
|
||||||
if is_menu_choice(&self.current_category, choice_index) {
|
if is_menu_choice(&self.current_category, choice_index) {
|
||||||
ChoiceItem::new("MENU", ButtonLayout::arrow_armed_arrow("RETURN".into()))
|
ChoiceItem::new("BACK", ButtonLayout::arrow_armed_arrow("RETURN".into()))
|
||||||
|
.with_icon(Icon::new(theme::ICON_ARROW_BACK_UP))
|
||||||
} else {
|
} else {
|
||||||
let ch = get_char(&self.current_category, choice_index);
|
let ch = get_char(&self.current_category, choice_index);
|
||||||
ChoiceItem::new(char_to_string::<1>(ch), ButtonLayout::default_three_icons())
|
ChoiceItem::new(char_to_string::<1>(ch), ButtonLayout::default_three_icons())
|
||||||
@ -173,9 +206,10 @@ pub struct PassphraseEntry {
|
|||||||
|
|
||||||
impl PassphraseEntry {
|
impl PassphraseEntry {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let menu_choices = ChoiceFactoryPassphrase::new(ChoiceCategory::Menu);
|
|
||||||
Self {
|
Self {
|
||||||
choice_page: ChoicePage::new(menu_choices),
|
choice_page: ChoicePage::new(ChoiceFactoryPassphrase::new(ChoiceCategory::Menu, true))
|
||||||
|
.with_carousel(true)
|
||||||
|
.with_initial_page_counter(LOWERCASE_INDEX as u8),
|
||||||
passphrase_dots: Child::new(ChangingTextLine::center_mono(String::new())),
|
passphrase_dots: Child::new(ChangingTextLine::center_mono(String::new())),
|
||||||
show_plain_passphrase: false,
|
show_plain_passphrase: false,
|
||||||
textbox: TextBox::empty(),
|
textbox: TextBox::empty(),
|
||||||
@ -187,6 +221,7 @@ impl PassphraseEntry {
|
|||||||
fn update_passphrase_dots(&mut self, ctx: &mut EventCtx) {
|
fn update_passphrase_dots(&mut self, ctx: &mut EventCtx) {
|
||||||
// TODO: when the passphrase is longer than fits the screen, we might show
|
// TODO: when the passphrase is longer than fits the screen, we might show
|
||||||
// ellipsis
|
// ellipsis
|
||||||
|
// TODO: unite this with PIN, which has the same issue
|
||||||
if self.show_plain_passphrase {
|
if self.show_plain_passphrase {
|
||||||
let passphrase = String::from(self.passphrase());
|
let passphrase = String::from(self.passphrase());
|
||||||
self.passphrase_dots.inner_mut().update_text(passphrase);
|
self.passphrase_dots.inner_mut().update_text(passphrase);
|
||||||
@ -210,15 +245,15 @@ impl PassphraseEntry {
|
|||||||
|
|
||||||
/// Displaying the MENU
|
/// Displaying the MENU
|
||||||
fn show_menu_page(&mut self, ctx: &mut EventCtx) {
|
fn show_menu_page(&mut self, ctx: &mut EventCtx) {
|
||||||
let menu_choices = ChoiceFactoryPassphrase::new(ChoiceCategory::Menu);
|
let menu_choices = ChoiceFactoryPassphrase::new(ChoiceCategory::Menu, self.is_empty());
|
||||||
self.choice_page.reset(ctx, menu_choices, Some(0), false);
|
|
||||||
// Going back to the last MENU position before showing the MENU
|
// Going back to the last MENU position before showing the MENU
|
||||||
self.choice_page.set_page_counter(ctx, self.menu_position);
|
self.choice_page
|
||||||
|
.reset(ctx, menu_choices, Some(self.menu_position), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Displaying the character category
|
/// Displaying the character category
|
||||||
fn show_category_page(&mut self, ctx: &mut EventCtx) {
|
fn show_category_page(&mut self, ctx: &mut EventCtx) {
|
||||||
let category_choices = ChoiceFactoryPassphrase::new(self.current_category.clone());
|
let category_choices = ChoiceFactoryPassphrase::new(self.current_category, self.is_empty());
|
||||||
self.choice_page.reset(ctx, category_choices, Some(0), true);
|
self.choice_page.reset(ctx, category_choices, Some(0), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,6 +261,10 @@ impl PassphraseEntry {
|
|||||||
self.textbox.content()
|
self.textbox.content()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
self.textbox.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
fn is_full(&self) -> bool {
|
fn is_full(&self) -> bool {
|
||||||
self.textbox.is_full()
|
self.textbox.is_full()
|
||||||
}
|
}
|
||||||
@ -249,36 +288,47 @@ impl Component for PassphraseEntry {
|
|||||||
self.update_passphrase_dots(ctx);
|
self.update_passphrase_dots(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
let msg = self.choice_page.event(ctx, event);
|
if let Some(ChoicePageMsg::Choice(page_counter)) = self.choice_page.event(ctx, event) {
|
||||||
|
// Event handling based on MENU vs CATEGORY
|
||||||
if self.current_category == ChoiceCategory::Menu {
|
if self.current_category == ChoiceCategory::Menu {
|
||||||
match msg {
|
|
||||||
// Going to new category, applying some action or returning the result
|
// Going to new category, applying some action or returning the result
|
||||||
Some(ChoicePageMsg::Choice(page_counter)) => match page_counter as usize {
|
match page_counter as usize {
|
||||||
DELETE_INDEX => {
|
CANCEL_DELETE_INDEX => {
|
||||||
self.delete_last_digit(ctx);
|
if self.is_empty() {
|
||||||
self.update_passphrase_dots(ctx);
|
return Some(PassphraseEntryMsg::Cancelled);
|
||||||
ctx.request_paint();
|
} else {
|
||||||
|
self.delete_last_digit(ctx);
|
||||||
|
self.update_passphrase_dots(ctx);
|
||||||
|
if self.is_empty() {
|
||||||
|
// Allowing for DELETE/CANCEL change
|
||||||
|
self.menu_position = CANCEL_DELETE_INDEX as u8;
|
||||||
|
self.show_menu_page(ctx);
|
||||||
|
}
|
||||||
|
ctx.request_paint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ENTER_INDEX => {
|
||||||
|
return Some(PassphraseEntryMsg::Confirmed);
|
||||||
}
|
}
|
||||||
SHOW_INDEX => {
|
SHOW_INDEX => {
|
||||||
self.show_plain_passphrase = true;
|
self.show_plain_passphrase = true;
|
||||||
self.update_passphrase_dots(ctx);
|
self.update_passphrase_dots(ctx);
|
||||||
ctx.request_paint();
|
ctx.request_paint();
|
||||||
}
|
}
|
||||||
|
SPACE_INDEX => {
|
||||||
|
self.append_char(ctx, ' ');
|
||||||
|
self.update_passphrase_dots(ctx);
|
||||||
|
ctx.request_paint();
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.menu_position = page_counter;
|
self.menu_position = page_counter;
|
||||||
self.current_category = get_category_from_menu(page_counter);
|
self.current_category = get_category_from_menu(page_counter);
|
||||||
self.show_category_page(ctx);
|
self.show_category_page(ctx);
|
||||||
ctx.request_paint();
|
ctx.request_paint();
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Some(ChoicePageMsg::LeftMost) => return Some(PassphraseEntryMsg::Confirmed),
|
} else {
|
||||||
Some(ChoicePageMsg::RightMost) => return Some(PassphraseEntryMsg::Cancelled),
|
// Coming back to MENU or adding new character
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Coming back to MENU or adding new character
|
|
||||||
if let Some(ChoicePageMsg::Choice(page_counter)) = msg {
|
|
||||||
if is_menu_choice(&self.current_category, page_counter) {
|
if is_menu_choice(&self.current_category, page_counter) {
|
||||||
self.current_category = ChoiceCategory::Menu;
|
self.current_category = ChoiceCategory::Menu;
|
||||||
self.show_menu_page(ctx);
|
self.show_menu_page(ctx);
|
||||||
@ -330,7 +380,7 @@ impl crate::trace::Trace for PassphraseEntry {
|
|||||||
let current_index = self.choice_page.page_index() as usize;
|
let current_index = self.choice_page.page_index() as usize;
|
||||||
match &self.current_category {
|
match &self.current_category {
|
||||||
ChoiceCategory::Menu => match current_index {
|
ChoiceCategory::Menu => match current_index {
|
||||||
DELETE_INDEX => ButtonAction::Action("Del last char").string(),
|
CANCEL_DELETE_INDEX => ButtonAction::Action("Del last char").string(),
|
||||||
SHOW_INDEX => ButtonAction::Action("Show pass").string(),
|
SHOW_INDEX => ButtonAction::Action("Show pass").string(),
|
||||||
_ => ButtonAction::select_item(MENU[current_index]),
|
_ => ButtonAction::select_item(MENU[current_index]),
|
||||||
},
|
},
|
||||||
|
@ -852,7 +852,7 @@ extern "C" fn new_request_passphrase(n_args: usize, args: *const Obj, kwargs: *m
|
|||||||
let prompt: StrBuffer = kwargs.get(Qstr::MP_QSTR_prompt)?.try_into()?;
|
let prompt: StrBuffer = kwargs.get(Qstr::MP_QSTR_prompt)?.try_into()?;
|
||||||
let _max_len: u8 = kwargs.get(Qstr::MP_QSTR_max_len)?.try_into()?;
|
let _max_len: u8 = kwargs.get(Qstr::MP_QSTR_max_len)?.try_into()?;
|
||||||
|
|
||||||
let obj = LayoutObj::new(Frame::new(prompt, PassphraseEntry::new()))?;
|
let obj = LayoutObj::new(Frame::new(prompt, PassphraseEntry::new()).with_title_centered())?;
|
||||||
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) }
|
||||||
|
BIN
core/embed/rust/src/ui/model_tr/res/arrow_back_up.toif
Normal file
BIN
core/embed/rust/src/ui/model_tr/res/arrow_back_up.toif
Normal file
Binary file not shown.
BIN
core/embed/rust/src/ui/model_tr/res/space.toif
Normal file
BIN
core/embed/rust/src/ui/model_tr/res/space.toif
Normal file
Binary file not shown.
@ -42,6 +42,10 @@ pub const ICON_ARROW_UP: IconAndName =
|
|||||||
IconAndName::new(include_res!("model_tr/res/arrow_up.toif"), "arrow_up"); // 10*6
|
IconAndName::new(include_res!("model_tr/res/arrow_up.toif"), "arrow_up"); // 10*6
|
||||||
pub const ICON_ARROW_DOWN: IconAndName =
|
pub const ICON_ARROW_DOWN: IconAndName =
|
||||||
IconAndName::new(include_res!("model_tr/res/arrow_down.toif"), "arrow_down"); // 10*6
|
IconAndName::new(include_res!("model_tr/res/arrow_down.toif"), "arrow_down"); // 10*6
|
||||||
|
pub const ICON_ARROW_BACK_UP: IconAndName = IconAndName::new(
|
||||||
|
include_res!("model_tr/res/arrow_back_up.toif"),
|
||||||
|
"arrow_back_up",
|
||||||
|
); // 8*8
|
||||||
pub const ICON_BIN: IconAndName = IconAndName::new(include_res!("model_tr/res/bin.toif"), "bin"); // 10*10
|
pub const ICON_BIN: IconAndName = IconAndName::new(include_res!("model_tr/res/bin.toif"), "bin"); // 10*10
|
||||||
pub const ICON_CANCEL: IconAndName = IconAndName::new(
|
pub const ICON_CANCEL: IconAndName = IconAndName::new(
|
||||||
include_res!("model_tr/res/cancel_no_outline.toif"),
|
include_res!("model_tr/res/cancel_no_outline.toif"),
|
||||||
@ -56,9 +60,11 @@ pub const ICON_NEXT_PAGE: IconAndName =
|
|||||||
IconAndName::new(include_res!("model_tr/res/next_page.toif"), "next_page"); // 10*8
|
IconAndName::new(include_res!("model_tr/res/next_page.toif"), "next_page"); // 10*8
|
||||||
pub const ICON_PREV_PAGE: IconAndName =
|
pub const ICON_PREV_PAGE: IconAndName =
|
||||||
IconAndName::new(include_res!("model_tr/res/prev_page.toif"), "prev_page"); // 8*10
|
IconAndName::new(include_res!("model_tr/res/prev_page.toif"), "prev_page"); // 8*10
|
||||||
|
pub const ICON_SPACE: IconAndName =
|
||||||
|
IconAndName::new(include_res!("model_tr/res/space.toif"), "space"); // 12*3
|
||||||
pub const ICON_SUCCESS: IconAndName =
|
pub const ICON_SUCCESS: IconAndName =
|
||||||
IconAndName::new(include_res!("model_tr/res/success.toif"), "success");
|
IconAndName::new(include_res!("model_tr/res/success.toif"), "success");
|
||||||
pub const ICON_TICK: IconAndName = IconAndName::new(include_res!("model_tr/res/tick.toif"), "tick"); // 10*10
|
pub const ICON_TICK: IconAndName = IconAndName::new(include_res!("model_tr/res/tick.toif"), "tick"); // 8*6
|
||||||
pub const ICON_TICK_FAT: IconAndName =
|
pub const ICON_TICK_FAT: IconAndName =
|
||||||
IconAndName::new(include_res!("model_tr/res/tick_fat.toif"), "tick_fat"); // 8*6
|
IconAndName::new(include_res!("model_tr/res/tick_fat.toif"), "tick_fat"); // 8*6
|
||||||
pub const ICON_WARNING: IconAndName =
|
pub const ICON_WARNING: IconAndName =
|
||||||
|
@ -1258,7 +1258,7 @@ async def request_passphrase_on_device(ctx: GenericContext, max_len: int) -> str
|
|||||||
result = await ctx.wait(
|
result = await ctx.wait(
|
||||||
RustLayout(
|
RustLayout(
|
||||||
trezorui2.request_passphrase(
|
trezorui2.request_passphrase(
|
||||||
prompt="Enter passphrase",
|
prompt="ENTER PASSPHRASE",
|
||||||
max_len=max_len,
|
max_len=max_len,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user