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:
parent
cb9eb28dc9
commit
cf1e892d13
@ -1,23 +1,23 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
strutil::TString,
|
strutil::TString,
|
||||||
|
trezorhal::ble,
|
||||||
ui::{
|
ui::{
|
||||||
component::{Component, Event, EventCtx},
|
component::{Component, Event, EventCtx},
|
||||||
geometry::{Offset, Point, Rect},
|
geometry::{Alignment2D, Offset, Point, Rect},
|
||||||
shape::{self, Renderer},
|
shape::{self, Renderer},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
super::{constant::SCREEN, fonts, theme},
|
super::{component::Button, constant::SCREEN, fonts, theme},
|
||||||
BldActionBar, BldHeader,
|
BldActionBar, BldActionBarMsg, BldHeader,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "power_manager")]
|
#[cfg(feature = "power_manager")]
|
||||||
use super::BldHeaderMsg;
|
use super::BldHeaderMsg;
|
||||||
|
|
||||||
// TODO: adjust the origin
|
const TEXT_ORIGIN: Point = Point::new(24, 76);
|
||||||
const TEXT_ORIGIN: Point = Point::new(24, 205);
|
const STRIDE: i16 = 46;
|
||||||
const STRIDE: i16 = 38;
|
|
||||||
|
|
||||||
#[repr(u32)]
|
#[repr(u32)]
|
||||||
#[derive(Copy, Clone, ToPrimitive)]
|
#[derive(Copy, Clone, ToPrimitive)]
|
||||||
@ -27,48 +27,60 @@ pub enum WelcomeMsg {
|
|||||||
Menu = 3,
|
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 {
|
pub struct BldWelcomeScreen {
|
||||||
header: Option<BldHeader<'static>>,
|
header: Option<BldHeader<'static>>,
|
||||||
action_bar: Option<BldActionBar>,
|
action_bar: BldActionBar,
|
||||||
|
ble_paired: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BldWelcomeScreen {
|
impl BldWelcomeScreen {
|
||||||
pub fn new() -> Self {
|
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 {
|
Self {
|
||||||
header: Some(BldHeader::new(TString::empty()).with_menu_button()),
|
header,
|
||||||
action_bar: None,
|
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 {
|
impl Component for BldWelcomeScreen {
|
||||||
type Msg = WelcomeMsg;
|
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 (header_area, rest) = SCREEN.split_top(theme::HEADER_HEIGHT);
|
||||||
let (_rest, action_bar_area) = rest.split_bottom(theme::ACTION_BAR_HEIGHT);
|
let (_rest, action_bar_area) = rest.split_bottom(theme::ACTION_BAR_HEIGHT);
|
||||||
|
|
||||||
self.header.place(header_area);
|
self.header.place(header_area);
|
||||||
self.action_bar.place(action_bar_area);
|
self.action_bar.place(action_bar_area);
|
||||||
bounds
|
SCREEN
|
||||||
}
|
}
|
||||||
|
|
||||||
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> {
|
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> {
|
||||||
#[cfg(all(feature = "ble", feature = "button"))]
|
#[cfg(feature = "ble")]
|
||||||
if let Event::Button(_) = _event {
|
if let Some(BldActionBarMsg::Confirmed) = self.action_bar.event(_ctx, _event) {
|
||||||
return Some(WelcomeMsg::PairingMode);
|
return Some(WelcomeMsg::PairingMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "power_manager")]
|
#[cfg(feature = "power_manager")]
|
||||||
if let Some(BldHeaderMsg::Menu) = self.header.event(_ctx, _event) {
|
if let Some(BldHeaderMsg::Menu) = self.header.event(_ctx, _event) {
|
||||||
return Some(WelcomeMsg::Menu);
|
return Some(WelcomeMsg::Menu);
|
||||||
@ -77,31 +89,40 @@ impl Component for BldWelcomeScreen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||||
self.action_bar.render(target);
|
|
||||||
#[cfg(feature = "power_manager")]
|
#[cfg(feature = "power_manager")]
|
||||||
self.header.render(target);
|
self.header.render(target);
|
||||||
|
|
||||||
let font = fonts::FONT_SATOSHI_REGULAR_38;
|
let font = fonts::FONT_SATOSHI_REGULAR_38;
|
||||||
shape::Text::new(TEXT_ORIGIN, "Get started", font)
|
shape::Text::new(TEXT_ORIGIN, "Trezor", font)
|
||||||
.with_fg(theme::GREY)
|
.with_fg(theme::GREY_LIGHT)
|
||||||
.render(target);
|
.render(target);
|
||||||
|
shape::Text::new(TEXT_ORIGIN + Offset::y(STRIDE), "Safe", font)
|
||||||
shape::Text::new(TEXT_ORIGIN + Offset::y(STRIDE), "with your Trezor", font)
|
.with_fg(theme::GREY_LIGHT)
|
||||||
.with_fg(theme::GREY)
|
|
||||||
.render(target);
|
.render(target);
|
||||||
|
shape::ToifImage::new(
|
||||||
shape::Text::new(TEXT_ORIGIN + Offset::y(2 * STRIDE), "at", font)
|
TEXT_ORIGIN + Offset::y(2 * STRIDE),
|
||||||
.with_fg(theme::GREY)
|
theme::bootloader::ICON_SEVEN.toif,
|
||||||
.render(target);
|
|
||||||
|
|
||||||
let at_width = font.text_width("at ");
|
|
||||||
|
|
||||||
shape::Text::new(
|
|
||||||
TEXT_ORIGIN + Offset::new(at_width, 2 * STRIDE),
|
|
||||||
"trezor.io/start",
|
|
||||||
font,
|
|
||||||
)
|
)
|
||||||
.with_fg(theme::GREY_EXTRA_LIGHT)
|
.with_fg(theme::GREY)
|
||||||
|
.with_align(Alignment2D::CENTER_LEFT)
|
||||||
.render(target);
|
.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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,8 @@ use super::{
|
|||||||
component::{ButtonStyle, ButtonStyleSheet},
|
component::{ButtonStyle, ButtonStyleSheet},
|
||||||
fonts,
|
fonts,
|
||||||
},
|
},
|
||||||
BLACK, BLUE, GREY, GREY_DARK, GREY_EXTRA_LIGHT, GREY_LIGHT, GREY_SUPER_DARK, ORANGE, RED,
|
BLACK, BLUE, GREEN_LIGHT, GREY, GREY_DARK, GREY_EXTRA_LIGHT, GREY_LIGHT, GREY_SUPER_DARK,
|
||||||
WHITE,
|
ORANGE, RED, WHITE,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const BLD_BG: Color = BLACK;
|
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 {
|
pub const fn text_title(bg: Color) -> TextStyle {
|
||||||
TextStyle::new(fonts::FONT_SATOSHI_MEDIUM_26, GREY, bg, GREY, GREY)
|
TextStyle::new(fonts::FONT_SATOSHI_MEDIUM_26, GREY, bg, GREY, GREY)
|
||||||
}
|
}
|
||||||
|
@ -133,8 +133,6 @@ impl BootloaderLayoutType for BootloaderLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn init_welcome() -> Self {
|
fn init_welcome() -> Self {
|
||||||
// TODO: different UI. needs to decide based on some host already paired:
|
|
||||||
// peer_count() > 0
|
|
||||||
let screen = BldWelcomeScreen::new();
|
let screen = BldWelcomeScreen::new();
|
||||||
Self::Welcome(screen)
|
Self::Welcome(screen)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user