feat(core): bootloader: T3T1 startup UI

[no changelog]
pull/3626/head
Martin Milata 1 month ago
parent c277dbcfcb
commit 804d97c9d8

@ -45,8 +45,8 @@ elif TREZOR_MODEL in ('T', 'DISC1', 'DISC2'):
elif TREZOR_MODEL in ('T3T1',):
FONT_NORMAL='Font_TTSatoshi_DemiBold_21'
FONT_DEMIBOLD='Font_TTSatoshi_DemiBold_21'
FONT_BOLD='Font_TTSatoshi_DemiBold_21'
FONT_MONO='Font_RobotoMono_Medium_21'
FONT_BOLD='Font_TTHoves_Bold_17'
FONT_MONO='Font_TTSatoshi_DemiBold_21'
FONT_BIG=None
# modtrezorcrypto

@ -42,8 +42,8 @@ elif TREZOR_MODEL in ('T', 'DISC2'):
elif TREZOR_MODEL in ('T3T1',):
FONT_NORMAL='Font_TTSatoshi_DemiBold_21'
FONT_DEMIBOLD='Font_TTSatoshi_DemiBold_21'
FONT_BOLD='Font_TTSatoshi_DemiBold_21'
FONT_MONO='Font_RobotoMono_Medium_21'
FONT_BOLD='Font_TTHoves_Bold_17'
FONT_MONO='Font_TTSatoshi_DemiBold_21'
FONT_BIG=None
# modtrezorcrypto

@ -5,7 +5,7 @@ use crate::{
ui::{
component::{connect::Connect, Label},
display::{self, Color, Font, Icon},
geometry::{Point, Rect},
geometry::{Offset, Point, Rect},
layout::simplified::{run, show},
},
};
@ -19,11 +19,11 @@ use super::{
theme::{
bootloader::{
button_bld, button_bld_menu, button_confirm, button_wipe_cancel, button_wipe_confirm,
BLD_BG, BLD_FG, BLD_TITLE_COLOR, BLD_WIPE_COLOR, CHECK24, CHECK40, DOWNLOAD32, FIRE32,
FIRE40, RESULT_FW_INSTALL, RESULT_INITIAL, RESULT_WIPE, TEXT_BOLD, TEXT_NORMAL,
TEXT_WIPE_BOLD, TEXT_WIPE_NORMAL, WARNING40, WELCOME_COLOR, X24,
BLD_BG, BLD_FG, BLD_TITLE_COLOR, BLD_WIPE_COLOR, CHECK24, CHECK40, DOWNLOAD24, FIRE32,
FIRE40, RESULT_FW_INSTALL, RESULT_WIPE, TEXT_BOLD, TEXT_NORMAL, TEXT_WIPE_BOLD,
TEXT_WIPE_NORMAL, WARNING40, WELCOME_COLOR, X24,
},
BACKLIGHT_NORMAL, BLACK, FG, WHITE,
BACKLIGHT_NORMAL, BLACK, GREEN_LIGHT, GREY, WHITE,
},
ModelMercuryFeatures,
};
@ -41,6 +41,7 @@ pub type BootloaderString = String<128>;
const RECONNECT_MESSAGE: &str = "PLEASE RECONNECT\nTHE DEVICE";
const SCREEN: Rect = ModelMercuryFeatures::SCREEN;
const PROGRESS_TEXT_ORIGIN: Point = Point::new(2, 28);
impl ModelMercuryFeatures {
fn screen_progress(
@ -50,47 +51,32 @@ impl ModelMercuryFeatures {
fg_color: Color,
bg_color: Color,
icon: Option<(Icon, Color)>,
center_text: Option<&str>,
) {
let loader_offset: i16 = 19;
let center_text_offset: i16 = 10;
if initialize {
ModelMercuryFeatures::fadeout();
Self::fadeout();
display::rect_fill(SCREEN, bg_color);
}
display::text_center(
Point::new(SCREEN.width() / 2, SCREEN.height() - 45),
text,
Font::NORMAL,
BLD_FG,
bg_color,
);
display::loader(progress, -20, fg_color, bg_color, icon);
display::text_left(PROGRESS_TEXT_ORIGIN, text, Font::NORMAL, BLD_FG, bg_color);
display::loader(progress, 19, fg_color, bg_color, icon);
if let Some(center_text) = center_text {
display::text_center(
SCREEN.center() + Offset::y(loader_offset + center_text_offset),
center_text,
Font::NORMAL,
GREY,
bg_color,
);
}
display::refresh();
if initialize {
ModelMercuryFeatures::fadein();
Self::fadein();
}
}
fn screen_install_success_bld(msg: &str, complete_draw: bool) {
let mut frame = ResultScreen::new(
&RESULT_FW_INSTALL,
Icon::new(CHECK40),
"Firmware installed\nsuccessfully".into(),
Label::centered(msg.into(), RESULT_FW_INSTALL.title_style()).vertically_centered(),
complete_draw,
);
show(&mut frame, complete_draw);
}
fn screen_install_success_initial(msg: &str, complete_draw: bool) {
let mut frame = ResultScreen::new(
&RESULT_INITIAL,
Icon::new(CHECK40),
"Firmware installed\nsuccessfully".into(),
Label::centered(msg.into(), RESULT_INITIAL.title_style()).vertically_centered(),
complete_draw,
);
show(&mut frame, complete_draw);
}
}
impl UIFeaturesBootloader for ModelMercuryFeatures {
@ -112,20 +98,36 @@ impl UIFeaturesBootloader for ModelMercuryFeatures {
fn screen_install_success(restart_seconds: u8, initial_setup: bool, complete_draw: bool) {
let mut reboot_msg = BootloaderString::new();
let bg_color = if initial_setup { WELCOME_COLOR } else { BLD_BG };
let fg_color = if initial_setup { GREEN_LIGHT } else { BLD_FG };
if restart_seconds >= 1 {
unwrap!(reboot_msg.push_str("RESTARTING IN "));
// in practice, restart_seconds is 5 or less so this is fine
let seconds_char = b'0' + restart_seconds % 10;
unwrap!(reboot_msg.push(seconds_char as char));
let progress = (5 - (restart_seconds as u16)).clamp(0, 5) * 200;
Self::screen_progress(
"Restarting device",
progress,
complete_draw,
fg_color,
bg_color,
None,
Some(reboot_msg.as_str()),
);
} else {
unwrap!(reboot_msg.push_str(RECONNECT_MESSAGE));
Self::screen_progress(
"Firmware installed",
1000,
complete_draw,
fg_color,
bg_color,
Some((Icon::new(CHECK24), BLD_FG)),
None,
);
}
if initial_setup {
ModelMercuryFeatures::screen_install_success_initial(reboot_msg.as_str(), complete_draw)
} else {
ModelMercuryFeatures::screen_install_success_bld(reboot_msg.as_str(), complete_draw)
}
display::refresh();
}
@ -247,16 +249,16 @@ impl UIFeaturesBootloader for ModelMercuryFeatures {
fn screen_boot_empty(fading: bool) {
if fading {
ModelMercuryFeatures::fadeout();
Self::fadeout();
}
display::rect_fill(SCREEN, BLACK);
let mut frame = WelcomeScreen::new(true);
let mut frame = WelcomeScreen::new();
show(&mut frame, false);
if fading {
ModelMercuryFeatures::fadein();
Self::fadein();
} else {
display::set_backlight(BACKLIGHT_NORMAL);
}
@ -264,36 +266,30 @@ impl UIFeaturesBootloader for ModelMercuryFeatures {
}
fn screen_wipe_progress(progress: u16, initialize: bool) {
ModelMercuryFeatures::screen_progress(
Self::screen_progress(
"Resetting Trezor",
progress,
initialize,
BLD_FG,
BLD_WIPE_COLOR,
Some((Icon::new(FIRE32), BLD_FG)),
None,
)
}
fn screen_install_progress(progress: u16, initialize: bool, initial_setup: bool) {
let bg_color = if initial_setup { WELCOME_COLOR } else { BLD_BG };
let fg_color = if initial_setup {
Color::rgb(0x0B, 0xA5, 0x67)
} else {
BLD_FG
};
let icon_color = if initial_setup {
Color::rgb(0x8B, 0x8B, 0x93)
} else {
BLD_FG
};
let fg_color = if initial_setup { GREEN_LIGHT } else { BLD_FG };
let icon_color = BLD_FG;
ModelMercuryFeatures::screen_progress(
Self::screen_progress(
"Installing firmware",
progress,
initialize,
fg_color,
bg_color,
Some((Icon::new(DOWNLOAD32), icon_color)),
Some((Icon::new(DOWNLOAD24), icon_color)),
None,
)
}

@ -1,14 +1,14 @@
use crate::ui::{
component::{Component, Event, EventCtx, Never, Pad},
constant::screen,
display::{self, Font, Icon},
geometry::{Alignment2D, Offset, Rect},
display::{self, Font},
geometry::{Offset, Point, Rect},
};
use super::super::theme::{
bootloader::{START_URL, WELCOME_COLOR},
BLACK, GREY_MEDIUM, WHITE,
};
use super::super::theme::{BLACK, GREY, WHITE};
const TEXT_ORIGIN: Point = Point::new(0, 105);
const STRIDE: i16 = 22;
pub struct Welcome {
bg: Pad,
@ -17,7 +17,7 @@ pub struct Welcome {
impl Welcome {
pub fn new() -> Self {
Self {
bg: Pad::with_background(WELCOME_COLOR).with_clear(),
bg: Pad::with_background(BLACK).with_clear(),
}
}
}
@ -35,24 +35,28 @@ impl Component for Welcome {
}
fn paint(&mut self) {
let at_width = Font::NORMAL.text_width("at ");
self.bg.paint();
display::text_center(
screen().top_center() + Offset::y(102),
"Get started with",
display::text_left(TEXT_ORIGIN, "Get started", Font::NORMAL, GREY, BLACK);
display::text_left(
TEXT_ORIGIN + Offset::y(STRIDE),
"with your Trezor",
Font::NORMAL,
GREY_MEDIUM,
GREY,
BLACK,
);
display::text_center(
screen().top_center() + Offset::y(126),
"your Trezor at",
display::text_left(
TEXT_ORIGIN + Offset::y(2 * STRIDE),
"at",
Font::NORMAL,
GREY_MEDIUM,
GREY,
BLACK,
);
Icon::new(START_URL).draw(
screen().top_center() + Offset::y(135),
Alignment2D::TOP_CENTER,
display::text_left(
TEXT_ORIGIN + Offset::new(at_width, 2 * STRIDE),
"trezor.io/start",
Font::NORMAL,
WHITE,
BLACK,
);

@ -1,31 +1,25 @@
use crate::ui::{
component::{Component, Event, EventCtx, Never},
display,
geometry::{Alignment2D, Offset, Rect},
};
use super::theme;
#[cfg(feature = "bootloader")]
use crate::ui::{display::Icon, model_mercury::theme::bootloader::DEVICE_NAME};
const TEXT_BOTTOM_MARGIN: i16 = 24; // matching the homescreen label margin
const TEXT_BOTTOM_MARGIN: i16 = 54;
const ICON_TOP_MARGIN: i16 = 48;
#[cfg(not(feature = "bootloader"))]
const MODEL_NAME_FONT: display::Font = display::Font::DEMIBOLD;
#[cfg(not(feature = "bootloader"))]
use crate::{trezorhal::model, ui::display};
use crate::trezorhal::model;
pub struct WelcomeScreen {
area: Rect,
empty_lock: bool,
}
impl WelcomeScreen {
pub fn new(empty_lock: bool) -> Self {
Self {
area: Rect::zero(),
empty_lock,
}
pub fn new() -> Self {
Self { area: Rect::zero() }
}
}
@ -42,29 +36,16 @@ impl Component for WelcomeScreen {
}
fn paint(&mut self) {
let logo = if self.empty_lock {
theme::ICON_LOGO_EMPTY
} else {
theme::ICON_LOGO
};
logo.draw(
theme::ICON_LOGO.draw(
self.area.top_center() + Offset::y(ICON_TOP_MARGIN),
Alignment2D::TOP_CENTER,
theme::FG,
theme::BG,
);
#[cfg(not(feature = "bootloader"))]
display::text_center(
self.area.bottom_center() - Offset::y(TEXT_BOTTOM_MARGIN),
model::FULL_NAME,
MODEL_NAME_FONT,
theme::FG,
theme::BG,
);
#[cfg(feature = "bootloader")]
Icon::new(DEVICE_NAME).draw(
self.area.bottom_center() - Offset::y(TEXT_BOTTOM_MARGIN),
Alignment2D::BOTTOM_CENTER,
"Trezor Safe 5",
display::Font::NORMAL,
theme::FG,
theme::BG,
);

@ -12,7 +12,7 @@ pub fn screen_fatal_error(title: &str, msg: &str, footer: &str) {
}
pub fn screen_boot_full() {
let mut frame = WelcomeScreen::new(false);
let mut frame = WelcomeScreen::new();
frame.place(screen());
display::sync();
frame.paint();

@ -64,14 +64,11 @@ pub const FIRE40: &[u8] = include_res!("model_mercury/res/fire40.toif");
pub const REFRESH24: &[u8] = include_res!("model_mercury/res/refresh24.toif");
pub const MENU32: &[u8] = include_res!("model_mercury/res/menu32.toif");
pub const INFO32: &[u8] = include_res!("model_mercury/res/info32.toif");
pub const DOWNLOAD32: &[u8] = include_res!("model_mercury/res/download32.toif");
pub const DOWNLOAD24: &[u8] = include_res!("model_mercury/res/download24.toif");
pub const WARNING40: &[u8] = include_res!("model_mercury/res/warning40.toif");
pub const CHECK24: &[u8] = include_res!("model_mercury/res/check24.toif");
pub const CHECK40: &[u8] = include_res!("model_mercury/res/check40.toif");
pub const DEVICE_NAME: &[u8] = include_res!("model_mercury/res/device_name_T.toif");
pub const START_URL: &[u8] = include_res!("model_mercury/res/start.toif");
pub fn button_confirm() -> ButtonStyleSheet {
ButtonStyleSheet {
normal: &ButtonStyle {

@ -17,19 +17,16 @@ pub const WHITE: Color = Color::rgb(0xFF, 0xFF, 0xFF);
pub const BLACK: Color = Color::rgb(0, 0, 0);
pub const FG: Color = WHITE; // Default foreground (text & icon) color.
pub const BG: Color = BLACK; // Default background color.
pub const RED: Color = Color::rgb(0xE7, 0x0E, 0x0E); // button
pub const RED_DARK: Color = Color::rgb(0xAE, 0x09, 0x09); // button pressed
pub const YELLOW: Color = Color::rgb(0xD9, 0x9E, 0x00); // button
pub const YELLOW_DARK: Color = Color::rgb(0x7A, 0x58, 0x00); // button pressed
pub const GREEN: Color = Color::rgb(0x00, 0xAA, 0x35); // button
pub const GREEN_DARK: Color = Color::rgb(0x00, 0x55, 0x1D); // button pressed
pub const BLUE: Color = Color::rgb(0x06, 0x1E, 0xAD); // button
pub const BLUE_DARK: Color = Color::rgb(0x04, 0x10, 0x58); // button pressed
pub const OFF_WHITE: Color = Color::rgb(0xDE, 0xDE, 0xDE); // very light grey
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 GREY_EXTRA_DARK: Color = Color::rgb(0x16, 0x1F, 0x24);
pub const GREY_DARK: Color = Color::rgb(0x46, 0x48, 0x4A);
pub const GREY: Color = Color::rgb(0x8B, 0x8F, 0x93); // secondary text, subtitle, instructions
pub const GREY_LIGHT: Color = Color::rgb(0xC7, 0xCD, 0xD3); // content
pub const GREY_EXTRA_LIGHT: Color = Color::rgb(0xF0, 0xF0, 0xF0); // primary text, header
pub const GREEN: Color = Color::rgb(0x08, 0x74, 0x48);
pub const GREEN_LIGHT: Color = Color::rgb(0x0B, 0xA5, 0x67);
pub const GREEN_LIME: Color = Color::rgb(0x9B, 0xE8, 0x87);
pub const ORANGE_DIMMED: Color = Color::rgb(0x9E, 0x57, 0x42);
pub const ORANGE_LIGHT: Color = Color::rgb(0xFF, 0x8D, 0x6A); // cancel button
pub const FATAL_ERROR_COLOR: Color = Color::rgb(0xE7, 0x0E, 0x0E);
pub const FATAL_ERROR_HIGHLIGHT_COLOR: Color = Color::rgb(0xFF, 0x41, 0x41);
@ -59,16 +56,15 @@ include_icon!(ICON_PAGE_NEXT, "model_mercury/res/page-next.toif");
include_icon!(ICON_PAGE_PREV, "model_mercury/res/page-prev.toif");
// Large, three-color icons.
pub const WARN_COLOR: Color = YELLOW;
pub const INFO_COLOR: Color = BLUE;
pub const WARN_COLOR: Color = ORANGE_LIGHT;
pub const INFO_COLOR: Color = GREY_LIGHT;
pub const SUCCESS_COLOR: Color = GREEN;
pub const ERROR_COLOR: Color = RED;
pub const ERROR_COLOR: Color = ORANGE_DIMMED;
include_icon!(IMAGE_FG_SUCCESS, "model_mercury/res/fg-check48.toif");
include_icon!(IMAGE_BG_CIRCLE, "model_mercury/res/circle48.toif");
// Welcome screen.
include_icon!(ICON_LOGO, "model_mercury/res/lock_full.toif");
include_icon!(ICON_LOGO_EMPTY, "model_mercury/res/lock_empty.toif");
pub const fn button_default() -> ButtonStyleSheet {
ButtonStyleSheet {
@ -84,7 +80,7 @@ pub const fn button_default() -> ButtonStyleSheet {
active: &ButtonStyle {
font: Font::BOLD,
text_color: FG,
button_color: GREY_MEDIUM,
button_color: GREY,
background_color: BG,
border_color: FG,
border_radius: RADIUS,
@ -118,7 +114,7 @@ pub const fn button_moreinfo() -> ButtonStyleSheet {
text_color: FG,
button_color: BG,
background_color: BG,
border_color: GREY_MEDIUM,
border_color: GREY,
border_radius: RADIUS,
border_width: 2,
},

Loading…
Cancel
Save