1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-07-20 13:38:11 +00:00

feat(eckhart): bld welcome screen

[no changelog]
This commit is contained in:
obrusvit 2025-07-09 21:47:12 +02:00 committed by Vít Obrusník
parent cb9eb28dc9
commit cf1e892d13
3 changed files with 93 additions and 46 deletions

View File

@ -1,23 +1,23 @@
use crate::{
strutil::TString,
trezorhal::ble,
ui::{
component::{Component, Event, EventCtx},
geometry::{Offset, Point, Rect},
geometry::{Alignment2D, Offset, Point, Rect},
shape::{self, Renderer},
},
};
use super::{
super::{constant::SCREEN, fonts, theme},
BldActionBar, BldHeader,
super::{component::Button, constant::SCREEN, fonts, theme},
BldActionBar, BldActionBarMsg, BldHeader,
};
#[cfg(feature = "power_manager")]
use super::BldHeaderMsg;
// TODO: adjust the origin
const TEXT_ORIGIN: Point = Point::new(24, 205);
const STRIDE: i16 = 38;
const TEXT_ORIGIN: Point = Point::new(24, 76);
const STRIDE: i16 = 46;
#[repr(u32)]
#[derive(Copy, Clone, ToPrimitive)]
@ -27,48 +27,60 @@ pub enum WelcomeMsg {
Menu = 3,
}
/// Bootloader welcome screen
/// Full-screen component for Bootloader welcome screen. This is the first
/// screen shown after the bootloader is started on empty device. The user can
/// initiate pairing. If the device is already paired, the screen shows a
/// message that Trezor is paired and Bootloader Menu is accessible.
pub struct BldWelcomeScreen {
header: Option<BldHeader<'static>>,
action_bar: Option<BldActionBar>,
action_bar: BldActionBar,
ble_paired: bool,
}
impl BldWelcomeScreen {
pub fn new() -> Self {
let ble_paired = ble::peer_count() > 0;
let (header, button) = if ble_paired {
(
Some(BldHeader::new(TString::empty()).with_menu_button()),
Button::with_text("More at trezor.io/start".into())
.styled(theme::bootloader::button_welcome_screen())
.initially_enabled(false),
)
} else {
(
None,
Button::with_text("Tap to begin setup".into())
.styled(theme::bootloader::button_welcome_screen())
.initially_enabled(true),
)
};
Self {
header: Some(BldHeader::new(TString::empty()).with_menu_button()),
action_bar: None,
header,
action_bar: BldActionBar::new_single(button),
ble_paired,
}
}
pub fn with_header(mut self, header: BldHeader<'static>) -> Self {
self.header = Some(header);
self
}
pub fn with_action_bar(mut self, action_bar: BldActionBar) -> Self {
self.action_bar = Some(action_bar);
self
}
}
impl Component for BldWelcomeScreen {
type Msg = WelcomeMsg;
fn place(&mut self, bounds: Rect) -> Rect {
fn place(&mut self, _bounds: Rect) -> Rect {
let (header_area, rest) = SCREEN.split_top(theme::HEADER_HEIGHT);
let (_rest, action_bar_area) = rest.split_bottom(theme::ACTION_BAR_HEIGHT);
self.header.place(header_area);
self.action_bar.place(action_bar_area);
bounds
SCREEN
}
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> {
#[cfg(all(feature = "ble", feature = "button"))]
if let Event::Button(_) = _event {
#[cfg(feature = "ble")]
if let Some(BldActionBarMsg::Confirmed) = self.action_bar.event(_ctx, _event) {
return Some(WelcomeMsg::PairingMode);
}
#[cfg(feature = "power_manager")]
if let Some(BldHeaderMsg::Menu) = self.header.event(_ctx, _event) {
return Some(WelcomeMsg::Menu);
@ -77,31 +89,40 @@ impl Component for BldWelcomeScreen {
}
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
self.action_bar.render(target);
#[cfg(feature = "power_manager")]
self.header.render(target);
let font = fonts::FONT_SATOSHI_REGULAR_38;
shape::Text::new(TEXT_ORIGIN, "Get started", font)
.with_fg(theme::GREY)
shape::Text::new(TEXT_ORIGIN, "Trezor", font)
.with_fg(theme::GREY_LIGHT)
.render(target);
shape::Text::new(TEXT_ORIGIN + Offset::y(STRIDE), "with your Trezor", font)
.with_fg(theme::GREY)
shape::Text::new(TEXT_ORIGIN + Offset::y(STRIDE), "Safe", font)
.with_fg(theme::GREY_LIGHT)
.render(target);
shape::Text::new(TEXT_ORIGIN + Offset::y(2 * STRIDE), "at", font)
.with_fg(theme::GREY)
.render(target);
let at_width = font.text_width("at ");
shape::Text::new(
TEXT_ORIGIN + Offset::new(at_width, 2 * STRIDE),
"trezor.io/start",
font,
shape::ToifImage::new(
TEXT_ORIGIN + Offset::y(2 * STRIDE),
theme::bootloader::ICON_SEVEN.toif,
)
.with_fg(theme::GREY_EXTRA_LIGHT)
.with_fg(theme::GREY)
.with_align(Alignment2D::CENTER_LEFT)
.render(target);
// hint
let icon_pos = Point::new(24, 398);
let link_pos = icon_pos + Offset::x(theme::ICON_INFO.toif.width() + 12);
let (hint_color, hint_text) = if self.ble_paired {
(theme::GREEN_LIME, "Trezor is paired")
} else {
(theme::GREY, "trezor.io/start")
};
shape::ToifImage::new(icon_pos, theme::ICON_INFO.toif)
.with_fg(hint_color)
.with_align(Alignment2D::BOTTOM_LEFT)
.render(target);
shape::Text::new(link_pos, hint_text, fonts::FONT_SATOSHI_MEDIUM_26)
.with_fg(hint_color)
.render(target);
self.action_bar.render(target);
}
}

View File

@ -9,8 +9,8 @@ use super::{
component::{ButtonStyle, ButtonStyleSheet},
fonts,
},
BLACK, BLUE, GREY, GREY_DARK, GREY_EXTRA_LIGHT, GREY_LIGHT, GREY_SUPER_DARK, ORANGE, RED,
WHITE,
BLACK, BLUE, GREEN_LIGHT, GREY, GREY_DARK, GREY_EXTRA_LIGHT, GREY_LIGHT, GREY_SUPER_DARK,
ORANGE, RED, WHITE,
};
pub const BLD_BG: Color = BLACK;
@ -181,6 +181,34 @@ pub fn button_bld_menu_danger() -> ButtonStyleSheet {
}
}
/// Button style for the welcome screen
pub fn button_welcome_screen() -> ButtonStyleSheet {
ButtonStyleSheet {
normal: &ButtonStyle {
font: fonts::FONT_SATOSHI_MEDIUM_26,
text_color: GREY_LIGHT,
button_color: BLD_BG,
icon_color: GREY_LIGHT,
background_color: BLD_BG,
},
active: &ButtonStyle {
font: fonts::FONT_SATOSHI_MEDIUM_26,
text_color: GREY_EXTRA_LIGHT,
button_color: GREY_SUPER_DARK,
icon_color: GREY_EXTRA_LIGHT,
background_color: BLD_BG,
},
// used for the "Trezor is paired" button/footer
disabled: &ButtonStyle {
font: fonts::FONT_SATOSHI_MEDIUM_26,
text_color: GREEN_LIGHT,
button_color: BLD_BG,
icon_color: GREEN_LIGHT,
background_color: BLD_FG,
},
}
}
pub const fn text_title(bg: Color) -> TextStyle {
TextStyle::new(fonts::FONT_SATOSHI_MEDIUM_26, GREY, bg, GREY, GREY)
}

View File

@ -133,8 +133,6 @@ impl BootloaderLayoutType for BootloaderLayout {
}
fn init_welcome() -> Self {
// TODO: different UI. needs to decide based on some host already paired:
// peer_count() > 0
let screen = BldWelcomeScreen::new();
Self::Welcome(screen)
}