From 51fb99d79292c3abef7ac82f640e5175f8e7c100 Mon Sep 17 00:00:00 2001 From: grdddj Date: Tue, 5 Mar 2024 10:46:47 +0100 Subject: [PATCH] feat(core): create new design for PIN entry --- .../model_mercury/component/keyboard/pin.rs | 62 ++++++------ .../rust/src/ui/model_mercury/theme/mod.rs | 98 ++++++++++++++++--- .../rust/src/ui/model_tr/component/loader.rs | 9 +- 3 files changed, 117 insertions(+), 52 deletions(-) diff --git a/core/embed/rust/src/ui/model_mercury/component/keyboard/pin.rs b/core/embed/rust/src/ui/model_mercury/component/keyboard/pin.rs index ee1b05d43..c34ad3f10 100644 --- a/core/embed/rust/src/ui/model_mercury/component/keyboard/pin.rs +++ b/core/embed/rust/src/ui/model_mercury/component/keyboard/pin.rs @@ -13,11 +13,13 @@ use crate::{ event::TouchEvent, geometry::{Alignment, Alignment2D, Grid, Insets, Offset, Rect}, model_mercury::component::{ - button::{Button, ButtonContent, ButtonMsg, ButtonMsg::Clicked}, + button::{ + Button, ButtonContent, + ButtonMsg::{self, Clicked}, + }, theme, }, - shape, - shape::Renderer, + shape::{self, Renderer}, }, }; @@ -31,11 +33,11 @@ const MAX_VISIBLE_DOTS: usize = 14; const MAX_VISIBLE_DIGITS: usize = 16; const DIGIT_COUNT: usize = 10; // 0..10 -const HEADER_PADDING_SIDE: i16 = 5; -const HEADER_PADDING_BOTTOM: i16 = 12; +const HEADER_PADDING_SIDE: i16 = 2; +const HEADER_PADDING_BOTTOM: i16 = 2; const HEADER_PADDING: Insets = Insets::new( - theme::borders().top, + 0, HEADER_PADDING_SIDE, HEADER_PADDING_BOTTOM, HEADER_PADDING_SIDE, @@ -60,8 +62,8 @@ where T: AsRef, { // Label position fine-tuning. - const MAJOR_OFF: Offset = Offset::y(11); - const MINOR_OFF: Offset = Offset::y(11); + const MAJOR_OFF: Offset = Offset::y(0); + const MINOR_OFF: Offset = Offset::y(0); pub fn new( major_prompt: T, @@ -70,17 +72,13 @@ where allow_cancel: bool, ) -> Self { // Control buttons. - let erase_btn = Button::with_icon_blend( - theme::IMAGE_BG_BACK_BTN, - theme::ICON_BACK, - Offset::new(30, 12), - ) - .styled(theme::button_reset()) - .with_long_press(theme::ERASE_HOLD_DURATION) - .initially_enabled(false); + let erase_btn = Button::with_icon(theme::ICON_DELETE) + .styled(theme::button_pin_erase()) + .with_long_press(theme::ERASE_HOLD_DURATION) + .initially_enabled(false); let erase_btn = Maybe::hidden(theme::BG, erase_btn).into_child(); - let cancel_btn = Button::with_icon(theme::ICON_CANCEL).styled(theme::button_cancel()); + let cancel_btn = Button::with_icon(theme::ICON_CANCEL).styled(theme::button_pin_cancel()); let cancel_btn = Maybe::new(theme::BG, cancel_btn, allow_cancel).into_child(); Self { @@ -96,7 +94,7 @@ where erase_btn, cancel_btn, confirm_btn: Button::with_icon(theme::ICON_CONFIRM) - .styled(theme::button_confirm()) + .styled(theme::button_pin_confirm()) .initially_enabled(false) .into_child(), digit_btns: Self::generate_digit_buttons(), @@ -155,23 +153,16 @@ where type Msg = PinKeyboardMsg; fn place(&mut self, bounds: Rect) -> Rect { - // Ignore the top padding for now, we need it to reliably register textbox touch - // events. - let borders_no_top = Insets { - top: 0, - ..theme::borders() - }; // Prompts and PIN dots display. - let (header, keypad) = bounds - .inset(borders_no_top) - .split_bottom(4 * theme::PIN_BUTTON_HEIGHT + 3 * theme::BUTTON_SPACING); + let (header, keypad) = + bounds.split_bottom(4 * theme::PIN_BUTTON_HEIGHT + 3 * theme::PIN_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::BUTTON_SPACING); + let grid = Grid::new(keypad, 4, 3).with_spacing(theme::PIN_BUTTON_SPACING); // Prompts and PIN dots display. self.textbox_pad.place(header); @@ -272,6 +263,7 @@ where fn render(&mut self, target: &mut impl Renderer) { self.erase_btn.render(target); self.textbox_pad.render(target); + if self.textbox.inner().is_empty() { if let Some(ref mut w) = self.major_warning { w.render(target); @@ -283,7 +275,12 @@ where } else { self.textbox.render(target); } - self.confirm_btn.render(target); + + // Painting the confirm only if there is already a pin + if !self.textbox.inner().is_empty() { + self.confirm_btn.render(target); + } + for btn in &mut self.digit_btns { btn.render(target); } @@ -390,13 +387,14 @@ impl PinDots { } fn render_digits(&self, area: Rect, target: &mut impl Renderer) { + let left = area.left_center() + Offset::y(Font::MONO.text_height() / 2); let center = area.center() + Offset::y(Font::MONO.text_height() / 2); let right = center + Offset::x(Font::MONO.text_width("0") * (MAX_VISIBLE_DOTS as i16) / 2); let digits = self.digits.len(); if digits <= MAX_VISIBLE_DOTS { - shape::Text::new(center, &self.digits) - .with_align(Alignment::Center) + shape::Text::new(left, &self.digits) + .with_align(Alignment::Start) .with_font(Font::MONO) .with_fg(self.style.text_color) .render(target); @@ -456,7 +454,7 @@ impl PinDots { fn render_dots(&self, area: Rect, target: &mut impl Renderer) { // let mut cursor = self.size().snap(area.left_center(), Alignment2D::CENTER); - let cursor = area.bottom_left(); + let mut cursor = area.bottom_left(); let digits = self.digits.len(); let dots_visible = digits.min(MAX_VISIBLE_DOTS); diff --git a/core/embed/rust/src/ui/model_mercury/theme/mod.rs b/core/embed/rust/src/ui/model_mercury/theme/mod.rs index cd1251e21..fa5315b58 100644 --- a/core/embed/rust/src/ui/model_mercury/theme/mod.rs +++ b/core/embed/rust/src/ui/model_mercury/theme/mod.rs @@ -43,6 +43,7 @@ pub const GREY_LIGHT: Color = Color::rgb(0x90, 0x90, 0x90); // secondary text pub const GREY_MEDIUM: Color = Color::rgb(0x4F, 0x4F, 0x4F); // button pressed pub const GREY_DARK: Color = Color::rgb(0x35, 0x35, 0x35); // button pub const VIOLET: Color = Color::rgb(0x95, 0x00, 0xCA); +pub const PIN_BUTTON_COLOR: Color = Color::rgb(0x16, 0x1F, 0x24); pub const FATAL_ERROR_COLOR: Color = Color::rgb(0xE7, 0x0E, 0x0E); pub const FATAL_ERROR_HIGHLIGHT_COLOR: Color = Color::rgb(0xFF, 0x41, 0x41); @@ -373,10 +374,10 @@ pub const fn button_pin() -> ButtonStyleSheet { normal: &ButtonStyle { font: Font::MONO, text_color: FG, - button_color: GREY_DARK, + button_color: PIN_BUTTON_COLOR, background_color: BG, border_color: BG, - border_radius: RADIUS, + border_radius: 0, border_width: 0, }, active: &ButtonStyle { @@ -385,7 +386,7 @@ pub const fn button_pin() -> ButtonStyleSheet { button_color: GREY_MEDIUM, background_color: BG, border_color: FG, - border_radius: RADIUS, + border_radius: 0, border_width: 0, }, disabled: &ButtonStyle { @@ -394,39 +395,103 @@ pub const fn button_pin() -> ButtonStyleSheet { button_color: BG, // so there is no "button" itself, just the text background_color: BG, border_color: BG, - border_radius: RADIUS, + border_radius: 0, border_width: 0, }, } } -pub const fn button_pin_confirm() -> ButtonStyleSheet { +pub const fn button_pin_cancel() -> ButtonStyleSheet { ButtonStyleSheet { normal: &ButtonStyle { - font: Font::MONO, - text_color: FG, - button_color: GREEN, + font: Font::BOLD, + text_color: RED, + button_color: BG, background_color: BG, border_color: BG, - border_radius: RADIUS, + border_radius: 0, border_width: 0, }, active: &ButtonStyle { - font: Font::MONO, + font: Font::BOLD, + text_color: RED, + button_color: BG, + background_color: BG, + border_color: FG, + border_radius: 0, + border_width: 0, + }, + disabled: &ButtonStyle { + font: Font::BOLD, + text_color: GREY_LIGHT, + button_color: BG, + background_color: BG, + border_color: BG, + border_radius: 0, + border_width: 0, + }, + } +} + +pub const fn button_pin_erase() -> ButtonStyleSheet { + ButtonStyleSheet { + normal: &ButtonStyle { + font: Font::BOLD, + text_color: GREY_LIGHT, + button_color: BG, + background_color: BG, + border_color: BG, + border_radius: 0, + border_width: 0, + }, + active: &ButtonStyle { + font: Font::BOLD, text_color: FG, - button_color: GREEN_DARK, + button_color: BG, background_color: BG, border_color: FG, - border_radius: RADIUS, + border_radius: 0, border_width: 0, }, disabled: &ButtonStyle { - font: Font::MONO, + font: Font::BOLD, + text_color: FG, + button_color: BG, + background_color: BG, + border_color: BG, + border_radius: 0, + border_width: 0, + }, + } +} + +pub const fn button_pin_confirm() -> ButtonStyleSheet { + ButtonStyleSheet { + normal: &ButtonStyle { + font: Font::BOLD, + text_color: GREEN, + button_color: BG, + background_color: BG, + border_color: BG, + border_radius: 0, + border_width: 0, + }, + active: &ButtonStyle { + font: Font::BOLD, + text_color: GREEN, + button_color: BG, + background_color: BG, + border_color: GREEN, + border_radius: 0, + border_width: 0, + }, + disabled: &ButtonStyle { + font: Font::BOLD, text_color: GREY_LIGHT, - button_color: GREY_DARK, + button_color: BG, background_color: BG, border_color: BG, - border_radius: RADIUS, + border_radius: 0, border_width: 0, }, } @@ -657,7 +722,8 @@ pub const RECOVERY_SPACING: i16 = 18; pub const CORNER_BUTTON_SIDE: i16 = 44; pub const CORNER_BUTTON_SPACING: i16 = BUTTON_SPACING; pub const INFO_BUTTON_HEIGHT: i16 = 44; -pub const PIN_BUTTON_HEIGHT: i16 = 40; +pub const PIN_BUTTON_HEIGHT: i16 = 52; +pub const PIN_BUTTON_SPACING: i16 = 2; pub const MNEMONIC_BUTTON_HEIGHT: i16 = 52; pub const RESULT_PADDING: i16 = 6; pub const RESULT_FOOTER_START: i16 = 171; diff --git a/core/embed/rust/src/ui/model_tr/component/loader.rs b/core/embed/rust/src/ui/model_tr/component/loader.rs index bf9c8f542..5412a2662 100644 --- a/core/embed/rust/src/ui/model_tr/component/loader.rs +++ b/core/embed/rust/src/ui/model_tr/component/loader.rs @@ -180,10 +180,11 @@ impl Loader { let text_width = style.font.text_width(t); let text_height = style.font.text_max_height(); - let pt = self.area.top_left() + Offset::new( - (self.area.width() - text_width) / 2, - (self.area.height() - text_height) / 2, - ); + let pt = self.area.top_left() + + Offset::new( + (self.area.width() - text_width) / 2, + (self.area.height() - text_height) / 2, + ); shape::Text::new(pt, t) .with_baseline(false)