mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-07-15 11:08:08 +00:00
fix(core/ui): style update: mnemonic keyboards
[no changelog]
This commit is contained in:
parent
f91ea05449
commit
e16a37b0cf
@ -3,9 +3,8 @@ use crate::ui::{
|
||||
component::{
|
||||
base::ComponentExt, label::Label, text::TextStyle, Child, Component, Event, EventCtx,
|
||||
},
|
||||
display::{self, toif::Icon, Color},
|
||||
display::{self, Color, Font},
|
||||
geometry::{Alignment, Insets, Offset, Rect},
|
||||
util::icon_text_center,
|
||||
};
|
||||
|
||||
pub struct Frame<T, U> {
|
||||
@ -116,7 +115,6 @@ where
|
||||
|
||||
pub struct NotificationFrame<T, U> {
|
||||
area: Rect,
|
||||
icon: Icon,
|
||||
title: U,
|
||||
content: Child<T>,
|
||||
}
|
||||
@ -128,13 +126,10 @@ where
|
||||
{
|
||||
const HEIGHT: i16 = 36;
|
||||
const COLOR: Color = theme::YELLOW;
|
||||
const TEXT_OFFSET: Offset = Offset::new(1, -2);
|
||||
const ICON_SPACE: i16 = 8;
|
||||
const BORDER: i16 = 6;
|
||||
|
||||
pub fn new(icon: Icon, title: U, content: T) -> Self {
|
||||
pub fn new(title: U, content: T) -> Self {
|
||||
Self {
|
||||
icon,
|
||||
title,
|
||||
area: Rect::zero(),
|
||||
content: Child::new(content),
|
||||
@ -145,22 +140,18 @@ where
|
||||
self.content.inner()
|
||||
}
|
||||
|
||||
pub fn paint_notification(area: Rect, icon: Icon, title: &str, color: Color) {
|
||||
pub fn paint_notification(area: Rect, title: &str, color: Color) {
|
||||
let (area, _) = area
|
||||
.inset(Insets::uniform(Self::BORDER))
|
||||
.split_top(Self::HEIGHT);
|
||||
let style = TextStyle {
|
||||
background_color: color,
|
||||
..theme::TEXT_BOLD
|
||||
};
|
||||
let font = Font::BOLD;
|
||||
display::rect_fill_rounded(area, color, theme::BG, 2);
|
||||
icon_text_center(
|
||||
area.center(),
|
||||
icon,
|
||||
Self::ICON_SPACE,
|
||||
display::text_center(
|
||||
area.center() + Offset::y((font.text_max_height() - font.text_baseline()) / 2),
|
||||
title,
|
||||
style,
|
||||
Self::TEXT_OFFSET,
|
||||
Font::BOLD,
|
||||
theme::FG,
|
||||
color,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -184,7 +175,7 @@ where
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
Self::paint_notification(self.area, self.icon, self.title.as_ref(), Self::COLOR);
|
||||
Self::paint_notification(self.area, self.title.as_ref(), Self::COLOR);
|
||||
self.content.paint();
|
||||
}
|
||||
|
||||
|
@ -215,20 +215,21 @@ impl Bip39Input {
|
||||
{
|
||||
// Confirm button.
|
||||
self.button.enable(ctx);
|
||||
self.button.set_stylesheet(ctx, theme::button_confirm());
|
||||
self.button.set_stylesheet(ctx, theme::button_pin_confirm());
|
||||
self.button
|
||||
.set_content(ctx, ButtonContent::Icon(Icon::new(theme::ICON_CONFIRM)));
|
||||
.set_content(ctx, ButtonContent::Icon(Icon::new(theme::ICON_LIST_CHECK)));
|
||||
} else {
|
||||
// Auto-complete button.
|
||||
self.button.enable(ctx);
|
||||
self.button.set_stylesheet(ctx, theme::button_default());
|
||||
self.button
|
||||
.set_stylesheet(ctx, theme::button_pin_autocomplete());
|
||||
self.button
|
||||
.set_content(ctx, ButtonContent::Icon(Icon::new(theme::ICON_CLICK)));
|
||||
}
|
||||
} else {
|
||||
// Disabled button.
|
||||
self.button.disable(ctx);
|
||||
self.button.set_stylesheet(ctx, theme::button_default());
|
||||
self.button.set_stylesheet(ctx, theme::button_pin());
|
||||
self.button.set_content(ctx, ButtonContent::Text(""));
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ where
|
||||
Icon::new(theme::ICON_BACK),
|
||||
Offset::new(30, 17),
|
||||
)
|
||||
.styled(theme::button_clear())
|
||||
.styled(theme::button_reset())
|
||||
.with_long_press(theme::ERASE_HOLD_DURATION),
|
||||
)),
|
||||
input: Child::new(Maybe::hidden(theme::BG, input)),
|
||||
@ -96,8 +96,10 @@ where
|
||||
type Msg = MnemonicKeyboardMsg;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
let grid =
|
||||
Grid::new(bounds.inset(theme::borders()), 4, 3).with_spacing(theme::KEYBOARD_SPACING);
|
||||
let (_, bounds) = bounds
|
||||
.inset(theme::borders())
|
||||
.split_bottom(4 * theme::MNEMONIC_BUTTON_HEIGHT + 3 * theme::KEYBOARD_SPACING);
|
||||
let grid = Grid::new(bounds, 4, 3).with_spacing(theme::KEYBOARD_SPACING);
|
||||
let back_area = grid.row_col(0, 0);
|
||||
let input_area = grid.row_col(0, 1).union(grid.row_col(0, 3));
|
||||
|
||||
|
@ -2,13 +2,10 @@ use crate::ui::{
|
||||
component::{base::ComponentExt, Child, Component, Event, EventCtx, Never},
|
||||
display,
|
||||
display::toif::Icon,
|
||||
geometry::{Grid, Insets, Offset, Rect},
|
||||
geometry::{Grid, Offset, Rect},
|
||||
model_tt::component::{
|
||||
button::{Button, ButtonContent, ButtonMsg},
|
||||
keyboard::common::{
|
||||
paint_pending_marker, MultiTapKeyboard, TextBox, HEADER_HEIGHT, HEADER_PADDING_BOTTOM,
|
||||
HEADER_PADDING_SIDE,
|
||||
},
|
||||
keyboard::common::{paint_pending_marker, MultiTapKeyboard, TextBox},
|
||||
swipe::{Swipe, SwipeDirection},
|
||||
theme, ScrollBar,
|
||||
},
|
||||
@ -41,6 +38,7 @@ const KEYBOARD: [[&str; KEY_COUNT]; PAGE_COUNT] = [
|
||||
];
|
||||
|
||||
const MAX_LENGTH: usize = 50;
|
||||
const INPUT_AREA_HEIGHT: i16 = ScrollBar::DOT_SIZE + 9;
|
||||
|
||||
impl PassphraseKeyboard {
|
||||
pub fn new() -> Self {
|
||||
@ -59,8 +57,9 @@ impl PassphraseKeyboard {
|
||||
.initially_enabled(false)
|
||||
.with_long_press(theme::ERASE_HOLD_DURATION)
|
||||
.into_child(),
|
||||
keys: KEYBOARD[STARTING_PAGE]
|
||||
.map(|text| Child::new(Button::new(Self::key_content(text)))),
|
||||
keys: KEYBOARD[STARTING_PAGE].map(|text| {
|
||||
Child::new(Button::new(Self::key_content(text)).styled(theme::button_pin()))
|
||||
}),
|
||||
scrollbar: ScrollBar::horizontal(),
|
||||
fade: false,
|
||||
}
|
||||
@ -152,14 +151,13 @@ impl Component for PassphraseKeyboard {
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
let bounds = bounds.inset(theme::borders());
|
||||
|
||||
let (input_area, key_grid_area) = bounds.split_top(HEADER_HEIGHT + HEADER_PADDING_BOTTOM);
|
||||
let (input_area, key_grid_area) =
|
||||
bounds.split_bottom(4 * theme::PIN_BUTTON_HEIGHT + 3 * theme::BUTTON_SPACING);
|
||||
|
||||
let (input_area, scroll_area) =
|
||||
input_area.split_bottom(ScrollBar::DOT_SIZE + theme::KEYBOARD_SPACING);
|
||||
let (input_area, scroll_area) = input_area.split_bottom(INPUT_AREA_HEIGHT);
|
||||
let (scroll_area, _) = scroll_area.split_top(ScrollBar::DOT_SIZE);
|
||||
let input_area = input_area.inset(Insets::sides(HEADER_PADDING_SIDE));
|
||||
|
||||
let key_grid = Grid::new(key_grid_area, 4, 3).with_spacing(theme::KEYBOARD_SPACING);
|
||||
let key_grid = Grid::new(key_grid_area, 4, 3).with_spacing(theme::BUTTON_SPACING);
|
||||
let confirm_btn_area = key_grid.cell(11);
|
||||
let back_btn_area = key_grid.cell(9);
|
||||
|
||||
|
@ -59,8 +59,8 @@ where
|
||||
T: AsRef<str>,
|
||||
{
|
||||
// Label position fine-tuning.
|
||||
const MAJOR_OFF: Offset = Offset::y(-2);
|
||||
const MINOR_OFF: Offset = Offset::y(-1);
|
||||
const MAJOR_OFF: Offset = Offset::y(11);
|
||||
const MINOR_OFF: Offset = Offset::y(11);
|
||||
|
||||
pub fn new(
|
||||
major_prompt: T,
|
||||
@ -165,14 +165,14 @@ where
|
||||
// Prompts and PIN dots display.
|
||||
let (header, keypad) = bounds
|
||||
.inset(borders_no_top)
|
||||
.split_top(theme::borders().top + HEADER_HEIGHT + HEADER_PADDING_BOTTOM);
|
||||
.split_bottom(4 * theme::PIN_BUTTON_HEIGHT + 3 * theme::BUTTON_SPACING);
|
||||
let prompt = header.inset(HEADER_PADDING);
|
||||
// the inset -3 is a workaround for long text in "re-enter wipe code"
|
||||
let major_area = prompt.translate(Self::MAJOR_OFF).inset(Insets::right(-3));
|
||||
let minor_area = prompt.translate(Self::MINOR_OFF);
|
||||
|
||||
// Control buttons.
|
||||
let grid = Grid::new(keypad, 4, 3).with_spacing(theme::KEYBOARD_SPACING);
|
||||
let grid = Grid::new(keypad, 4, 3).with_spacing(theme::BUTTON_SPACING);
|
||||
|
||||
// Prompts and PIN dots display.
|
||||
self.textbox_pad.place(header);
|
||||
|
@ -224,13 +224,13 @@ impl Slip39Input {
|
||||
if self.final_word.is_some() {
|
||||
// Confirm button.
|
||||
self.button.enable(ctx);
|
||||
self.button.set_stylesheet(ctx, theme::button_confirm());
|
||||
self.button.set_stylesheet(ctx, theme::button_pin_confirm());
|
||||
self.button
|
||||
.set_content(ctx, ButtonContent::Icon(Icon::new(theme::ICON_CONFIRM)));
|
||||
.set_content(ctx, ButtonContent::Icon(Icon::new(theme::ICON_LIST_CHECK)));
|
||||
} else {
|
||||
// Disabled button.
|
||||
self.button.disable(ctx);
|
||||
self.button.set_stylesheet(ctx, theme::button_default());
|
||||
self.button.set_stylesheet(ctx, theme::button_pin());
|
||||
self.button.set_content(ctx, ButtonContent::Text(""));
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ pub enum SelectWordCountMsg {
|
||||
impl SelectWordCount {
|
||||
pub fn new() -> Self {
|
||||
SelectWordCount {
|
||||
button: LABELS.map(Button::with_text),
|
||||
button: LABELS.map(|t| Button::with_text(t).styled(theme::button_pin())),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -31,7 +31,7 @@ impl Component for SelectWordCount {
|
||||
type Msg = SelectWordCountMsg;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
let (_, bounds) = bounds.split_bottom(theme::button_rows(2));
|
||||
let (_, bounds) = bounds.split_bottom(2 * theme::BUTTON_HEIGHT + theme::BUTTON_SPACING);
|
||||
let grid = Grid::new(bounds, 2, 6).with_spacing(theme::BUTTON_SPACING);
|
||||
for (btn, (x, y)) in self.button.iter_mut().zip(CELLS) {
|
||||
btn.place(grid.cells(GridCellSpan {
|
||||
|
@ -87,13 +87,12 @@ where
|
||||
theme::CONTENT_BORDER,
|
||||
));
|
||||
|
||||
let grid = Grid::new(button_area, 1, 3).with_spacing(theme::KEYBOARD_SPACING);
|
||||
let grid = Grid::new(button_area, 1, 2).with_spacing(theme::KEYBOARD_SPACING);
|
||||
self.input.place(input_area);
|
||||
self.paragraphs.place(content_area);
|
||||
self.paragraphs_pad.place(content_area);
|
||||
self.info_button.place(grid.row_col(0, 0));
|
||||
self.confirm_button
|
||||
.place(grid.row_col(0, 1).union(grid.row_col(0, 2)));
|
||||
self.confirm_button.place(grid.row_col(0, 1));
|
||||
bounds
|
||||
}
|
||||
|
||||
|
@ -588,15 +588,16 @@ extern "C" fn new_confirm_reset_device(n_args: usize, args: *const Obj, kwargs:
|
||||
let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||
let button: StrBuffer = kwargs.get(Qstr::MP_QSTR_button)?.try_into()?;
|
||||
|
||||
let paragraphs = Paragraphs::new(Paragraph::new(
|
||||
&theme::TEXT_NORMAL,
|
||||
StrBuffer::from("By continuing you agree\nto Trezor Company's\nterms and conditions."),
|
||||
));
|
||||
let url = FormattedText::new(
|
||||
theme::TEXT_NORMAL,
|
||||
theme::FORMATTED,
|
||||
"More info at {demibold}trezor.io/tos",
|
||||
);
|
||||
let paragraphs = Paragraphs::new([
|
||||
Paragraph::new(
|
||||
&theme::TEXT_NORMAL,
|
||||
StrBuffer::from(
|
||||
"By continuing you agree\nto Trezor Company's\nterms and conditions.\r",
|
||||
),
|
||||
),
|
||||
Paragraph::new(&theme::TEXT_NORMAL, StrBuffer::from("More info at")),
|
||||
Paragraph::new(&theme::TEXT_DEMIBOLD, StrBuffer::from("trezor.io/tos")),
|
||||
]);
|
||||
let buttons = Button::cancel_confirm(
|
||||
Button::with_icon(Icon::new(theme::ICON_CANCEL)),
|
||||
Button::with_text(button).styled(theme::button_confirm()),
|
||||
@ -606,15 +607,7 @@ extern "C" fn new_confirm_reset_device(n_args: usize, args: *const Obj, kwargs:
|
||||
Frame::left_aligned(
|
||||
theme::label_title(),
|
||||
title,
|
||||
Dialog::new(
|
||||
(
|
||||
GridPlaced::new(paragraphs)
|
||||
.with_grid(3, 1)
|
||||
.with_from_to((0, 0), (1, 0)),
|
||||
GridPlaced::new(url).with_grid(3, 1).with_row_col(2, 0),
|
||||
),
|
||||
buttons,
|
||||
),
|
||||
Dialog::new(paragraphs, buttons),
|
||||
)
|
||||
.with_border(theme::borders()),
|
||||
)?;
|
||||
@ -1299,7 +1292,7 @@ extern "C" fn new_confirm_recovery(n_args: usize, args: *const Obj, kwargs: *mut
|
||||
let info_button: bool = kwargs.get_or(Qstr::MP_QSTR_info_button, false).unwrap();
|
||||
|
||||
let paragraphs = Paragraphs::new([
|
||||
Paragraph::new(&theme::TEXT_BOLD, title).centered(),
|
||||
Paragraph::new(&theme::TEXT_DEMIBOLD, title).centered(),
|
||||
Paragraph::new(&theme::TEXT_NORMAL_OFF_WHITE, description).centered(),
|
||||
])
|
||||
.with_spacing(theme::RECOVERY_SPACING);
|
||||
@ -1312,7 +1305,6 @@ extern "C" fn new_confirm_recovery(n_args: usize, args: *const Obj, kwargs: *mut
|
||||
|
||||
let obj = if info_button {
|
||||
LayoutObj::new(NotificationFrame::new(
|
||||
Icon::new(theme::ICON_WARN),
|
||||
notification,
|
||||
Dialog::new(
|
||||
paragraphs,
|
||||
@ -1321,7 +1313,6 @@ extern "C" fn new_confirm_recovery(n_args: usize, args: *const Obj, kwargs: *mut
|
||||
))?
|
||||
} else {
|
||||
LayoutObj::new(NotificationFrame::new(
|
||||
Icon::new(theme::ICON_WARN),
|
||||
notification,
|
||||
Dialog::new(paragraphs, Button::cancel_confirm_text(None, Some(button))),
|
||||
))?
|
||||
@ -1341,11 +1332,15 @@ extern "C" fn new_select_word_count(n_args: usize, args: *const Obj, kwargs: *mu
|
||||
let title = if dry_run {
|
||||
"SEED CHECK"
|
||||
} else {
|
||||
"RECOVERY MODE"
|
||||
"WALLET RECOVERY"
|
||||
};
|
||||
|
||||
let paragraphs = Paragraphs::new(
|
||||
Paragraph::new(&theme::TEXT_BOLD, StrBuffer::from("Number of words?")).centered(),
|
||||
Paragraph::new(
|
||||
&theme::TEXT_DEMIBOLD,
|
||||
StrBuffer::from("Select number of words in your recovery seed."),
|
||||
)
|
||||
.centered(),
|
||||
);
|
||||
|
||||
let obj = LayoutObj::new(
|
||||
|
@ -384,6 +384,70 @@ pub const fn button_pin() -> ButtonStyleSheet {
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn button_pin_confirm() -> ButtonStyleSheet {
|
||||
ButtonStyleSheet {
|
||||
normal: &ButtonStyle {
|
||||
font: Font::MONO,
|
||||
text_color: FG,
|
||||
button_color: GREEN,
|
||||
background_color: BG,
|
||||
border_color: BG,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
active: &ButtonStyle {
|
||||
font: Font::MONO,
|
||||
text_color: FG,
|
||||
button_color: GREY_DARK,
|
||||
background_color: BG,
|
||||
border_color: FG,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
disabled: &ButtonStyle {
|
||||
font: Font::MONO,
|
||||
text_color: GREY_LIGHT,
|
||||
button_color: GREEN,
|
||||
background_color: BG,
|
||||
border_color: BG,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn button_pin_autocomplete() -> ButtonStyleSheet {
|
||||
ButtonStyleSheet {
|
||||
normal: &ButtonStyle {
|
||||
font: Font::MONO,
|
||||
text_color: FG,
|
||||
button_color: BG,
|
||||
background_color: BG,
|
||||
border_color: BG,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
active: &ButtonStyle {
|
||||
font: Font::MONO,
|
||||
text_color: FG,
|
||||
button_color: GREY_DARK,
|
||||
background_color: BG,
|
||||
border_color: FG,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
disabled: &ButtonStyle {
|
||||
font: Font::MONO,
|
||||
text_color: GREY_LIGHT,
|
||||
button_color: BG,
|
||||
background_color: BG,
|
||||
border_color: BG,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn button_counter() -> ButtonStyleSheet {
|
||||
ButtonStyleSheet {
|
||||
normal: &ButtonStyle {
|
||||
|
@ -42,7 +42,7 @@ async def request_word_count(ctx: GenericContext, dry_run: bool) -> int:
|
||||
async def request_word(
|
||||
ctx: GenericContext, word_index: int, word_count: int, is_slip39: bool
|
||||
) -> str:
|
||||
prompt = f"Type word {word_index + 1} of {word_count}:"
|
||||
prompt = f"Type word {word_index + 1} of {word_count}"
|
||||
if is_slip39:
|
||||
keyboard = RustLayout(trezorui2.request_slip39(prompt=prompt))
|
||||
else:
|
||||
|
@ -41,7 +41,7 @@ def select_number_of_words(
|
||||
assert layout.text == "WordSelector"
|
||||
else:
|
||||
# Two title options
|
||||
assert layout.get_title() in ("SEED CHECK", "RECOVERY MODE")
|
||||
assert layout.get_title() in ("SEED CHECK", "WALLET RECOVERY")
|
||||
|
||||
# click the number
|
||||
word_option_offset = 6
|
||||
|
@ -53,7 +53,7 @@ def test_abort(emulator: Emulator):
|
||||
assert layout.get_title() == "WALLET RECOVERY"
|
||||
|
||||
layout = debug.click(buttons.OK, wait=True)
|
||||
assert "Select number of words" in layout.text
|
||||
assert "Select number of words" in layout.get_content()
|
||||
|
||||
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 number of words" in layout.get_content()
|
||||
layout = debug.click(buttons.CANCEL, wait=True)
|
||||
|
||||
assert layout.get_title() == "ABORT RECOVERY"
|
||||
|
Loading…
Reference in New Issue
Block a user