mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-04 21:48:17 +00:00
Compare commits
17 Commits
6c84fdf56f
...
f602e2e968
Author | SHA1 | Date | |
---|---|---|---|
|
f602e2e968 | ||
|
6a25ea7675 | ||
|
ebf7c38ffc | ||
|
83afdc4e32 | ||
|
c3ac40889f | ||
|
da71639ce3 | ||
|
5c2bacd39a | ||
|
acee4b605e | ||
|
0dcc125c4d | ||
|
61448aad34 | ||
|
b1850b904a | ||
|
f9c897d2df | ||
|
e7c5bc2632 | ||
|
29cf6d3557 | ||
|
ff7f6ea446 | ||
|
2b559fc22f | ||
|
c08e495c9b |
@ -38,8 +38,6 @@ static void _librust_qstrs(void) {
|
||||
MP_QSTR___name__;
|
||||
MP_QSTR_account;
|
||||
MP_QSTR_account_items;
|
||||
MP_QSTR_account_items_title;
|
||||
MP_QSTR_account_label;
|
||||
MP_QSTR_account_path;
|
||||
MP_QSTR_accounts;
|
||||
MP_QSTR_action;
|
||||
@ -69,12 +67,11 @@ static void _librust_qstrs(void) {
|
||||
MP_QSTR_address_qr;
|
||||
MP_QSTR_address_title;
|
||||
MP_QSTR_allow_cancel;
|
||||
MP_QSTR_altcoin_tx_summary;
|
||||
MP_QSTR_amount;
|
||||
MP_QSTR_amount_change;
|
||||
MP_QSTR_amount_label;
|
||||
MP_QSTR_amount_new;
|
||||
MP_QSTR_amount_title;
|
||||
MP_QSTR_amount_value;
|
||||
MP_QSTR_app_name;
|
||||
MP_QSTR_area_bytesize;
|
||||
MP_QSTR_attach_timer_fn;
|
||||
@ -175,8 +172,6 @@ static void _librust_qstrs(void) {
|
||||
MP_QSTR_buttons__view_all_data;
|
||||
MP_QSTR_can_go_back;
|
||||
MP_QSTR_cancel;
|
||||
MP_QSTR_cancel_arrow;
|
||||
MP_QSTR_cancel_cross;
|
||||
MP_QSTR_cancel_text;
|
||||
MP_QSTR_case_sensitive;
|
||||
MP_QSTR_check_homescreen_format;
|
||||
@ -209,7 +204,7 @@ static void _librust_qstrs(void) {
|
||||
MP_QSTR_confirm_properties;
|
||||
MP_QSTR_confirm_recovery;
|
||||
MP_QSTR_confirm_reset_device;
|
||||
MP_QSTR_confirm_total;
|
||||
MP_QSTR_confirm_summary;
|
||||
MP_QSTR_confirm_total__fee_rate;
|
||||
MP_QSTR_confirm_total__fee_rate_colon;
|
||||
MP_QSTR_confirm_total__sending_from_account;
|
||||
@ -242,12 +237,12 @@ static void _librust_qstrs(void) {
|
||||
MP_QSTR_experimental_mode__only_for_dev;
|
||||
MP_QSTR_experimental_mode__title;
|
||||
MP_QSTR_extra;
|
||||
MP_QSTR_fee_amount;
|
||||
MP_QSTR_extra_items;
|
||||
MP_QSTR_extra_title;
|
||||
MP_QSTR_fee;
|
||||
MP_QSTR_fee_items;
|
||||
MP_QSTR_fee_label;
|
||||
MP_QSTR_fee_rate_amount;
|
||||
MP_QSTR_fee_title;
|
||||
MP_QSTR_fee_value;
|
||||
MP_QSTR_fingerprint;
|
||||
MP_QSTR_firmware_update__title;
|
||||
MP_QSTR_firmware_update__title_fingerprint;
|
||||
@ -255,7 +250,6 @@ static void _librust_qstrs(void) {
|
||||
MP_QSTR_flow_confirm_output;
|
||||
MP_QSTR_flow_confirm_reset;
|
||||
MP_QSTR_flow_confirm_set_new_pin;
|
||||
MP_QSTR_flow_confirm_summary;
|
||||
MP_QSTR_flow_continue_recovery;
|
||||
MP_QSTR_flow_get_address;
|
||||
MP_QSTR_flow_prompt_backup;
|
||||
@ -317,7 +311,6 @@ static void _librust_qstrs(void) {
|
||||
MP_QSTR_instructions__view_all_data;
|
||||
MP_QSTR_is_type_of;
|
||||
MP_QSTR_items;
|
||||
MP_QSTR_items_title;
|
||||
MP_QSTR_joint__title;
|
||||
MP_QSTR_joint__to_the_total_amount;
|
||||
MP_QSTR_joint__you_are_contributing;
|
||||
@ -697,7 +690,6 @@ static void _librust_qstrs(void) {
|
||||
MP_QSTR_title;
|
||||
MP_QSTR_total_amount;
|
||||
MP_QSTR_total_fee_new;
|
||||
MP_QSTR_total_label;
|
||||
MP_QSTR_total_len;
|
||||
MP_QSTR_touch_event;
|
||||
MP_QSTR_trace;
|
||||
|
@ -25,7 +25,7 @@ pub enum VerticalMenuChoiceMsg {
|
||||
|
||||
/// Number of buttons.
|
||||
/// Presently, VerticalMenu holds only fixed number of buttons.
|
||||
const MAX_ITEMS: usize = 3;
|
||||
const MENU_MAX_ITEMS: usize = 3;
|
||||
|
||||
/// Fixed height of each menu button.
|
||||
const MENU_BUTTON_HEIGHT: i16 = 64;
|
||||
@ -33,7 +33,7 @@ const MENU_BUTTON_HEIGHT: i16 = 64;
|
||||
/// Fixed height of a separator.
|
||||
const MENU_SEP_HEIGHT: i16 = 2;
|
||||
|
||||
type VerticalMenuButtons = Vec<Button, MAX_ITEMS>;
|
||||
type VerticalMenuButtons = Vec<Button, MENU_MAX_ITEMS>;
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
struct AttachAnimation {
|
||||
@ -180,7 +180,7 @@ impl VerticalMenu {
|
||||
fn new(buttons: VerticalMenuButtons) -> Self {
|
||||
Self {
|
||||
buttons,
|
||||
n_items: MAX_ITEMS,
|
||||
n_items: MENU_MAX_ITEMS,
|
||||
attach_animation: AttachAnimation::default(),
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,15 @@
|
||||
use heapless::Vec;
|
||||
|
||||
use crate::{
|
||||
error,
|
||||
error::{self},
|
||||
maybe_trace::MaybeTrace,
|
||||
strutil::TString,
|
||||
translations::TR,
|
||||
ui::{
|
||||
button_request::ButtonRequest,
|
||||
component::{swipe_detect::SwipeSettings, ButtonRequestExt, ComponentExt},
|
||||
component::{swipe_detect::SwipeSettings, Component, ComponentExt},
|
||||
flow::{
|
||||
base::{Decision, DecisionBuilder as _},
|
||||
FlowController, FlowMsg, SwipeFlow,
|
||||
FlowController, FlowMsg, Swipable, SwipeFlow,
|
||||
},
|
||||
geometry::Direction,
|
||||
},
|
||||
@ -27,7 +27,7 @@ use super::{
|
||||
};
|
||||
|
||||
const MENU_ITEM_CANCEL: usize = 0;
|
||||
const MENU_ITEM_FEE_INFO: usize = 1;
|
||||
const MENU_ITEM_EXTRA_INFO: usize = 1;
|
||||
const MENU_ITEM_ACCOUNT_INFO: usize = 2;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
@ -35,7 +35,7 @@ pub enum ConfirmSummary {
|
||||
Summary,
|
||||
Hold,
|
||||
Menu,
|
||||
FeeInfo,
|
||||
ExtraInfo,
|
||||
AccountInfo,
|
||||
CancelTap,
|
||||
}
|
||||
@ -52,7 +52,7 @@ impl FlowController for ConfirmSummary {
|
||||
(Self::Summary, Direction::Up) => Self::Hold.swipe(direction),
|
||||
(Self::Hold, Direction::Down) => Self::Summary.swipe(direction),
|
||||
(Self::Menu, Direction::Right) => Self::Summary.swipe(direction),
|
||||
(Self::AccountInfo | Self::FeeInfo | Self::CancelTap, Direction::Right) => {
|
||||
(Self::ExtraInfo | Self::AccountInfo | Self::CancelTap, Direction::Right) => {
|
||||
Self::Menu.swipe(direction)
|
||||
}
|
||||
_ => self.do_nothing(),
|
||||
@ -64,7 +64,7 @@ impl FlowController for ConfirmSummary {
|
||||
(_, FlowMsg::Info) => Self::Menu.goto(),
|
||||
(Self::Hold, FlowMsg::Confirmed) => self.return_msg(FlowMsg::Confirmed),
|
||||
(Self::Menu, FlowMsg::Choice(MENU_ITEM_CANCEL)) => Self::CancelTap.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Choice(MENU_ITEM_FEE_INFO)) => Self::FeeInfo.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Choice(MENU_ITEM_EXTRA_INFO)) => Self::ExtraInfo.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Choice(MENU_ITEM_ACCOUNT_INFO)) => Self::AccountInfo.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Cancelled) => Self::Summary.swipe_right(),
|
||||
(Self::CancelTap, FlowMsg::Confirmed) => self.return_msg(FlowMsg::Cancelled),
|
||||
@ -74,18 +74,20 @@ impl FlowController for ConfirmSummary {
|
||||
}
|
||||
}
|
||||
|
||||
fn dummy_page() -> impl Component<Msg = FlowMsg> + Swipable + MaybeTrace {
|
||||
Frame::left_aligned(TString::empty(), VerticalMenu::empty()).map(|_| Some(FlowMsg::Cancelled))
|
||||
}
|
||||
|
||||
pub fn new_confirm_summary(
|
||||
summary_params: ShowInfoParams,
|
||||
account_params: ShowInfoParams,
|
||||
fee_params: ShowInfoParams,
|
||||
br_name: TString<'static>,
|
||||
br_code: u16,
|
||||
cancel_text: Option<TString<'static>>,
|
||||
account_params: Option<ShowInfoParams>,
|
||||
extra_params: Option<ShowInfoParams>,
|
||||
extra_title: Option<TString<'static>>,
|
||||
verb_cancel: Option<TString<'static>>,
|
||||
) -> Result<SwipeFlow, error::Error> {
|
||||
// Summary
|
||||
let content_summary = summary_params
|
||||
.into_layout()?
|
||||
.one_button_request(ButtonRequest::from_num(br_code, br_name))
|
||||
// Summary(1) + Hold(1)
|
||||
.with_pages(|summary_pages| summary_pages + 1);
|
||||
|
||||
@ -104,25 +106,26 @@ pub fn new_confirm_summary(
|
||||
_ => None,
|
||||
});
|
||||
|
||||
// FeeInfo
|
||||
let has_fee_info = !fee_params.is_empty();
|
||||
let content_fee = fee_params.into_layout()?;
|
||||
|
||||
// ExtraInfo
|
||||
let content_extra = extra_params
|
||||
.map(|params| params.into_layout())
|
||||
.transpose()?;
|
||||
// AccountInfo
|
||||
let has_account_info = !account_params.is_empty();
|
||||
let content_account = account_params.into_layout()?;
|
||||
let content_account = account_params
|
||||
.map(|params| params.into_layout())
|
||||
.transpose()?;
|
||||
|
||||
// Menu
|
||||
// Menu with provided info and cancel
|
||||
let mut menu = VerticalMenu::empty();
|
||||
let mut menu_items = Vec::<usize, 3>::new();
|
||||
if has_fee_info {
|
||||
if content_extra.is_some() {
|
||||
menu = menu.item(
|
||||
theme::ICON_CHEVRON_RIGHT,
|
||||
TR::confirm_total__title_fee.into(),
|
||||
extra_title.unwrap_or(TR::buttons__more_info.into()),
|
||||
);
|
||||
unwrap!(menu_items.push(MENU_ITEM_FEE_INFO));
|
||||
unwrap!(menu_items.push(MENU_ITEM_EXTRA_INFO));
|
||||
}
|
||||
if has_account_info {
|
||||
if content_account.is_some() {
|
||||
menu = menu.item(
|
||||
theme::ICON_CHEVRON_RIGHT,
|
||||
TR::address_details__account_info.into(),
|
||||
@ -131,7 +134,7 @@ pub fn new_confirm_summary(
|
||||
}
|
||||
menu = menu.danger(
|
||||
theme::ICON_CANCEL,
|
||||
cancel_text.unwrap_or(TR::send__cancel_sign.into()),
|
||||
verb_cancel.unwrap_or(TR::send__cancel_sign.into()),
|
||||
);
|
||||
unwrap!(menu_items.push(MENU_ITEM_CANCEL));
|
||||
let content_menu = Frame::left_aligned(TString::empty(), menu)
|
||||
@ -159,13 +162,21 @@ pub fn new_confirm_summary(
|
||||
_ => None,
|
||||
});
|
||||
|
||||
let res = SwipeFlow::new(&ConfirmSummary::Summary)?
|
||||
let mut res = SwipeFlow::new(&ConfirmSummary::Summary)?
|
||||
.with_page(&ConfirmSummary::Summary, content_summary)?
|
||||
.with_page(&ConfirmSummary::Hold, content_hold)?
|
||||
.with_page(&ConfirmSummary::Menu, content_menu)?
|
||||
.with_page(&ConfirmSummary::FeeInfo, content_fee)?
|
||||
.with_page(&ConfirmSummary::AccountInfo, content_account)?
|
||||
.with_page(&ConfirmSummary::CancelTap, content_cancel_tap)?;
|
||||
.with_page(&ConfirmSummary::Menu, content_menu)?;
|
||||
if let Some(content_extra) = content_extra {
|
||||
res = res.with_page(&ConfirmSummary::ExtraInfo, content_extra)?
|
||||
} else {
|
||||
res = res.with_page(&ConfirmSummary::ExtraInfo, dummy_page())?
|
||||
};
|
||||
if let Some(content_account) = content_account {
|
||||
res = res.with_page(&ConfirmSummary::AccountInfo, content_account)?
|
||||
} else {
|
||||
res = res.with_page(&ConfirmSummary::AccountInfo, dummy_page())?
|
||||
};
|
||||
res = res.with_page(&ConfirmSummary::CancelTap, content_cancel_tap)?;
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
@ -624,50 +624,68 @@ extern "C" fn new_confirm_output(n_args: usize, args: *const Obj, kwargs: *mut M
|
||||
|
||||
extern "C" fn new_confirm_summary(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||
let items: Obj = kwargs.get(Qstr::MP_QSTR_items)?;
|
||||
let account_items: Obj = kwargs.get(Qstr::MP_QSTR_account_items)?;
|
||||
let account_items_title: Option<TString> = kwargs
|
||||
.get(Qstr::MP_QSTR_account_items_title)
|
||||
.unwrap_or(Obj::const_none())
|
||||
let amount: TString = kwargs.get(Qstr::MP_QSTR_amount)?.try_into()?;
|
||||
let amount_label: TString = kwargs.get(Qstr::MP_QSTR_amount_label)?.try_into()?;
|
||||
let fee: TString = kwargs.get(Qstr::MP_QSTR_fee)?.try_into()?;
|
||||
let fee_label: TString = kwargs.get(Qstr::MP_QSTR_fee_label)?.try_into()?;
|
||||
let title: Option<TString> = kwargs
|
||||
.get(Qstr::MP_QSTR_title)
|
||||
.unwrap_or_else(|_| Obj::const_none())
|
||||
.try_into_option()?;
|
||||
let account_items: Option<Obj> = kwargs
|
||||
.get(Qstr::MP_QSTR_account_items)
|
||||
.unwrap_or_else(|_| Obj::const_none())
|
||||
.try_into_option()?;
|
||||
let extra_items: Option<Obj> = kwargs
|
||||
.get(Qstr::MP_QSTR_extra_items)
|
||||
.unwrap_or_else(|_| Obj::const_none())
|
||||
.try_into_option()?;
|
||||
let extra_title: Option<TString> = kwargs
|
||||
.get(Qstr::MP_QSTR_extra_title)
|
||||
.unwrap_or_else(|_| Obj::const_none())
|
||||
.try_into_option()?;
|
||||
let verb_cancel: Option<TString> = kwargs
|
||||
.get(Qstr::MP_QSTR_verb_cancel)
|
||||
.unwrap_or_else(|_| Obj::const_none())
|
||||
.try_into_option()?;
|
||||
let fee_items: Obj = kwargs.get(Qstr::MP_QSTR_fee_items)?;
|
||||
let br_name: TString = kwargs.get(Qstr::MP_QSTR_br_name)?.try_into()?;
|
||||
let br_code: u16 = kwargs.get(Qstr::MP_QSTR_br_code)?.try_into()?;
|
||||
let cancel_text: Option<TString> =
|
||||
kwargs.get(Qstr::MP_QSTR_cancel_text)?.try_into_option()?;
|
||||
|
||||
let mut summary_params = ShowInfoParams::new(title)
|
||||
let mut summary_params = ShowInfoParams::new(title.unwrap_or(TString::empty()))
|
||||
.with_menu_button()
|
||||
.with_footer(TR::instructions__swipe_up.into(), None)
|
||||
.with_swipe_up();
|
||||
for pair in IterBuf::new().try_iterate(items)? {
|
||||
let [label, value]: [TString; 2] = util::iter_into_array(pair)?;
|
||||
summary_params = unwrap!(summary_params.add(label, value));
|
||||
}
|
||||
summary_params = unwrap!(summary_params.add(amount_label, amount));
|
||||
summary_params = unwrap!(summary_params.add(fee_label, fee));
|
||||
|
||||
// collect available info
|
||||
let account_params = if let Some(items) = account_items {
|
||||
let mut account_params =
|
||||
ShowInfoParams::new(account_items_title.unwrap_or(TR::send__send_from.into()))
|
||||
.with_cancel_button();
|
||||
for pair in IterBuf::new().try_iterate(account_items)? {
|
||||
ShowInfoParams::new(TR::send__send_from.into()).with_cancel_button();
|
||||
for pair in IterBuf::new().try_iterate(items)? {
|
||||
let [label, value]: [TString; 2] = util::iter_into_array(pair)?;
|
||||
account_params = unwrap!(account_params.add(label, value));
|
||||
}
|
||||
|
||||
let mut fee_params =
|
||||
ShowInfoParams::new(TR::confirm_total__title_fee.into()).with_cancel_button();
|
||||
for pair in IterBuf::new().try_iterate(fee_items)? {
|
||||
Some(account_params)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let extra_params = if let Some(items) = extra_items {
|
||||
let extra_title = extra_title.unwrap_or(TR::buttons__more_info.into());
|
||||
let mut extra_params = ShowInfoParams::new(extra_title).with_cancel_button();
|
||||
for pair in IterBuf::new().try_iterate(items)? {
|
||||
let [label, value]: [TString; 2] = util::iter_into_array(pair)?;
|
||||
fee_params = unwrap!(fee_params.add(label, value));
|
||||
extra_params = unwrap!(extra_params.add(label, value));
|
||||
}
|
||||
Some(extra_params)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let flow = flow::new_confirm_summary(
|
||||
summary_params,
|
||||
account_params,
|
||||
fee_params,
|
||||
br_name,
|
||||
br_code,
|
||||
cancel_text,
|
||||
extra_params,
|
||||
extra_title,
|
||||
verb_cancel,
|
||||
)?;
|
||||
Ok(LayoutObj::new_root(flow)?.into())
|
||||
};
|
||||
@ -761,34 +779,6 @@ extern "C" fn new_confirm_value(n_args: usize, args: *const Obj, kwargs: *mut Ma
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
|
||||
extern "C" fn new_confirm_total(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||
let items: Obj = kwargs.get(Qstr::MP_QSTR_items)?;
|
||||
|
||||
let mut paragraphs = ParagraphVecShort::new();
|
||||
|
||||
for pair in IterBuf::new().try_iterate(items)? {
|
||||
let [label, value]: [TString; 2] = util::iter_into_array(pair)?;
|
||||
paragraphs.add(Paragraph::new(&theme::TEXT_NORMAL, label).no_break());
|
||||
paragraphs.add(Paragraph::new(&theme::TEXT_MONO, value));
|
||||
}
|
||||
|
||||
new_confirm_action_simple(
|
||||
paragraphs.into_paragraphs(),
|
||||
ConfirmActionExtra::Menu(ConfirmActionMenuStrings::new()),
|
||||
ConfirmActionStrings::new(title, None, None, Some(title)),
|
||||
true,
|
||||
None,
|
||||
0,
|
||||
false,
|
||||
)
|
||||
.and_then(LayoutObj::new_root)
|
||||
.map(Into::into)
|
||||
};
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
|
||||
extern "C" fn new_confirm_modify_output(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||
let sign: i32 = kwargs.get(Qstr::MP_QSTR_sign)?.try_into()?;
|
||||
@ -1649,16 +1639,6 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
||||
/// """Confirm value. Merge of confirm_total and confirm_output."""
|
||||
Qstr::MP_QSTR_confirm_value => obj_fn_kw!(0, new_confirm_value).as_obj(),
|
||||
|
||||
/// def confirm_total(
|
||||
/// *,
|
||||
/// title: str,
|
||||
/// items: Iterable[tuple[str, str]],
|
||||
/// info_button: bool = False,
|
||||
/// cancel_arrow: bool = False,
|
||||
/// ) -> LayoutObj[UiResult]:
|
||||
/// """Transaction summary. Always hold to confirm."""
|
||||
Qstr::MP_QSTR_confirm_total => obj_fn_kw!(0, new_confirm_total).as_obj(),
|
||||
|
||||
/// def confirm_modify_output(
|
||||
/// *,
|
||||
/// sign: int,
|
||||
@ -2004,19 +1984,20 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
||||
/// """Confirm the recipient, (optionally) confirm the amount and (optionally) confirm the summary and present a Hold to Sign page."""
|
||||
Qstr::MP_QSTR_flow_confirm_output => obj_fn_kw!(0, new_confirm_output).as_obj(),
|
||||
|
||||
/// def flow_confirm_summary(
|
||||
/// def confirm_summary(
|
||||
/// *,
|
||||
/// title: str,
|
||||
/// items: Iterable[tuple[str, str]],
|
||||
/// account_items: Iterable[tuple[str, str]],
|
||||
/// account_items_title: str | None,
|
||||
/// fee_items: Iterable[tuple[str, str]],
|
||||
/// br_code: ButtonRequestType,
|
||||
/// br_name: str,
|
||||
/// cancel_text: str | None = None,
|
||||
/// amount: str,
|
||||
/// amount_label: str,
|
||||
/// fee: str,
|
||||
/// fee_label: str,
|
||||
/// title: str | None = None,
|
||||
/// account_items: Iterable[tuple[str, str]] | None = None,
|
||||
/// extra_items: Iterable[tuple[str, str]] | None = None,
|
||||
/// extra_title: str | None = None,
|
||||
/// verb_cancel: str | None = None,
|
||||
/// ) -> LayoutObj[UiResult]:
|
||||
/// """Total summary and hold to confirm."""
|
||||
Qstr::MP_QSTR_flow_confirm_summary => obj_fn_kw!(0, new_confirm_summary).as_obj(),
|
||||
/// """Confirm summary of a transaction."""
|
||||
Qstr::MP_QSTR_confirm_summary => obj_fn_kw!(0, new_confirm_summary).as_obj(),
|
||||
|
||||
/// class BacklightLevels:
|
||||
/// """Backlight levels. Values dynamically update based on user settings."""
|
||||
|
@ -915,6 +915,15 @@ impl ButtonActions {
|
||||
)
|
||||
}
|
||||
|
||||
/// Cancelling with left and confirming with middle
|
||||
pub fn cancel_confirm_none() -> Self {
|
||||
Self::new(
|
||||
Some(ButtonAction::Cancel),
|
||||
Some(ButtonAction::Confirm),
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
/// Cancelling with left, confirming with middle and info with right
|
||||
pub fn cancel_confirm_info() -> Self {
|
||||
Self::new(
|
||||
|
@ -45,6 +45,7 @@ use crate::{
|
||||
},
|
||||
ComponentExt, FormattedText, Label, LineBreaking, Never, Timeout,
|
||||
},
|
||||
display::Font,
|
||||
geometry,
|
||||
layout::{
|
||||
base::LAYOUT_STATE,
|
||||
@ -638,131 +639,109 @@ extern "C" fn new_confirm_output_amount(n_args: usize, args: *const Obj, kwargs:
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
|
||||
extern "C" fn new_confirm_total(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
extern "C" fn new_confirm_summary(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = |_args: &[Obj], kwargs: &Map| {
|
||||
let total_amount: TString = kwargs.get(Qstr::MP_QSTR_total_amount)?.try_into()?;
|
||||
let fee_amount: TString = kwargs.get(Qstr::MP_QSTR_fee_amount)?.try_into()?;
|
||||
let fee_rate_amount: Option<TString> = kwargs
|
||||
.get(Qstr::MP_QSTR_fee_rate_amount)?
|
||||
.try_into_option()?;
|
||||
let account_label: Option<TString> =
|
||||
kwargs.get(Qstr::MP_QSTR_account_label)?.try_into_option()?;
|
||||
let total_label: TString = kwargs.get(Qstr::MP_QSTR_total_label)?.try_into()?;
|
||||
let amount: TString = kwargs.get(Qstr::MP_QSTR_amount)?.try_into()?;
|
||||
let amount_label: TString = kwargs.get(Qstr::MP_QSTR_amount_label)?.try_into()?;
|
||||
let fee: TString = kwargs.get(Qstr::MP_QSTR_fee)?.try_into()?;
|
||||
let fee_label: TString = kwargs.get(Qstr::MP_QSTR_fee_label)?.try_into()?;
|
||||
let _title: Option<TString> = kwargs
|
||||
.get(Qstr::MP_QSTR_title)
|
||||
.unwrap_or_else(|_| Obj::const_none())
|
||||
.try_into_option()?;
|
||||
let account_items: Option<Obj> = kwargs
|
||||
.get(Qstr::MP_QSTR_account_items)
|
||||
.unwrap_or_else(|_| Obj::const_none())
|
||||
.try_into_option()?;
|
||||
let extra_items: Option<Obj> = kwargs
|
||||
.get(Qstr::MP_QSTR_extra_items)
|
||||
.unwrap_or_else(|_| Obj::const_none())
|
||||
.try_into_option()?;
|
||||
let extra_title: Option<TString> = kwargs
|
||||
.get(Qstr::MP_QSTR_extra_title)
|
||||
.unwrap_or_else(|_| Obj::const_none())
|
||||
.try_into_option()?;
|
||||
let verb_cancel: Option<TString<'static>> = kwargs
|
||||
.get(Qstr::MP_QSTR_verb_cancel)
|
||||
.unwrap_or_else(|_| Obj::const_none())
|
||||
.try_into_option()?;
|
||||
|
||||
// collect available info pages
|
||||
let mut info_pages: Vec<(TString, Obj), 2> = Vec::new();
|
||||
if let Some(info) = extra_items {
|
||||
// put extra items first as it's typically used for fee info
|
||||
let extra_title = extra_title.unwrap_or(TR::words__title_information.into());
|
||||
unwrap!(info_pages.push((extra_title, info)));
|
||||
}
|
||||
if let Some(info) = account_items {
|
||||
unwrap!(info_pages.push((TR::confirm_total__title_sending_from.into(), info)));
|
||||
}
|
||||
|
||||
// button layouts and actions
|
||||
let verb_cancel: TString = verb_cancel.unwrap_or(TString::empty());
|
||||
let btns_summary_page = move |has_pages_after: bool| -> (ButtonLayout, ButtonActions) {
|
||||
// if there are no info pages, the right button is not needed
|
||||
// if verb_cancel is "^", the left button is an arrow pointing up
|
||||
let left_btn = Some(ButtonDetails::from_text_possible_icon(verb_cancel));
|
||||
let right_btn = has_pages_after.then(|| {
|
||||
ButtonDetails::text("i".into())
|
||||
.with_fixed_width(theme::BUTTON_ICON_WIDTH)
|
||||
.with_font(Font::NORMAL)
|
||||
});
|
||||
let middle_btn = Some(ButtonDetails::armed_text(TR::buttons__confirm.into()));
|
||||
|
||||
(
|
||||
ButtonLayout::new(left_btn, middle_btn, right_btn),
|
||||
if has_pages_after {
|
||||
ButtonActions::cancel_confirm_next()
|
||||
} else {
|
||||
ButtonActions::cancel_confirm_none()
|
||||
},
|
||||
)
|
||||
};
|
||||
let btns_info_page = |is_last: bool| -> (ButtonLayout, ButtonActions) {
|
||||
// on the last info page, the right button is not needed
|
||||
if is_last {
|
||||
(
|
||||
ButtonLayout::arrow_none_none(),
|
||||
ButtonActions::prev_none_none(),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
ButtonLayout::arrow_none_arrow(),
|
||||
ButtonActions::prev_none_next(),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let total_pages = 1 + info_pages.len();
|
||||
let get_page = move |page_index| {
|
||||
match page_index {
|
||||
0 => {
|
||||
// Total amount + fee
|
||||
let btn_layout = ButtonLayout::cancel_armed_info(TR::buttons__confirm.into());
|
||||
let btn_actions = ButtonActions::cancel_confirm_next();
|
||||
let (btn_layout, btn_actions) = btns_summary_page(!info_pages.is_empty());
|
||||
|
||||
let ops = OpTextLayout::new(theme::TEXT_MONO)
|
||||
.text_bold(total_label)
|
||||
.text_bold(amount_label)
|
||||
.newline()
|
||||
.text_mono(total_amount)
|
||||
.text_mono(amount)
|
||||
.newline()
|
||||
.newline()
|
||||
.text_bold(fee_label)
|
||||
.newline()
|
||||
.text_mono(fee_amount);
|
||||
.text_mono(fee);
|
||||
|
||||
let formatted = FormattedText::new(ops);
|
||||
Page::new(btn_layout, btn_actions, formatted)
|
||||
}
|
||||
1 => {
|
||||
// Fee rate info
|
||||
let btn_layout = ButtonLayout::arrow_none_arrow();
|
||||
let btn_actions = ButtonActions::prev_none_next();
|
||||
|
||||
let fee_rate_amount = fee_rate_amount.unwrap_or("".into());
|
||||
|
||||
let ops = OpTextLayout::new(theme::TEXT_MONO)
|
||||
.text_bold_upper(TR::confirm_total__title_fee)
|
||||
.newline()
|
||||
.newline()
|
||||
.newline_half()
|
||||
.text_bold(TR::confirm_total__fee_rate_colon)
|
||||
.newline()
|
||||
.text_mono(fee_rate_amount);
|
||||
|
||||
let formatted = FormattedText::new(ops);
|
||||
Page::new(btn_layout, btn_actions, formatted)
|
||||
}
|
||||
2 => {
|
||||
// Wallet and account info
|
||||
let btn_layout = ButtonLayout::arrow_none_none();
|
||||
let btn_actions = ButtonActions::prev_none_none();
|
||||
|
||||
let account_label = account_label.unwrap_or("".into());
|
||||
|
||||
// TODO: include wallet info when available
|
||||
|
||||
let ops = OpTextLayout::new(theme::TEXT_MONO)
|
||||
.text_bold_upper(TR::confirm_total__title_sending_from)
|
||||
.newline()
|
||||
.newline()
|
||||
.newline_half()
|
||||
.text_bold(TR::words__account_colon)
|
||||
.newline()
|
||||
.text_mono(account_label);
|
||||
|
||||
let formatted = FormattedText::new(ops);
|
||||
Page::new(btn_layout, btn_actions, formatted)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
};
|
||||
let pages = FlowPages::new(get_page, 3);
|
||||
|
||||
let obj = LayoutObj::new(Flow::new(pages))?;
|
||||
Ok(obj.into())
|
||||
};
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
|
||||
extern "C" fn new_altcoin_tx_summary(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = |_args: &[Obj], kwargs: &Map| {
|
||||
let amount_title: TString = kwargs.get(Qstr::MP_QSTR_amount_title)?.try_into()?;
|
||||
let amount_value: TString = kwargs.get(Qstr::MP_QSTR_amount_value)?.try_into()?;
|
||||
let fee_title: TString = kwargs.get(Qstr::MP_QSTR_fee_title)?.try_into()?;
|
||||
let fee_value: TString = kwargs.get(Qstr::MP_QSTR_fee_value)?.try_into()?;
|
||||
let items_title: TString = kwargs.get(Qstr::MP_QSTR_items_title)?.try_into()?;
|
||||
let items: Obj = kwargs.get(Qstr::MP_QSTR_items)?;
|
||||
let cancel_cross: bool = kwargs.get_or(Qstr::MP_QSTR_cancel_cross, false)?;
|
||||
|
||||
let get_page = move |page_index| {
|
||||
match page_index {
|
||||
0 => {
|
||||
// Amount + fee
|
||||
let btn_layout = if cancel_cross {
|
||||
ButtonLayout::cancel_armed_info(TR::buttons__confirm.into())
|
||||
} else {
|
||||
ButtonLayout::up_arrow_armed_info(TR::buttons__confirm.into())
|
||||
};
|
||||
let btn_actions = ButtonActions::cancel_confirm_next();
|
||||
|
||||
let ops = OpTextLayout::new(theme::TEXT_MONO)
|
||||
.text_bold(amount_title)
|
||||
.newline()
|
||||
.text_mono(amount_value)
|
||||
.newline()
|
||||
.newline_half()
|
||||
.text_bold(fee_title)
|
||||
.newline()
|
||||
.text_mono(fee_value);
|
||||
|
||||
let formatted = FormattedText::new(ops);
|
||||
Page::new(btn_layout, btn_actions, formatted)
|
||||
}
|
||||
1 => {
|
||||
// Other information
|
||||
let btn_layout = ButtonLayout::arrow_none_none();
|
||||
let btn_actions = ButtonActions::prev_none_none();
|
||||
i => {
|
||||
// Other info pages as provided
|
||||
let (title, info_obj) = &info_pages[i - 1];
|
||||
let is_last = i == total_pages - 1;
|
||||
let (btn_layout, btn_actions) = btns_info_page(is_last);
|
||||
|
||||
let mut ops = OpTextLayout::new(theme::TEXT_MONO);
|
||||
|
||||
for item in unwrap!(IterBuf::new().try_iterate(items)) {
|
||||
for item in unwrap!(IterBuf::new().try_iterate(*info_obj)) {
|
||||
let [key, value]: [Obj; 2] = unwrap!(util::iter_into_array(item));
|
||||
if !ops.is_empty() {
|
||||
// Each key-value pair is on its own page
|
||||
@ -776,13 +755,12 @@ extern "C" fn new_altcoin_tx_summary(n_args: usize, args: *const Obj, kwargs: *m
|
||||
|
||||
let formatted = FormattedText::new(ops).vertically_centered();
|
||||
Page::new(btn_layout, btn_actions, formatted)
|
||||
.with_title(items_title)
|
||||
.with_slim_arrows()
|
||||
.with_title(*title)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
};
|
||||
let pages = FlowPages::new(get_page, 2);
|
||||
let pages = FlowPages::new(get_page, total_pages);
|
||||
|
||||
let obj = LayoutObj::new(Flow::new(pages).with_scrollbar(false))?;
|
||||
Ok(obj.into())
|
||||
@ -1810,30 +1788,20 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
||||
/// """Confirm output amount."""
|
||||
Qstr::MP_QSTR_confirm_output_amount => obj_fn_kw!(0, new_confirm_output_amount).as_obj(),
|
||||
|
||||
/// def confirm_total(
|
||||
/// def confirm_summary(
|
||||
/// *,
|
||||
/// total_amount: str,
|
||||
/// fee_amount: str,
|
||||
/// fee_rate_amount: str | None,
|
||||
/// account_label: str | None,
|
||||
/// total_label: str,
|
||||
/// amount: str,
|
||||
/// amount_label: str,
|
||||
/// fee: str,
|
||||
/// fee_label: str,
|
||||
/// title: str | None = None,
|
||||
/// account_items: Iterable[tuple[str, str]] | None = None,
|
||||
/// extra_items: Iterable[tuple[str, str]] | None = None,
|
||||
/// extra_title: str | None = None,
|
||||
/// verb_cancel: str | None = None,
|
||||
/// ) -> LayoutObj[UiResult]:
|
||||
/// """Confirm summary of a transaction."""
|
||||
Qstr::MP_QSTR_confirm_total => obj_fn_kw!(0, new_confirm_total).as_obj(),
|
||||
|
||||
/// def altcoin_tx_summary(
|
||||
/// *,
|
||||
/// amount_title: str,
|
||||
/// amount_value: str,
|
||||
/// fee_title: str,
|
||||
/// fee_value: str,
|
||||
/// items_title: str,
|
||||
/// items: Iterable[Tuple[str, str]],
|
||||
/// cancel_cross: bool = False,
|
||||
/// ) -> LayoutObj[UiResult]:
|
||||
/// """Confirm details about altcoin transaction."""
|
||||
Qstr::MP_QSTR_altcoin_tx_summary => obj_fn_kw!(0, new_altcoin_tx_summary).as_obj(),
|
||||
Qstr::MP_QSTR_confirm_summary => obj_fn_kw!(0, new_confirm_summary).as_obj(),
|
||||
|
||||
/// def tutorial() -> LayoutObj[UiResult]:
|
||||
/// """Show user how to interact with the device."""
|
||||
|
@ -93,20 +93,12 @@ where
|
||||
left: Option<TString<'static>>,
|
||||
right: Option<TString<'static>>,
|
||||
) -> Self {
|
||||
let cancel = match left {
|
||||
Some(verb) => verb.map(|s| match s {
|
||||
"^" => Button::with_icon(theme::ICON_UP),
|
||||
"<" => Button::with_icon(theme::ICON_BACK),
|
||||
_ => Button::with_text(verb),
|
||||
}),
|
||||
_ => Button::with_icon(theme::ICON_CANCEL),
|
||||
};
|
||||
let confirm = match right {
|
||||
Some(verb) => Button::with_text(verb).styled(theme::button_confirm()),
|
||||
_ => Button::with_icon(theme::ICON_CONFIRM).styled(theme::button_confirm()),
|
||||
};
|
||||
self.button_cancel = Some(cancel);
|
||||
self.button_confirm = confirm;
|
||||
self = self.with_cancel_button(left);
|
||||
self
|
||||
}
|
||||
|
||||
@ -117,8 +109,16 @@ where
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_cancel_arrow(mut self) -> Self {
|
||||
self.button_cancel = Some(Button::with_icon(theme::ICON_UP));
|
||||
pub fn with_cancel_button(mut self, left: Option<TString<'static>>) -> Self {
|
||||
let cancel = match left {
|
||||
Some(verb) => verb.map(|s| match s {
|
||||
"^" => Button::with_icon(theme::ICON_UP),
|
||||
"<" => Button::with_icon(theme::ICON_BACK),
|
||||
_ => Button::with_text(verb),
|
||||
}),
|
||||
_ => Button::with_icon(theme::ICON_CANCEL),
|
||||
};
|
||||
self.button_cancel = Some(cancel);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -763,28 +763,52 @@ extern "C" fn new_confirm_value(n_args: usize, args: *const Obj, kwargs: *mut Ma
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
|
||||
extern "C" fn new_confirm_total(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
extern "C" fn new_confirm_summary(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||
let items: Obj = kwargs.get(Qstr::MP_QSTR_items)?;
|
||||
let info_button: bool = kwargs.get_or(Qstr::MP_QSTR_info_button, false)?;
|
||||
let cancel_arrow: bool = kwargs.get_or(Qstr::MP_QSTR_cancel_arrow, false)?;
|
||||
let amount: TString = kwargs.get(Qstr::MP_QSTR_amount)?.try_into()?;
|
||||
let amount_label: TString = kwargs.get(Qstr::MP_QSTR_amount_label)?.try_into()?;
|
||||
let fee: TString = kwargs.get(Qstr::MP_QSTR_fee)?.try_into()?;
|
||||
let fee_label: TString = kwargs.get(Qstr::MP_QSTR_fee_label)?.try_into()?;
|
||||
let title: Option<TString> = kwargs
|
||||
.get(Qstr::MP_QSTR_title)
|
||||
.unwrap_or_else(|_| Obj::const_none())
|
||||
.try_into_option()?;
|
||||
let account_items: Option<Obj> = kwargs
|
||||
.get(Qstr::MP_QSTR_account_items)
|
||||
.unwrap_or_else(|_| Obj::const_none())
|
||||
.try_into_option()?;
|
||||
let extra_items: Option<Obj> = kwargs
|
||||
.get(Qstr::MP_QSTR_extra_items)
|
||||
.unwrap_or_else(|_| Obj::const_none())
|
||||
.try_into_option()?;
|
||||
let _extra_title: Option<TString> = kwargs
|
||||
.get(Qstr::MP_QSTR_extra_title)
|
||||
.unwrap_or_else(|_| Obj::const_none())
|
||||
.try_into_option()?;
|
||||
let verb_cancel: Option<TString<'static>> = kwargs
|
||||
.get(Qstr::MP_QSTR_verb_cancel)
|
||||
.unwrap_or_else(|_| Obj::const_none())
|
||||
.try_into_option()?;
|
||||
|
||||
let mut paragraphs = ParagraphVecShort::new();
|
||||
let info_button: bool = account_items.is_some() || extra_items.is_some();
|
||||
let paragraphs = ParagraphVecShort::from_iter([
|
||||
Paragraph::new(&theme::TEXT_NORMAL, amount_label).no_break(),
|
||||
Paragraph::new(&theme::TEXT_MONO, amount),
|
||||
Paragraph::new(&theme::TEXT_NORMAL, fee_label).no_break(),
|
||||
Paragraph::new(&theme::TEXT_MONO, fee),
|
||||
]);
|
||||
|
||||
for pair in IterBuf::new().try_iterate(items)? {
|
||||
let [label, value]: [TString; 2] = util::iter_into_array(pair)?;
|
||||
paragraphs.add(Paragraph::new(&theme::TEXT_NORMAL, label).no_break());
|
||||
paragraphs.add(Paragraph::new(&theme::TEXT_MONO, value));
|
||||
}
|
||||
let mut page = ButtonPage::new(paragraphs.into_paragraphs(), theme::BG).with_hold()?;
|
||||
if cancel_arrow {
|
||||
page = page.with_cancel_arrow()
|
||||
}
|
||||
let mut page = ButtonPage::new(paragraphs.into_paragraphs(), theme::BG)
|
||||
.with_hold()?
|
||||
.with_cancel_button(verb_cancel);
|
||||
if info_button {
|
||||
page = page.with_swipe_left();
|
||||
}
|
||||
let mut frame = Frame::left_aligned(theme::label_title(), title, page);
|
||||
let mut frame = Frame::left_aligned(
|
||||
theme::label_title(),
|
||||
title.unwrap_or(TString::empty()),
|
||||
page,
|
||||
);
|
||||
if info_button {
|
||||
frame = frame.with_info_button();
|
||||
}
|
||||
@ -1868,15 +1892,20 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
||||
/// """Confirm value. Merge of confirm_total and confirm_output."""
|
||||
Qstr::MP_QSTR_confirm_value => obj_fn_kw!(0, new_confirm_value).as_obj(),
|
||||
|
||||
/// def confirm_total(
|
||||
/// def confirm_summary(
|
||||
/// *,
|
||||
/// title: str,
|
||||
/// items: Iterable[tuple[str, str]],
|
||||
/// info_button: bool = False,
|
||||
/// cancel_arrow: bool = False,
|
||||
/// amount: str,
|
||||
/// amount_label: str,
|
||||
/// fee: str,
|
||||
/// fee_label: str,
|
||||
/// title: str | None = None,
|
||||
/// account_items: Iterable[tuple[str, str]] | None = None,
|
||||
/// extra_items: Iterable[tuple[str, str]] | None = None,
|
||||
/// extra_title: str | None = None,
|
||||
/// verb_cancel: str | None = None,
|
||||
/// ) -> LayoutObj[UiResult]:
|
||||
/// """Transaction summary. Always hold to confirm."""
|
||||
Qstr::MP_QSTR_confirm_total => obj_fn_kw!(0, new_confirm_total).as_obj(),
|
||||
/// """Confirm summary of a transaction."""
|
||||
Qstr::MP_QSTR_confirm_summary => obj_fn_kw!(0, new_confirm_summary).as_obj(),
|
||||
|
||||
/// def confirm_modify_output(
|
||||
/// *,
|
||||
|
@ -144,17 +144,6 @@ def confirm_value(
|
||||
"""Confirm value. Merge of confirm_total and confirm_output."""
|
||||
|
||||
|
||||
# rust/src/ui/model_mercury/layout.rs
|
||||
def confirm_total(
|
||||
*,
|
||||
title: str,
|
||||
items: Iterable[tuple[str, str]],
|
||||
info_button: bool = False,
|
||||
cancel_arrow: bool = False,
|
||||
) -> LayoutObj[UiResult]:
|
||||
"""Transaction summary. Always hold to confirm."""
|
||||
|
||||
|
||||
# rust/src/ui/model_mercury/layout.rs
|
||||
def confirm_modify_output(
|
||||
*,
|
||||
@ -534,18 +523,19 @@ def flow_confirm_output(
|
||||
|
||||
|
||||
# rust/src/ui/model_mercury/layout.rs
|
||||
def flow_confirm_summary(
|
||||
def confirm_summary(
|
||||
*,
|
||||
title: str,
|
||||
items: Iterable[tuple[str, str]],
|
||||
account_items: Iterable[tuple[str, str]],
|
||||
account_items_title: str | None,
|
||||
fee_items: Iterable[tuple[str, str]],
|
||||
br_code: ButtonRequestType,
|
||||
br_name: str,
|
||||
cancel_text: str | None = None,
|
||||
amount: str,
|
||||
amount_label: str,
|
||||
fee: str,
|
||||
fee_label: str,
|
||||
title: str | None = None,
|
||||
account_items: Iterable[tuple[str, str]] | None = None,
|
||||
extra_items: Iterable[tuple[str, str]] | None = None,
|
||||
extra_title: str | None = None,
|
||||
verb_cancel: str | None = None,
|
||||
) -> LayoutObj[UiResult]:
|
||||
"""Total summary and hold to confirm."""
|
||||
"""Confirm summary of a transaction."""
|
||||
|
||||
|
||||
# rust/src/ui/model_mercury/layout.rs
|
||||
@ -743,32 +733,21 @@ def confirm_output_amount(
|
||||
|
||||
|
||||
# rust/src/ui/model_tr/layout.rs
|
||||
def confirm_total(
|
||||
def confirm_summary(
|
||||
*,
|
||||
total_amount: str,
|
||||
fee_amount: str,
|
||||
fee_rate_amount: str | None,
|
||||
account_label: str | None,
|
||||
total_label: str,
|
||||
amount: str,
|
||||
amount_label: str,
|
||||
fee: str,
|
||||
fee_label: str,
|
||||
title: str | None = None,
|
||||
account_items: Iterable[tuple[str, str]] | None = None,
|
||||
extra_items: Iterable[tuple[str, str]] | None = None,
|
||||
extra_title: str | None = None,
|
||||
verb_cancel: str | None = None,
|
||||
) -> LayoutObj[UiResult]:
|
||||
"""Confirm summary of a transaction."""
|
||||
|
||||
|
||||
# rust/src/ui/model_tr/layout.rs
|
||||
def altcoin_tx_summary(
|
||||
*,
|
||||
amount_title: str,
|
||||
amount_value: str,
|
||||
fee_title: str,
|
||||
fee_value: str,
|
||||
items_title: str,
|
||||
items: Iterable[Tuple[str, str]],
|
||||
cancel_cross: bool = False,
|
||||
) -> LayoutObj[UiResult]:
|
||||
"""Confirm details about altcoin transaction."""
|
||||
|
||||
|
||||
# rust/src/ui/model_tr/layout.rs
|
||||
def tutorial() -> LayoutObj[UiResult]:
|
||||
"""Show user how to interact with the device."""
|
||||
@ -1290,14 +1269,19 @@ def confirm_value(
|
||||
|
||||
|
||||
# rust/src/ui/model_tt/layout.rs
|
||||
def confirm_total(
|
||||
def confirm_summary(
|
||||
*,
|
||||
title: str,
|
||||
items: Iterable[tuple[str, str]],
|
||||
info_button: bool = False,
|
||||
cancel_arrow: bool = False,
|
||||
amount: str,
|
||||
amount_label: str,
|
||||
fee: str,
|
||||
fee_label: str,
|
||||
title: str | None = None,
|
||||
account_items: Iterable[tuple[str, str]] | None = None,
|
||||
extra_items: Iterable[tuple[str, str]] | None = None,
|
||||
extra_title: str | None = None,
|
||||
verb_cancel: str | None = None,
|
||||
) -> LayoutObj[UiResult]:
|
||||
"""Transaction summary. Always hold to confirm."""
|
||||
"""Confirm summary of a transaction."""
|
||||
|
||||
|
||||
# rust/src/ui/model_tt/layout.rs
|
||||
|
@ -686,10 +686,6 @@ def confirm_total(
|
||||
total_label = total_label or TR.send__total_amount # def_arg
|
||||
fee_label = fee_label or TR.send__incl_transaction_fee # def_arg
|
||||
|
||||
items = [
|
||||
(total_label, total_amount),
|
||||
(fee_label, fee_amount),
|
||||
]
|
||||
fee_items = []
|
||||
account_items = []
|
||||
if source_account:
|
||||
@ -700,44 +696,48 @@ def confirm_total(
|
||||
fee_items.append((TR.confirm_total__fee_rate, fee_rate_amount))
|
||||
|
||||
return raise_if_not_confirmed(
|
||||
trezorui2.flow_confirm_summary(
|
||||
trezorui2.confirm_summary(
|
||||
amount=total_amount,
|
||||
amount_label=total_label,
|
||||
fee=fee_amount,
|
||||
fee_label=fee_label,
|
||||
title=title,
|
||||
items=items,
|
||||
fee_items=fee_items,
|
||||
account_items=account_items,
|
||||
account_items_title=None,
|
||||
br_name=br_name,
|
||||
br_code=br_code,
|
||||
cancel_text=TR.send__cancel_sign,
|
||||
account_items=account_items or None,
|
||||
extra_items=fee_items or None,
|
||||
extra_title=TR.confirm_total__title_fee,
|
||||
),
|
||||
None,
|
||||
br_name,
|
||||
br_code,
|
||||
)
|
||||
|
||||
|
||||
def _confirm_summary(
|
||||
items: Iterable[tuple[str, str]] | None = None,
|
||||
amount: str,
|
||||
amount_label: str,
|
||||
fee: str,
|
||||
fee_label: str,
|
||||
title: str | None = None,
|
||||
info_items: Iterable[tuple[str, str]] | None = None,
|
||||
info_title: str | None = None,
|
||||
fee_items: Iterable[tuple[str, str]] | None = None,
|
||||
account_items: Iterable[tuple[str, str]] | None = None,
|
||||
extra_items: Iterable[tuple[str, str]] | None = None,
|
||||
extra_title: str | None = None,
|
||||
br_name: str = "confirm_total",
|
||||
br_code: ButtonRequestType = ButtonRequestType.SignTx,
|
||||
cancel_text: str | None = None,
|
||||
) -> Awaitable[None]:
|
||||
title = title or TR.words__title_summary # def_arg
|
||||
|
||||
return raise_if_not_confirmed(
|
||||
trezorui2.flow_confirm_summary(
|
||||
trezorui2.confirm_summary(
|
||||
amount=amount,
|
||||
amount_label=amount_label,
|
||||
fee=fee,
|
||||
fee_label=fee_label,
|
||||
title=title,
|
||||
items=items or (),
|
||||
fee_items=fee_items or (),
|
||||
account_items=info_items or (),
|
||||
account_items_title=info_title,
|
||||
br_name=br_name,
|
||||
br_code=br_code,
|
||||
cancel_text=cancel_text,
|
||||
account_items=account_items or None,
|
||||
extra_items=extra_items or None,
|
||||
extra_title=extra_title or None,
|
||||
),
|
||||
None,
|
||||
br_name,
|
||||
br_code,
|
||||
)
|
||||
|
||||
|
||||
@ -853,8 +853,11 @@ if not utils.BITCOIN_ONLY:
|
||||
) # def_arg
|
||||
fee_title = fee_title or TR.words__fee # def_arg
|
||||
return _confirm_summary(
|
||||
items=((amount_title, amount), (fee_title, fee)),
|
||||
info_items=items,
|
||||
amount,
|
||||
amount_title,
|
||||
fee,
|
||||
fee_title,
|
||||
extra_items=items,
|
||||
br_name=br_name,
|
||||
br_code=br_code,
|
||||
)
|
||||
@ -866,13 +869,13 @@ if not utils.BITCOIN_ONLY:
|
||||
) -> Awaitable[None]:
|
||||
amount_title = TR.send__total_amount
|
||||
fee_title = TR.send__incl_transaction_fee
|
||||
more_info_title = TR.buttons__more_info
|
||||
|
||||
return _confirm_summary(
|
||||
items=((amount_title, amount), (fee_title, fee)),
|
||||
info_items=items,
|
||||
info_title=more_info_title,
|
||||
fee_items=None,
|
||||
amount,
|
||||
amount_title,
|
||||
fee,
|
||||
fee_title,
|
||||
extra_items=items,
|
||||
br_name="confirm_cardano_tx",
|
||||
br_code=ButtonRequestType.SignTx,
|
||||
)
|
||||
@ -880,10 +883,10 @@ if not utils.BITCOIN_ONLY:
|
||||
|
||||
def confirm_joint_total(spending_amount: str, total_amount: str) -> Awaitable[None]:
|
||||
return _confirm_summary(
|
||||
items=(
|
||||
(TR.send__you_are_contributing, spending_amount),
|
||||
(TR.send__to_the_total_amount, total_amount),
|
||||
),
|
||||
spending_amount,
|
||||
TR.send__you_are_contributing,
|
||||
total_amount,
|
||||
TR.send__to_the_total_amount,
|
||||
title=TR.send__title_joint_transaction,
|
||||
br_name="confirm_joint_total",
|
||||
br_code=ButtonRequestType.SignTx,
|
||||
|
@ -814,15 +814,23 @@ def confirm_total(
|
||||
) -> Awaitable[None]:
|
||||
total_label = total_label or f"{TR.send__total_amount}:" # def_arg
|
||||
fee_label = fee_label or TR.send__including_fee # def_arg
|
||||
return interact(
|
||||
# TODO: resolve these differences in TT's and TR's confirm_total
|
||||
trezorui2.confirm_total( # type: ignore [Arguments missing]
|
||||
total_amount=total_amount, # type: ignore [No parameter named]
|
||||
fee_amount=fee_amount, # type: ignore [No parameter named]
|
||||
fee_rate_amount=fee_rate_amount, # type: ignore [No parameter named]
|
||||
account_label=source_account, # type: ignore [No parameter named]
|
||||
total_label=total_label, # type: ignore [No parameter named]
|
||||
fee_label=fee_label, # type: ignore [No parameter named]
|
||||
|
||||
fee_info_items = []
|
||||
if fee_rate_amount:
|
||||
fee_info_items.append((TR.confirm_total__fee_rate_colon, fee_rate_amount))
|
||||
account_info_items = []
|
||||
if source_account:
|
||||
account_info_items.append((TR.words__account_colon, source_account))
|
||||
|
||||
return raise_if_not_confirmed(
|
||||
trezorui2.confirm_summary(
|
||||
amount=total_amount,
|
||||
amount_label=total_label,
|
||||
fee=fee_amount,
|
||||
fee_label=fee_label,
|
||||
account_items=account_info_items or None,
|
||||
extra_items=fee_info_items or None,
|
||||
extra_title=TR.confirm_total__title_fee,
|
||||
),
|
||||
br_name,
|
||||
br_code,
|
||||
@ -871,14 +879,13 @@ if not utils.BITCOIN_ONLY:
|
||||
amount_title = f"{TR.words__amount}:"
|
||||
amount_value = total_amount
|
||||
await raise_if_not_confirmed(
|
||||
trezorui2.altcoin_tx_summary(
|
||||
amount_title=amount_title,
|
||||
amount_value=amount_value,
|
||||
fee_title=f"{TR.send__maximum_fee}:",
|
||||
fee_value=maximum_fee,
|
||||
items_title=TR.confirm_total__title_fee,
|
||||
items=[(f"{k}:", v) for (k, v) in info_items],
|
||||
cancel_cross=True,
|
||||
trezorui2.confirm_summary(
|
||||
amount=amount_value,
|
||||
amount_label=amount_title,
|
||||
fee=maximum_fee,
|
||||
fee_label=f"{TR.send__maximum_fee}:",
|
||||
extra_items=[(f"{k}:", v) for (k, v) in info_items],
|
||||
extra_title=TR.confirm_total__title_fee,
|
||||
),
|
||||
br_name=br_name,
|
||||
br_code=br_code,
|
||||
@ -898,14 +905,12 @@ if not utils.BITCOIN_ONLY:
|
||||
) # def_arg
|
||||
fee_title = fee_title or TR.words__fee # def_arg
|
||||
return raise_if_not_confirmed(
|
||||
trezorui2.altcoin_tx_summary(
|
||||
amount_title=amount_title,
|
||||
amount_value=amount,
|
||||
fee_title=fee_title,
|
||||
fee_value=fee,
|
||||
items_title=TR.confirm_total__title_fee,
|
||||
items=items,
|
||||
cancel_cross=True,
|
||||
trezorui2.confirm_summary(
|
||||
amount=amount,
|
||||
amount_label=amount_title,
|
||||
fee=fee,
|
||||
fee_label=fee_title,
|
||||
extra_items=items, # TODO: extra_title here?
|
||||
),
|
||||
br_name=br_name,
|
||||
br_code=br_code,
|
||||
@ -922,14 +927,12 @@ if not utils.BITCOIN_ONLY:
|
||||
fee_title = TR.send__including_fee
|
||||
|
||||
return raise_if_not_confirmed(
|
||||
trezorui2.altcoin_tx_summary(
|
||||
amount_title=amount_title,
|
||||
amount_value=amount,
|
||||
fee_title=fee_title,
|
||||
fee_value=fee,
|
||||
items_title=TR.words__title_information,
|
||||
items=items,
|
||||
cancel_cross=True,
|
||||
trezorui2.confirm_summary(
|
||||
amount=amount,
|
||||
amount_label=amount_title,
|
||||
fee=fee,
|
||||
fee_label=fee_title,
|
||||
extra_items=items,
|
||||
),
|
||||
br_name="confirm_cardano_tx",
|
||||
br_code=ButtonRequestType.SignTx,
|
||||
@ -947,13 +950,13 @@ if not utils.BITCOIN_ONLY:
|
||||
br_code: ButtonRequestType = ButtonRequestType.SignTx,
|
||||
chunkify: bool = False,
|
||||
) -> None:
|
||||
summary_layout = trezorui2.altcoin_tx_summary(
|
||||
amount_title=f"{TR.words__amount}:",
|
||||
amount_value=total_amount,
|
||||
fee_title=f"{TR.send__maximum_fee}:",
|
||||
fee_value=maximum_fee,
|
||||
items_title=TR.confirm_total__title_fee,
|
||||
items=[(f"{k}:", v) for (k, v) in fee_info_items],
|
||||
summary_layout = trezorui2.confirm_summary(
|
||||
amount=total_amount,
|
||||
amount_label=f"{TR.words__amount}:",
|
||||
fee=maximum_fee,
|
||||
fee_label=f"{TR.send__maximum_fee}:",
|
||||
extra_items=[(f"{k}:", v) for (k, v) in fee_info_items],
|
||||
extra_title=TR.confirm_total__title_fee,
|
||||
)
|
||||
|
||||
if not is_contract_interaction:
|
||||
|
@ -750,43 +750,61 @@ def confirm_total(
|
||||
total_label = total_label or f"{TR.send__total_amount}:" # def_arg
|
||||
fee_label = fee_label or TR.send__including_fee # def_arg
|
||||
|
||||
items = [
|
||||
(total_label, total_amount),
|
||||
(fee_label, fee_amount),
|
||||
]
|
||||
info_items = []
|
||||
account_info_items = []
|
||||
extra_info_items = []
|
||||
if source_account:
|
||||
info_items.append((TR.confirm_total__sending_from_account, source_account))
|
||||
account_info_items.append(
|
||||
(TR.confirm_total__sending_from_account, source_account)
|
||||
)
|
||||
if fee_rate_amount:
|
||||
info_items.append((f"{TR.confirm_total__fee_rate}:", fee_rate_amount))
|
||||
extra_info_items.append((f"{TR.confirm_total__fee_rate}:", fee_rate_amount))
|
||||
|
||||
return _confirm_summary(
|
||||
items,
|
||||
TR.words__title_summary,
|
||||
info_items=info_items,
|
||||
total_amount,
|
||||
total_label,
|
||||
fee_amount,
|
||||
fee_label,
|
||||
title=title,
|
||||
account_items=account_info_items,
|
||||
extra_items=extra_info_items,
|
||||
extra_title=TR.words__title_information,
|
||||
br_name=br_name,
|
||||
br_code=br_code,
|
||||
)
|
||||
|
||||
|
||||
def _confirm_summary(
|
||||
items: Iterable[tuple[str, str]],
|
||||
amount: str,
|
||||
amount_label: str,
|
||||
fee: str,
|
||||
fee_label: str,
|
||||
title: str | None = None,
|
||||
info_items: Iterable[tuple[str, str]] | None = None,
|
||||
info_title: str | None = None,
|
||||
account_items: Iterable[tuple[str, str]] | None = None,
|
||||
extra_items: Iterable[tuple[str, str]] | None = None,
|
||||
extra_title: str | None = None,
|
||||
br_name: str = "confirm_total",
|
||||
br_code: ButtonRequestType = ButtonRequestType.SignTx,
|
||||
) -> Awaitable[None]:
|
||||
title = title or TR.words__title_summary # def_arg
|
||||
|
||||
total_layout = trezorui2.confirm_total(
|
||||
total_layout = trezorui2.confirm_summary(
|
||||
amount=amount,
|
||||
amount_label=amount_label,
|
||||
fee=fee,
|
||||
fee_label=fee_label,
|
||||
title=title,
|
||||
items=items,
|
||||
info_button=bool(info_items),
|
||||
account_items=account_items or None,
|
||||
extra_items=extra_items or None,
|
||||
)
|
||||
info_items = info_items or []
|
||||
|
||||
# TODO: use `_info` params directly in this^ layout instead of using `with_info`
|
||||
info_items = []
|
||||
if account_items:
|
||||
info_items.extend(account_items)
|
||||
if extra_items:
|
||||
info_items.extend(extra_items)
|
||||
info_layout = trezorui2.show_info_with_cancel(
|
||||
title=info_title if info_title else TR.words__title_information,
|
||||
title=extra_title if extra_title else TR.words__title_information,
|
||||
items=info_items,
|
||||
)
|
||||
return with_info(total_layout, info_layout, br_name, br_code)
|
||||
@ -811,14 +829,16 @@ if not utils.BITCOIN_ONLY:
|
||||
br_code: ButtonRequestType = ButtonRequestType.SignTx,
|
||||
chunkify: bool = False,
|
||||
) -> None:
|
||||
total_layout = trezorui2.confirm_total(
|
||||
# NOTE: fee_info used so that info button is shown
|
||||
total_layout = trezorui2.confirm_summary(
|
||||
amount=total_amount,
|
||||
amount_label=f"{TR.words__amount}:",
|
||||
fee=maximum_fee,
|
||||
fee_label=f"{TR.send__maximum_fee}:",
|
||||
title=TR.words__title_summary,
|
||||
items=[
|
||||
(f"{TR.words__amount}:", total_amount),
|
||||
(f"{TR.send__maximum_fee}:", maximum_fee),
|
||||
],
|
||||
info_button=True,
|
||||
cancel_arrow=True,
|
||||
extra_items=fee_info_items,
|
||||
extra_title=TR.confirm_total__title_fee,
|
||||
verb_cancel="^",
|
||||
)
|
||||
info_layout = trezorui2.show_info_with_cancel(
|
||||
title=TR.confirm_total__title_fee,
|
||||
@ -879,17 +899,23 @@ if not utils.BITCOIN_ONLY:
|
||||
|
||||
# confirmation
|
||||
if verb == TR.ethereum__staking_claim:
|
||||
items = ((f"{TR.send__maximum_fee}:", maximum_fee),)
|
||||
amount = ""
|
||||
amount_label = ""
|
||||
fee_label = f"{TR.send__maximum_fee}:"
|
||||
fee = maximum_fee
|
||||
else:
|
||||
items = (
|
||||
(f"{TR.words__amount}:", total_amount),
|
||||
(f"{TR.send__maximum_fee}:", maximum_fee),
|
||||
)
|
||||
amount_label = f"{TR.words__amount}:"
|
||||
amount = total_amount
|
||||
fee_label = f"{TR.send__maximum_fee}:"
|
||||
fee = maximum_fee
|
||||
await _confirm_summary(
|
||||
items, # items
|
||||
amount,
|
||||
amount_label,
|
||||
fee,
|
||||
fee_label,
|
||||
title=title,
|
||||
info_title=TR.confirm_total__title_fee,
|
||||
info_items=[(f"{k}:", v) for (k, v) in info_items],
|
||||
extra_items=[(f"{k}:", v) for (k, v) in info_items],
|
||||
extra_title=TR.confirm_total__title_fee,
|
||||
br_name=br_name,
|
||||
br_code=br_code,
|
||||
)
|
||||
@ -908,8 +934,11 @@ if not utils.BITCOIN_ONLY:
|
||||
) # def_arg
|
||||
fee_title = fee_title or TR.words__fee # def_arg
|
||||
return _confirm_summary(
|
||||
((amount_title, amount), (fee_title, fee)),
|
||||
info_items=items,
|
||||
amount,
|
||||
amount_title,
|
||||
fee,
|
||||
fee_title,
|
||||
extra_items=items,
|
||||
br_name=br_name,
|
||||
br_code=br_code,
|
||||
)
|
||||
@ -922,8 +951,11 @@ if not utils.BITCOIN_ONLY:
|
||||
amount_title = f"{TR.send__total_amount}:"
|
||||
fee_title = TR.send__including_fee
|
||||
return _confirm_summary(
|
||||
((amount_title, amount), (fee_title, fee)),
|
||||
info_items=items,
|
||||
amount,
|
||||
amount_title,
|
||||
fee,
|
||||
fee_title,
|
||||
extra_items=items,
|
||||
br_name="confirm_cardano_tx",
|
||||
br_code=ButtonRequestType.SignTx,
|
||||
)
|
||||
@ -931,12 +963,13 @@ if not utils.BITCOIN_ONLY:
|
||||
|
||||
def confirm_joint_total(spending_amount: str, total_amount: str) -> Awaitable[None]:
|
||||
return raise_if_not_confirmed(
|
||||
trezorui2.confirm_total(
|
||||
# FIXME: arguments for amount/fee are misused here
|
||||
trezorui2.confirm_summary(
|
||||
amount=spending_amount,
|
||||
amount_label=TR.send__you_are_contributing,
|
||||
fee=total_amount,
|
||||
fee_label=TR.send__to_the_total_amount,
|
||||
title=TR.send__title_joint_transaction,
|
||||
items=[
|
||||
(TR.send__you_are_contributing, spending_amount),
|
||||
(TR.send__to_the_total_amount, total_amount),
|
||||
],
|
||||
),
|
||||
"confirm_joint_total",
|
||||
ButtonRequestType.SignTx,
|
||||
|
@ -835,10 +835,10 @@ def sign_tx_go_to_info_tr(
|
||||
yield
|
||||
|
||||
layout = client.debug.press_right()
|
||||
screen_texts.append(layout.text_content())
|
||||
screen_texts.append(layout.visible_screen())
|
||||
|
||||
layout = client.debug.press_right()
|
||||
screen_texts.append(layout.text_content())
|
||||
screen_texts.append(layout.visible_screen())
|
||||
|
||||
client.debug.press_left()
|
||||
client.debug.press_left()
|
||||
|
Loading…
Reference in New Issue
Block a user