diff --git a/core/embed/rust/src/ui/model_mercury/component/keyboard/bip39.rs b/core/embed/rust/src/ui/model_mercury/component/keyboard/bip39.rs index f1459d71b1..5fb9488af2 100644 --- a/core/embed/rust/src/ui/model_mercury/component/keyboard/bip39.rs +++ b/core/embed/rust/src/ui/model_mercury/component/keyboard/bip39.rs @@ -2,16 +2,16 @@ use crate::{ trezorhal::bip39, ui::{ component::{text::common::TextBox, Component, Event, EventCtx}, - display, - geometry::{Alignment2D, Offset, Rect}, + geometry::{Alignment, Alignment2D, Offset, Point, Rect}, model_mercury::{ component::{ keyboard::{ - common::{paint_pending_marker, render_pending_marker, MultiTapKeyboard}, + common::{render_pending_marker, render_pill_shape, MultiTapKeyboard}, mnemonic::{MnemonicInput, MnemonicInputMsg, MNEMONIC_KEY_COUNT}, }, - Button, ButtonContent, ButtonMsg, + Button, ButtonMsg, }, + constant::WIDTH, theme, }, shape, @@ -104,100 +104,66 @@ impl Component for Bip39Input { } fn paint(&mut self) { - let area = self.button.area(); - let style = self.button.style(); - - // First, paint the button background. - self.button.paint_background(style); - - // Paint the entered content (the prefix of the suggested word). - let text = self.textbox.content(); - let width = style.font.text_width(text); - // Content starts in the left-center point, offset by 16px to the right and 8px - // to the bottom. - let text_baseline = area.top_left().center(area.bottom_left()) + Offset::new(16, 8); - display::text_left( - text_baseline, - text, - style.font, - style.text_color, - style.button_color, - ); - - // Paint the rest of the suggested dictionary word. - if let Some(word) = self.suggested_word.and_then(|w| w.get(text.len()..)) { - let word_baseline = text_baseline + Offset::new(width, 0); - let style = self.button_suggestion.style(); - display::text_left( - word_baseline, - word, - style.font, - style.text_color, - style.button_color, - ); - } - - // Paint the pending marker. - if self.multi_tap.pending_key().is_some() { - paint_pending_marker(text_baseline, text, style.font, style.text_color); - } - - // Paint the icon. - if let ButtonContent::Icon(icon) = self.button.content() { - // Icon is painted in the right-center point, of expected size 16x16 pixels, and - // 16px from the right edge. - let icon_center = area.top_right().center(area.bottom_right()) - Offset::new(16 + 8, 0); - icon.draw( - icon_center, - Alignment2D::CENTER, - style.text_color, - style.button_color, - ); - } + todo!("remove when ui-t3t1 done"); } fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { let area = self.button.area(); let style = self.button.style(); - // First, paint the button background. - self.button.render_background(target, style); - // Paint the entered content (the prefix of the suggested word). let text = self.textbox.content(); let width = style.font.text_width(text); - // Content starts in the left-center point, offset by 16px to the right and 8px - // to the bottom. - let text_baseline = area.top_left().center(area.bottom_left()) + Offset::new(16, 8); - shape::Text::new(text_baseline, text) + + // User input together with suggestion is centered vertically in the input area + // and centered horizontally on the screen + let text_base_y = area.left_center().y + style.font.allcase_text_height() / 2; + let text_base_x = if let Some(word) = self.suggested_word { + style.font.horz_center(0, WIDTH, word) + } else { + style.font.horz_center(0, WIDTH, text) + }; + let text_base = Point::new(text_base_x, text_base_y); + + // Render pill-shaped button + if let Some(word) = self.suggested_word { + let choice_unambiguous = self.is_choice_unambiguous(); + render_pill_shape( + target, + text_base, + word, + style, + if choice_unambiguous { Some(area) } else { None }, + ); + if choice_unambiguous { + // Icon is painted in the right-center point, 10px from the right edge. + let icon_right_center = area.right_center() - Offset::x(10); + shape::ToifImage::new(icon_right_center, theme::ICON_SIMPLE_CHECKMARK24.toif) + .with_align(Alignment2D::CENTER_RIGHT) + .with_fg(style.icon_color) + .render(target); + } + }; + + // Render text input + suggested completion + shape::Text::new(text_base, text) .with_font(style.font) .with_fg(style.text_color) + .with_align(Alignment::Start) .render(target); - - // Paint the rest of the suggested dictionary word. if let Some(word) = self.suggested_word.and_then(|w| w.get(text.len()..)) { - let word_baseline = text_baseline + Offset::new(width, 0); + let word_baseline = text_base + Offset::x(width); let style = self.button_suggestion.style(); shape::Text::new(word_baseline, word) .with_font(style.font) .with_fg(style.text_color) + .with_align(Alignment::Start) .render(target); } // Paint the pending marker. if self.multi_tap.pending_key().is_some() { - render_pending_marker(target, text_baseline, text, style.font, style.text_color); - } - - // Paint the icon. - if let ButtonContent::Icon(icon) = self.button.content() { - // Icon is painted in the right-center point, of expected size 16x16 pixels, and - // 16px from the right edge. - let icon_center = area.top_right().center(area.bottom_right()) - Offset::new(16 + 8, 0); - shape::ToifImage::new(icon_center, icon.toif) - .with_align(Alignment2D::CENTER) - .with_fg(style.icon_color) - .render(target); + render_pending_marker(target, text_base, text, style.font, style.text_color); } } @@ -227,8 +193,7 @@ impl Bip39Input { // Styling the input to reflect already filled word Self { - button: Button::with_icon(theme::ICON_CONFIRM_INPUT) - .styled(theme::button_pin_confirm()), + button: Button::empty().styled(theme::button_recovery_confirm()), textbox: TextBox::new(unwrap!(String::try_from(word))), multi_tap: MultiTapKeyboard::new(), options_num: bip39::options_num(word), @@ -249,13 +214,18 @@ impl Bip39Input { mask } + fn is_choice_unambiguous(&self) -> bool { + if let (Some(word), Some(_num)) = (self.suggested_word, self.options_num) { + return word.eq(self.textbox.content()); + } + false + } + /// Input button was clicked. If the content matches the suggested word, /// let's confirm it, otherwise just auto-complete. fn on_input_click(&mut self, ctx: &mut EventCtx) -> Option { - if let (Some(word), Some(num)) = (self.suggested_word, self.options_num) { - return if num == 1 && word.starts_with(self.textbox.content()) - || num > 1 && word.eq(self.textbox.content()) - { + if let (Some(word), Some(_num)) = (self.suggested_word, self.options_num) { + return if word.eq(self.textbox.content()) { // Confirm button. self.textbox.clear(ctx); Some(MnemonicInputMsg::Confirmed) @@ -286,24 +256,19 @@ impl Bip39Input { self.suggested_word = bip39::complete_word(self.textbox.content()); // Change the style of the button depending on the completed word. - if let (Some(word), Some(num)) = (self.suggested_word, self.options_num) { - if num == 1 && word.starts_with(self.textbox.content()) - || num > 1 && word.eq(self.textbox.content()) - { + if let (Some(word), Some(_num)) = (self.suggested_word, self.options_num) { + if word.eq(self.textbox.content()) { // Confirm button. self.button.enable(ctx); - self.button.set_stylesheet(ctx, theme::button_pin_confirm()); self.button - .set_content(ctx, ButtonContent::Icon(theme::ICON_CONFIRM_INPUT)); + .set_stylesheet(ctx, theme::button_recovery_confirm()); self.button_suggestion .set_stylesheet(ctx, theme::button_suggestion_confirm()); } else { // Auto-complete button. self.button.enable(ctx); self.button - .set_stylesheet(ctx, theme::button_bip39_autocomplete()); - self.button - .set_content(ctx, ButtonContent::Icon(theme::ICON_AUTOFILL)); + .set_stylesheet(ctx, theme::button_recovery_autocomplete()); self.button_suggestion .set_stylesheet(ctx, theme::button_suggestion_autocomplete()); } @@ -311,7 +276,6 @@ impl Bip39Input { // Disabled button. self.button.disable(ctx); self.button.set_stylesheet(ctx, theme::button_keyboard()); - self.button.set_content(ctx, ButtonContent::Text("".into())); } } } diff --git a/core/embed/rust/src/ui/model_mercury/component/keyboard/common.rs b/core/embed/rust/src/ui/model_mercury/component/keyboard/common.rs index 9868770bc4..58544b75a1 100644 --- a/core/embed/rust/src/ui/model_mercury/component/keyboard/common.rs +++ b/core/embed/rust/src/ui/model_mercury/component/keyboard/common.rs @@ -3,12 +3,14 @@ use crate::{ ui::{ component::{text::common::TextEdit, Event, EventCtx, TimerToken}, display::{self, Color, Font}, - geometry::{Offset, Point, Rect}, + geometry::{Alignment2D, Offset, Point, Rect}, shape, shape::Renderer, }, }; +use super::super::ButtonStyle; + /// Contains state commonly used in implementations multi-tap keyboards. pub struct MultiTapKeyboard { /// Configured timeout after which we cancel currently pending key. @@ -150,3 +152,41 @@ pub fn render_pending_marker<'s>( shape::Bar::new(marker_rect).with_bg(color).render(target); } } + +/// Create a pill-shaped button around a text. +pub fn render_pill_shape<'s>( + target: &mut impl Renderer<'s>, + base_point: Point, + text: &str, + style: &ButtonStyle, + expand_area: Option, +) { + let pill_radius = 18; + let pill_bearing_x = 17; + let pill_bearing_y = 12; + let pill_height = 2 * pill_radius + 4; // adding 4px looks better, if the height is just 2*r it does not look like a + // perfect half-circle but there is a visible narrowing of the pill shape + let pill_width = style.font.text_width(text) + 2 * pill_bearing_x; + + let pill_baseline = base_point + Offset::new(-pill_bearing_x, pill_bearing_y); + let mut pill_area = Rect::snap( + pill_baseline, + Offset::new(pill_width, pill_height), + Alignment2D::BOTTOM_LEFT, + ); + if let Some(area) = expand_area { + // "dummy" rectangle to use in the `union` call + let expander = Rect::snap( + area.bottom_right(), + Offset::uniform(1), + Alignment2D::BOTTOM_RIGHT, + ); + pill_area = pill_area.union(expander); + } + shape::Bar::new(pill_area) + .with_bg(style.background_color) + .with_fg(style.button_color) + .with_radius(pill_radius) + .with_thickness(2) + .render(target); +} diff --git a/core/embed/rust/src/ui/model_mercury/component/keyboard/mnemonic.rs b/core/embed/rust/src/ui/model_mercury/component/keyboard/mnemonic.rs index 2a5ad0829a..381e4fe222 100644 --- a/core/embed/rust/src/ui/model_mercury/component/keyboard/mnemonic.rs +++ b/core/embed/rust/src/ui/model_mercury/component/keyboard/mnemonic.rs @@ -2,7 +2,7 @@ use crate::{ strutil::TString, ui::{ component::{maybe::paint_overlapping, Child, Component, Event, EventCtx, Label, Maybe}, - geometry::{Alignment, Grid, Rect}, + geometry::{Alignment, Grid, Insets, Rect}, model_mercury::{ component::{Button, ButtonMsg, Swipe, SwipeDirection}, theme, @@ -12,6 +12,7 @@ use crate::{ }; pub const MNEMONIC_KEY_COUNT: usize = 9; +const BACK_BUTTON_RIGHT_EXPAND: i16 = 24; pub enum MnemonicKeyboardMsg { Confirmed, @@ -21,7 +22,9 @@ pub enum MnemonicKeyboardMsg { pub struct MnemonicKeyboard { /// Initial prompt, displayed on empty input. prompt: Child>>, - /// Backspace button. + /// Delete a char button. + erase: Child>, + /// Go to previous word button back: Child>, /// Input area, acting as the auto-complete and confirm button. input: Child>, @@ -40,19 +43,24 @@ where pub fn new(input: T, prompt: TString<'static>, can_go_back: bool) -> Self { // Input might be already pre-filled let prompt_visible = input.is_empty(); - + let erase_btn = Button::with_icon(theme::ICON_DELETE) + .styled(theme::button_default()) + .with_expanded_touch_area(Insets::right(BACK_BUTTON_RIGHT_EXPAND)) + .with_long_press(theme::ERASE_HOLD_DURATION); + let back_btn = Button::with_icon(theme::ICON_CHEVRON_LEFT) + .styled(theme::button_default()) + .with_expanded_touch_area(Insets::right(BACK_BUTTON_RIGHT_EXPAND)); Self { prompt: Child::new(Maybe::new( theme::BG, - Label::centered(prompt, theme::TEXT_MAIN_GREY_LIGHT), + Label::centered(prompt, theme::TEXT_MAIN_GREY_LIGHT).vertically_centered(), prompt_visible, )), + erase: Child::new(Maybe::new(theme::BG, erase_btn, !prompt_visible)), back: Child::new(Maybe::new( theme::BG, - Button::with_icon(theme::ICON_DELETE) - .styled(theme::button_default()) - .with_long_press(theme::ERASE_HOLD_DURATION), - !prompt_visible, + back_btn, + prompt_visible && can_go_back, )), input: Child::new(Maybe::new(theme::BG, input, !prompt_visible)), keys: T::keys() @@ -86,15 +94,18 @@ where } /// After edit operations, we need to either show or hide the prompt, the - /// input, and the back button. + /// input, the erase button and the back button. fn toggle_prompt_or_input(&mut self, ctx: &mut EventCtx) { let prompt_visible = self.input.inner().inner().is_empty(); self.prompt .mutate(ctx, |ctx, p| p.show_if(ctx, prompt_visible)); self.input .mutate(ctx, |ctx, i| i.show_if(ctx, !prompt_visible)); - self.back + self.erase .mutate(ctx, |ctx, b| b.show_if(ctx, !prompt_visible)); + self.back.mutate(ctx, |ctx, b| { + b.show_if(ctx, prompt_visible && self.can_go_back) + }); } pub fn mnemonic(&self) -> Option<&'static str> { @@ -109,22 +120,25 @@ where type Msg = MnemonicKeyboardMsg; fn place(&mut self, bounds: Rect) -> Rect { - let height_input_area: i16 = 30; - let space_top: i16 = 8; + let height_input_area: i16 = 38; + let padding_top: i16 = 6; + let back_btn_area_width: i16 = 32; let (remaining, keyboard_area) = - bounds.split_bottom(3 * theme::BUTTON_HEIGHT + 2 * theme::KEYBOARD_SPACING); + bounds.split_bottom(3 * theme::MNEMONIC_BUTTON_HEIGHT + 2 * theme::KEYBOARD_SPACING); let prompt_area = remaining - .split_top(space_top) + .split_top(padding_top) .1 .split_top(height_input_area) .0; assert!(prompt_area.height() == height_input_area); - let (back_btn_area, input_area) = prompt_area.split_left(30); + let (back_btn_area, input_area) = prompt_area.split_left(back_btn_area_width); + let input_area = input_area.inset(Insets::left(BACK_BUTTON_RIGHT_EXPAND)); let keyboard_grid = Grid::new(keyboard_area, 3, 3).with_spacing(theme::KEYBOARD_SPACING); self.swipe.place(bounds); self.prompt.place(prompt_area); + self.erase.place(back_btn_area); self.back.place(back_btn_area); self.input.place(input_area); @@ -135,8 +149,11 @@ where } fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { - // Swipe will cause going back to the previous word when allowed. + // Back button or swipe will cause going back to the previous word when allowed. if self.can_go_back { + if let Some(ButtonMsg::Clicked) = self.back.event(ctx, event) { + return Some(MnemonicKeyboardMsg::Previous); + } if let Some(SwipeDirection::Right) = self.swipe.event(ctx, event) { return Some(MnemonicKeyboardMsg::Previous); } @@ -155,7 +172,7 @@ where _ => {} } - match self.back.event(ctx, event) { + match self.erase.event(ctx, event) { Some(ButtonMsg::Clicked) => { self.input .mutate(ctx, |ctx, i| i.inner_mut().on_backspace_click(ctx)); @@ -182,7 +199,7 @@ where } fn paint(&mut self) { - paint_overlapping(&mut [&mut self.prompt, &mut self.input, &mut self.back]); + paint_overlapping(&mut [&mut self.prompt, &mut self.input, &mut self.erase]); for btn in &mut self.keys { btn.paint(); } @@ -191,9 +208,12 @@ where fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { if self.input.inner().inner().is_empty() { self.prompt.render(target); + if self.can_go_back { + self.back.render(target); + } } else { self.input.render(target); - self.back.render(target); + self.erase.render(target); } for btn in &self.keys { @@ -205,6 +225,7 @@ where fn bounds(&self, sink: &mut dyn FnMut(Rect)) { self.prompt.bounds(sink); self.input.bounds(sink); + self.erase.bounds(sink); self.back.bounds(sink); for btn in &self.keys { btn.bounds(sink) diff --git a/core/embed/rust/src/ui/model_mercury/component/keyboard/slip39.rs b/core/embed/rust/src/ui/model_mercury/component/keyboard/slip39.rs index 5160e7ddc8..79173a1db0 100644 --- a/core/embed/rust/src/ui/model_mercury/component/keyboard/slip39.rs +++ b/core/embed/rust/src/ui/model_mercury/component/keyboard/slip39.rs @@ -9,12 +9,12 @@ use crate::{ text::common::{TextBox, TextEdit}, Component, Event, EventCtx, }, - display, - geometry::{Alignment2D, Offset, Rect}, + constant::WIDTH, + geometry::{Alignment, Alignment2D, Offset, Point, Rect}, model_mercury::{ component::{ keyboard::{ - common::{paint_pending_marker, render_pending_marker, MultiTapKeyboard}, + common::{render_pending_marker, render_pill_shape, MultiTapKeyboard}, mnemonic::{MnemonicInput, MnemonicInputMsg, MNEMONIC_KEY_COUNT}, }, Button, ButtonContent, ButtonMsg, @@ -124,88 +124,35 @@ impl Component for Slip39Input { } fn paint(&mut self) { - let area = self.button.area(); - let style = self.button.style(); - - // First, paint the button background. - self.button.paint_background(style); - - // Content starts in the left-center point, offset by 16px to the right and 8px - // to the bottom. - let text_baseline = area.top_left().center(area.bottom_left()) + Offset::new(16, 8); - - // To simplify things, we always copy the printed string here, even if it - // wouldn't be strictly necessary. - let mut text: String = String::new(); - - if let Some(word) = self.final_word { - // We're done with input, paint the full word. - text.push_str(word) - .assert_if_debugging_ui("Text buffer is too small"); - } else { - // Paint an asterisk for each letter of input. - for ch in iter::repeat('*').take(self.textbox.content().len()) { - text.push(ch) - .assert_if_debugging_ui("Text buffer is too small"); - } - // If we're in the pending state, paint the pending character at the end. - if let (Some(key), Some(press)) = - (self.multi_tap.pending_key(), self.multi_tap.pending_press()) - { - assert!(!Self::keys()[key].is_empty()); - // Now we can be sure that the looped iterator will return a value. - let ch = unwrap!(Self::keys()[key].chars().cycle().nth(press)); - text.pop(); - text.push(ch) - .assert_if_debugging_ui("Text buffer is too small"); - } - } - display::text_left( - text_baseline, - text.as_str(), - style.font, - style.text_color, - style.button_color, - ); - - // Paint the pending marker. - if self.multi_tap.pending_key().is_some() && self.final_word.is_none() { - paint_pending_marker(text_baseline, text.as_str(), style.font, style.text_color); - } - - // Paint the icon. - if let ButtonContent::Icon(icon) = self.button.content() { - // Icon is painted in the right-center point, of expected size 16x16 pixels, and - // 16px from the right edge. - let icon_center = area.top_right().center(area.bottom_right()) - Offset::new(16 + 8, 0); - icon.draw( - icon_center, - Alignment2D::CENTER, - style.icon_color, - style.button_color, - ); - } + todo!("remove when ui-t3t1 done") } fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { let area = self.button.area(); let style = self.button.style(); - // First, paint the button background. - self.button.render_background(target, style); - - // Content starts in the left-center point, offset by 16px to the right and 8px - // to the bottom. - let text_baseline = area.top_left().center(area.bottom_left()) + Offset::new(16, 8); + // Content is center-aligned + let text_base_y = area.left_center().y + style.font.allcase_text_height() / 2; + let text_center = Point::new(WIDTH / 2, text_base_y); // To simplify things, we always copy the printed string here, even if it // wouldn't be strictly necessary. let mut text: String = String::new(); - if let Some(word) = self.final_word { // We're done with input, paint the full word. text.push_str(word) .assert_if_debugging_ui("Text buffer is too small"); + let pill_base = Point::new( + style.font.horz_center(0, WIDTH, text.as_str()), + text_center.y, + ); + render_pill_shape(target, pill_base, text.as_str(), style, Some(area)); + // Icon is painted in the right-center point, 10px from the right edge. + let icon_right_center = area.right_center() - Offset::x(10); + shape::ToifImage::new(icon_right_center, theme::ICON_SIMPLE_CHECKMARK24.toif) + .with_align(Alignment2D::CENTER_RIGHT) + .with_fg(style.icon_color) + .render(target); } else { // Paint an asterisk for each letter of input. for ch in iter::repeat('*').take(self.textbox.content().len()) { @@ -224,32 +171,26 @@ impl Component for Slip39Input { .assert_if_debugging_ui("Text buffer is too small"); } } - shape::Text::new(text_baseline, text.as_str()) + shape::Text::new(text_center, text.as_str()) .with_font(style.font) .with_fg(style.text_color) + .with_align(Alignment::Center) .render(target); // Paint the pending marker. + let text_base = Point::new( + style.font.horz_center(0, WIDTH, text.as_str()), + text_center.y, + ); if self.multi_tap.pending_key().is_some() && self.final_word.is_none() { render_pending_marker( target, - text_baseline, + text_base, text.as_str(), style.font, style.text_color, ); } - - // Paint the icon. - if let ButtonContent::Icon(icon) = self.button.content() { - // Icon is painted in the right-center point, of expected size 16x16 pixels, and - // 16px from the right edge. - let icon_center = area.top_right().center(area.bottom_right()) - Offset::new(16 + 8, 0); - shape::ToifImage::new(icon_center, icon.toif) - .with_align(Alignment2D::CENTER) - .with_fg(style.icon_color) - .render(target); - } } #[cfg(feature = "ui_bounds")] @@ -262,7 +203,7 @@ impl Slip39Input { pub fn new() -> Self { Self { // Button has the same style the whole time - button: Button::empty().styled(theme::button_pin_confirm()), + button: Button::empty().styled(theme::button_recovery_confirm()), textbox: TextBox::empty(), multi_tap: MultiTapKeyboard::new(), final_word: None, @@ -280,7 +221,7 @@ impl Slip39Input { Self { // Button has the same style the whole time - button: Button::empty().styled(theme::button_pin_confirm()), + button: Button::empty().styled(theme::button_recovery_confirm()), textbox: TextBox::new(buff), multi_tap: MultiTapKeyboard::new(), final_word, @@ -356,7 +297,7 @@ impl Slip39Input { // Confirm button. self.button.enable(ctx); self.button - .set_content(ctx, ButtonContent::Icon(theme::ICON_CONFIRM_INPUT)); + .set_content(ctx, ButtonContent::Icon(theme::ICON_SIMPLE_CHECKMARK24)); } else { // Disabled button. self.button.disable(ctx); 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 406e091a0d..0309576682 100644 --- a/core/embed/rust/src/ui/model_mercury/theme/mod.rs +++ b/core/embed/rust/src/ui/model_mercury/theme/mod.rs @@ -75,6 +75,7 @@ include_icon!(ICON_PAGE_UP, "model_mercury/res/page_up20.toif"); // 24x24 include_icon!(ICON_CANCEL, "model_mercury/res/cancel24.toif"); +include_icon!(ICON_CHEVRON_LEFT, "model_mercury/res/chevron_left24.toif"); include_icon!(ICON_CHEVRON_RIGHT, "model_mercury/res/chevron_right24.toif"); include_icon!(ICON_DOWNLOAD, "model_mercury/res/download24.toif"); include_icon!(ICON_KEY, "model_mercury/res/key20.toif"); @@ -576,27 +577,28 @@ pub const fn button_passphrase_next() -> ButtonStyleSheet { } } -pub const fn button_bip39_autocomplete() -> ButtonStyleSheet { +pub const fn button_recovery_confirm() -> ButtonStyleSheet { ButtonStyleSheet { normal: &ButtonStyle { - font: Font::MONO, - text_color: FG, - button_color: BG, - icon_color: GREY_LIGHT, - background_color: BG, + font: Font::DEMIBOLD, + text_color: GREEN_LIME, + button_color: GREEN_LIGHT, + icon_color: GREEN_LIME, + background_color: GREEN_DARK, }, active: &ButtonStyle { - font: Font::MONO, - text_color: FG, - button_color: BG, - icon_color: GREY_LIGHT, - background_color: BG, + font: Font::DEMIBOLD, + text_color: GREEN_DARK, + button_color: GREEN_LIGHT, + icon_color: GREEN_DARK, + background_color: GREEN_LIGHT, }, + // used in SLIP-39 recovery for "*" disabled: &ButtonStyle { - font: Font::MONO, - text_color: FG, + font: Font::DEMIBOLD, + text_color: GREY_LIGHT, button_color: BG, - icon_color: GREY_LIGHT, + icon_color: BG, background_color: BG, }, } @@ -605,24 +607,52 @@ pub const fn button_bip39_autocomplete() -> ButtonStyleSheet { pub const fn button_suggestion_confirm() -> ButtonStyleSheet { ButtonStyleSheet { normal: &ButtonStyle { - font: Font::MONO, + font: Font::DEMIBOLD, + text_color: GREY_LIGHT, // difference + button_color: GREEN_LIGHT, + icon_color: GREEN_LIME, + background_color: GREEN_DARK, + }, + active: &ButtonStyle { + font: Font::DEMIBOLD, + text_color: GREEN_LIME, + button_color: GREEN_LIGHT, + icon_color: GREEN_DARK, + background_color: GREEN_LIGHT, + }, + // not used + disabled: &ButtonStyle { + font: Font::DEMIBOLD, + text_color: BG, + button_color: BG, + icon_color: BG, + background_color: BG, + }, + } +} + +pub const fn button_recovery_autocomplete() -> ButtonStyleSheet { + ButtonStyleSheet { + normal: &ButtonStyle { + font: Font::DEMIBOLD, text_color: GREY_LIGHT, - button_color: GREEN, + button_color: GREY_EXTRA_DARK, icon_color: GREY_LIGHT, background_color: BG, }, active: &ButtonStyle { - font: Font::MONO, - text_color: FG, - button_color: GREEN_DARK, - icon_color: GREY_LIGHT, - background_color: BG, + font: Font::DEMIBOLD, + text_color: BG, + button_color: FG, + icon_color: BG, + background_color: FG, }, + // not used disabled: &ButtonStyle { - font: Font::MONO, - text_color: GREY_LIGHT, - button_color: GREY_DARK, - icon_color: GREY_LIGHT, + font: Font::DEMIBOLD, + text_color: BG, + button_color: BG, + icon_color: BG, background_color: BG, }, } @@ -631,24 +661,25 @@ pub const fn button_suggestion_confirm() -> ButtonStyleSheet { pub const fn button_suggestion_autocomplete() -> ButtonStyleSheet { ButtonStyleSheet { normal: &ButtonStyle { - font: Font::MONO, - text_color: GREY_LIGHT, - button_color: GREY_DARK, // same as PIN buttons - icon_color: GREY_LIGHT, + font: Font::DEMIBOLD, + text_color: GREY, + button_color: BG, + icon_color: BG, background_color: BG, }, active: &ButtonStyle { font: Font::MONO, - text_color: FG, - button_color: GREEN_DARK, - icon_color: GREY_LIGHT, - background_color: BG, + text_color: BG, + button_color: FG, + icon_color: BG, + background_color: FG, }, + // not used disabled: &ButtonStyle { font: Font::MONO, - text_color: GREY_LIGHT, + text_color: BG, button_color: BG, - icon_color: GREY_LIGHT, + icon_color: BG, background_color: BG, }, } diff --git a/core/src/trezor/ui/layouts/mercury/recovery.py b/core/src/trezor/ui/layouts/mercury/recovery.py index 6b2641fd7b..5ed3d7ca75 100644 --- a/core/src/trezor/ui/layouts/mercury/recovery.py +++ b/core/src/trezor/ui/layouts/mercury/recovery.py @@ -34,7 +34,7 @@ async def request_word_count(dry_run: bool) -> int: async def request_word( word_index: int, word_count: int, is_slip39: bool, prefill_word: str = "" ) -> str: - prompt = TR.recovery__type_word_x_of_y_template.format(word_index + 1, word_count) + prompt = TR.recovery__word_x_of_y_template.format(word_index + 1, word_count) can_go_back = word_index > 0 if is_slip39: keyboard = RustLayout(