diff --git a/core/embed/rust/src/ui/layout_eckhart/flow/confirm_output.rs b/core/embed/rust/src/ui/layout_eckhart/flow/confirm_output.rs index f88765c54a..cacd00fea8 100644 --- a/core/embed/rust/src/ui/layout_eckhart/flow/confirm_output.rs +++ b/core/embed/rust/src/ui/layout_eckhart/flow/confirm_output.rs @@ -16,6 +16,7 @@ use crate::{ FlowController, FlowMsg, SwipeFlow, }, geometry::{Alignment, Direction, LinearPlacement, Offset}, + layout::util::StrOrBytes, }, }; @@ -134,7 +135,7 @@ pub enum ConfirmOutputWithSummary { SummaryMenu, SummaryMenuCancel, SummaryMenuFeeInfo, - SummaryMenuAccountInfo, + SummaryMenuExtraInfo, Cancelled, } @@ -175,12 +176,12 @@ impl FlowController for ConfirmOutputWithSummary { Self::SummaryMenuFeeInfo.goto() } (Self::SummaryMenu, FlowMsg::Choice(MENU_ITEM_EXTRA_INFO)) => { - Self::SummaryMenuAccountInfo.goto() + Self::SummaryMenuExtraInfo.goto() } (Self::SummaryMenu, FlowMsg::Cancelled) => Self::Summary.goto(), (Self::SummaryMenuCancel, FlowMsg::Cancelled) => Self::SummaryMenu.goto(), (Self::SummaryMenuCancel, FlowMsg::Confirmed) => Self::Cancelled.goto(), - (Self::SummaryMenuAccountInfo | Self::SummaryMenuFeeInfo, FlowMsg::Cancelled) => { + (Self::SummaryMenuExtraInfo | Self::SummaryMenuFeeInfo, FlowMsg::Cancelled) => { Self::SummaryMenu.goto() } (Self::Cancelled, _) => self.return_msg(FlowMsg::Cancelled), @@ -220,7 +221,8 @@ fn content_main_menu( main_menu = main_menu.item( Button::with_text(address_title) .styled(theme::menu_item_title()) - .with_text_align(Alignment::Start), + .with_text_align(Alignment::Start) + .with_content_offset(Offset::x(12)), ); unwrap!(main_menu_items.push(MENU_ITEM_ADDRESS_INFO)); } @@ -277,42 +279,37 @@ fn content_menu_info( pub fn new_confirm_output( title: Option>, subtitle: Option>, - chunkify: bool, - message: Obj, + main_paragraphs: ParagraphVecShort<'static>, amount: Option, br_name: TString<'static>, br_code: u16, account_title: TString<'static>, account_paragraphs: Option>, address_title: Option>, - address_paragraphs: Option>, + address_paragraph: Option>, summary_title: Option>, summary_paragraphs: Option>, summary_br_code: Option, summary_br_name: Option>, - fee_params: Option>, + extra_title: Option>, + extra_paragraph: Option>, + fee_paragraphs: Option>, cancel_menu_label: Option>, ) -> Result { let cancel_menu_label = cancel_menu_label.unwrap_or(TR::buttons__cancel.into()); - let address_menu_item = address_paragraphs.is_some(); + let address_menu_item = address_paragraph.is_some(); let account_menu_item = account_paragraphs.is_some(); - let fee_menu_item = fee_params.is_some(); + let fee_menu_item = fee_paragraphs.is_some(); + let extra_menu_item = extra_paragraph.is_some(); let address_title = address_title.unwrap_or(TR::words__address.into()); let account_subtitle = Some(TR::send__send_from.into()); // Main - let main_paragraphs = Paragraph::new( - if chunkify { - &theme::TEXT_MONO_ADDRESS_CHUNKS - } else { - &theme::TEXT_MONO_LIGHT - }, - message.try_into().unwrap_or(TString::empty()), - ); let content_main = TextScreen::new( main_paragraphs .into_paragraphs() - .with_placement(LinearPlacement::vertical()), + .with_placement(LinearPlacement::vertical()) + .with_spacing(12), ) .with_header(Header::new(title.unwrap_or(TString::empty())).with_menu_button()) .with_action_bar(ActionBar::new_single(Button::with_text( @@ -324,8 +321,7 @@ pub fn new_confirm_output( TextScreenMsg::Cancelled => Some(FlowMsg::Cancelled), TextScreenMsg::Menu => Some(FlowMsg::Info), }) - .one_button_request(ButtonRequest::from_num(br_code, br_name)) - .with_pages(|_| 1); + .one_button_request(ButtonRequest::from_num(br_code, br_name)); // Cancelled let content_cancelled = TextScreen::new( @@ -345,7 +341,10 @@ pub fn new_confirm_output( Paragraph::new(&theme::TEXT_SMALL_LIGHT, TR::words__amount).no_break(), Paragraph::new( &theme::TEXT_MONO_MEDIUM_LIGHT, - amount.try_into().unwrap_or(TString::empty()), + amount + .try_into() + .unwrap_or(StrOrBytes::Str("".into())) + .as_str_offset(0), ), ]); @@ -365,8 +364,7 @@ pub fn new_confirm_output( TextScreenMsg::Cancelled => Some(FlowMsg::Cancelled), TextScreenMsg::Menu => Some(FlowMsg::Info), }) - .one_button_request(ButtonRequest::from_num(br_code, br_name)) - .with_pages(|_| 1); + .one_button_request(ButtonRequest::from_num(br_code, br_name)); let mut flow = SwipeFlow::new(&ConfirmOutputWithAmount::Address)?; flow.add_page(&ConfirmOutputWithAmount::Address, content_main)? @@ -430,23 +428,36 @@ pub fn new_confirm_output( .one_button_request(ButtonRequest::from_num( summary_br_code.unwrap(), summary_br_name.unwrap(), - )) - .with_pages(|_| 1); + )); // SummaryMenu let mut summary_menu = VerticalMenu::empty(); let mut summary_menu_items = Vec::::new(); - if account_menu_item { - summary_menu = summary_menu.item(Button::with_text(account_title)); + + if extra_menu_item { + summary_menu = summary_menu.item( + Button::with_text(extra_title.unwrap_or(TString::empty())) + .styled(theme::menu_item_title()) + .with_text_align(Alignment::Start) + .with_content_offset(Offset::x(12)), + ); unwrap!(summary_menu_items.push(MENU_ITEM_EXTRA_INFO)); } if fee_menu_item { - summary_menu = - summary_menu.item(Button::with_text(TR::confirm_total__title_fee.into())); + summary_menu = summary_menu.item( + Button::with_text(TR::confirm_total__title_fee.into()) + .styled(theme::menu_item_title()) + .with_text_align(Alignment::Start) + .with_content_offset(Offset::x(12)), + ); unwrap!(summary_menu_items.push(MENU_ITEM_FEE_INFO)); } - summary_menu = summary_menu - .item(Button::with_text(cancel_menu_label).styled(theme::menu_item_title_orange())); + summary_menu = summary_menu.item( + Button::with_text(cancel_menu_label) + .styled(theme::menu_item_title_orange()) + .with_text_align(Alignment::Start) + .with_content_offset(Offset::x(12)), + ); unwrap!(summary_menu_items.push(MENU_ITEM_CANCEL)); let content_summary_menu = VerticalMenuScreen::new(summary_menu) .with_header(Header::new(TString::empty()).with_close_button()) @@ -473,7 +484,12 @@ pub fn new_confirm_output( .add_page(&ConfirmOutputWithSummary::MainMenuCancel, content_cancel())? .add_page( &ConfirmOutputWithSummary::MainMenuAddresInfo, - content_menu_info(address_title, None, address_paragraphs), + content_menu_info( + address_title, + None, + address_paragraph + .map(|address_paragraph| ParagraphVecShort::from_iter([address_paragraph])), + ), )? .add_page( &ConfirmOutputWithSummary::MainMenuAccountInfo, @@ -487,11 +503,16 @@ pub fn new_confirm_output( )? .add_page( &ConfirmOutputWithSummary::SummaryMenuFeeInfo, - content_menu_info(TR::confirm_total__title_fee.into(), None, fee_params), + content_menu_info(TR::confirm_total__title_fee.into(), None, fee_paragraphs), )? .add_page( - &ConfirmOutputWithSummary::SummaryMenuAccountInfo, - content_menu_info(account_title, account_subtitle, account_paragraphs), + &ConfirmOutputWithSummary::SummaryMenuExtraInfo, + content_menu_info( + extra_title.unwrap_or(TString::empty()), + None, + extra_paragraph + .map(|extra_paragraph| ParagraphVecShort::from_iter([extra_paragraph])), + ), )? .add_page(&ConfirmOutputWithSummary::Cancelled, content_cancelled)?; flow diff --git a/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs b/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs index 6e9f5fd43c..818e6ab626 100644 --- a/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs +++ b/core/embed/rust/src/ui/layout_eckhart/ui_firmware.rs @@ -274,7 +274,7 @@ impl FirmwareUI for UIEckhart { description: Option>, is_data: bool, extra: Option>, - _subtitle: Option>, + subtitle: Option>, verb: Option>, _verb_cancel: Option>, info: bool, @@ -296,14 +296,15 @@ impl FirmwareUI for UIEckhart { let value: TString = value.try_into()?; theme::get_chunkified_text_style(value.len()) } else if is_data { - &theme::TEXT_MONO_MEDIUM + &theme::TEXT_MONO_ADDRESS } else { &theme::TEXT_MEDIUM }, description_font: &theme::TEXT_SMALL, extra_font: &theme::TEXT_SMALL, } - .into_paragraphs(); + .into_paragraphs() + .with_placement(LinearPlacement::vertical()); let verb = verb.unwrap_or(TR::buttons__confirm.into()); let right_button = if hold { @@ -320,6 +321,7 @@ impl FirmwareUI for UIEckhart { let mut screen = TextScreen::new(paragraphs) .with_header(header) + .with_subtitle(subtitle.unwrap_or(TString::empty())) .with_action_bar(ActionBar::new_double( Button::with_icon(theme::ICON_CROSS), right_button, @@ -389,19 +391,19 @@ impl FirmwareUI for UIEckhart { fn flow_confirm_output( title: Option>, subtitle: Option>, - _description: Option>, - _extra: Option>, + description: Option>, + extra: Option>, message: Obj, amount: Option, chunkify: bool, - _text_mono: bool, + text_mono: bool, account_title: TString<'static>, account: Option>, account_path: Option>, br_code: u16, br_name: TString<'static>, address_item: Option<(TString<'static>, Obj)>, - _extra_item: Option<(TString<'static>, Obj)>, + extra_item: Option<(TString<'static>, Obj)>, summary_items: Option, fee_items: Option, summary_title: Option>, @@ -409,14 +411,36 @@ impl FirmwareUI for UIEckhart { summary_br_name: Option>, cancel_text: Option>, ) -> Result { - let (address_title, address_paragraphs) = if let Some(address_item) = address_item { - let mut paragraphs = ParagraphVecShort::new(); - for pair in IterBuf::new().try_iterate(address_item.1)? { - let [label, value]: [TString; 2] = util::iter_into_array(pair)?; - unwrap!(paragraphs.push(Paragraph::new(&theme::TEXT_SMALL_LIGHT, label).no_break())); - unwrap!(paragraphs.push(Paragraph::new(&theme::TEXT_MONO_MEDIUM_LIGHT, value))); - } - (Some(address_item.0), Some(paragraphs)) + let mut main_paragraphs = ParagraphVecShort::new(); + if let Some(description) = description { + unwrap!(main_paragraphs.push(Paragraph::new(&theme::TEXT_NORMAL, description))); + } + if let Some(extra) = extra { + unwrap!(main_paragraphs.push(Paragraph::new(&theme::TEXT_SMALL, extra))); + } + let font = if chunkify { + &theme::TEXT_MONO_ADDRESS_CHUNKS + } else if text_mono { + &theme::TEXT_MONO_LIGHT + } else { + &theme::TEXT_MEDIUM + }; + unwrap!(main_paragraphs.push(Paragraph::new( + font, + message + .try_into() + .unwrap_or(StrOrBytes::Str("".into())) + .as_str_offset(0), + ))); + + let (address_title, address_paragraph) = if let Some((title, item)) = address_item { + let paragraph = Paragraph::new( + &theme::TEXT_MONO_ADDRESS_CHUNKS, + item.try_into() + .unwrap_or(StrOrBytes::Str("".into())) + .as_str_offset(0), + ); + (Some(title), Some(paragraph)) } else { (None, None) }; @@ -475,22 +499,35 @@ impl FirmwareUI for UIEckhart { None }; + let (extra_title, extra_paragraph) = if let Some((title, item)) = extra_item { + let paragraph = Paragraph::new( + &theme::TEXT_MONO_ADDRESS, + item.try_into() + .unwrap_or(StrOrBytes::Str("".into())) + .as_str_offset(0), + ); + (Some(title), Some(paragraph)) + } else { + (None, None) + }; + let flow = flow::confirm_output::new_confirm_output( title, subtitle, - chunkify, - message, + main_paragraphs, amount, br_name, br_code, account_title, account_paragraphs, address_title, - address_paragraphs, + address_paragraph, summary_title, summary_paragraphs, summary_br_code, summary_br_name, + extra_title, + extra_paragraph, fee_paragraphs, cancel_text, )?; @@ -902,14 +939,18 @@ impl FirmwareUI for UIEckhart { let url: TString = TR::addr_mismatch__support_url.into(); let button: TString = TR::buttons__quit.into(); - let paragraphs = ParagraphVecShort::from_iter([ - Paragraph::new(&theme::TEXT_REGULAR, description).centered(), - Paragraph::new(&theme::TEXT_MONO_MEDIUM, url).centered(), - ]) - .into_paragraphs(); - let screen = TextScreen::new(paragraphs) + let text_style = theme::TEXT_REGULAR; + let ops = OpTextLayout::new(text_style) + .text(description, text_style.text_font) + .text(url, theme::TEXT_MONO_MEDIUM.text_font); + let text = FormattedText::new(ops); + + let screen = TextScreen::new(text) .with_header(Header::new(title)) - .with_action_bar(ActionBar::new_single(Button::with_text(button))); + .with_action_bar(ActionBar::new_double( + Button::with_icon(theme::ICON_CROSS), + Button::with_text(button), + )); let layout = RootComponent::new(screen); Ok(layout)