mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-06-27 10:22:34 +00:00
chore(eckhart): provide short and long vertical menu
This commit is contained in:
parent
1e653a33cc
commit
00f58bd199
@ -18,14 +18,14 @@ use crate::{
|
|||||||
constant::SCREEN,
|
constant::SCREEN,
|
||||||
firmware::{
|
firmware::{
|
||||||
Header, HeaderMsg, TextScreen, TextScreenMsg, VerticalMenu, VerticalMenuScreen,
|
Header, HeaderMsg, TextScreen, TextScreenMsg, VerticalMenu, VerticalMenuScreen,
|
||||||
VerticalMenuScreenMsg, MENU_MAX_ITEMS,
|
VerticalMenuScreenMsg, SHORT_MENU_ITEMS,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
shape::Renderer,
|
shape::Renderer,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::theme;
|
use super::{theme, ShortMenuVec};
|
||||||
use heapless::Vec;
|
use heapless::Vec;
|
||||||
|
|
||||||
const MAX_DEPTH: usize = 3;
|
const MAX_DEPTH: usize = 3;
|
||||||
@ -96,11 +96,11 @@ impl MenuItem {
|
|||||||
struct Submenu {
|
struct Submenu {
|
||||||
header_text: TString<'static>,
|
header_text: TString<'static>,
|
||||||
show_battery: bool,
|
show_battery: bool,
|
||||||
items: Vec<MenuItem, MENU_MAX_ITEMS>,
|
items: Vec<MenuItem, SHORT_MENU_ITEMS>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Submenu {
|
impl Submenu {
|
||||||
pub fn new(header_text: TString<'static>, items: Vec<MenuItem, MENU_MAX_ITEMS>) -> Self {
|
pub fn new(header_text: TString<'static>, items: Vec<MenuItem, SHORT_MENU_ITEMS>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
header_text,
|
header_text,
|
||||||
show_battery: false,
|
show_battery: false,
|
||||||
@ -140,7 +140,7 @@ pub struct DeviceMenuScreen<'a> {
|
|||||||
// as defined by `enum Subscreen` (DeviceScreen is still a VerticalMenuScreen!)
|
// as defined by `enum Subscreen` (DeviceScreen is still a VerticalMenuScreen!)
|
||||||
// The active one will be Some(...) and the other one will be None.
|
// The active one will be Some(...) and the other one will be None.
|
||||||
// This way we only need to keep one screen at any time in memory.
|
// This way we only need to keep one screen at any time in memory.
|
||||||
menu_screen: GcBox<Option<VerticalMenuScreen>>,
|
menu_screen: GcBox<Option<VerticalMenuScreen<ShortMenuVec>>>,
|
||||||
about_screen: GcBox<Option<TextScreen<Paragraphs<[Paragraph<'a>; 2]>>>>,
|
about_screen: GcBox<Option<TextScreen<Paragraphs<[Paragraph<'a>; 2]>>>>,
|
||||||
|
|
||||||
// Information needed to construct any subscreen on demand
|
// Information needed to construct any subscreen on demand
|
||||||
@ -209,7 +209,7 @@ impl<'a> DeviceMenuScreen<'a> {
|
|||||||
paired_devices: Vec<TString<'static>, 1>,
|
paired_devices: Vec<TString<'static>, 1>,
|
||||||
paired_device_indices: Vec<usize, 1>,
|
paired_device_indices: Vec<usize, 1>,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
let mut items: Vec<MenuItem, MENU_MAX_ITEMS> = Vec::new();
|
let mut items: Vec<MenuItem, SHORT_MENU_ITEMS> = Vec::new();
|
||||||
for (device, idx) in paired_devices.iter().zip(paired_device_indices) {
|
for (device, idx) in paired_devices.iter().zip(paired_device_indices) {
|
||||||
unwrap!(items.push(
|
unwrap!(items.push(
|
||||||
MenuItem::new(*device, Some(Action::GoTo(idx))).with_subtext(Some((
|
MenuItem::new(*device, Some(Action::GoTo(idx))).with_subtext(Some((
|
||||||
@ -224,7 +224,7 @@ impl<'a> DeviceMenuScreen<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn add_pair_and_connect_menu(&mut self, manage_devices_index: usize) -> usize {
|
fn add_pair_and_connect_menu(&mut self, manage_devices_index: usize) -> usize {
|
||||||
let mut items: Vec<MenuItem, MENU_MAX_ITEMS> = Vec::new();
|
let mut items: Vec<MenuItem, SHORT_MENU_ITEMS> = Vec::new();
|
||||||
unwrap!(items.push(
|
unwrap!(items.push(
|
||||||
MenuItem::new(
|
MenuItem::new(
|
||||||
"Manage paired devices".into(),
|
"Manage paired devices".into(),
|
||||||
@ -245,7 +245,7 @@ impl<'a> DeviceMenuScreen<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn add_settings_menu(&mut self, security_index: usize, device_index: usize) -> usize {
|
fn add_settings_menu(&mut self, security_index: usize, device_index: usize) -> usize {
|
||||||
let mut items: Vec<MenuItem, MENU_MAX_ITEMS> = Vec::new();
|
let mut items: Vec<MenuItem, SHORT_MENU_ITEMS> = Vec::new();
|
||||||
unwrap!(items.push(MenuItem::new(
|
unwrap!(items.push(MenuItem::new(
|
||||||
"Security".into(),
|
"Security".into(),
|
||||||
Some(Action::GoTo(security_index))
|
Some(Action::GoTo(security_index))
|
||||||
@ -260,7 +260,7 @@ impl<'a> DeviceMenuScreen<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn add_security_menu(&mut self) -> usize {
|
fn add_security_menu(&mut self) -> usize {
|
||||||
let mut items: Vec<MenuItem, MENU_MAX_ITEMS> = Vec::new();
|
let mut items: Vec<MenuItem, SHORT_MENU_ITEMS> = Vec::new();
|
||||||
unwrap!(items.push(MenuItem::new(
|
unwrap!(items.push(MenuItem::new(
|
||||||
"Check backup".into(),
|
"Check backup".into(),
|
||||||
Some(Action::Return(DeviceMenuMsg::CheckBackup)),
|
Some(Action::Return(DeviceMenuMsg::CheckBackup)),
|
||||||
@ -275,7 +275,7 @@ impl<'a> DeviceMenuScreen<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn add_device_menu(&mut self, device_name: TString<'static>, about_index: usize) -> usize {
|
fn add_device_menu(&mut self, device_name: TString<'static>, about_index: usize) -> usize {
|
||||||
let mut items: Vec<MenuItem, MENU_MAX_ITEMS> = Vec::new();
|
let mut items: Vec<MenuItem, SHORT_MENU_ITEMS> = Vec::new();
|
||||||
unwrap!(
|
unwrap!(
|
||||||
items.push(MenuItem::new("Name".into(), None).with_subtext(Some((device_name, None))))
|
items.push(MenuItem::new("Name".into(), None).with_subtext(Some((device_name, None))))
|
||||||
);
|
);
|
||||||
@ -298,7 +298,7 @@ impl<'a> DeviceMenuScreen<'a> {
|
|||||||
pair_and_connect_index: usize,
|
pair_and_connect_index: usize,
|
||||||
settings_index: usize,
|
settings_index: usize,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
let mut items: Vec<MenuItem, MENU_MAX_ITEMS> = Vec::new();
|
let mut items: Vec<MenuItem, SHORT_MENU_ITEMS> = Vec::new();
|
||||||
if failed_backup {
|
if failed_backup {
|
||||||
unwrap!(items.push(
|
unwrap!(items.push(
|
||||||
MenuItem::new(
|
MenuItem::new(
|
||||||
@ -349,7 +349,7 @@ impl<'a> DeviceMenuScreen<'a> {
|
|||||||
Subscreen::Submenu(ref mut submenu_index) => {
|
Subscreen::Submenu(ref mut submenu_index) => {
|
||||||
let submenu = &self.submenus[*submenu_index];
|
let submenu = &self.submenus[*submenu_index];
|
||||||
*self.about_screen.deref_mut() = None;
|
*self.about_screen.deref_mut() = None;
|
||||||
let mut menu = VerticalMenu::empty().with_separators();
|
let mut menu = VerticalMenu::<ShortMenuVec>::empty().with_separators();
|
||||||
for item in &submenu.items {
|
for item in &submenu.items {
|
||||||
let button = if let Some((subtext, subtext_style)) = item.subtext {
|
let button = if let Some((subtext, subtext_style)) = item.subtext {
|
||||||
Button::new_menu_item_with_subtext(
|
Button::new_menu_item_with_subtext(
|
||||||
@ -361,7 +361,7 @@ impl<'a> DeviceMenuScreen<'a> {
|
|||||||
} else {
|
} else {
|
||||||
Button::new_menu_item(item.text, item.stylesheet)
|
Button::new_menu_item(item.text, item.stylesheet)
|
||||||
};
|
};
|
||||||
menu = menu.item(button);
|
menu.item(button);
|
||||||
}
|
}
|
||||||
let mut header = Header::new(submenu.header_text).with_close_button();
|
let mut header = Header::new(submenu.header_text).with_close_button();
|
||||||
if submenu.show_battery {
|
if submenu.show_battery {
|
||||||
@ -385,8 +385,8 @@ impl<'a> DeviceMenuScreen<'a> {
|
|||||||
Subscreen::DeviceScreen(device, _) => {
|
Subscreen::DeviceScreen(device, _) => {
|
||||||
*self.about_screen.deref_mut() = None;
|
*self.about_screen.deref_mut() = None;
|
||||||
let mut menu = VerticalMenu::empty().with_separators();
|
let mut menu = VerticalMenu::empty().with_separators();
|
||||||
menu = menu.item(Button::new_menu_item(device, theme::menu_item_title()));
|
menu.item(Button::new_menu_item(device, theme::menu_item_title()));
|
||||||
menu = menu.item(Button::new_menu_item(
|
menu.item(Button::new_menu_item(
|
||||||
"Disconnect".into(),
|
"Disconnect".into(),
|
||||||
theme::menu_item_title_red(),
|
theme::menu_item_title_red(),
|
||||||
));
|
));
|
||||||
|
@ -40,7 +40,10 @@ pub use qr_screen::{QrMsg, QrScreen};
|
|||||||
pub use select_word_screen::{SelectWordMsg, SelectWordScreen};
|
pub use select_word_screen::{SelectWordMsg, SelectWordScreen};
|
||||||
pub use share_words::{ShareWordsScreen, ShareWordsScreenMsg};
|
pub use share_words::{ShareWordsScreen, ShareWordsScreenMsg};
|
||||||
pub use text_screen::{AllowedTextContent, TextScreen, TextScreenMsg};
|
pub use text_screen::{AllowedTextContent, TextScreen, TextScreenMsg};
|
||||||
pub use vertical_menu::{VerticalMenu, VerticalMenuMsg, MENU_MAX_ITEMS};
|
pub use vertical_menu::{
|
||||||
|
LongMenuGc, MenuItems, ShortMenuVec, VerticalMenu, VerticalMenuMsg, LONG_MENU_ITEMS,
|
||||||
|
SHORT_MENU_ITEMS,
|
||||||
|
};
|
||||||
pub use vertical_menu_screen::{VerticalMenuScreen, VerticalMenuScreenMsg};
|
pub use vertical_menu_screen::{VerticalMenuScreen, VerticalMenuScreenMsg};
|
||||||
|
|
||||||
use super::{constant, theme};
|
use super::{constant, theme};
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
use crate::ui::{
|
use core::ops::DerefMut;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
micropython::gc::GcBox,
|
||||||
|
ui::{
|
||||||
component::{Component, Event, EventCtx},
|
component::{Component, Event, EventCtx},
|
||||||
event::TouchEvent,
|
event::TouchEvent,
|
||||||
geometry::{Direction, Insets, Offset, Rect},
|
geometry::{Direction, Insets, Offset, Rect},
|
||||||
shape::{Bar, Renderer},
|
shape::{Bar, Renderer},
|
||||||
util::animation_disabled,
|
util::animation_disabled,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
@ -14,15 +19,78 @@ use heapless::Vec;
|
|||||||
|
|
||||||
/// Number of buttons.
|
/// Number of buttons.
|
||||||
/// Presently, VerticalMenu holds only fixed number of buttons.
|
/// Presently, VerticalMenu holds only fixed number of buttons.
|
||||||
pub const MENU_MAX_ITEMS: usize = 5;
|
pub const LONG_MENU_ITEMS: usize = 100;
|
||||||
|
pub const SHORT_MENU_ITEMS: usize = 5;
|
||||||
|
|
||||||
type VerticalMenuButtons = Vec<Button, MENU_MAX_ITEMS>;
|
pub type LongMenuGc = GcBox<Vec<Button, LONG_MENU_ITEMS>>;
|
||||||
|
pub type ShortMenuVec = Vec<Button, SHORT_MENU_ITEMS>;
|
||||||
|
|
||||||
pub struct VerticalMenu {
|
pub trait MenuItems: Default {
|
||||||
|
fn empty() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
fn push(&mut self, button: Button);
|
||||||
|
fn iter(&self) -> core::slice::Iter<'_, Button>;
|
||||||
|
fn iter_mut(&mut self) -> core::slice::IterMut<'_, Button>;
|
||||||
|
fn get_len(&self) -> usize;
|
||||||
|
fn get_last(&self) -> Option<&Button>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MenuItems for ShortMenuVec {
|
||||||
|
fn push(&mut self, button: Button) {
|
||||||
|
unwrap!(self.push(button));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iter(&self) -> core::slice::Iter<'_, Button> {
|
||||||
|
self.as_slice().iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iter_mut(&mut self) -> core::slice::IterMut<'_, Button> {
|
||||||
|
self.as_mut_slice().iter_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_len(&self) -> usize {
|
||||||
|
self.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_last(&self) -> Option<&Button> {
|
||||||
|
self.last()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for GcBox<Vec<Button, LONG_MENU_ITEMS>> {
|
||||||
|
fn default() -> Self {
|
||||||
|
unwrap!(GcBox::new(Vec::new()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MenuItems for LongMenuGc {
|
||||||
|
fn push(&mut self, button: Button) {
|
||||||
|
unwrap!(self.deref_mut().push(button));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iter(&self) -> core::slice::Iter<'_, Button> {
|
||||||
|
self.as_slice().iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iter_mut(&mut self) -> core::slice::IterMut<'_, Button> {
|
||||||
|
self.as_mut_slice().iter_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_len(&self) -> usize {
|
||||||
|
self.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_last(&self) -> Option<&Button> {
|
||||||
|
self.last()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct VerticalMenu<T = ShortMenuVec> {
|
||||||
/// Bounds the sliding window of the menu.
|
/// Bounds the sliding window of the menu.
|
||||||
bounds: Rect,
|
bounds: Rect,
|
||||||
/// Menu items.
|
/// Menu items.
|
||||||
buttons: VerticalMenuButtons,
|
buttons: T,
|
||||||
/// Full height of the menu, including overflowing items.
|
/// Full height of the menu, including overflowing items.
|
||||||
total_height: i16,
|
total_height: i16,
|
||||||
/// Vertical offset of the current view.
|
/// Vertical offset of the current view.
|
||||||
@ -37,12 +105,12 @@ pub enum VerticalMenuMsg {
|
|||||||
Selected(usize),
|
Selected(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VerticalMenu {
|
impl<T: MenuItems> VerticalMenu<T> {
|
||||||
const SIDE_INSETS: Insets = Insets::sides(12);
|
const SIDE_INSETS: Insets = Insets::sides(12);
|
||||||
const DEFAULT_PADDING: i16 = 28;
|
const DEFAULT_PADDING: i16 = 28;
|
||||||
const MIN_PADDING: i16 = 2;
|
const MIN_PADDING: i16 = 2;
|
||||||
|
|
||||||
fn new(buttons: VerticalMenuButtons) -> Self {
|
fn new(buttons: T) -> Self {
|
||||||
Self {
|
Self {
|
||||||
bounds: Rect::zero(),
|
bounds: Rect::zero(),
|
||||||
buttons,
|
buttons,
|
||||||
@ -54,7 +122,7 @@ impl VerticalMenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn empty() -> Self {
|
pub fn empty() -> Self {
|
||||||
Self::new(VerticalMenuButtons::new())
|
Self::new(T::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_separators(mut self) -> Self {
|
pub fn with_separators(mut self) -> Self {
|
||||||
@ -62,8 +130,13 @@ impl VerticalMenu {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn item(mut self, button: Button) -> Self {
|
pub fn with_item(mut self, button: Button) -> Self {
|
||||||
unwrap!(self.buttons.push(button));
|
self.buttons.push(button);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn item(&mut self, button: Button) -> &mut Self {
|
||||||
|
self.buttons.push(button);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +185,7 @@ impl VerticalMenu {
|
|||||||
debug_assert!(dir == Direction::Up || dir == Direction::Down);
|
debug_assert!(dir == Direction::Up || dir == Direction::Down);
|
||||||
|
|
||||||
// For single button, the menu is not scrollable
|
// For single button, the menu is not scrollable
|
||||||
if self.buttons.len() < 2 {
|
if self.buttons.get_len() < 2 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +193,11 @@ impl VerticalMenu {
|
|||||||
let current = self.offset_y;
|
let current = self.offset_y;
|
||||||
let mut cumsum = 0;
|
let mut cumsum = 0;
|
||||||
|
|
||||||
for button in &self.buttons[..self.buttons.len() - 1] {
|
for button in self
|
||||||
|
.buttons
|
||||||
|
.iter()
|
||||||
|
.take(self.buttons.get_len().saturating_sub(1))
|
||||||
|
{
|
||||||
let new_cumsum = cumsum + button.area().height();
|
let new_cumsum = cumsum + button.area().height();
|
||||||
match dir {
|
match dir {
|
||||||
Direction::Up if new_cumsum > current => {
|
Direction::Up if new_cumsum > current => {
|
||||||
@ -146,7 +223,7 @@ impl VerticalMenu {
|
|||||||
self.offset_y_max = self.total_height
|
self.offset_y_max = self.total_height
|
||||||
- self
|
- self
|
||||||
.buttons
|
.buttons
|
||||||
.last()
|
.get_last()
|
||||||
.unwrap_or(&Button::empty())
|
.unwrap_or(&Button::empty())
|
||||||
.area()
|
.area()
|
||||||
.height();
|
.height();
|
||||||
@ -158,7 +235,7 @@ impl VerticalMenu {
|
|||||||
|
|
||||||
// Find the first button from the top that would completely fit in the menu area
|
// Find the first button from the top that would completely fit in the menu area
|
||||||
// in the bottom position
|
// in the bottom position
|
||||||
for button in &self.buttons {
|
for button in self.buttons.iter() {
|
||||||
let offset = button.area().top_left().y - self.bounds.top_left().y;
|
let offset = button.area().top_left().y - self.bounds.top_left().y;
|
||||||
if offset > menu_overflow {
|
if offset > menu_overflow {
|
||||||
self.offset_y_max = offset;
|
self.offset_y_max = offset;
|
||||||
@ -186,15 +263,16 @@ impl VerticalMenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn render_buttons<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
fn render_buttons<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||||
for button in &self.buttons {
|
for button in self.buttons.iter() {
|
||||||
button.render(target);
|
button.render(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_separators<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
fn render_separators<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||||
for i in 1..self.buttons.len() {
|
for pair in self.buttons.iter().as_slice().windows(2) {
|
||||||
let button = &self.buttons[i];
|
let [button_prev, button] = pair else {
|
||||||
let button_prev = &self.buttons[i - 1];
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
if !button.is_pressed() && !button_prev.is_pressed() {
|
if !button.is_pressed() && !button_prev.is_pressed() {
|
||||||
let separator = Rect::from_top_left_and_size(
|
let separator = Rect::from_top_left_and_size(
|
||||||
@ -212,7 +290,7 @@ impl VerticalMenu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for VerticalMenu {
|
impl<T: MenuItems> Component for VerticalMenu<T> {
|
||||||
type Msg = VerticalMenuMsg;
|
type Msg = VerticalMenuMsg;
|
||||||
|
|
||||||
fn place(&mut self, bounds: Rect) -> Rect {
|
fn place(&mut self, bounds: Rect) -> Rect {
|
||||||
@ -269,11 +347,14 @@ impl Component for VerticalMenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
#[cfg(feature = "ui_debug")]
|
||||||
impl crate::trace::Trace for VerticalMenu {
|
impl<T: MenuItems> crate::trace::Trace for VerticalMenu<T> {
|
||||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||||
|
// Trace the VerticalMenu component
|
||||||
t.component("VerticalMenu");
|
t.component("VerticalMenu");
|
||||||
|
|
||||||
|
// Trace the buttons as a list
|
||||||
t.in_list("buttons", &|button_list| {
|
t.in_list("buttons", &|button_list| {
|
||||||
for button in &self.buttons {
|
for button in self.buttons.iter() {
|
||||||
button_list.child(button);
|
button_list.child(button);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -13,12 +13,12 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{constant::SCREEN, theme, Header, HeaderMsg, VerticalMenu, VerticalMenuMsg};
|
use super::{constant::SCREEN, theme, Header, HeaderMsg, MenuItems, VerticalMenu, VerticalMenuMsg};
|
||||||
|
|
||||||
pub struct VerticalMenuScreen {
|
pub struct VerticalMenuScreen<T> {
|
||||||
header: Header,
|
header: Header,
|
||||||
/// Scrollable vertical menu
|
/// Scrollable vertical menu
|
||||||
menu: VerticalMenu,
|
menu: VerticalMenu<T>,
|
||||||
/// Base position of the menu sliding window to scroll around
|
/// Base position of the menu sliding window to scroll around
|
||||||
offset_base: i16,
|
offset_base: i16,
|
||||||
/// Swipe detector
|
/// Swipe detector
|
||||||
@ -37,9 +37,9 @@ pub enum VerticalMenuScreenMsg {
|
|||||||
Menu,
|
Menu,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VerticalMenuScreen {
|
impl<T: MenuItems> VerticalMenuScreen<T> {
|
||||||
const TOUCH_SENSITIVITY_DIVIDER: i16 = 15;
|
const TOUCH_SENSITIVITY_DIVIDER: i16 = 15;
|
||||||
pub fn new(menu: VerticalMenu) -> Self {
|
pub fn new(menu: VerticalMenu<T>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
header: Header::new(TString::empty()),
|
header: Header::new(TString::empty()),
|
||||||
menu,
|
menu,
|
||||||
@ -164,7 +164,7 @@ impl VerticalMenuScreen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for VerticalMenuScreen {
|
impl<T: MenuItems> Component for VerticalMenuScreen<T> {
|
||||||
type Msg = VerticalMenuScreenMsg;
|
type Msg = VerticalMenuScreenMsg;
|
||||||
|
|
||||||
fn place(&mut self, bounds: Rect) -> Rect {
|
fn place(&mut self, bounds: Rect) -> Rect {
|
||||||
@ -211,7 +211,7 @@ impl Component for VerticalMenuScreen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "micropython")]
|
#[cfg(feature = "micropython")]
|
||||||
impl Swipable for VerticalMenuScreen {
|
impl<T: MenuItems> Swipable for VerticalMenuScreen<T> {
|
||||||
fn get_swipe_config(&self) -> SwipeConfig {
|
fn get_swipe_config(&self) -> SwipeConfig {
|
||||||
self.swipe_config
|
self.swipe_config
|
||||||
}
|
}
|
||||||
@ -222,7 +222,7 @@ impl Swipable for VerticalMenuScreen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
#[cfg(feature = "ui_debug")]
|
||||||
impl crate::trace::Trace for VerticalMenuScreen {
|
impl<T: MenuItems> crate::trace::Trace for VerticalMenuScreen<T> {
|
||||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||||
t.component("VerticalMenuScreen");
|
t.component("VerticalMenuScreen");
|
||||||
t.child("Header", &self.header);
|
t.child("Header", &self.header);
|
||||||
|
@ -19,8 +19,8 @@ use crate::{
|
|||||||
use super::super::{
|
use super::super::{
|
||||||
component::Button,
|
component::Button,
|
||||||
firmware::{
|
firmware::{
|
||||||
ActionBar, FidoCredential, Header, TextScreen, TextScreenMsg, VerticalMenu,
|
ActionBar, FidoCredential, Header, LongMenuGc, ShortMenuVec, TextScreen, TextScreenMsg,
|
||||||
VerticalMenuScreen, VerticalMenuScreenMsg,
|
VerticalMenu, VerticalMenuScreen, VerticalMenuScreenMsg,
|
||||||
},
|
},
|
||||||
theme,
|
theme,
|
||||||
};
|
};
|
||||||
@ -111,13 +111,13 @@ pub fn new_confirm_fido(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Choose credential screen
|
// Choose credential screen
|
||||||
let mut credentials = VerticalMenu::empty();
|
let mut credentials = VerticalMenu::<LongMenuGc>::empty();
|
||||||
for i in 0..num_accounts {
|
for i in 0..num_accounts {
|
||||||
let account = unwrap!(accounts.get(i));
|
let account = unwrap!(accounts.get(i));
|
||||||
let label = account
|
let label = account
|
||||||
.try_into()
|
.try_into()
|
||||||
.unwrap_or_else(|_| TString::from_str("-"));
|
.unwrap_or_else(|_| TString::from_str("-"));
|
||||||
credentials = credentials.item(Button::new_menu_item(label, theme::menu_item_title()));
|
credentials.item(Button::new_menu_item(label, theme::menu_item_title()));
|
||||||
}
|
}
|
||||||
let content_choose_credential = VerticalMenuScreen::new(credentials)
|
let content_choose_credential = VerticalMenuScreen::new(credentials)
|
||||||
.with_header(Header::new(TR::fido__title_select_credential.into()))
|
.with_header(Header::new(TR::fido__title_select_credential.into()))
|
||||||
@ -158,10 +158,9 @@ pub fn new_confirm_fido(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Menu screen
|
// Menu screen
|
||||||
let content_menu = VerticalMenuScreen::new(VerticalMenu::empty().item(Button::new_menu_item(
|
let content_menu = VerticalMenuScreen::new(VerticalMenu::<ShortMenuVec>::empty().with_item(
|
||||||
TR::buttons__cancel.into(),
|
Button::new_menu_item(TR::buttons__cancel.into(), theme::menu_item_title_orange()),
|
||||||
theme::menu_item_title_orange(),
|
))
|
||||||
)))
|
|
||||||
.with_header(Header::new(title).with_close_button())
|
.with_header(Header::new(title).with_close_button())
|
||||||
.map(|msg| match msg {
|
.map(|msg| match msg {
|
||||||
VerticalMenuScreenMsg::Selected(0) => Some(FlowMsg::Choice(0)),
|
VerticalMenuScreenMsg::Selected(0) => Some(FlowMsg::Choice(0)),
|
||||||
|
@ -22,8 +22,8 @@ use crate::{
|
|||||||
use super::super::{
|
use super::super::{
|
||||||
component::Button,
|
component::Button,
|
||||||
firmware::{
|
firmware::{
|
||||||
ActionBar, Header, TextScreen, TextScreenMsg, VerticalMenu, VerticalMenuScreen,
|
ActionBar, Header, ShortMenuVec, TextScreen, TextScreenMsg, VerticalMenu,
|
||||||
VerticalMenuScreenMsg,
|
VerticalMenuScreen, VerticalMenuScreenMsg,
|
||||||
},
|
},
|
||||||
theme,
|
theme,
|
||||||
};
|
};
|
||||||
@ -213,11 +213,11 @@ fn content_main_menu(
|
|||||||
address_params: bool,
|
address_params: bool,
|
||||||
account_params: bool,
|
account_params: bool,
|
||||||
cancel_menu_label: TString<'static>,
|
cancel_menu_label: TString<'static>,
|
||||||
) -> MsgMap<VerticalMenuScreen, impl Fn(VerticalMenuScreenMsg) -> Option<FlowMsg>> {
|
) -> MsgMap<VerticalMenuScreen<ShortMenuVec>, impl Fn(VerticalMenuScreenMsg) -> Option<FlowMsg>> {
|
||||||
let mut main_menu = VerticalMenu::empty();
|
let mut main_menu = VerticalMenu::<ShortMenuVec>::empty();
|
||||||
let mut main_menu_items = Vec::<usize, 3>::new();
|
let mut main_menu_items = Vec::<usize, 3>::new();
|
||||||
if address_params {
|
if address_params {
|
||||||
main_menu = main_menu.item(
|
main_menu.item(
|
||||||
Button::with_text(address_title)
|
Button::with_text(address_title)
|
||||||
.styled(theme::menu_item_title())
|
.styled(theme::menu_item_title())
|
||||||
.with_text_align(Alignment::Start),
|
.with_text_align(Alignment::Start),
|
||||||
@ -225,7 +225,7 @@ fn content_main_menu(
|
|||||||
unwrap!(main_menu_items.push(MENU_ITEM_ADDRESS_INFO));
|
unwrap!(main_menu_items.push(MENU_ITEM_ADDRESS_INFO));
|
||||||
}
|
}
|
||||||
if account_params {
|
if account_params {
|
||||||
main_menu = main_menu.item(
|
main_menu.item(
|
||||||
Button::with_text(TR::address_details__account_info.into())
|
Button::with_text(TR::address_details__account_info.into())
|
||||||
.styled(theme::menu_item_title())
|
.styled(theme::menu_item_title())
|
||||||
.with_text_align(Alignment::Start)
|
.with_text_align(Alignment::Start)
|
||||||
@ -233,7 +233,7 @@ fn content_main_menu(
|
|||||||
);
|
);
|
||||||
unwrap!(main_menu_items.push(MENU_ITEM_ACCOUNT_INFO));
|
unwrap!(main_menu_items.push(MENU_ITEM_ACCOUNT_INFO));
|
||||||
}
|
}
|
||||||
main_menu = main_menu.item(
|
main_menu.item(
|
||||||
Button::with_text(cancel_menu_label)
|
Button::with_text(cancel_menu_label)
|
||||||
.styled(theme::menu_item_title_orange())
|
.styled(theme::menu_item_title_orange())
|
||||||
.with_text_align(Alignment::Start)
|
.with_text_align(Alignment::Start)
|
||||||
@ -241,7 +241,7 @@ fn content_main_menu(
|
|||||||
);
|
);
|
||||||
unwrap!(main_menu_items.push(MENU_ITEM_CANCEL));
|
unwrap!(main_menu_items.push(MENU_ITEM_CANCEL));
|
||||||
|
|
||||||
VerticalMenuScreen::new(main_menu)
|
VerticalMenuScreen::<ShortMenuVec>::new(main_menu)
|
||||||
.with_header(Header::new(TString::empty()).with_close_button())
|
.with_header(Header::new(TString::empty()).with_close_button())
|
||||||
.map(move |msg| match msg {
|
.map(move |msg| match msg {
|
||||||
VerticalMenuScreenMsg::Selected(i) => {
|
VerticalMenuScreenMsg::Selected(i) => {
|
||||||
@ -434,18 +434,17 @@ pub fn new_confirm_output(
|
|||||||
.with_pages(|_| 1);
|
.with_pages(|_| 1);
|
||||||
|
|
||||||
// SummaryMenu
|
// SummaryMenu
|
||||||
let mut summary_menu = VerticalMenu::empty();
|
let mut summary_menu = VerticalMenu::<ShortMenuVec>::empty();
|
||||||
let mut summary_menu_items = Vec::<usize, 3>::new();
|
let mut summary_menu_items = Vec::<usize, 3>::new();
|
||||||
if account_menu_item {
|
if account_menu_item {
|
||||||
summary_menu = summary_menu.item(Button::with_text(account_title));
|
summary_menu.item(Button::with_text(account_title));
|
||||||
unwrap!(summary_menu_items.push(MENU_ITEM_EXTRA_INFO));
|
unwrap!(summary_menu_items.push(MENU_ITEM_EXTRA_INFO));
|
||||||
}
|
}
|
||||||
if fee_menu_item {
|
if fee_menu_item {
|
||||||
summary_menu =
|
|
||||||
summary_menu.item(Button::with_text(TR::confirm_total__title_fee.into()));
|
summary_menu.item(Button::with_text(TR::confirm_total__title_fee.into()));
|
||||||
unwrap!(summary_menu_items.push(MENU_ITEM_FEE_INFO));
|
unwrap!(summary_menu_items.push(MENU_ITEM_FEE_INFO));
|
||||||
}
|
}
|
||||||
summary_menu = summary_menu
|
summary_menu
|
||||||
.item(Button::with_text(cancel_menu_label).styled(theme::menu_item_title_orange()));
|
.item(Button::with_text(cancel_menu_label).styled(theme::menu_item_title_orange()));
|
||||||
unwrap!(summary_menu_items.push(MENU_ITEM_CANCEL));
|
unwrap!(summary_menu_items.push(MENU_ITEM_CANCEL));
|
||||||
let content_summary_menu = VerticalMenuScreen::new(summary_menu)
|
let content_summary_menu = VerticalMenuScreen::new(summary_menu)
|
||||||
|
@ -9,7 +9,7 @@ use crate::{
|
|||||||
FlowController, FlowMsg, SwipeFlow,
|
FlowController, FlowMsg, SwipeFlow,
|
||||||
},
|
},
|
||||||
geometry::{Alignment, Direction, Offset},
|
geometry::{Alignment, Direction, Offset},
|
||||||
layout_eckhart::component::Button,
|
layout_eckhart::{component::Button, firmware::ShortMenuVec},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ pub fn new_confirm_reset(recovery: bool) -> Result<SwipeFlow, error::Error> {
|
|||||||
.one_button_request(br);
|
.one_button_request(br);
|
||||||
|
|
||||||
let content_menu = VerticalMenuScreen::new(
|
let content_menu = VerticalMenuScreen::new(
|
||||||
VerticalMenu::empty().item(
|
VerticalMenu::<ShortMenuVec>::empty().with_item(
|
||||||
Button::with_text(TR::buttons__cancel.into())
|
Button::with_text(TR::buttons__cancel.into())
|
||||||
.styled(theme::menu_item_title_orange())
|
.styled(theme::menu_item_title_orange())
|
||||||
.with_text_align(Alignment::Start)
|
.with_text_align(Alignment::Start)
|
||||||
|
@ -20,8 +20,8 @@ use crate::{
|
|||||||
use super::super::{
|
use super::super::{
|
||||||
component::Button,
|
component::Button,
|
||||||
firmware::{
|
firmware::{
|
||||||
ActionBar, Header, Hint, TextScreen, TextScreenMsg, VerticalMenu, VerticalMenuScreen,
|
ActionBar, Header, Hint, ShortMenuVec, TextScreen, TextScreenMsg, VerticalMenu,
|
||||||
VerticalMenuScreenMsg,
|
VerticalMenuScreen, VerticalMenuScreenMsg,
|
||||||
},
|
},
|
||||||
theme,
|
theme,
|
||||||
};
|
};
|
||||||
@ -131,11 +131,11 @@ pub fn new_confirm_summary(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Menu
|
// Menu
|
||||||
let mut menu = VerticalMenu::empty();
|
let mut menu = VerticalMenu::<ShortMenuVec>::empty();
|
||||||
let mut menu_items = Vec::<usize, 3>::new();
|
let mut menu_items = Vec::<usize, 3>::new();
|
||||||
|
|
||||||
if account_paragraphs.is_some() {
|
if account_paragraphs.is_some() {
|
||||||
menu = menu.item(
|
menu.item(
|
||||||
Button::with_text(TR::address_details__account_info.into())
|
Button::with_text(TR::address_details__account_info.into())
|
||||||
.styled(theme::menu_item_title())
|
.styled(theme::menu_item_title())
|
||||||
.with_text_align(Alignment::Start)
|
.with_text_align(Alignment::Start)
|
||||||
@ -144,7 +144,7 @@ pub fn new_confirm_summary(
|
|||||||
unwrap!(menu_items.push(MENU_ITEM_ACCOUNT_INFO));
|
unwrap!(menu_items.push(MENU_ITEM_ACCOUNT_INFO));
|
||||||
}
|
}
|
||||||
if extra_paragraphs.is_some() {
|
if extra_paragraphs.is_some() {
|
||||||
menu = menu.item(
|
menu.item(
|
||||||
Button::with_text(extra_title.unwrap_or(TR::buttons__more_info.into()))
|
Button::with_text(extra_title.unwrap_or(TR::buttons__more_info.into()))
|
||||||
.styled(theme::menu_item_title())
|
.styled(theme::menu_item_title())
|
||||||
.with_text_align(Alignment::Start)
|
.with_text_align(Alignment::Start)
|
||||||
@ -152,7 +152,7 @@ pub fn new_confirm_summary(
|
|||||||
);
|
);
|
||||||
unwrap!(menu_items.push(MENU_ITEM_EXTRA_INFO));
|
unwrap!(menu_items.push(MENU_ITEM_EXTRA_INFO));
|
||||||
}
|
}
|
||||||
menu = menu.item(
|
menu.item(
|
||||||
Button::with_text(verb_cancel.unwrap_or(TR::buttons__cancel.into()))
|
Button::with_text(verb_cancel.unwrap_or(TR::buttons__cancel.into()))
|
||||||
.styled(theme::menu_item_title_orange())
|
.styled(theme::menu_item_title_orange())
|
||||||
.with_text_align(Alignment::Start)
|
.with_text_align(Alignment::Start)
|
||||||
|
@ -23,8 +23,8 @@ use crate::{
|
|||||||
use super::super::{
|
use super::super::{
|
||||||
component::Button,
|
component::Button,
|
||||||
firmware::{
|
firmware::{
|
||||||
ActionBar, Header, TextScreen, TextScreenMsg, VerticalMenu, VerticalMenuScreen,
|
ActionBar, Header, ShortMenuVec, TextScreen, TextScreenMsg, VerticalMenu,
|
||||||
VerticalMenuScreenMsg,
|
VerticalMenuScreen, VerticalMenuScreenMsg,
|
||||||
},
|
},
|
||||||
theme,
|
theme,
|
||||||
};
|
};
|
||||||
@ -208,7 +208,7 @@ pub fn new_continue_recovery_homepage(
|
|||||||
|
|
||||||
let res = if show_instructions {
|
let res = if show_instructions {
|
||||||
let content_menu = VerticalMenuScreen::new(
|
let content_menu = VerticalMenuScreen::new(
|
||||||
VerticalMenu::empty().item(
|
VerticalMenu::<ShortMenuVec>::empty().with_item(
|
||||||
Button::with_text(cancel_btn.into())
|
Button::with_text(cancel_btn.into())
|
||||||
.styled(theme::menu_item_title_orange())
|
.styled(theme::menu_item_title_orange())
|
||||||
.with_text_align(Alignment::Start)
|
.with_text_align(Alignment::Start)
|
||||||
@ -228,8 +228,8 @@ pub fn new_continue_recovery_homepage(
|
|||||||
res
|
res
|
||||||
} else if pages.is_none() {
|
} else if pages.is_none() {
|
||||||
let content_menu = VerticalMenuScreen::new(
|
let content_menu = VerticalMenuScreen::new(
|
||||||
VerticalMenu::empty()
|
VerticalMenu::<ShortMenuVec>::empty()
|
||||||
.item(
|
.with_item(
|
||||||
Button::with_text_and_subtext(
|
Button::with_text_and_subtext(
|
||||||
TR::words__recovery_share.into(),
|
TR::words__recovery_share.into(),
|
||||||
TR::buttons__more_info.into(),
|
TR::buttons__more_info.into(),
|
||||||
@ -239,7 +239,7 @@ pub fn new_continue_recovery_homepage(
|
|||||||
.with_text_align(Alignment::Start)
|
.with_text_align(Alignment::Start)
|
||||||
.with_content_offset(Offset::x(12)),
|
.with_content_offset(Offset::x(12)),
|
||||||
)
|
)
|
||||||
.item(
|
.with_item(
|
||||||
Button::with_text(cancel_btn.into())
|
Button::with_text(cancel_btn.into())
|
||||||
.styled(theme::menu_item_title_orange())
|
.styled(theme::menu_item_title_orange())
|
||||||
.with_text_align(Alignment::Start)
|
.with_text_align(Alignment::Start)
|
||||||
@ -280,14 +280,14 @@ pub fn new_continue_recovery_homepage(
|
|||||||
res
|
res
|
||||||
} else {
|
} else {
|
||||||
let content_menu = VerticalMenuScreen::new(
|
let content_menu = VerticalMenuScreen::new(
|
||||||
VerticalMenu::empty()
|
VerticalMenu::<ShortMenuVec>::empty()
|
||||||
.item(
|
.with_item(
|
||||||
Button::with_text(TR::recovery__title_remaining_shares.into())
|
Button::with_text(TR::recovery__title_remaining_shares.into())
|
||||||
.styled(theme::menu_item_title())
|
.styled(theme::menu_item_title())
|
||||||
.with_text_align(Alignment::Start)
|
.with_text_align(Alignment::Start)
|
||||||
.with_content_offset(Offset::x(12)),
|
.with_content_offset(Offset::x(12)),
|
||||||
)
|
)
|
||||||
.item(
|
.with_item(
|
||||||
Button::with_text(cancel_btn.into())
|
Button::with_text(cancel_btn.into())
|
||||||
.styled(theme::menu_item_title_orange())
|
.styled(theme::menu_item_title_orange())
|
||||||
.with_text_align(Alignment::Start)
|
.with_text_align(Alignment::Start)
|
||||||
|
@ -20,8 +20,8 @@ use crate::{
|
|||||||
use super::super::{
|
use super::super::{
|
||||||
component::Button,
|
component::Button,
|
||||||
firmware::{
|
firmware::{
|
||||||
ActionBar, Header, HeaderMsg, Hint, QrScreen, TextScreen, TextScreenMsg, VerticalMenu,
|
ActionBar, Header, HeaderMsg, Hint, QrScreen, ShortMenuVec, TextScreen, TextScreenMsg,
|
||||||
VerticalMenuScreen, VerticalMenuScreenMsg,
|
VerticalMenu, VerticalMenuScreen, VerticalMenuScreenMsg,
|
||||||
},
|
},
|
||||||
theme,
|
theme,
|
||||||
};
|
};
|
||||||
@ -132,20 +132,20 @@ pub fn new_get_address(
|
|||||||
// Menu
|
// Menu
|
||||||
|
|
||||||
let content_menu = VerticalMenuScreen::new(
|
let content_menu = VerticalMenuScreen::new(
|
||||||
VerticalMenu::empty()
|
VerticalMenu::<ShortMenuVec>::empty()
|
||||||
.item(
|
.with_item(
|
||||||
Button::with_text(TR::address__qr_code.into())
|
Button::with_text(TR::address__qr_code.into())
|
||||||
.styled(theme::menu_item_title())
|
.styled(theme::menu_item_title())
|
||||||
.with_text_align(Alignment::Start)
|
.with_text_align(Alignment::Start)
|
||||||
.with_content_offset(Offset::x(12)),
|
.with_content_offset(Offset::x(12)),
|
||||||
)
|
)
|
||||||
.item(
|
.with_item(
|
||||||
Button::with_text(TR::address_details__account_info.into())
|
Button::with_text(TR::address_details__account_info.into())
|
||||||
.styled(theme::menu_item_title())
|
.styled(theme::menu_item_title())
|
||||||
.with_text_align(Alignment::Start)
|
.with_text_align(Alignment::Start)
|
||||||
.with_content_offset(Offset::x(12)),
|
.with_content_offset(Offset::x(12)),
|
||||||
)
|
)
|
||||||
.item(
|
.with_item(
|
||||||
Button::with_text(TR::buttons__cancel.into())
|
Button::with_text(TR::buttons__cancel.into())
|
||||||
.styled(theme::menu_item_title_orange())
|
.styled(theme::menu_item_title_orange())
|
||||||
.with_text_align(Alignment::Start)
|
.with_text_align(Alignment::Start)
|
||||||
|
@ -18,7 +18,7 @@ use crate::{
|
|||||||
use super::super::{
|
use super::super::{
|
||||||
component::Button,
|
component::Button,
|
||||||
firmware::{
|
firmware::{
|
||||||
ActionBar, Header, HeaderMsg, Hint, TextScreen, TextScreenMsg, VerticalMenu,
|
ActionBar, Header, HeaderMsg, Hint, ShortMenuVec, TextScreen, TextScreenMsg, VerticalMenu,
|
||||||
VerticalMenuScreen, VerticalMenuScreenMsg,
|
VerticalMenuScreen, VerticalMenuScreenMsg,
|
||||||
},
|
},
|
||||||
theme,
|
theme,
|
||||||
@ -73,7 +73,7 @@ pub fn new_prompt_backup() -> Result<SwipeFlow, error::Error> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let content_menu = VerticalMenuScreen::new(
|
let content_menu = VerticalMenuScreen::new(
|
||||||
VerticalMenu::empty().item(
|
VerticalMenu::<ShortMenuVec>::empty().with_item(
|
||||||
Button::with_text(TR::backup__title_skip.into())
|
Button::with_text(TR::backup__title_skip.into())
|
||||||
.styled(theme::menu_item_title_orange())
|
.styled(theme::menu_item_title_orange())
|
||||||
.with_text_align(Alignment::Start)
|
.with_text_align(Alignment::Start)
|
||||||
|
@ -18,8 +18,8 @@ use crate::{
|
|||||||
use super::super::{
|
use super::super::{
|
||||||
component::Button,
|
component::Button,
|
||||||
firmware::{
|
firmware::{
|
||||||
ActionBar, Header, HeaderMsg, TextScreen, TextScreenMsg, VerticalMenu, VerticalMenuScreen,
|
ActionBar, Header, HeaderMsg, ShortMenuVec, TextScreen, TextScreenMsg, VerticalMenu,
|
||||||
VerticalMenuScreenMsg,
|
VerticalMenuScreen, VerticalMenuScreenMsg,
|
||||||
},
|
},
|
||||||
theme,
|
theme,
|
||||||
};
|
};
|
||||||
@ -89,15 +89,15 @@ pub fn new_show_danger(
|
|||||||
|
|
||||||
// Menu
|
// Menu
|
||||||
let content_menu = VerticalMenuScreen::new(
|
let content_menu = VerticalMenuScreen::new(
|
||||||
VerticalMenu::empty()
|
VerticalMenu::<ShortMenuVec>::empty()
|
||||||
.with_separators()
|
.with_separators()
|
||||||
.item(
|
.with_item(
|
||||||
Button::with_text(verb_cancel)
|
Button::with_text(verb_cancel)
|
||||||
.styled(theme::menu_item_title())
|
.styled(theme::menu_item_title())
|
||||||
.with_text_align(Alignment::Start)
|
.with_text_align(Alignment::Start)
|
||||||
.with_content_offset(Offset::x(12)),
|
.with_content_offset(Offset::x(12)),
|
||||||
)
|
)
|
||||||
.item(
|
.with_item(
|
||||||
Button::with_text(TR::words__continue_anyway.into())
|
Button::with_text(TR::words__continue_anyway.into())
|
||||||
.styled(theme::menu_item_title_orange())
|
.styled(theme::menu_item_title_orange())
|
||||||
.with_text_align(Alignment::Start)
|
.with_text_align(Alignment::Start)
|
||||||
|
Loading…
Reference in New Issue
Block a user