1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-04 21:48:17 +00:00

refactor(core): model_r confirm_summary

- altcoin_tx_summary removed and replaced with confirm_summary

[no changelog]
This commit is contained in:
obrusvit 2024-11-28 16:05:50 +01:00
parent c08e495c9b
commit 2b559fc22f
6 changed files with 159 additions and 200 deletions

View File

@ -40,7 +40,6 @@ static void _librust_qstrs(void) {
MP_QSTR_account_info;
MP_QSTR_account_items;
MP_QSTR_account_items_title;
MP_QSTR_account_label;
MP_QSTR_account_path;
MP_QSTR_accounts;
MP_QSTR_action;
@ -70,13 +69,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;
@ -178,7 +175,6 @@ static void _librust_qstrs(void) {
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;
@ -212,7 +208,6 @@ static void _librust_qstrs(void) {
MP_QSTR_confirm_recovery;
MP_QSTR_confirm_reset_device;
MP_QSTR_confirm_summary;
MP_QSTR_confirm_total;
MP_QSTR_confirm_total__fee_rate;
MP_QSTR_confirm_total__fee_rate_colon;
MP_QSTR_confirm_total__sending_from_account;
@ -247,13 +242,10 @@ static void _librust_qstrs(void) {
MP_QSTR_extra;
MP_QSTR_extra_info;
MP_QSTR_fee;
MP_QSTR_fee_amount;
MP_QSTR_fee_info;
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;
@ -324,7 +316,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;
@ -703,7 +694,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;

View File

@ -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(

View File

@ -45,6 +45,7 @@ use crate::{
},
ComponentExt, FormattedText, Label, LineBreaking, Never, Timeout,
},
display::Font,
geometry,
layout::{
base::LAYOUT_STATE,
@ -638,131 +639,112 @@ 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 fee_items: Option<Obj> = kwargs
.get(Qstr::MP_QSTR_fee_items)
.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 cancel_arrow: bool = kwargs.get_or(Qstr::MP_QSTR_cancel_arrow, false)?;
// collect available info pages
let mut info_pages: Vec<(TString, Obj), 3> = Vec::new();
if let Some(info) = fee_items {
unwrap!(info_pages.push((TR::confirm_total__title_fee.into(), info)));
}
if let Some(info) = account_items {
unwrap!(info_pages.push((TR::confirm_total__title_sending_from.into(), info)));
}
if let Some(info) = extra_items {
unwrap!(info_pages.push((TR::words__title_information.into(), info)));
}
// button layouts and actions
let btns_summary_page =
|cancel_arrow: bool, has_pages_after: bool| -> (ButtonLayout, ButtonActions) {
// if there are no info pages, the right button is not needed
// if cancel_arrow is true, the left button is an arrow pointing up
let left_button = Some(if cancel_arrow {
ButtonDetails::up_arrow_icon()
} else {
ButtonDetails::cancel_icon()
});
let right_button = has_pages_after.then(|| {
ButtonDetails::text("i".into())
.with_fixed_width(theme::BUTTON_ICON_WIDTH)
.with_font(Font::NORMAL)
});
let middle_button = Some(ButtonDetails::armed_text(TR::buttons__confirm.into()));
(
ButtonLayout::new(left_button, middle_button, right_button),
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(cancel_arrow, !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 +758,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())
@ -1809,30 +1790,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,
/// fee_items: Iterable[tuple[str, str]] | None = None,
/// account_items: Iterable[tuple[str, str]] | None = None,
/// extra_items: Iterable[tuple[str, str]] | None = None,
/// cancel_arrow: bool = False,
/// ) -> 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."""

View File

@ -755,32 +755,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,
fee_items: Iterable[tuple[str, str]] | None = None,
account_items: Iterable[tuple[str, str]] | None = None,
extra_items: Iterable[tuple[str, str]] | None = None,
cancel_arrow: bool = False,
) -> 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."""

View File

@ -789,15 +789,22 @@ 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,
fee_items=fee_info_items or None,
account_items=account_info_items or None,
),
br_name,
br_code,
@ -849,14 +856,12 @@ 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}:",
fee_items=[(f"{k}:", v) for (k, v) in info_items],
),
br_name=br_name,
br_code=br_code,
@ -876,14 +881,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,
fee_items=items,
),
br_name=br_name,
br_code=br_code,
@ -900,14 +903,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,
@ -925,13 +926,12 @@ 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}:",
fee_items=[(f"{k}:", v) for (k, v) in fee_info_items],
)
if not is_contract_interaction:

View File

@ -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()