From 6c8671c455620e19f29c69f05ed1437f6fb8c906 Mon Sep 17 00:00:00 2001 From: lbqds Date: Sat, 28 Sep 2024 10:54:35 +0800 Subject: [PATCH 1/4] Support displaying an icon followed by two lines of bold text --- ledger_device_sdk/src/ui/gadgets.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ledger_device_sdk/src/ui/gadgets.rs b/ledger_device_sdk/src/ui/gadgets.rs index 041f54d7..dcc51011 100644 --- a/ledger_device_sdk/src/ui/gadgets.rs +++ b/ledger_device_sdk/src/ui/gadgets.rs @@ -461,8 +461,9 @@ impl<'a> Page<'a> { self.label[0].place(Location::Bottom, Layout::Centered, true); } else { icon_x = 57; - icon_y = 17; - self.label[0].place(Location::Custom(35), Layout::Centered, true); + icon_y = 10; + self.label[0].place(Location::Custom(28), Layout::Centered, true); + self.label[1].place(Location::Custom(42), Layout::Centered, true); } if let Some(glyph) = self.glyph { let icon = Icon::from(glyph); From 0e494b544aea2b41ce999e801c5afa485980a776 Mon Sep 17 00:00:00 2001 From: lbqds Date: Sat, 28 Sep 2024 11:14:54 +0800 Subject: [PATCH 2/4] Update the MultiFieldReview to align with app-bitcoin --- ledger_device_sdk/src/ui/gadgets.rs | 73 ++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 22 deletions(-) diff --git a/ledger_device_sdk/src/ui/gadgets.rs b/ledger_device_sdk/src/ui/gadgets.rs index dcc51011..6f60b27a 100644 --- a/ledger_device_sdk/src/ui/gadgets.rs +++ b/ledger_device_sdk/src/ui/gadgets.rs @@ -730,7 +730,7 @@ pub struct Field<'a> { } impl<'a> Field<'a> { - pub fn event_loop(&self, incoming_direction: ButtonEvent) -> ButtonEvent { + pub fn event_loop(&self, incoming_direction: ButtonEvent, is_first_field: bool) -> ButtonEvent { let mut buttons = ButtonsState::new(); let chunk_max_lines = layout::MAX_LINES - 1; let page_count = 1 + self.value.len() / (chunk_max_lines * MAX_CHAR_PER_LINE); @@ -778,8 +778,10 @@ impl<'a> Field<'a> { .trim_end_matches(' '); chunks[0] = Label::from(header).bold(); - LEFT_ARROW.display(); - RIGHT_ARROW.display(); + if !is_first_field { + bagls::LEFT_ARROW.display(); + } + bagls::RIGHT_ARROW.display(); chunks.place(Location::Middle, Layout::Centered, false); @@ -824,7 +826,7 @@ pub struct MultiFieldReview<'a> { fields: &'a [Field<'a>], review_message: &'a [&'a str], review_glyph: Option<&'a Glyph<'a>>, - validation_message: &'a str, + validation_message: [&'a str; 2], validation_glyph: Option<&'a Glyph<'a>>, cancel_message: &'a str, cancel_glyph: Option<&'a Glyph<'a>>, @@ -853,7 +855,7 @@ impl<'a> MultiFieldReview<'a> { fields: &'a [Field<'a>], review_message: &'a [&'a str], review_glyph: Option<&'a Glyph<'a>>, - validation_message: &'a str, + validation_message: [&'a str; 2], validation_glyph: Option<&'a Glyph<'a>>, cancel_message: &'a str, cancel_glyph: Option<&'a Glyph<'a>>, @@ -870,27 +872,25 @@ impl<'a> MultiFieldReview<'a> { } pub fn show(&self) -> bool { - let first_page = match self.review_message.len() { - 0 => Page::new(PageStyle::PictureNormal, ["", ""], self.review_glyph), - 1 => Page::new( + let first_page_opt = match self.review_message.len() { + 0 => None, + 1 => Some(Page::new( PageStyle::PictureBold, [self.review_message[0], ""], self.review_glyph, - ), - _ => Page::new( + )), + _ => Some(Page::new( PageStyle::PictureNormal, [self.review_message[0], self.review_message[1]], self.review_glyph, - ), + )), }; - clear_screen(); - first_page.place_and_wait(); - crate::ui::screen_util::screen_update(); + display_first_page(&first_page_opt); let validation_page = Page::new( PageStyle::PictureBold, - [self.validation_message, ""], + self.validation_message, self.validation_glyph, ); let cancel_page = Page::new( @@ -904,9 +904,10 @@ impl<'a> MultiFieldReview<'a> { loop { match cur_page { - cancel if cancel == self.fields.len() => { + cancel if cancel == self.fields.len() + 1 => { let mut buttons = ButtonsState::new(); clear_screen(); + bagls::LEFT_ARROW.display(); cancel_page.place(); crate::ui::screen_util::screen_update(); loop { @@ -915,24 +916,31 @@ impl<'a> MultiFieldReview<'a> { cur_page = cur_page.saturating_sub(1); break; } - Some(ButtonEvent::RightButtonRelease) => { - cur_page += 1; - break; - } Some(ButtonEvent::BothButtonsRelease) => return false, _ => (), } } } - validation if validation == self.fields.len() + 1 => { + validation if validation == self.fields.len() => { let mut buttons = ButtonsState::new(); clear_screen(); + bagls::LEFT_ARROW.display(); + bagls::RIGHT_ARROW.display(); validation_page.place(); crate::ui::screen_util::screen_update(); loop { match get_event(&mut buttons) { Some(ButtonEvent::LeftButtonRelease) => { cur_page = cur_page.saturating_sub(1); + if cur_page == 0 && self.fields.is_empty() { + display_first_page(&first_page_opt); + } else { + direction = ButtonEvent::LeftButtonRelease; + } + break; + } + Some(ButtonEvent::RightButtonRelease) => { + cur_page += 1; break; } Some(ButtonEvent::BothButtonsRelease) => return true, @@ -941,10 +949,12 @@ impl<'a> MultiFieldReview<'a> { } } _ => { - direction = self.fields[cur_page].event_loop(direction); + direction = self.fields[cur_page] + .event_loop(direction, cur_page == 0 && first_page_opt.is_none()); match direction { ButtonEvent::LeftButtonRelease => { if cur_page == 0 { + display_first_page(&first_page_opt); direction = ButtonEvent::RightButtonRelease; } else { cur_page -= 1; @@ -960,3 +970,22 @@ impl<'a> MultiFieldReview<'a> { } } } + +fn display_first_page(page_opt: &Option) { + match page_opt { + Some(page) => { + clear_screen(); + bagls::RIGHT_ARROW.display(); + page.place(); + crate::ui::screen_util::screen_update(); + + let mut buttons = ButtonsState::new(); + loop { + if let Some(ButtonEvent::RightButtonRelease) = get_event(&mut buttons) { + return; + } + } + } + None => (), + } +} From e0a815eedd4650038339df9b2a6a9ac41937482b Mon Sep 17 00:00:00 2001 From: GroM Date: Mon, 30 Sep 2024 11:28:43 +0200 Subject: [PATCH 3/4] Remove bagls prefix --- ledger_device_sdk/src/ui/gadgets.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ledger_device_sdk/src/ui/gadgets.rs b/ledger_device_sdk/src/ui/gadgets.rs index 6f60b27a..749f2b27 100644 --- a/ledger_device_sdk/src/ui/gadgets.rs +++ b/ledger_device_sdk/src/ui/gadgets.rs @@ -779,9 +779,9 @@ impl<'a> Field<'a> { chunks[0] = Label::from(header).bold(); if !is_first_field { - bagls::LEFT_ARROW.display(); + LEFT_ARROW.display(); } - bagls::RIGHT_ARROW.display(); + RIGHT_ARROW.display(); chunks.place(Location::Middle, Layout::Centered, false); @@ -907,7 +907,7 @@ impl<'a> MultiFieldReview<'a> { cancel if cancel == self.fields.len() + 1 => { let mut buttons = ButtonsState::new(); clear_screen(); - bagls::LEFT_ARROW.display(); + LEFT_ARROW.display(); cancel_page.place(); crate::ui::screen_util::screen_update(); loop { @@ -924,8 +924,8 @@ impl<'a> MultiFieldReview<'a> { validation if validation == self.fields.len() => { let mut buttons = ButtonsState::new(); clear_screen(); - bagls::LEFT_ARROW.display(); - bagls::RIGHT_ARROW.display(); + LEFT_ARROW.display(); + RIGHT_ARROW.display(); validation_page.place(); crate::ui::screen_util::screen_update(); loop { @@ -975,7 +975,7 @@ fn display_first_page(page_opt: &Option) { match page_opt { Some(page) => { clear_screen(); - bagls::RIGHT_ARROW.display(); + RIGHT_ARROW.display(); page.place(); crate::ui::screen_util::screen_update(); From b4fcc0fff865598efd92bef48ad3aaf1071d74b7 Mon Sep 17 00:00:00 2001 From: lbqds Date: Mon, 30 Sep 2024 20:01:00 +0800 Subject: [PATCH 4/4] Add a new function to support an array of validation messages --- ledger_device_sdk/src/ui/gadgets.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/ledger_device_sdk/src/ui/gadgets.rs b/ledger_device_sdk/src/ui/gadgets.rs index 749f2b27..2ee63e20 100644 --- a/ledger_device_sdk/src/ui/gadgets.rs +++ b/ledger_device_sdk/src/ui/gadgets.rs @@ -852,6 +852,26 @@ fn concatenate(strings: &[&str], output: &mut [u8]) { impl<'a> MultiFieldReview<'a> { pub fn new( + fields: &'a [Field<'a>], + review_message: &'a [&'a str], + review_glyph: Option<&'a Glyph<'a>>, + validation_message: &'a str, + validation_glyph: Option<&'a Glyph<'a>>, + cancel_message: &'a str, + cancel_glyph: Option<&'a Glyph<'a>>, + ) -> Self { + Self::new_with_validation_messages( + fields, + review_message, + review_glyph, + [validation_message, ""], + validation_glyph, + cancel_message, + cancel_glyph, + ) + } + + pub fn new_with_validation_messages( fields: &'a [Field<'a>], review_message: &'a [&'a str], review_glyph: Option<&'a Glyph<'a>>,