1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-02-03 11:20:59 +00:00

feat(core/bootloader): new style for result screens (fixes #2910)

This commit is contained in:
matejcik 2023-03-29 16:22:45 +02:00
parent 6d434122f7
commit 839a940990
7 changed files with 188 additions and 273 deletions

View File

@ -30,14 +30,13 @@ use crate::{
connect::Connect, connect::Connect,
theme::{ theme::{
button_bld, button_confirm, button_wipe_cancel, button_wipe_confirm, BLD_BG, button_bld, button_confirm, button_wipe_cancel, button_wipe_confirm, BLD_BG,
BLD_BTN_COLOR, BLD_FG, BLD_WIPE_CANCEL_BTN_COLOR, BLD_WIPE_COLOR, CHECK24, BLD_FG, BLD_WIPE_COLOR, CHECK24, CHECK40, DOWNLOAD32, FIRE32, FIRE40,
CHECK40, DOWNLOAD32, FIRE32, FIRE40, LOGO_EMPTY, TEXT_WIPE_BOLD, LOGO_EMPTY, TEXT_WIPE_BOLD, TEXT_WIPE_NORMAL, WARNING40, WELCOME_COLOR, X24,
TEXT_WIPE_NORMAL, WARNING40, WELCOME_COLOR, WELCOME_HIGHLIGHT_COLOR, X24,
}, },
welcome::Welcome, welcome::Welcome,
}, },
component::{Button, ResultScreen}, component::{Button, ResultScreen},
theme::{BACKLIGHT_DIM, BACKLIGHT_NORMAL, BLACK, FG, TEXT_ERROR_HIGHLIGHT, WHITE}, theme::{BACKLIGHT_DIM, BACKLIGHT_NORMAL, BLACK, FG, WHITE},
}, },
util::{from_c_array, from_c_str}, util::{from_c_array, from_c_str},
}, },
@ -46,6 +45,10 @@ use confirm::Confirm;
use intro::Intro; use intro::Intro;
use menu::Menu; use menu::Menu;
use self::theme::{RESULT_FW_INSTALL, RESULT_INITIAL, RESULT_WIPE};
const RECONNECT_MESSAGE: &str = "PLEASE RECONNECT\nTHE DEVICE";
pub trait ReturnToC { pub trait ReturnToC {
fn return_to_c(self) -> u32; fn return_to_c(self) -> u32;
} }
@ -333,28 +336,11 @@ extern "C" fn screen_connect() {
#[no_mangle] #[no_mangle]
extern "C" fn screen_wipe_success() { extern "C" fn screen_wipe_success() {
let mut messages = ParagraphVecShort::new();
messages.add(Paragraph::new(&TEXT_WIPE_NORMAL, "Trezor reset").centered());
messages.add(Paragraph::new(&TEXT_WIPE_NORMAL, "successfully").centered());
let m_top =
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
let mut messages = ParagraphVecShort::new();
messages.add(Paragraph::new(&TEXT_ERROR_HIGHLIGHT, "PLEASE RECONNECT").centered());
messages.add(Paragraph::new(&TEXT_ERROR_HIGHLIGHT, "THE DEVICE").centered());
let m_bottom =
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
let mut frame = ResultScreen::new( let mut frame = ResultScreen::new(
WHITE, &RESULT_WIPE,
BLD_WIPE_COLOR,
BLD_WIPE_CANCEL_BTN_COLOR,
Icon::new(CHECK40), Icon::new(CHECK40),
m_top, "Trezor reset\nsuccessfully.",
Some(m_bottom), RECONNECT_MESSAGE,
true, true,
); );
show(&mut frame, true); show(&mut frame, true);
@ -362,27 +348,11 @@ extern "C" fn screen_wipe_success() {
#[no_mangle] #[no_mangle]
extern "C" fn screen_wipe_fail() { extern "C" fn screen_wipe_fail() {
let mut messages = ParagraphVecShort::new();
messages.add(Paragraph::new(&TEXT_WIPE_NORMAL, "Trezor reset was").centered());
messages.add(Paragraph::new(&TEXT_WIPE_NORMAL, "not successful.").centered());
let m_top =
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
let mut messages = ParagraphVecShort::new();
messages.add(Paragraph::new(&TEXT_ERROR_HIGHLIGHT, "PLEASE RECONNECT").centered());
messages.add(Paragraph::new(&TEXT_ERROR_HIGHLIGHT, "THE DEVICE").centered());
let m_bottom =
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
let mut frame = ResultScreen::new( let mut frame = ResultScreen::new(
WHITE, &RESULT_WIPE,
BLD_WIPE_COLOR,
BLD_WIPE_CANCEL_BTN_COLOR,
Icon::new(WARNING40), Icon::new(WARNING40),
m_top, "Trezor reset was\nnot successful.",
Some(m_bottom), RECONNECT_MESSAGE,
true, true,
); );
show(&mut frame, true); show(&mut frame, true);
@ -410,76 +380,33 @@ extern "C" fn screen_boot_empty(fading: bool) {
#[no_mangle] #[no_mangle]
extern "C" fn screen_install_fail() { extern "C" fn screen_install_fail() {
let mut messages = ParagraphVecShort::new();
messages.add(Paragraph::new(&theme::TEXT_NORMAL, "Firmware installation was").centered());
messages.add(Paragraph::new(&theme::TEXT_NORMAL, "not successful.").centered());
let m_top =
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
let mut messages = ParagraphVecShort::new();
messages.add(Paragraph::new(&theme::TEXT_SUBMSG, "PLEASE RECONNECT").centered());
messages.add(Paragraph::new(&theme::TEXT_SUBMSG, "THE DEVICE").centered());
let m_bottom =
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
let mut frame = ResultScreen::new( let mut frame = ResultScreen::new(
WHITE, &RESULT_FW_INSTALL,
BLD_BG,
BLD_BTN_COLOR,
Icon::new(WARNING40), Icon::new(WARNING40),
m_top, "Firmware installation was\nnot successful.",
Some(m_bottom), RECONNECT_MESSAGE,
true, true,
); );
show(&mut frame, true); show(&mut frame, true);
} }
fn screen_install_success_bld(msg: &'static str, complete_draw: bool) { fn screen_install_success_bld(msg: &'static str, complete_draw: bool) {
let mut messages = ParagraphVecShort::new();
messages.add(Paragraph::new(&theme::TEXT_NORMAL, "Firmware installed").centered());
messages.add(Paragraph::new(&theme::TEXT_NORMAL, "successfully").centered());
let m_top =
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
let mut messages = ParagraphVecShort::new();
messages.add(Paragraph::new(&theme::TEXT_SUBMSG, msg).centered());
let m_bottom =
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
let mut frame = ResultScreen::new( let mut frame = ResultScreen::new(
WHITE, &RESULT_FW_INSTALL,
BLD_BG,
BLD_BTN_COLOR,
Icon::new(CHECK40), Icon::new(CHECK40),
m_top, "Firmware installed\nsuccessfully.",
Some(m_bottom), msg,
complete_draw, complete_draw,
); );
show(&mut frame, complete_draw); show(&mut frame, complete_draw);
} }
fn screen_install_success_initial(msg: &'static str, complete_draw: bool) { fn screen_install_success_initial(msg: &'static str, complete_draw: bool) {
let mut messages = ParagraphVecShort::new();
messages.add(Paragraph::new(&theme::TEXT_WELCOME_URL, "Firmware installed").centered());
messages.add(Paragraph::new(&theme::TEXT_WELCOME_URL, "successfully").centered());
let m_top =
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
let mut messages = ParagraphVecShort::new();
messages.add(Paragraph::new(&theme::TEXT_SUBMSG_INITIAL, msg).centered());
let m_bottom =
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
let mut frame = ResultScreen::new( let mut frame = ResultScreen::new(
FG, &RESULT_INITIAL,
WELCOME_COLOR,
WELCOME_HIGHLIGHT_COLOR,
Icon::new(CHECK40), Icon::new(CHECK40),
m_top, "Firmware installed\nsuccessfully.",
Some(m_bottom), msg,
complete_draw, complete_draw,
); );
show(&mut frame, complete_draw); show(&mut frame, complete_draw);

View File

@ -4,8 +4,8 @@ use crate::ui::{
display::{Color, Font}, display::{Color, Font},
geometry::{Offset, Point, Rect}, geometry::{Offset, Point, Rect},
model_tt::{ model_tt::{
component::{ButtonStyle, ButtonStyleSheet}, component::{ButtonStyle, ButtonStyleSheet, ResultStyle},
theme::{BLACK, FG, GREY_DARK, GREY_LIGHT, GREY_MEDIUM, WHITE}, theme::{BLACK, FG, GREY_DARK, GREY_LIGHT, WHITE},
}, },
}; };
@ -232,14 +232,7 @@ pub fn button_bld() -> ButtonStyleSheet {
}, },
} }
} }
pub const TEXT_WELCOME: TextStyle = TextStyle::new(
Font::NORMAL,
GREY_MEDIUM,
WELCOME_COLOR,
GREY_MEDIUM,
GREY_MEDIUM,
);
pub const TEXT_WELCOME_URL: TextStyle = TextStyle::new(Font::NORMAL, FG, WELCOME_COLOR, FG, FG);
pub const TEXT_TITLE: TextStyle = TextStyle::new( pub const TEXT_TITLE: TextStyle = TextStyle::new(
Font::BOLD, Font::BOLD,
BLD_TITLE_COLOR, BLD_TITLE_COLOR,
@ -247,13 +240,6 @@ pub const TEXT_TITLE: TextStyle = TextStyle::new(
BLD_TITLE_COLOR, BLD_TITLE_COLOR,
BLD_TITLE_COLOR, BLD_TITLE_COLOR,
); );
pub const TEXT_SUBMSG_INITIAL: TextStyle = TextStyle::new(
Font::BOLD,
WHITE,
WELCOME_HIGHLIGHT_COLOR,
GREY_MEDIUM,
GREY_MEDIUM,
);
pub const TEXT_NORMAL: TextStyle = TextStyle::new(Font::NORMAL, BLD_FG, BLD_BG, BLD_FG, BLD_FG); pub const TEXT_NORMAL: TextStyle = TextStyle::new(Font::NORMAL, BLD_FG, BLD_BG, BLD_FG, BLD_FG);
pub const TEXT_FINGERPRINT: TextStyle = pub const TEXT_FINGERPRINT: TextStyle =
@ -274,4 +260,14 @@ pub const TEXT_WIPE_NORMAL: TextStyle = TextStyle::new(
BLD_WIPE_TEXT_COLOR, BLD_WIPE_TEXT_COLOR,
BLD_WIPE_TEXT_COLOR, BLD_WIPE_TEXT_COLOR,
); );
pub const TEXT_SUBMSG: TextStyle = TextStyle::new(Font::BOLD, WHITE, BLD_BTN_COLOR, WHITE, WHITE);
pub const RESULT_WIPE: ResultStyle = ResultStyle::new(
BLD_WIPE_TEXT_COLOR,
BLD_WIPE_COLOR,
BLD_WIPE_CANCEL_BTN_COLOR,
);
pub const RESULT_FW_INSTALL: ResultStyle = ResultStyle::new(BLD_FG, BLD_BG, BLD_BTN_COLOR);
pub const RESULT_INITIAL: ResultStyle =
ResultStyle::new(FG, WELCOME_COLOR, WELCOME_HIGHLIGHT_COLOR);

View File

@ -1,38 +1,38 @@
use crate::ui::{ use crate::ui::{
component::{ component::{Child, Component, Event, EventCtx, Label, Never, Pad},
text::paragraphs::{ParagraphStrType, ParagraphVecShort, Paragraphs},
Child, Component, Event, EventCtx, Label, Never, Pad,
},
constant::screen, constant::screen,
display::{self, Icon}, display::Icon,
geometry::{Alignment::Center, Point, Rect, TOP_CENTER}, geometry::{Alignment::Center, Point, Rect, TOP_CENTER},
}; };
use crate::ui::model_tt::{ use crate::ui::model_tt::{
component::{ResultFooter, ResultStyle},
constant::WIDTH, constant::WIDTH,
theme::{ theme::{FATAL_ERROR_COLOR, ICON_WARNING40, RESULT_FOOTER_START, RESULT_PADDING, WHITE},
FATAL_ERROR_COLOR, FATAL_ERROR_HIGHLIGHT_COLOR, ICON_WARNING40, RESULT_FOOTER_HEIGHT,
RESULT_FOOTER_START, RESULT_PADDING, TEXT_ERROR_BOLD, WHITE,
},
}; };
const ICON_TOP: i16 = 23;
const TITLE_AREA_START: i16 = 70; const TITLE_AREA_START: i16 = 70;
const ICON_TOP: i16 = 27; const MESSAGE_AREA_START: i16 = 116;
pub struct ErrorScreen<T> { #[cfg(feature = "bootloader")]
const STYLE: &ResultStyle = &crate::ui::model_tt::bootloader::theme::RESULT_WIPE;
#[cfg(not(feature = "bootloader"))]
const STYLE: &ResultStyle = &super::theme::RESULT_ERROR;
pub struct ErrorScreen<'a, T> {
bg: Pad, bg: Pad,
title: Child<Label<T>>, title: Child<Label<T>>,
message: Child<Paragraphs<ParagraphVecShort<T>>>, message: Child<Label<T>>,
footer: Child<Paragraphs<ParagraphVecShort<T>>>, footer: Child<ResultFooter<'a, T>>,
} }
impl<T: ParagraphStrType> ErrorScreen<T> { impl<T: AsRef<str>> ErrorScreen<'_, T> {
pub fn new( pub fn new(title: T, message: T, footer: T) -> Self {
title: T, let title = Label::new(title, Center, STYLE.title_style());
message: Paragraphs<ParagraphVecShort<T>>, let message = Label::new(message, Center, STYLE.message_style());
footer: Paragraphs<ParagraphVecShort<T>>, let footer = ResultFooter::new(footer, STYLE);
) -> Self {
let title = Label::new(title, Center, TEXT_ERROR_BOLD);
Self { Self {
bg: Pad::with_background(FATAL_ERROR_COLOR).with_clear(), bg: Pad::with_background(FATAL_ERROR_COLOR).with_clear(),
title: Child::new(title), title: Child::new(title),
@ -42,33 +42,28 @@ impl<T: ParagraphStrType> ErrorScreen<T> {
} }
} }
impl<T: ParagraphStrType> Component for ErrorScreen<T> { impl<T: AsRef<str>> Component for ErrorScreen<'_, T> {
type Msg = Never; type Msg = Never;
fn place(&mut self, bounds: Rect) -> Rect { fn place(&mut self, _bounds: Rect) -> Rect {
self.bg.place(screen()); self.bg.place(screen());
let title_area = Rect::new( let title_area = Rect::new(
Point::new(RESULT_PADDING, TITLE_AREA_START), Point::new(RESULT_PADDING, TITLE_AREA_START),
Point::new(WIDTH - RESULT_PADDING, RESULT_FOOTER_START), Point::new(WIDTH - RESULT_PADDING, MESSAGE_AREA_START),
); );
self.title.place(title_area); self.title.place(title_area);
let (_, message_area) = title_area.split_top(self.title.inner().area().height()); let message_area = Rect::new(
Point::new(RESULT_PADDING, MESSAGE_AREA_START),
Point::new(WIDTH - RESULT_PADDING, RESULT_FOOTER_START),
);
self.message.place(message_area); self.message.place(message_area);
let bottom_area = Rect::new( let (_, bottom_area) = ResultFooter::<T>::split_bounds();
Point::new(RESULT_PADDING, RESULT_FOOTER_START),
Point::new(
WIDTH - RESULT_PADDING,
RESULT_FOOTER_START + RESULT_FOOTER_HEIGHT,
),
);
self.footer.place(bottom_area); self.footer.place(bottom_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> {
@ -87,19 +82,6 @@ impl<T: ParagraphStrType> Component for ErrorScreen<T> {
); );
self.title.paint(); self.title.paint();
self.message.paint(); self.message.paint();
display::rect_fill_rounded(
Rect::new(
Point::new(RESULT_PADDING, RESULT_FOOTER_START),
Point::new(
WIDTH - RESULT_PADDING,
RESULT_FOOTER_START + RESULT_FOOTER_HEIGHT,
),
),
FATAL_ERROR_HIGHLIGHT_COLOR,
FATAL_ERROR_COLOR,
2,
);
self.footer.paint(); self.footer.paint();
} }
} }

View File

@ -47,7 +47,7 @@ pub use loader::{Loader, LoaderMsg, LoaderStyle, LoaderStyleSheet};
pub use number_input::{NumberInputDialog, NumberInputDialogMsg}; pub use number_input::{NumberInputDialog, NumberInputDialogMsg};
pub use page::{SwipeHoldPage, SwipePage}; pub use page::{SwipeHoldPage, SwipePage};
pub use progress::Progress; pub use progress::Progress;
pub use result::ResultScreen; pub use result::{ResultFooter, ResultScreen, ResultStyle};
pub use scroll::ScrollBar; pub use scroll::ScrollBar;
pub use swipe::{Swipe, SwipeDirection}; pub use swipe::{Swipe, SwipeDirection};
pub use welcome_screen::WelcomeScreen; pub use welcome_screen::WelcomeScreen;

View File

@ -1,51 +1,124 @@
use crate::ui::{ use crate::ui::{
component::{ component::{
text::paragraphs::{ParagraphStrType, ParagraphVecShort, Paragraphs}, text::{paragraphs::ParagraphStrType, TextStyle},
Child, Component, Event, EventCtx, Never, Pad, Child, Component, Event, EventCtx, Label, Never, Pad,
}, },
constant::screen, constant::screen,
display::{self, Color, Icon}, display::{self, Color, Font, Icon},
geometry::{Point, Rect, CENTER}, geometry::{Alignment::Center, Insets, Offset, Point, Rect, CENTER},
model_tt::theme::FG,
}; };
use crate::ui::model_tt::{ use crate::ui::model_tt::{
constant::WIDTH, constant::WIDTH,
theme::{RESULT_FOOTER_HEIGHT, RESULT_FOOTER_START, RESULT_PADDING}, theme::{RESULT_FOOTER_START, RESULT_PADDING},
}; };
const MESSAGE_AREA_START: i16 = 82; const MESSAGE_AREA_START: i16 = 97;
const ICON_CENTER_Y: i16 = 62; const ICON_CENTER_Y: i16 = 62;
pub struct ResultScreen<T> { pub struct ResultStyle {
bg: Pad, pub fg_color: Color,
footer_pad: Pad, pub bg_color: Color,
fg_color: Color, pub divider_color: Color,
bg_color: Color,
msg_area_color: Color,
icon: Icon,
message: Child<Paragraphs<ParagraphVecShort<T>>>,
footer: Option<Child<Paragraphs<ParagraphVecShort<T>>>>,
} }
impl<T: ParagraphStrType> ResultScreen<T> { impl ResultStyle {
pub const fn new(fg_color: Color, bg_color: Color, divider_color: Color) -> Self {
Self {
fg_color,
bg_color,
divider_color,
}
}
pub const fn message_style(&self) -> TextStyle {
TextStyle::new(Font::NORMAL, self.fg_color, self.bg_color, FG, FG)
}
pub const fn title_style(&self) -> TextStyle {
TextStyle::new(Font::BOLD, self.fg_color, self.bg_color, FG, FG)
}
}
pub struct ResultFooter<'a, T> {
style: &'a ResultStyle,
text: Label<T>,
area: Rect,
}
impl<'a, T: AsRef<str>> ResultFooter<'a, T> {
pub fn new(text: T, style: &'a ResultStyle) -> Self {
Self {
style,
text: Label::new(text, Center, style.title_style()).vertically_aligned(Center),
area: Rect::zero(),
}
}
pub const fn split_bounds() -> (Rect, Rect) {
let main_area = Rect::new(
Point::new(RESULT_PADDING, 0),
Point::new(WIDTH - RESULT_PADDING, RESULT_FOOTER_START),
);
let footer_area = Rect::new(
Point::new(RESULT_PADDING, RESULT_FOOTER_START),
Point::new(WIDTH - RESULT_PADDING, screen().height()),
);
(main_area, footer_area)
}
}
impl<T: AsRef<str>> Component for ResultFooter<'_, T> {
type Msg = Never;
fn place(&mut self, bounds: Rect) -> Rect {
self.area = bounds;
self.text.place(bounds);
bounds
}
fn paint(&mut self) {
// divider line
let bar = Rect::from_center_and_size(
Point::new(self.area.center().x, self.area.y0),
Offset::new(self.area.width(), 1),
);
display::rect_fill(bar, self.style.divider_color);
// footer text
self.text.paint();
}
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> {
None
}
}
pub struct ResultScreen<'a, T> {
bg: Pad,
footer_pad: Pad,
style: &'a ResultStyle,
icon: Icon,
message: Child<Label<T>>,
footer: Child<ResultFooter<'a, T>>,
}
impl<'a, T: ParagraphStrType> ResultScreen<'a, T> {
pub fn new( pub fn new(
fg_color: Color, style: &'a ResultStyle,
bg_color: Color,
msg_area_color: Color,
icon: Icon, icon: Icon,
message: Paragraphs<ParagraphVecShort<T>>, message: T,
footer: Option<Paragraphs<ParagraphVecShort<T>>>, footer: T,
complete_draw: bool, complete_draw: bool,
) -> Self { ) -> Self {
let mut instance = Self { let mut instance = Self {
bg: Pad::with_background(bg_color), bg: Pad::with_background(style.bg_color),
footer_pad: Pad::with_background(bg_color), footer_pad: Pad::with_background(style.bg_color),
fg_color, style,
bg_color,
msg_area_color,
icon, icon,
message: Child::new(message), message: Child::new(Label::new(message, Center, style.message_style())),
footer: footer.map(Child::new), footer: Child::new(ResultFooter::new(footer, style)),
}; };
if complete_draw { if complete_draw {
@ -57,39 +130,21 @@ impl<T: ParagraphStrType> ResultScreen<T> {
} }
} }
impl<T: ParagraphStrType> Component for ResultScreen<T> { impl<T: ParagraphStrType> Component for ResultScreen<'_, T> {
type Msg = Never; type Msg = Never;
fn place(&mut self, bounds: Rect) -> Rect { fn place(&mut self, _bounds: Rect) -> Rect {
self.bg.place(screen()); self.bg.place(screen());
let message_arae = if let Some(footer) = &mut self.footer { let (main_area, footer_area) = ResultFooter::<T>::split_bounds();
let footer_area = Rect::new(
Point::new(RESULT_PADDING, RESULT_FOOTER_START),
Point::new(
WIDTH - RESULT_PADDING,
RESULT_FOOTER_START + RESULT_FOOTER_HEIGHT,
),
);
self.footer_pad.place(footer_area);
footer.place(footer_area);
Rect::new(
Point::new(RESULT_PADDING, MESSAGE_AREA_START),
Point::new(WIDTH - RESULT_PADDING, RESULT_FOOTER_START),
)
} else {
Rect::new(
Point::new(RESULT_PADDING, MESSAGE_AREA_START),
Point::new(
WIDTH - RESULT_PADDING,
RESULT_FOOTER_START + RESULT_FOOTER_HEIGHT,
),
)
};
self.message.place(message_arae); self.footer_pad.place(footer_area);
self.footer.place(footer_area);
bounds let message_area = main_area.inset(Insets::top(MESSAGE_AREA_START));
self.message.place(message_area);
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> {
@ -103,25 +158,10 @@ impl<T: ParagraphStrType> Component for ResultScreen<T> {
self.icon.draw( self.icon.draw(
Point::new(screen().center().x, ICON_CENTER_Y), Point::new(screen().center().x, ICON_CENTER_Y),
CENTER, CENTER,
self.fg_color, self.style.fg_color,
self.bg_color, self.style.bg_color,
); );
self.message.paint(); self.message.paint();
self.footer.paint();
if let Some(bottom) = &mut self.footer {
display::rect_fill_rounded(
Rect::new(
Point::new(RESULT_PADDING, RESULT_FOOTER_START),
Point::new(
WIDTH - RESULT_PADDING,
RESULT_FOOTER_START + RESULT_FOOTER_HEIGHT,
),
),
self.msg_area_color,
self.bg_color,
2,
);
bottom.paint();
}
} }
} }

View File

@ -1,16 +1,8 @@
#[cfg(feature = "micropython")] #[cfg(feature = "micropython")]
use crate::micropython::buffer::StrBuffer; use crate::micropython::buffer::StrBuffer;
use crate::ui::{ use crate::ui::{
component::{ component::Component,
text::paragraphs::{Paragraph, ParagraphVecShort, Paragraphs, VecExt}, model_tt::{component::ErrorScreen, constant},
Component,
},
geometry::LinearPlacement,
model_tt::{
component::ErrorScreen,
constant,
theme::{TEXT_ERROR_HIGHLIGHT, TEXT_ERROR_NORMAL},
},
}; };
#[cfg(not(feature = "micropython"))] #[cfg(not(feature = "micropython"))]
@ -32,21 +24,7 @@ pub fn screen_fatal_error(title: &str, msg: &str, footer: &str) {
let msg = unsafe { get_str(msg) }; let msg = unsafe { get_str(msg) };
let footer = unsafe { get_str(footer) }; let footer = unsafe { get_str(footer) };
let mut messages = ParagraphVecShort::new(); let mut frame = ErrorScreen::new(title, msg, footer);
messages.add(Paragraph::new(&TEXT_ERROR_NORMAL, msg).centered());
let m_top =
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
let mut messages = ParagraphVecShort::new();
messages.add(Paragraph::new(&TEXT_ERROR_HIGHLIGHT, footer).centered());
let m_bottom =
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
let mut frame = ErrorScreen::new(title, m_top, m_bottom);
frame.place(constant::screen()); frame.place(constant::screen());
frame.paint(); frame.paint();
} }

View File

@ -10,7 +10,7 @@ use crate::{
}, },
}; };
use super::component::{ButtonStyle, ButtonStyleSheet, LoaderStyle, LoaderStyleSheet}; use super::component::{ButtonStyle, ButtonStyleSheet, LoaderStyle, LoaderStyleSheet, ResultStyle};
use num_traits::FromPrimitive; use num_traits::FromPrimitive;
@ -516,17 +516,6 @@ pub fn textstyle_number(num: i32) -> &'static TextStyle {
_ => &TEXT_NORMAL, _ => &TEXT_NORMAL,
} }
} }
pub const TEXT_ERROR_NORMAL: TextStyle =
TextStyle::new(Font::NORMAL, FG, FATAL_ERROR_COLOR, GREY_LIGHT, GREY_LIGHT);
pub const TEXT_ERROR_BOLD: TextStyle =
TextStyle::new(Font::BOLD, FG, FATAL_ERROR_COLOR, GREY_LIGHT, GREY_LIGHT);
pub const TEXT_ERROR_HIGHLIGHT: TextStyle = TextStyle::new(
Font::BOLD,
FG,
FATAL_ERROR_HIGHLIGHT_COLOR,
GREY_LIGHT,
GREY_LIGHT,
);
pub const TEXT_NORMAL_OFF_WHITE: TextStyle = pub const TEXT_NORMAL_OFF_WHITE: TextStyle =
TextStyle::new(Font::NORMAL, OFF_WHITE, BG, GREY_LIGHT, GREY_LIGHT); TextStyle::new(Font::NORMAL, OFF_WHITE, BG, GREY_LIGHT, GREY_LIGHT);
@ -557,8 +546,8 @@ pub const INFO_BUTTON_HEIGHT: i16 = 44;
pub const PIN_BUTTON_HEIGHT: i16 = 40; pub const PIN_BUTTON_HEIGHT: i16 = 40;
pub const MNEMONIC_BUTTON_HEIGHT: i16 = 52; pub const MNEMONIC_BUTTON_HEIGHT: i16 = 52;
pub const RESULT_PADDING: i16 = 6; pub const RESULT_PADDING: i16 = 6;
pub const RESULT_FOOTER_START: i16 = 178; pub const RESULT_FOOTER_START: i16 = 171;
pub const RESULT_FOOTER_HEIGHT: i16 = 56; pub const RESULT_FOOTER_HEIGHT: i16 = 62;
pub const fn button_bar<T>(inner: T) -> FixedHeightBar<T> { pub const fn button_bar<T>(inner: T) -> FixedHeightBar<T> {
FixedHeightBar::bottom(inner, BUTTON_HEIGHT) FixedHeightBar::bottom(inner, BUTTON_HEIGHT)
@ -582,3 +571,6 @@ pub const fn borders_horizontal_scroll() -> Insets {
pub const fn borders_notification() -> Insets { pub const fn borders_notification() -> Insets {
Insets::new(48, 6, 6, 6) Insets::new(48, 6, 6, 6)
} }
pub const RESULT_ERROR: ResultStyle =
ResultStyle::new(FG, FATAL_ERROR_COLOR, FATAL_ERROR_HIGHLIGHT_COLOR);