From 468ddaab9d6809f01baeadcce28d447db47595f3 Mon Sep 17 00:00:00 2001 From: Lukas Bielesch Date: Tue, 20 May 2025 15:22:53 +0200 Subject: [PATCH] chore(eckhart): simplify updatable info screen [no changelog] --- .../src/ui/layout_eckhart/firmware/mod.rs | 2 +- .../firmware/updatable_info_screen.rs | 99 ++++++++++++++----- .../ui/layout_eckhart/flow/request_number.rs | 14 ++- 3 files changed, 80 insertions(+), 35 deletions(-) diff --git a/core/embed/rust/src/ui/layout_eckhart/firmware/mod.rs b/core/embed/rust/src/ui/layout_eckhart/firmware/mod.rs index d17885c5f9..ccb5825230 100644 --- a/core/embed/rust/src/ui/layout_eckhart/firmware/mod.rs +++ b/core/embed/rust/src/ui/layout_eckhart/firmware/mod.rs @@ -42,7 +42,7 @@ pub use qr_screen::{QrMsg, QrScreen}; pub use select_word_screen::{SelectWordMsg, SelectWordScreen}; pub use share_words::{ShareWordsScreen, ShareWordsScreenMsg}; pub use text_screen::{AllowedTextContent, TextScreen, TextScreenMsg}; -pub use updatable_info_screen::UpdatableInfoScreen; +pub use updatable_info_screen::{UpdatableInfoScreen, UpdatableInfoScreenMsg}; pub use value_input_screen::{ DurationInput, NumberInput, ValueInput, ValueInputScreen, ValueInputScreenMsg, }; diff --git a/core/embed/rust/src/ui/layout_eckhart/firmware/updatable_info_screen.rs b/core/embed/rust/src/ui/layout_eckhart/firmware/updatable_info_screen.rs index 2ed59527ec..220ae31d84 100644 --- a/core/embed/rust/src/ui/layout_eckhart/firmware/updatable_info_screen.rs +++ b/core/embed/rust/src/ui/layout_eckhart/firmware/updatable_info_screen.rs @@ -5,7 +5,7 @@ use crate::{ component::{ swipe_detect::SwipeConfig, text::paragraphs::{Paragraph, ParagraphSource, Paragraphs}, - Component, Event, EventCtx, + Component, Event, EventCtx, PaginateFull, }, flow::Swipable, geometry::{LinearPlacement, Rect}, @@ -14,16 +14,20 @@ use crate::{ }, }; -use super::{theme, Header, TextScreen, TextScreenMsg}; +use super::{constant::SCREEN, theme, ActionBar, ActionBarMsg, Header}; + +pub enum UpdatableInfoScreenMsg { + Close, +} pub struct UpdatableInfoScreen where F: Fn() -> TString<'static>, { + header: Header, info_func: F, - paragraphs: Paragraphs>, - area: Rect, - text_screen: TextScreen>>, + paragraph: Paragraphs>, + action_bar: ActionBar, } impl UpdatableInfoScreen @@ -31,59 +35,97 @@ where F: Fn() -> TString<'static>, { pub fn new(info_func: F) -> Self { - let paragraphs = Paragraph::new(&theme::TEXT_REGULAR, TString::empty()) + let paragraph = Paragraph::new(&theme::TEXT_REGULAR, TString::empty()) .into_paragraphs() .with_placement(LinearPlacement::vertical()); - let text_screen = create_text_screen(paragraphs.clone()); Self { + header: Header::new(TR::buttons__more_info.into()).with_close_button(), info_func, - paragraphs, - area: Rect::zero(), - text_screen, + paragraph, + action_bar: ActionBar::new_paginate_only(), } } + pub fn with_header(mut self, header: Header) -> Self { + self.header = header; + self + } + fn update_text(&mut self, ctx: &mut EventCtx) { let text = (self.info_func)(); - self.paragraphs.update(text); - self.text_screen = create_text_screen(self.paragraphs.clone()); - self.text_screen.place(self.area); + self.paragraph.update(text); + + self.update_page(0); ctx.request_paint(); } + + fn update_page(&mut self, page_idx: u16) { + self.paragraph.change_page(page_idx); + self.action_bar.update(self.paragraph.pager()); + } } impl Component for UpdatableInfoScreen where F: Fn() -> TString<'static>, { - type Msg = TextScreenMsg; + type Msg = UpdatableInfoScreenMsg; fn place(&mut self, bounds: Rect) -> Rect { - self.text_screen.place(bounds); - self.area = bounds; + // assert full screen + debug_assert_eq!(bounds.height(), SCREEN.height()); + debug_assert_eq!(bounds.width(), SCREEN.width()); + + let (header_area, rest) = bounds.split_top(Header::HEADER_HEIGHT); + let (info_area, action_bar_area) = rest.split_bottom(ActionBar::ACTION_BAR_HEIGHT); + + self.header.place(header_area); + self.paragraph.place(info_area.inset(theme::SIDE_INSETS)); + self.action_bar.place(action_bar_area); + + self.update_page(0); + bounds } fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { + // Update page count of the screen + ctx.set_page_count(self.paragraph.pager().total() as usize); + if let Event::Attach(_) = event { self.update_text(ctx); } - self.text_screen.event(ctx, event) + self.paragraph.event(ctx, event); + + if self.header.event(ctx, event).is_some() { + return Some(UpdatableInfoScreenMsg::Close); + } + + if let Some(msg) = self.action_bar.event(ctx, event) { + match msg { + ActionBarMsg::Prev => { + self.update_page(self.paragraph.pager().prev()); + return None; + } + ActionBarMsg::Next => { + self.update_page(self.paragraph.pager().next()); + return None; + } + _ => {} + } + } + + None } fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { - self.text_screen.render(target); + self.header.render(target); + self.paragraph.render(target); + self.action_bar.render(target); } } -fn create_text_screen( - paragraphs: Paragraphs>, -) -> TextScreen>> { - TextScreen::new(paragraphs) - .with_header(Header::new(TR::buttons__more_info.into()).with_close_button()) -} - impl TString<'static>> Swipable for UpdatableInfoScreen { fn get_pager(&self) -> Pager { Pager::single_page() @@ -93,6 +135,9 @@ impl TString<'static>> Swipable for UpdatableInfoScreen { } } +trait UpdatableTextContent: Component + PaginateFull {} +impl<'a, T> UpdatableTextContent for Paragraphs where T: ParagraphSource<'a> {} + #[cfg(feature = "ui_debug")] impl crate::trace::Trace for UpdatableInfoScreen where @@ -100,6 +145,8 @@ where { fn trace(&self, t: &mut dyn crate::trace::Tracer) { t.component("UpdatableInfoScreen"); - t.child("screen", &self.text_screen); + t.child("Header", &self.header); + t.child("Content", &self.paragraph); + t.child("ActionBar", &self.action_bar); } } diff --git a/core/embed/rust/src/ui/layout_eckhart/flow/request_number.rs b/core/embed/rust/src/ui/layout_eckhart/flow/request_number.rs index f6423092c5..edac5f8bf4 100644 --- a/core/embed/rust/src/ui/layout_eckhart/flow/request_number.rs +++ b/core/embed/rust/src/ui/layout_eckhart/flow/request_number.rs @@ -17,9 +17,8 @@ use core::sync::atomic::{AtomicU16, Ordering}; use super::super::{ component::Button, firmware::{ - ActionBar, Header, NumberInput, ShortMenuVec, TextScreenMsg, UpdatableInfoScreen, - ValueInputScreen, ValueInputScreenMsg, VerticalMenu, VerticalMenuScreen, - VerticalMenuScreenMsg, + ActionBar, Header, NumberInput, ShortMenuVec, UpdatableInfoScreen, ValueInputScreen, + ValueInputScreenMsg, VerticalMenu, VerticalMenuScreen, VerticalMenuScreenMsg, }, theme, }; @@ -104,17 +103,16 @@ pub fn new_request_number( )); let content_menu = VerticalMenuScreen::new(menu_items) - .with_header(Header::new(TString::empty()).with_close_button()) + .with_header(Header::new(title).with_close_button()) .map(move |msg| match msg { VerticalMenuScreenMsg::Selected(i) => Some(FlowMsg::Choice(i)), VerticalMenuScreenMsg::Close => Some(FlowMsg::Cancelled), _ => None, }); - let content_info = UpdatableInfoScreen::new(info_closure).map(|msg| match msg { - TextScreenMsg::Cancelled => Some(FlowMsg::Cancelled), - _ => None, - }); + let content_info = UpdatableInfoScreen::new(info_closure) + .with_header(Header::new(title).with_close_button()) + .map(|_| Some(FlowMsg::Cancelled)); let mut res = SwipeFlow::new(&RequestNumber::Number)?; res.add_page(&RequestNumber::Number, content_input)?