mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-22 15:38:11 +00:00
feat(core/ui): add cancel button to paginated blobs
[no changelog]
This commit is contained in:
parent
8313c30d5a
commit
2bc787a652
@ -174,6 +174,7 @@ static void _librust_qstrs(void) {
|
|||||||
MP_QSTR_buttons__turn_on;
|
MP_QSTR_buttons__turn_on;
|
||||||
MP_QSTR_buttons__view_all_data;
|
MP_QSTR_buttons__view_all_data;
|
||||||
MP_QSTR_can_go_back;
|
MP_QSTR_can_go_back;
|
||||||
|
MP_QSTR_cancel;
|
||||||
MP_QSTR_cancel_arrow;
|
MP_QSTR_cancel_arrow;
|
||||||
MP_QSTR_cancel_cross;
|
MP_QSTR_cancel_cross;
|
||||||
MP_QSTR_cancel_text;
|
MP_QSTR_cancel_text;
|
||||||
|
@ -25,94 +25,20 @@ use super::super::{
|
|||||||
theme,
|
theme,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
const MENU_ITEM_CANCEL: usize = 0;
|
||||||
pub enum ConfirmAction {
|
const MENU_ITEM_INFO: usize = 1;
|
||||||
Intro,
|
|
||||||
Menu,
|
|
||||||
Confirm,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FlowController for ConfirmAction {
|
// Extra button at the top-right corner of the Action screen
|
||||||
fn index(&'static self) -> usize {
|
#[derive(PartialEq)]
|
||||||
*self as usize
|
pub enum ConfirmActionExtra {
|
||||||
}
|
// Opens a menu which can (optionally) lead to an extra Info screen, or cancel the action
|
||||||
|
Menu {
|
||||||
fn handle_swipe(&'static self, direction: Direction) -> Decision {
|
|
||||||
match (self, direction) {
|
|
||||||
(Self::Intro, Direction::Left) => Self::Menu.swipe(direction),
|
|
||||||
(Self::Menu, Direction::Right) => Self::Intro.swipe(direction),
|
|
||||||
(Self::Intro, Direction::Up) => Self::Confirm.swipe(direction),
|
|
||||||
(Self::Confirm, Direction::Down) => Self::Intro.swipe(direction),
|
|
||||||
(Self::Confirm, Direction::Left) => Self::Menu.swipe(direction),
|
|
||||||
_ => self.do_nothing(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_event(&'static self, msg: FlowMsg) -> Decision {
|
|
||||||
match (self, msg) {
|
|
||||||
(Self::Intro, FlowMsg::Info) => Self::Menu.goto(),
|
|
||||||
(Self::Menu, FlowMsg::Cancelled) => Self::Intro.swipe_right(),
|
|
||||||
(Self::Menu, FlowMsg::Choice(0)) => self.return_msg(FlowMsg::Cancelled),
|
|
||||||
(Self::Menu, FlowMsg::Choice(1)) => self.return_msg(FlowMsg::Info),
|
|
||||||
(Self::Confirm, FlowMsg::Confirmed) => self.return_msg(FlowMsg::Confirmed),
|
|
||||||
(Self::Confirm, FlowMsg::Info) => Self::Menu.goto(),
|
|
||||||
_ => self.do_nothing(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ConfirmAction flow without a separate "Tap to confirm" or "Hold to confirm"
|
|
||||||
/// screen. Swiping up directly from the intro screen confirms action.
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
|
||||||
pub enum ConfirmActionSimple {
|
|
||||||
Intro,
|
|
||||||
Menu,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FlowController for ConfirmActionSimple {
|
|
||||||
#[inline]
|
|
||||||
fn index(&'static self) -> usize {
|
|
||||||
*self as usize
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_swipe(&'static self, direction: Direction) -> Decision {
|
|
||||||
match (self, direction) {
|
|
||||||
(Self::Intro, Direction::Left) => Self::Menu.swipe(direction),
|
|
||||||
(Self::Menu, Direction::Right) => Self::Intro.swipe(direction),
|
|
||||||
(Self::Intro, Direction::Up) => self.return_msg(FlowMsg::Confirmed),
|
|
||||||
_ => self.do_nothing(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_event(&'static self, msg: FlowMsg) -> Decision {
|
|
||||||
match (self, msg) {
|
|
||||||
(Self::Intro, FlowMsg::Info) => Self::Menu.goto(),
|
|
||||||
(Self::Menu, FlowMsg::Cancelled) => Self::Intro.swipe_right(),
|
|
||||||
(Self::Menu, FlowMsg::Choice(0)) => self.return_msg(FlowMsg::Cancelled),
|
|
||||||
(Self::Menu, FlowMsg::Choice(1)) => self.return_msg(FlowMsg::Info),
|
|
||||||
_ => self.do_nothing(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ConfirmActionMenu {
|
|
||||||
verb_cancel: Option<TString<'static>>,
|
verb_cancel: Option<TString<'static>>,
|
||||||
info: bool,
|
has_info: bool,
|
||||||
verb_info: Option<TString<'static>>,
|
verb_info: Option<TString<'static>>,
|
||||||
}
|
},
|
||||||
|
// Shows a cancel button directly
|
||||||
impl ConfirmActionMenu {
|
Cancel,
|
||||||
pub fn new(
|
|
||||||
verb_cancel: Option<TString<'static>>,
|
|
||||||
info: bool,
|
|
||||||
verb_info: Option<TString<'static>>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
verb_cancel,
|
|
||||||
info,
|
|
||||||
verb_info,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ConfirmActionStrings {
|
pub struct ConfirmActionStrings {
|
||||||
@ -138,6 +64,106 @@ impl ConfirmActionStrings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The simplest form of the ConfirmAction flow:
|
||||||
|
/// no menu, nor a separate "Tap to confirm" or "Hold to confirm".
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
|
enum ConfirmAction {
|
||||||
|
Action,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FlowController for ConfirmAction {
|
||||||
|
#[inline]
|
||||||
|
fn index(&'static self) -> usize {
|
||||||
|
*self as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_swipe(&'static self, direction: Direction) -> Decision {
|
||||||
|
match (self, direction) {
|
||||||
|
(Self::Action, Direction::Up) => self.return_msg(FlowMsg::Confirmed),
|
||||||
|
_ => self.do_nothing(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_event(&'static self, msg: FlowMsg) -> Decision {
|
||||||
|
match (self, msg) {
|
||||||
|
(Self::Action, FlowMsg::Cancelled) => self.return_msg(FlowMsg::Cancelled),
|
||||||
|
_ => self.do_nothing(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A ConfirmAction flow with a menu which can contain various items
|
||||||
|
/// as defined by ConfirmActionExtra::Menu.
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
|
enum ConfirmActionWithMenu {
|
||||||
|
Action,
|
||||||
|
Menu,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FlowController for ConfirmActionWithMenu {
|
||||||
|
#[inline]
|
||||||
|
fn index(&'static self) -> usize {
|
||||||
|
*self as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_swipe(&'static self, direction: Direction) -> Decision {
|
||||||
|
match (self, direction) {
|
||||||
|
(Self::Action, Direction::Left) => Self::Menu.swipe(direction),
|
||||||
|
(Self::Menu, Direction::Right) => Self::Action.swipe(direction),
|
||||||
|
(Self::Action, Direction::Up) => self.return_msg(FlowMsg::Confirmed),
|
||||||
|
_ => self.do_nothing(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_event(&'static self, msg: FlowMsg) -> Decision {
|
||||||
|
match (self, msg) {
|
||||||
|
(Self::Action, FlowMsg::Info) => Self::Menu.goto(),
|
||||||
|
(Self::Menu, FlowMsg::Cancelled) => Self::Action.swipe_right(),
|
||||||
|
(Self::Menu, FlowMsg::Choice(MENU_ITEM_CANCEL)) => self.return_msg(FlowMsg::Cancelled),
|
||||||
|
(Self::Menu, FlowMsg::Choice(MENU_ITEM_INFO)) => self.return_msg(FlowMsg::Info),
|
||||||
|
_ => self.do_nothing(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A ConfirmAction flow with a menu and
|
||||||
|
// a separate "Tap to confirm" or "Hold to confirm" screen.
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
|
enum ConfirmActionWithMenuAndConfirmation {
|
||||||
|
Action,
|
||||||
|
Menu,
|
||||||
|
Confirmation,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FlowController for ConfirmActionWithMenuAndConfirmation {
|
||||||
|
fn index(&'static self) -> usize {
|
||||||
|
*self as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_swipe(&'static self, direction: Direction) -> Decision {
|
||||||
|
match (self, direction) {
|
||||||
|
(Self::Action, Direction::Left) => Self::Menu.swipe(direction),
|
||||||
|
(Self::Menu, Direction::Right) => Self::Action.swipe(direction),
|
||||||
|
(Self::Action, Direction::Up) => Self::Confirmation.swipe(direction),
|
||||||
|
(Self::Confirmation, Direction::Down) => Self::Action.swipe(direction),
|
||||||
|
(Self::Confirmation, Direction::Left) => Self::Menu.swipe(direction),
|
||||||
|
_ => self.do_nothing(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_event(&'static self, msg: FlowMsg) -> Decision {
|
||||||
|
match (self, msg) {
|
||||||
|
(Self::Action, FlowMsg::Info) => Self::Menu.goto(),
|
||||||
|
(Self::Menu, FlowMsg::Cancelled) => Self::Action.swipe_right(),
|
||||||
|
(Self::Menu, FlowMsg::Choice(MENU_ITEM_CANCEL)) => self.return_msg(FlowMsg::Cancelled),
|
||||||
|
(Self::Menu, FlowMsg::Choice(MENU_ITEM_INFO)) => self.return_msg(FlowMsg::Info),
|
||||||
|
(Self::Confirmation, FlowMsg::Confirmed) => self.return_msg(FlowMsg::Confirmed),
|
||||||
|
(Self::Confirmation, FlowMsg::Info) => Self::Menu.goto(),
|
||||||
|
_ => self.do_nothing(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new_confirm_action(
|
pub fn new_confirm_action(
|
||||||
title: TString<'static>,
|
title: TString<'static>,
|
||||||
@ -168,7 +194,11 @@ pub fn new_confirm_action(
|
|||||||
|
|
||||||
new_confirm_action_simple(
|
new_confirm_action_simple(
|
||||||
paragraphs,
|
paragraphs,
|
||||||
ConfirmActionMenu::new(verb_cancel, false, None),
|
ConfirmActionExtra::Menu {
|
||||||
|
verb_cancel,
|
||||||
|
has_info: false,
|
||||||
|
verb_info: None,
|
||||||
|
},
|
||||||
ConfirmActionStrings::new(title, subtitle, None, prompt_screen.then_some(prompt_title)),
|
ConfirmActionStrings::new(title, subtitle, None, prompt_screen.then_some(prompt_title)),
|
||||||
hold,
|
hold,
|
||||||
None,
|
None,
|
||||||
@ -179,21 +209,29 @@ pub fn new_confirm_action(
|
|||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn new_confirm_action_uni<T: Component + Paginate + MaybeTrace + 'static>(
|
fn new_confirm_action_uni<T: Component + Paginate + MaybeTrace + 'static>(
|
||||||
content: SwipeContent<SwipePage<T>>,
|
content: SwipeContent<SwipePage<T>>,
|
||||||
menu: ConfirmActionMenu,
|
extra: ConfirmActionExtra,
|
||||||
strings: ConfirmActionStrings,
|
strings: ConfirmActionStrings,
|
||||||
hold: bool,
|
hold: bool,
|
||||||
show_page_counter: bool,
|
show_page_counter: bool,
|
||||||
) -> Result<SwipeFlow, error::Error> {
|
) -> Result<SwipeFlow, error::Error> {
|
||||||
let (prompt_screen, prompt_pages, flow, page) =
|
let (prompt_screen, prompt_pages, flow, page) =
|
||||||
create_flow(strings.title, strings.prompt_screen, hold);
|
create_flow(strings.title, strings.prompt_screen, hold, &extra);
|
||||||
|
|
||||||
let mut content_intro = Frame::left_aligned(strings.title, content)
|
let mut content = Frame::left_aligned(strings.title, content)
|
||||||
.with_swipe(Direction::Up, SwipeSettings::default())
|
.with_swipe(Direction::Up, SwipeSettings::default())
|
||||||
.with_swipe(Direction::Left, SwipeSettings::default())
|
.with_swipe(Direction::Left, SwipeSettings::default())
|
||||||
.with_vertical_pages()
|
.with_vertical_pages()
|
||||||
.with_menu_button()
|
|
||||||
.with_footer(TR::instructions__swipe_up.into(), None);
|
.with_footer(TR::instructions__swipe_up.into(), None);
|
||||||
|
|
||||||
|
match extra {
|
||||||
|
ConfirmActionExtra::Menu { .. } => {
|
||||||
|
content = content.with_menu_button();
|
||||||
|
}
|
||||||
|
ConfirmActionExtra::Cancel => {
|
||||||
|
content = content.with_cancel_button();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if show_page_counter {
|
if show_page_counter {
|
||||||
fn footer_update_fn<T: Component + Paginate>(
|
fn footer_update_fn<T: Component + Paginate>(
|
||||||
content: &SwipeContent<SwipePage<T>>,
|
content: &SwipeContent<SwipePage<T>>,
|
||||||
@ -205,26 +243,25 @@ fn new_confirm_action_uni<T: Component + Paginate + MaybeTrace + 'static>(
|
|||||||
footer.update_page_counter(ctx, current_page, page_count);
|
footer.update_page_counter(ctx, current_page, page_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
content_intro = content_intro
|
content = content
|
||||||
.with_footer_counter(TR::instructions__swipe_up.into())
|
.with_footer_counter(TR::instructions__swipe_up.into())
|
||||||
.register_footer_update_fn(footer_update_fn::<T>);
|
.register_footer_update_fn(footer_update_fn::<T>);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(subtitle) = strings.subtitle {
|
if let Some(subtitle) = strings.subtitle {
|
||||||
content_intro = content_intro.with_subtitle(subtitle);
|
content = content.with_subtitle(subtitle);
|
||||||
}
|
}
|
||||||
|
|
||||||
let content_intro = content_intro
|
let content = content
|
||||||
.map(move |msg| match msg {
|
.map(move |msg| match msg {
|
||||||
FrameMsg::Button(_) => Some(FlowMsg::Info),
|
FrameMsg::Button(FlowMsg::Info) => Some(FlowMsg::Info),
|
||||||
|
FrameMsg::Button(FlowMsg::Cancelled) => Some(FlowMsg::Cancelled),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.with_pages(move |intro_pages| intro_pages + prompt_pages);
|
.with_pages(move |intro_pages| intro_pages + prompt_pages);
|
||||||
|
|
||||||
let flow = flow?.with_page(page, content_intro)?;
|
let flow = flow?.with_page(page, content)?;
|
||||||
|
let flow = create_menu(flow, extra, prompt_screen)?;
|
||||||
let flow = create_menu(flow, menu, prompt_screen)?;
|
|
||||||
|
|
||||||
let flow = create_confirm(flow, strings.subtitle, hold, prompt_screen)?;
|
let flow = create_confirm(flow, strings.subtitle, hold, prompt_screen)?;
|
||||||
|
|
||||||
Ok(flow)
|
Ok(flow)
|
||||||
@ -234,6 +271,7 @@ fn create_flow(
|
|||||||
title: TString<'static>,
|
title: TString<'static>,
|
||||||
prompt_screen: Option<TString<'static>>,
|
prompt_screen: Option<TString<'static>>,
|
||||||
hold: bool,
|
hold: bool,
|
||||||
|
extra: &ConfirmActionExtra,
|
||||||
) -> (
|
) -> (
|
||||||
Option<TString<'static>>,
|
Option<TString<'static>>,
|
||||||
usize,
|
usize,
|
||||||
@ -242,34 +280,46 @@ fn create_flow(
|
|||||||
) {
|
) {
|
||||||
let prompt_screen = prompt_screen.or_else(|| hold.then_some(title));
|
let prompt_screen = prompt_screen.or_else(|| hold.then_some(title));
|
||||||
let prompt_pages: usize = prompt_screen.is_some().into();
|
let prompt_pages: usize = prompt_screen.is_some().into();
|
||||||
|
let initial_page: &dyn FlowController = match (extra, prompt_screen.is_some()) {
|
||||||
let (flow, page): (Result<SwipeFlow, Error>, &dyn FlowController) = if prompt_screen.is_some() {
|
(ConfirmActionExtra::Menu { .. }, false) => &ConfirmActionWithMenu::Action,
|
||||||
(SwipeFlow::new(&ConfirmAction::Intro), &ConfirmAction::Intro)
|
(ConfirmActionExtra::Menu { .. }, true) => &ConfirmActionWithMenuAndConfirmation::Action,
|
||||||
} else {
|
_ => &ConfirmAction::Action,
|
||||||
(
|
|
||||||
SwipeFlow::new(&ConfirmActionSimple::Intro),
|
|
||||||
&ConfirmActionSimple::Intro,
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
(prompt_screen, prompt_pages, flow, page)
|
(
|
||||||
|
prompt_screen,
|
||||||
|
prompt_pages,
|
||||||
|
SwipeFlow::new(initial_page),
|
||||||
|
initial_page,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_menu(
|
fn create_menu(
|
||||||
flow: SwipeFlow,
|
flow: SwipeFlow,
|
||||||
menu: ConfirmActionMenu,
|
extra: ConfirmActionExtra,
|
||||||
prompt_screen: Option<TString<'static>>,
|
prompt_screen: Option<TString<'static>>,
|
||||||
) -> Result<SwipeFlow, Error> {
|
) -> Result<SwipeFlow, Error> {
|
||||||
|
if let ConfirmActionExtra::Menu {
|
||||||
|
verb_cancel,
|
||||||
|
has_info,
|
||||||
|
verb_info,
|
||||||
|
} = extra
|
||||||
|
{
|
||||||
|
// NB: The Cancel menu item is always the first,
|
||||||
|
// because of the MENU_ITEM_CANCEL = 0.
|
||||||
|
// If we want the cancel item to be somewhere else,
|
||||||
|
// we would need to account for that and we could not use a constant.
|
||||||
let mut menu_choices = VerticalMenu::empty().danger(
|
let mut menu_choices = VerticalMenu::empty().danger(
|
||||||
theme::ICON_CANCEL,
|
theme::ICON_CANCEL,
|
||||||
menu.verb_cancel.unwrap_or(TR::buttons__cancel.into()),
|
verb_cancel.unwrap_or(TR::buttons__cancel.into()),
|
||||||
);
|
);
|
||||||
|
|
||||||
if menu.info {
|
if has_info {
|
||||||
|
// The Info menu item (if present) has to be the 2nd,
|
||||||
|
// because of MENU_ITEM_INFO = 1!
|
||||||
menu_choices = menu_choices.item(
|
menu_choices = menu_choices.item(
|
||||||
theme::ICON_CHEVRON_RIGHT,
|
theme::ICON_CHEVRON_RIGHT,
|
||||||
menu.verb_info
|
verb_info.unwrap_or(TR::words__title_information.into()),
|
||||||
.unwrap_or(TR::words__title_information.into()),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,12 +333,16 @@ fn create_menu(
|
|||||||
});
|
});
|
||||||
|
|
||||||
if prompt_screen.is_some() {
|
if prompt_screen.is_some() {
|
||||||
flow.with_page(&ConfirmAction::Menu, content_menu)
|
flow.with_page(&ConfirmActionWithMenuAndConfirmation::Menu, content_menu)
|
||||||
} else {
|
} else {
|
||||||
flow.with_page(&ConfirmActionSimple::Menu, content_menu)
|
flow.with_page(&ConfirmActionWithMenu::Menu, content_menu)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(flow) // no menu being added
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create the extra confirmation screen (optional).
|
||||||
fn create_confirm(
|
fn create_confirm(
|
||||||
flow: SwipeFlow,
|
flow: SwipeFlow,
|
||||||
subtitle: Option<TString<'static>>,
|
subtitle: Option<TString<'static>>,
|
||||||
@ -324,7 +378,10 @@ fn create_confirm(
|
|||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
|
|
||||||
flow.with_page(&ConfirmAction::Confirm, content_confirm)
|
flow.with_page(
|
||||||
|
&ConfirmActionWithMenuAndConfirmation::Confirmation,
|
||||||
|
content_confirm,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
Ok(flow)
|
Ok(flow)
|
||||||
}
|
}
|
||||||
@ -333,7 +390,7 @@ fn create_confirm(
|
|||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
pub fn new_confirm_action_simple<T: Component + Paginate + MaybeTrace + 'static>(
|
pub fn new_confirm_action_simple<T: Component + Paginate + MaybeTrace + 'static>(
|
||||||
content: T,
|
content: T,
|
||||||
menu: ConfirmActionMenu,
|
extra: ConfirmActionExtra,
|
||||||
strings: ConfirmActionStrings,
|
strings: ConfirmActionStrings,
|
||||||
hold: bool,
|
hold: bool,
|
||||||
page_limit: Option<usize>,
|
page_limit: Option<usize>,
|
||||||
@ -341,7 +398,7 @@ pub fn new_confirm_action_simple<T: Component + Paginate + MaybeTrace + 'static>
|
|||||||
) -> Result<SwipeFlow, error::Error> {
|
) -> Result<SwipeFlow, error::Error> {
|
||||||
new_confirm_action_uni(
|
new_confirm_action_uni(
|
||||||
SwipeContent::new(SwipePage::vertical(content).with_limit(page_limit)),
|
SwipeContent::new(SwipePage::vertical(content).with_limit(page_limit)),
|
||||||
menu,
|
extra,
|
||||||
strings,
|
strings,
|
||||||
hold,
|
hold,
|
||||||
show_page_counter,
|
show_page_counter,
|
||||||
|
@ -19,7 +19,7 @@ pub mod util;
|
|||||||
pub mod warning_hi_prio;
|
pub mod warning_hi_prio;
|
||||||
|
|
||||||
pub use confirm_action::{
|
pub use confirm_action::{
|
||||||
new_confirm_action, new_confirm_action_simple, ConfirmActionMenu, ConfirmActionStrings,
|
new_confirm_action, new_confirm_action_simple, ConfirmActionExtra, ConfirmActionStrings,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "universal_fw")]
|
#[cfg(feature = "universal_fw")]
|
||||||
pub use confirm_fido::new_confirm_fido;
|
pub use confirm_fido::new_confirm_fido;
|
||||||
|
@ -3,7 +3,7 @@ use super::{
|
|||||||
component::{Frame, FrameMsg},
|
component::{Frame, FrameMsg},
|
||||||
theme,
|
theme,
|
||||||
},
|
},
|
||||||
ConfirmActionMenu, ConfirmActionStrings,
|
ConfirmActionExtra, ConfirmActionStrings,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
error::Error,
|
error::Error,
|
||||||
@ -52,6 +52,7 @@ pub struct ConfirmBlobParams {
|
|||||||
swipe_up: bool,
|
swipe_up: bool,
|
||||||
swipe_down: bool,
|
swipe_down: bool,
|
||||||
swipe_right: bool,
|
swipe_right: bool,
|
||||||
|
cancel: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConfirmBlobParams {
|
impl ConfirmBlobParams {
|
||||||
@ -84,6 +85,7 @@ impl ConfirmBlobParams {
|
|||||||
swipe_up: false,
|
swipe_up: false,
|
||||||
swipe_down: false,
|
swipe_down: false,
|
||||||
swipe_right: false,
|
swipe_right: false,
|
||||||
|
cancel: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,6 +154,11 @@ impl ConfirmBlobParams {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const fn with_cancel(mut self, cancel: bool) -> Self {
|
||||||
|
self.cancel = cancel;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub const fn with_footer(
|
pub const fn with_footer(
|
||||||
mut self,
|
mut self,
|
||||||
instruction: TString<'static>,
|
instruction: TString<'static>,
|
||||||
@ -262,9 +269,19 @@ impl ConfirmBlobParams {
|
|||||||
}
|
}
|
||||||
.into_paragraphs();
|
.into_paragraphs();
|
||||||
|
|
||||||
|
let confirm_extra = if self.cancel {
|
||||||
|
ConfirmActionExtra::Cancel
|
||||||
|
} else {
|
||||||
|
ConfirmActionExtra::Menu {
|
||||||
|
verb_cancel: self.verb_cancel,
|
||||||
|
has_info: self.info_button,
|
||||||
|
verb_info: self.verb_info,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
flow::new_confirm_action_simple(
|
flow::new_confirm_action_simple(
|
||||||
paragraphs,
|
paragraphs,
|
||||||
ConfirmActionMenu::new(self.verb_cancel, self.info_button, self.verb_info),
|
confirm_extra,
|
||||||
ConfirmActionStrings::new(
|
ConfirmActionStrings::new(
|
||||||
self.title,
|
self.title,
|
||||||
self.subtitle,
|
self.subtitle,
|
||||||
|
@ -55,7 +55,7 @@ use crate::{
|
|||||||
flow::{
|
flow::{
|
||||||
new_confirm_action_simple,
|
new_confirm_action_simple,
|
||||||
util::{ConfirmBlobParams, ShowInfoParams},
|
util::{ConfirmBlobParams, ShowInfoParams},
|
||||||
ConfirmActionMenu, ConfirmActionStrings,
|
ConfirmActionExtra, ConfirmActionStrings,
|
||||||
},
|
},
|
||||||
theme::ICON_BULLET_CHECKMARK,
|
theme::ICON_BULLET_CHECKMARK,
|
||||||
},
|
},
|
||||||
@ -246,7 +246,11 @@ extern "C" fn new_confirm_emphasized(n_args: usize, args: *const Obj, kwargs: *m
|
|||||||
|
|
||||||
new_confirm_action_simple(
|
new_confirm_action_simple(
|
||||||
FormattedText::new(ops).vertically_centered(),
|
FormattedText::new(ops).vertically_centered(),
|
||||||
ConfirmActionMenu::new(None, false, None),
|
ConfirmActionExtra::Menu {
|
||||||
|
verb_cancel: None,
|
||||||
|
has_info: false,
|
||||||
|
verb_info: None,
|
||||||
|
},
|
||||||
ConfirmActionStrings::new(title, None, None, Some(title)),
|
ConfirmActionStrings::new(title, None, None, Some(title)),
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
@ -296,6 +300,7 @@ extern "C" fn new_confirm_blob(n_args: usize, args: *const Obj, kwargs: *mut Map
|
|||||||
.get(Qstr::MP_QSTR_page_limit)
|
.get(Qstr::MP_QSTR_page_limit)
|
||||||
.unwrap_or_else(|_| Obj::const_none())
|
.unwrap_or_else(|_| Obj::const_none())
|
||||||
.try_into_option()?;
|
.try_into_option()?;
|
||||||
|
let cancel: bool = kwargs.get_or(Qstr::MP_QSTR_cancel, false)?;
|
||||||
|
|
||||||
let (description, description_font) = if page_limit == Some(1) {
|
let (description, description_font) = if page_limit == Some(1) {
|
||||||
(
|
(
|
||||||
@ -318,6 +323,7 @@ extern "C" fn new_confirm_blob(n_args: usize, args: *const Obj, kwargs: *mut Map
|
|||||||
.with_chunkify(chunkify)
|
.with_chunkify(chunkify)
|
||||||
.with_page_counter(page_counter)
|
.with_page_counter(page_counter)
|
||||||
.with_page_limit(page_limit)
|
.with_page_limit(page_limit)
|
||||||
|
.with_cancel(cancel)
|
||||||
.with_prompt(prompt_screen)
|
.with_prompt(prompt_screen)
|
||||||
.with_hold(hold)
|
.with_hold(hold)
|
||||||
.into_flow()
|
.into_flow()
|
||||||
@ -389,7 +395,11 @@ extern "C" fn new_confirm_address(n_args: usize, args: *const Obj, kwargs: *mut
|
|||||||
|
|
||||||
flow::new_confirm_action_simple(
|
flow::new_confirm_action_simple(
|
||||||
paragraphs,
|
paragraphs,
|
||||||
ConfirmActionMenu::new(None, false, None),
|
ConfirmActionExtra::Menu {
|
||||||
|
verb_cancel: None,
|
||||||
|
has_info: false,
|
||||||
|
verb_info: None,
|
||||||
|
},
|
||||||
ConfirmActionStrings::new(title, None, None, None),
|
ConfirmActionStrings::new(title, None, None, None),
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
@ -432,7 +442,11 @@ extern "C" fn new_confirm_properties(n_args: usize, args: *const Obj, kwargs: *m
|
|||||||
|
|
||||||
new_confirm_action_simple(
|
new_confirm_action_simple(
|
||||||
paragraphs.into_paragraphs(),
|
paragraphs.into_paragraphs(),
|
||||||
ConfirmActionMenu::new(None, false, None),
|
ConfirmActionExtra::Menu {
|
||||||
|
verb_cancel: None,
|
||||||
|
has_info: false,
|
||||||
|
verb_info: None,
|
||||||
|
},
|
||||||
ConfirmActionStrings::new(title, None, None, hold.then_some(title)),
|
ConfirmActionStrings::new(title, None, None, hold.then_some(title)),
|
||||||
hold,
|
hold,
|
||||||
None,
|
None,
|
||||||
@ -462,7 +476,11 @@ extern "C" fn new_confirm_homescreen(n_args: usize, args: *const Obj, kwargs: *m
|
|||||||
|
|
||||||
new_confirm_action_simple(
|
new_confirm_action_simple(
|
||||||
paragraphs,
|
paragraphs,
|
||||||
ConfirmActionMenu::new(None, false, None),
|
ConfirmActionExtra::Menu {
|
||||||
|
verb_cancel: None,
|
||||||
|
has_info: false,
|
||||||
|
verb_info: None,
|
||||||
|
},
|
||||||
ConfirmActionStrings::new(
|
ConfirmActionStrings::new(
|
||||||
TR::homescreen__settings_title.into(),
|
TR::homescreen__settings_title.into(),
|
||||||
Some(TR::homescreen__settings_subtitle.into()),
|
Some(TR::homescreen__settings_subtitle.into()),
|
||||||
@ -774,7 +792,11 @@ extern "C" fn new_confirm_total(n_args: usize, args: *const Obj, kwargs: *mut Ma
|
|||||||
|
|
||||||
new_confirm_action_simple(
|
new_confirm_action_simple(
|
||||||
paragraphs.into_paragraphs(),
|
paragraphs.into_paragraphs(),
|
||||||
ConfirmActionMenu::new(None, true, None),
|
ConfirmActionExtra::Menu {
|
||||||
|
verb_cancel: None,
|
||||||
|
has_info: true,
|
||||||
|
verb_info: None,
|
||||||
|
},
|
||||||
ConfirmActionStrings::new(title, None, None, Some(title)),
|
ConfirmActionStrings::new(title, None, None, Some(title)),
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
@ -1091,7 +1113,11 @@ extern "C" fn new_confirm_coinjoin(n_args: usize, args: *const Obj, kwargs: *mut
|
|||||||
|
|
||||||
new_confirm_action_simple(
|
new_confirm_action_simple(
|
||||||
paragraphs,
|
paragraphs,
|
||||||
ConfirmActionMenu::new(None, false, None),
|
ConfirmActionExtra::Menu {
|
||||||
|
verb_cancel: None,
|
||||||
|
has_info: false,
|
||||||
|
verb_info: None,
|
||||||
|
},
|
||||||
ConfirmActionStrings::new(
|
ConfirmActionStrings::new(
|
||||||
TR::coinjoin__title.into(),
|
TR::coinjoin__title.into(),
|
||||||
None,
|
None,
|
||||||
@ -1587,6 +1613,7 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
|||||||
/// page_counter: bool = False,
|
/// page_counter: bool = False,
|
||||||
/// prompt_screen: bool = False,
|
/// prompt_screen: bool = False,
|
||||||
/// page_limit: int | None = None,
|
/// page_limit: int | None = None,
|
||||||
|
/// cancel: bool = False,
|
||||||
/// ) -> LayoutObj[UiResult]:
|
/// ) -> LayoutObj[UiResult]:
|
||||||
/// """Confirm byte sequence data."""
|
/// """Confirm byte sequence data."""
|
||||||
Qstr::MP_QSTR_confirm_blob => obj_fn_kw!(0, new_confirm_blob).as_obj(),
|
Qstr::MP_QSTR_confirm_blob => obj_fn_kw!(0, new_confirm_blob).as_obj(),
|
||||||
|
@ -1712,6 +1712,7 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
|||||||
/// page_counter: bool = False,
|
/// page_counter: bool = False,
|
||||||
/// prompt_screen: bool = False,
|
/// prompt_screen: bool = False,
|
||||||
/// page_limit: int | None = None,
|
/// page_limit: int | None = None,
|
||||||
|
/// cancel: bool = False,
|
||||||
/// ) -> LayoutObj[UiResult]:
|
/// ) -> LayoutObj[UiResult]:
|
||||||
/// """Confirm byte sequence data."""
|
/// """Confirm byte sequence data."""
|
||||||
Qstr::MP_QSTR_confirm_blob => obj_fn_kw!(0, new_confirm_blob).as_obj(),
|
Qstr::MP_QSTR_confirm_blob => obj_fn_kw!(0, new_confirm_blob).as_obj(),
|
||||||
|
@ -1806,6 +1806,7 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
|||||||
/// page_counter: bool = False,
|
/// page_counter: bool = False,
|
||||||
/// prompt_screen: bool = False,
|
/// prompt_screen: bool = False,
|
||||||
/// page_limit: int | None = None,
|
/// page_limit: int | None = None,
|
||||||
|
/// cancel: bool = False,
|
||||||
/// ) -> LayoutObj[UiResult]:
|
/// ) -> LayoutObj[UiResult]:
|
||||||
/// """Confirm byte sequence data."""
|
/// """Confirm byte sequence data."""
|
||||||
Qstr::MP_QSTR_confirm_blob => obj_fn_kw!(0, new_confirm_blob).as_obj(),
|
Qstr::MP_QSTR_confirm_blob => obj_fn_kw!(0, new_confirm_blob).as_obj(),
|
||||||
|
@ -71,6 +71,7 @@ def confirm_blob(
|
|||||||
page_counter: bool = False,
|
page_counter: bool = False,
|
||||||
prompt_screen: bool = False,
|
prompt_screen: bool = False,
|
||||||
page_limit: int | None = None,
|
page_limit: int | None = None,
|
||||||
|
cancel: bool = False,
|
||||||
) -> LayoutObj[UiResult]:
|
) -> LayoutObj[UiResult]:
|
||||||
"""Confirm byte sequence data."""
|
"""Confirm byte sequence data."""
|
||||||
|
|
||||||
@ -644,6 +645,7 @@ def confirm_blob(
|
|||||||
page_counter: bool = False,
|
page_counter: bool = False,
|
||||||
prompt_screen: bool = False,
|
prompt_screen: bool = False,
|
||||||
page_limit: int | None = None,
|
page_limit: int | None = None,
|
||||||
|
cancel: bool = False,
|
||||||
) -> LayoutObj[UiResult]:
|
) -> LayoutObj[UiResult]:
|
||||||
"""Confirm byte sequence data."""
|
"""Confirm byte sequence data."""
|
||||||
|
|
||||||
@ -1216,6 +1218,7 @@ def confirm_blob(
|
|||||||
page_counter: bool = False,
|
page_counter: bool = False,
|
||||||
prompt_screen: bool = False,
|
prompt_screen: bool = False,
|
||||||
page_limit: int | None = None,
|
page_limit: int | None = None,
|
||||||
|
cancel: bool = False,
|
||||||
) -> LayoutObj[UiResult]:
|
) -> LayoutObj[UiResult]:
|
||||||
"""Confirm byte sequence data."""
|
"""Confirm byte sequence data."""
|
||||||
|
|
||||||
|
@ -480,6 +480,7 @@ def confirm_blob(
|
|||||||
info_layout = trezorui2.confirm_blob(
|
info_layout = trezorui2.confirm_blob(
|
||||||
title=title,
|
title=title,
|
||||||
data=data,
|
data=data,
|
||||||
|
subtitle=description,
|
||||||
description=None,
|
description=None,
|
||||||
verb=None,
|
verb=None,
|
||||||
verb_cancel=verb_cancel,
|
verb_cancel=verb_cancel,
|
||||||
@ -488,6 +489,7 @@ def confirm_blob(
|
|||||||
chunkify=chunkify,
|
chunkify=chunkify,
|
||||||
page_counter=True,
|
page_counter=True,
|
||||||
prompt_screen=False,
|
prompt_screen=False,
|
||||||
|
cancel=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
return with_info(
|
return with_info(
|
||||||
|
Loading…
Reference in New Issue
Block a user