1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-19 14:08:11 +00:00

refactor(core/mercury): extract non-generic code from frame component

[no changelog]
This commit is contained in:
tychovrahe 2024-07-14 13:12:32 +02:00 committed by TychoVrahe
parent f2bdd6e189
commit 873658104d
4 changed files with 86 additions and 68 deletions

View File

@ -45,11 +45,14 @@ impl<'a> Footer<'a> {
const STYLE_INSTRUCTION: &'static TextStyle = &theme::TEXT_SUB_GREY; const STYLE_INSTRUCTION: &'static TextStyle = &theme::TEXT_SUB_GREY;
const STYLE_DESCRIPTION: &'static TextStyle = &theme::TEXT_SUB_GREY_LIGHT; const STYLE_DESCRIPTION: &'static TextStyle = &theme::TEXT_SUB_GREY_LIGHT;
pub fn new<T: Into<TString<'a>>>(instruction: T) -> Self { pub fn new<T: Into<TString<'a>>>(
instruction: T,
description: Option<TString<'static>>,
) -> Self {
Self { Self {
area: Rect::zero(), area: Rect::zero(),
instruction: instruction.into(), instruction: instruction.into(),
content: None, content: description.map(FooterContent::Description),
swipe_allow_down: false, swipe_allow_down: false,
swipe_allow_up: false, swipe_allow_up: false,
progress: 0, progress: 0,
@ -57,13 +60,6 @@ impl<'a> Footer<'a> {
} }
} }
pub fn with_description<T: Into<TString<'a>>>(self, description: T) -> Self {
Self {
content: Some(FooterContent::Description(description.into())),
..self
}
}
pub fn with_page_counter(self, max_pages: u8) -> Self { pub fn with_page_counter(self, max_pages: u8) -> Self {
Self { Self {
content: Some(FooterContent::PageCounter(PageCounter::new(max_pages))), content: Some(FooterContent::PageCounter(PageCounter::new(max_pages))),
@ -110,16 +106,17 @@ impl<'a> Footer<'a> {
} }
} }
pub fn with_swipe_up(self) -> Self { pub fn with_swipe(self, swipe_direction: SwipeDirection) -> Self {
Self { match swipe_direction {
swipe_allow_up: true, SwipeDirection::Up => Self {
..self swipe_allow_up: true,
} ..self
} },
pub fn with_swipe_down(self) -> Self { SwipeDirection::Down => Self {
Self { swipe_allow_down: true,
swipe_allow_down: true, ..self
..self },
_ => self,
} }
} }
} }

View File

@ -1,4 +1,4 @@
use super::{theme, ButtonMsg, ButtonStyleSheet, CancelInfoConfirmMsg, Footer, Header}; use super::{theme, ButtonStyleSheet, CancelInfoConfirmMsg, Footer, Header};
use crate::{ use crate::{
strutil::TString, strutil::TString,
ui::{ ui::{
@ -84,7 +84,6 @@ impl HorizontalSwipe {
pub struct Frame<T> { pub struct Frame<T> {
border: Insets, border: Insets,
bounds: Rect, bounds: Rect,
button_msg: CancelInfoConfirmMsg,
content: T, content: T,
header: Header, header: Header,
footer: Option<Footer<'static>>, footer: Option<Footer<'static>>,
@ -106,7 +105,6 @@ where
Self { Self {
bounds: Rect::zero(), bounds: Rect::zero(),
border: theme::borders(), border: theme::borders(),
button_msg: CancelInfoConfirmMsg::Cancelled,
content, content,
header: Header::new(alignment, title), header: Header::new(alignment, title),
footer: None, footer: None,
@ -145,8 +143,7 @@ where
#[inline(never)] #[inline(never)]
fn with_button(mut self, icon: Icon, msg: CancelInfoConfirmMsg, enabled: bool) -> Self { fn with_button(mut self, icon: Icon, msg: CancelInfoConfirmMsg, enabled: bool) -> Self {
self.header = self.header.with_button(icon, enabled); self.header = self.header.with_button(icon, enabled, msg);
self.button_msg = msg;
self self
} }
@ -189,17 +186,13 @@ where
instruction: TString<'static>, instruction: TString<'static>,
description: Option<TString<'static>>, description: Option<TString<'static>>,
) -> Self { ) -> Self {
let mut footer = Footer::new(instruction); self.footer = Some(Footer::new(instruction, description));
if let Some(description_text) = description {
footer = footer.with_description(description_text);
}
self.footer = Some(footer);
self self
} }
#[inline(never)] #[inline(never)]
pub fn with_footer_counter(mut self, instruction: TString<'static>, max_value: u8) -> Self { pub fn with_footer_counter(mut self, instruction: TString<'static>, max_value: u8) -> Self {
self.footer = Some(Footer::new(instruction).with_page_counter(max_value)); self.footer = Some(Footer::new(instruction, None).with_page_counter(max_value));
self self
} }
@ -213,8 +206,7 @@ where
} }
pub fn update_title(&mut self, ctx: &mut EventCtx, new_title: TString<'static>) { pub fn update_title(&mut self, ctx: &mut EventCtx, new_title: TString<'static>) {
self.header.update_title(new_title); self.header.update_title(ctx, new_title);
ctx.request_paint();
} }
pub fn update_subtitle( pub fn update_subtitle(
@ -223,8 +215,7 @@ where
new_subtitle: TString<'static>, new_subtitle: TString<'static>,
new_style: Option<TextStyle>, new_style: Option<TextStyle>,
) { ) {
self.header.update_subtitle(new_subtitle, new_style); self.header.update_subtitle(ctx, new_subtitle, new_style);
ctx.request_paint();
} }
pub fn update_content<F, R>(&mut self, ctx: &mut EventCtx, update_fn: F) -> R pub fn update_content<F, R>(&mut self, ctx: &mut EventCtx, update_fn: F) -> R
@ -244,11 +235,7 @@ where
#[inline(never)] #[inline(never)]
pub fn with_swipe(mut self, dir: SwipeDirection, settings: SwipeSettings) -> Self { pub fn with_swipe(mut self, dir: SwipeDirection, settings: SwipeSettings) -> Self {
self.footer = self.footer.map(|f| match dir { self.footer = self.footer.map(|f| f.with_swipe(dir));
SwipeDirection::Up => f.with_swipe_up(),
SwipeDirection::Down => f.with_swipe_down(),
_ => f,
});
self.swipe = self.swipe.with_swipe(dir, settings); self.swipe = self.swipe.with_swipe(dir, settings);
self self
} }
@ -275,21 +262,7 @@ where
fn place(&mut self, bounds: Rect) -> Rect { fn place(&mut self, bounds: Rect) -> Rect {
self.bounds = bounds; self.bounds = bounds;
let content_area = frame_place(&mut self.header, &mut self.footer, bounds);
let (mut header_area, mut content_area) = bounds.split_top(TITLE_HEIGHT);
content_area = content_area.inset(Insets::top(theme::SPACING));
header_area = header_area.inset(Insets::sides(theme::SPACING));
self.header.place(header_area);
if let Some(footer) = &mut self.footer {
// FIXME: spacer at the bottom might be applied also for usage without footer
// but not for VerticalMenu
content_area = content_area.inset(Insets::bottom(theme::SPACING));
let (remaining, footer_area) = content_area.split_bottom(footer.height());
footer.place(footer_area);
content_area = remaining;
}
self.content.place(content_area); self.content.place(content_area);
@ -297,9 +270,17 @@ where
} }
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> { fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
self.horizontal_swipe.event(event, self.swipe); if let Some(value) = frame_event(
&mut self.horizontal_swipe,
self.swipe,
&mut self.header,
&mut self.footer,
ctx,
event,
) {
return Some(FrameMsg::Button(value));
}
self.footer.event(ctx, event);
let msg = self.content.event(ctx, event).map(FrameMsg::Content); let msg = self.content.event(ctx, event).map(FrameMsg::Content);
if let Some(count) = ctx.page_count() { if let Some(count) = ctx.page_count() {
self.internal_page_cnt = count; self.internal_page_cnt = count;
@ -308,9 +289,7 @@ where
if msg.is_some() { if msg.is_some() {
return msg; return msg;
} }
if let Some(ButtonMsg::Clicked) = self.header.event(ctx, event) {
return Some(FrameMsg::Button(self.button_msg));
}
None None
} }
@ -328,6 +307,37 @@ where
.render_swipe_cover(target, self.bounds); .render_swipe_cover(target, self.bounds);
} }
} }
fn frame_event(
horizontal_swipe: &mut HorizontalSwipe,
swipe_config: SwipeConfig,
header: &mut Header,
footer: &mut Option<Footer>,
ctx: &mut EventCtx,
event: Event,
) -> Option<CancelInfoConfirmMsg> {
horizontal_swipe.event(event, swipe_config);
footer.event(ctx, event);
header.event(ctx, event)
}
fn frame_place(header: &mut Header, footer: &mut Option<Footer>, bounds: Rect) -> Rect {
let (mut header_area, mut content_area) = bounds.split_top(TITLE_HEIGHT);
content_area = content_area.inset(Insets::top(theme::SPACING));
header_area = header_area.inset(Insets::sides(theme::SPACING));
header.place(header_area);
if let Some(footer) = footer {
// FIXME: spacer at the bottom might be applied also for usage without footer
// but not for VerticalMenu
content_area = content_area.inset(Insets::bottom(theme::SPACING));
let (remaining, footer_area) = content_area.split_bottom(footer.height());
footer.place(footer_area);
content_area = remaining;
}
content_area
}
#[cfg(feature = "micropython")] #[cfg(feature = "micropython")]
impl<T> crate::ui::flow::Swipable for Frame<T> { impl<T> crate::ui::flow::Swipable for Frame<T> {

View File

@ -7,7 +7,7 @@ use crate::{
geometry::{Alignment, Alignment2D, Insets, Offset, Rect}, geometry::{Alignment, Alignment2D, Insets, Offset, Rect},
lerp::Lerp, lerp::Lerp,
model_mercury::{ model_mercury::{
component::{Button, ButtonMsg, ButtonStyleSheet}, component::{Button, ButtonMsg, ButtonStyleSheet, CancelInfoConfirmMsg},
theme, theme,
theme::TITLE_HEIGHT, theme::TITLE_HEIGHT,
}, },
@ -71,6 +71,7 @@ pub struct Header {
icon: Option<Icon>, icon: Option<Icon>,
color: Option<Color>, color: Option<Color>,
title_style: TextStyle, title_style: TextStyle,
button_msg: CancelInfoConfirmMsg,
} }
impl Header { impl Header {
@ -84,6 +85,7 @@ impl Header {
icon: None, icon: None,
color: None, color: None,
title_style: theme::label_title_main(), title_style: theme::label_title_main(),
button_msg: CancelInfoConfirmMsg::Cancelled,
} }
} }
#[inline(never)] #[inline(never)]
@ -107,12 +109,14 @@ impl Header {
self self
} }
#[inline(never)] #[inline(never)]
pub fn update_title(&mut self, title: TString<'static>) { pub fn update_title(&mut self, ctx: &mut EventCtx, title: TString<'static>) {
self.title.set_text(title); self.title.set_text(title);
ctx.request_paint();
} }
#[inline(never)] #[inline(never)]
pub fn update_subtitle( pub fn update_subtitle(
&mut self, &mut self,
ctx: &mut EventCtx,
new_subtitle: TString<'static>, new_subtitle: TString<'static>,
new_style: Option<TextStyle>, new_style: Option<TextStyle>,
) { ) {
@ -126,10 +130,11 @@ impl Header {
self.subtitle = Some(Label::new(new_subtitle, self.title.alignment(), style)); self.subtitle = Some(Label::new(new_subtitle, self.title.alignment(), style));
} }
} }
ctx.request_paint();
} }
#[inline(never)] #[inline(never)]
pub fn with_button(mut self, icon: Icon, enabled: bool) -> Self { pub fn with_button(mut self, icon: Icon, enabled: bool, msg: CancelInfoConfirmMsg) -> Self {
let touch_area = Insets::uniform(BUTTON_EXPAND_BORDER); let touch_area = Insets::uniform(BUTTON_EXPAND_BORDER);
self.button = Some( self.button = Some(
Button::with_icon(icon) Button::with_icon(icon)
@ -137,6 +142,7 @@ impl Header {
.initially_enabled(enabled) .initially_enabled(enabled)
.styled(theme::button_default()), .styled(theme::button_default()),
); );
self.button_msg = msg;
self self
} }
#[inline(never)] #[inline(never)]
@ -160,7 +166,7 @@ impl Header {
} }
impl Component for Header { impl Component for Header {
type Msg = ButtonMsg; type Msg = CancelInfoConfirmMsg;
fn place(&mut self, bounds: Rect) -> Rect { fn place(&mut self, bounds: Rect) -> Rect {
let header_area = if let Some(b) = &mut self.button { let header_area = if let Some(b) = &mut self.button {
@ -201,7 +207,11 @@ impl Component for Header {
} }
} }
self.button.event(ctx, event) if let Some(ButtonMsg::Clicked) = self.button.event(ctx, event) {
return Some(self.button_msg);
};
None
} }
fn paint(&mut self) { fn paint(&mut self) {

View File

@ -1,3 +1,4 @@
use super::{theme, Footer};
use crate::{ use crate::{
strutil::{ShortString, TString}, strutil::{ShortString, TString},
translations::TR, translations::TR,
@ -11,8 +12,6 @@ use crate::{
}, },
}; };
use super::{theme, Footer};
pub enum NumberInputSliderDialogMsg { pub enum NumberInputSliderDialogMsg {
Changed(u16), Changed(u16),
} }
@ -32,8 +31,10 @@ impl NumberInputSliderDialog {
Self { Self {
area: Rect::zero(), area: Rect::zero(),
input: NumberInputSlider::new(min, max, init_value).into_child(), input: NumberInputSlider::new(min, max, init_value).into_child(),
footer: Footer::new::<TString<'static>>(TR::instructions__swipe_horizontally.into()) footer: Footer::new::<TString<'static>>(
.with_description::<TString<'static>>(TR::setting__adjust.into()), TR::instructions__swipe_horizontally.into(),
Some(TR::setting__adjust.into()),
),
min, min,
max, max,
val: init_value, val: init_value,