1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-03-24 20:15:44 +00:00

refactor(core): port functions to FirmwareUI

- keyboards
- standalone functions
  - disable_animations
  - check_homescreen_format
- confirm_action
- selectors
- confirm_firmware_update
- show_homescreen/lockscreen
- confirm_homescreen
- confirm_homescreen of mercury changed according to Figma
- set_brightness
- show_wait_text
- show_progress
- request_number
- show_checklist
- show_mismatch
- confirm_reset
- tutorial
- confirm_coinjoin
- confirm_modify_output/fee
- show_group_share_success
- show_remaining_shares
- show_success/warning/error/danger
- show_simple
- continue_recovery
  - confirm_recovery of model_t and model_r merged with
flow_continue_recovery of mercury into a continue_recovery_homepage
trait function, parameters renamed to be more descriptive
- show_share_words moved and refactored
  - model_t version was moved from using plain Paragraph to a dedicated
component `ShareWords` so that it's consistent with other models. This
allowed to move formatting to Rust and allowed the trait function to
have `words` parameter of type `Vec<TString, 33>`
  - model_r ShareWords::render slightly refactored to be consistent with
the new model_t version
  - mercury uses a unique version. The reason is that mercury SwipeFlow
contains also the initial screen with instructions and prompt screen at
the end.
- confirm_with_info
- show_info_with_cancel
- confirm_blob
- confirm_value
- confirm_properties
- confirm_more
- confirm_address
- prompt_backub
- confirm_emphasized
- show_address_details
- confirm_summary
- TR removed:
  - confirm_output_address and confirm_output_amount replaced with
confirm_blob. UI diff is minimal.
  - confirm_joint_total, replaced a TR-specific function with a generic
`confirm_properties` with no UI changes
- confirm_multiple_pages_texts
  - the function is TR specific and is used only in confirm_set_new_pin,
it would be better to use something different
- remaining mercury flows with no counterpart
  - confirm_blob_intro
  - flow_confirm_set_new_pin
  - flow_confirm_output
  - flow_get_address

[no changelog]
This commit is contained in:
obrusvit 2024-10-22 22:24:40 +02:00 committed by Vít Obrusník
parent b2c6b09bfc
commit dd9ac038d0
42 changed files with 6838 additions and 7155 deletions

View File

@ -63,7 +63,6 @@ static void _librust_qstrs(void) {
MP_QSTR_address_details__derivation_path_colon;
MP_QSTR_address_details__title_receive_address;
MP_QSTR_address_details__title_receiving_to;
MP_QSTR_address_label;
MP_QSTR_address_qr;
MP_QSTR_address_title;
MP_QSTR_allow_cancel;
@ -71,7 +70,6 @@ static void _librust_qstrs(void) {
MP_QSTR_amount_change;
MP_QSTR_amount_label;
MP_QSTR_amount_new;
MP_QSTR_amount_title;
MP_QSTR_app_name;
MP_QSTR_area_bytesize;
MP_QSTR_attach_timer_fn;
@ -187,7 +185,6 @@ static void _librust_qstrs(void) {
MP_QSTR_coinjoin_authorized;
MP_QSTR_confirm_action;
MP_QSTR_confirm_address;
MP_QSTR_confirm_backup;
MP_QSTR_confirm_blob;
MP_QSTR_confirm_blob_intro;
MP_QSTR_confirm_coinjoin;
@ -195,14 +192,10 @@ static void _librust_qstrs(void) {
MP_QSTR_confirm_fido;
MP_QSTR_confirm_firmware_update;
MP_QSTR_confirm_homescreen;
MP_QSTR_confirm_joint_total;
MP_QSTR_confirm_modify_fee;
MP_QSTR_confirm_modify_output;
MP_QSTR_confirm_more;
MP_QSTR_confirm_output_address;
MP_QSTR_confirm_output_amount;
MP_QSTR_confirm_properties;
MP_QSTR_confirm_recovery;
MP_QSTR_confirm_reset_device;
MP_QSTR_confirm_summary;
MP_QSTR_confirm_total__fee_rate;
@ -212,6 +205,7 @@ static void _librust_qstrs(void) {
MP_QSTR_confirm_total__title_sending_from;
MP_QSTR_confirm_value;
MP_QSTR_confirm_with_info;
MP_QSTR_continue_recovery_homepage;
MP_QSTR_count;
MP_QSTR_current;
MP_QSTR_danger;
@ -246,16 +240,9 @@ static void _librust_qstrs(void) {
MP_QSTR_fingerprint;
MP_QSTR_firmware_update__title;
MP_QSTR_firmware_update__title_fingerprint;
MP_QSTR_first_screen;
MP_QSTR_flow_confirm_output;
MP_QSTR_flow_confirm_reset;
MP_QSTR_flow_confirm_set_new_pin;
MP_QSTR_flow_continue_recovery;
MP_QSTR_flow_get_address;
MP_QSTR_flow_prompt_backup;
MP_QSTR_flow_request_number;
MP_QSTR_flow_request_passphrase;
MP_QSTR_flow_show_share_words;
MP_QSTR_get_language;
MP_QSTR_get_transition_out;
MP_QSTR_haptic_feedback__disable;
@ -292,6 +279,7 @@ static void _librust_qstrs(void) {
MP_QSTR_inputs__return;
MP_QSTR_inputs__show;
MP_QSTR_inputs__space;
MP_QSTR_instructions;
MP_QSTR_instructions__continue_holding;
MP_QSTR_instructions__continue_in_app;
MP_QSTR_instructions__enter_next_share;
@ -347,6 +335,7 @@ static void _librust_qstrs(void) {
MP_QSTR_modify_fee__no_change;
MP_QSTR_modify_fee__title;
MP_QSTR_modify_fee__transaction_fee;
MP_QSTR_more_info_callback;
MP_QSTR_multiple_pages_texts;
MP_QSTR_notification;
MP_QSTR_notification_level;
@ -422,6 +411,7 @@ static void _librust_qstrs(void) {
MP_QSTR_progress__x_seconds_left_template;
MP_QSTR_progress_event;
MP_QSTR_prompt;
MP_QSTR_prompt_backup;
MP_QSTR_prompt_screen;
MP_QSTR_prompt_title;
MP_QSTR_qr_title;
@ -481,6 +471,7 @@ static void _librust_qstrs(void) {
MP_QSTR_recovery__x_of_y_entered_template;
MP_QSTR_recovery__you_have_entered;
MP_QSTR_recovery_type;
MP_QSTR_remaining_shares;
MP_QSTR_request_bip39;
MP_QSTR_request_complete_repaint;
MP_QSTR_request_number;
@ -639,7 +630,6 @@ static void _librust_qstrs(void) {
MP_QSTR_set_brightness;
MP_QSTR_setting__adjust;
MP_QSTR_setting__apply;
MP_QSTR_share_words;
MP_QSTR_share_words__words_in_order;
MP_QSTR_share_words__wrote_down_all;
MP_QSTR_show_address_details;
@ -653,11 +643,11 @@ static void _librust_qstrs(void) {
MP_QSTR_show_instructions;
MP_QSTR_show_lockscreen;
MP_QSTR_show_mismatch;
MP_QSTR_show_passphrase;
MP_QSTR_show_progress;
MP_QSTR_show_progress_coinjoin;
MP_QSTR_show_remaining_shares;
MP_QSTR_show_share_words;
MP_QSTR_show_share_words_mercury;
MP_QSTR_show_simple;
MP_QSTR_show_success;
MP_QSTR_show_wait_text;
@ -669,7 +659,6 @@ static void _librust_qstrs(void) {
MP_QSTR_sign_message__message_size;
MP_QSTR_sign_message__verify_address;
MP_QSTR_skip_first_paint;
MP_QSTR_spending_amount;
MP_QSTR_storage_msg__processing;
MP_QSTR_storage_msg__starting;
MP_QSTR_storage_msg__verifying_pin;
@ -683,12 +672,12 @@ static void _librust_qstrs(void) {
MP_QSTR_summary_title;
MP_QSTR_text;
MP_QSTR_text_confirm;
MP_QSTR_text_info;
MP_QSTR_text_footer;
MP_QSTR_text_mono;
MP_QSTR_time_ms;
MP_QSTR_timer;
MP_QSTR_title;
MP_QSTR_total_amount;
MP_QSTR_title_success;
MP_QSTR_total_fee_new;
MP_QSTR_total_len;
MP_QSTR_touch_event;
@ -738,7 +727,6 @@ static void _librust_qstrs(void) {
MP_QSTR_verb_info;
MP_QSTR_verify;
MP_QSTR_version;
MP_QSTR_warning;
MP_QSTR_wipe__info;
MP_QSTR_wipe__title;
MP_QSTR_wipe__want_to_wipe;

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
use crate::{
error,
micropython::{gc::Gc, list::List, map::Map, obj::Obj, qstr::Qstr, util},
micropython::{gc::Gc, list::List},
strutil::TString,
translations::TR,
ui::{
@ -14,7 +14,6 @@ use crate::{
FlowController, FlowMsg, SwipeFlow, SwipePage,
},
geometry::Direction,
layout::obj::LayoutObj,
},
};
@ -39,6 +38,7 @@ pub enum ConfirmFido {
static CRED_SELECTED: AtomicUsize = AtomicUsize::new(0);
static SINGLE_CRED: AtomicBool = AtomicBool::new(false);
const EXTRA_PADDING: i16 = 6;
impl FlowController for ConfirmFido {
#[inline]
@ -50,7 +50,7 @@ impl FlowController for ConfirmFido {
match (self, direction) {
(Self::Intro, Direction::Left) => Self::Menu.swipe(direction),
(Self::Menu, Direction::Right) => {
if Self::single_cred() {
if single_cred() {
Self::Details.swipe_right()
} else {
Self::Intro.swipe_right()
@ -69,7 +69,7 @@ impl FlowController for ConfirmFido {
(_, FlowMsg::Info) => Self::Menu.goto(),
(Self::Menu, FlowMsg::Choice(0)) => self.return_msg(FlowMsg::Cancelled),
(Self::Menu, FlowMsg::Cancelled) => {
if Self::single_cred() {
if single_cred() {
Self::Details.swipe_right()
} else {
Self::Intro.swipe_right()
@ -88,11 +88,6 @@ impl FlowController for ConfirmFido {
}
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub extern "C" fn new_confirm_fido(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, ConfirmFido::new_obj) }
}
fn footer_update_fn(
content: &SwipeContent<SwipePage<PagedVerticalMenu<impl Fn(usize) -> TString<'static>>>>,
ctx: &mut EventCtx,
@ -103,124 +98,120 @@ fn footer_update_fn(
footer.update_page_counter(ctx, current_page, total_pages);
}
impl ConfirmFido {
const EXTRA_PADDING: i16 = 6;
fn single_cred() -> bool {
SINGLE_CRED.load(Ordering::Relaxed)
}
fn single_cred() -> bool {
SINGLE_CRED.load(Ordering::Relaxed)
pub fn new_confirm_fido(
title: TString<'static>,
app_name: TString<'static>,
icon_name: Option<TString<'static>>,
accounts: Gc<List>,
) -> Result<SwipeFlow, error::Error> {
let num_accounts = accounts.len();
SINGLE_CRED.store(num_accounts <= 1, Ordering::Relaxed);
CRED_SELECTED.store(0, Ordering::Relaxed);
let content_intro = Frame::left_aligned(
title,
SwipeContent::new(Paragraphs::new(Paragraph::new::<TString>(
&theme::TEXT_MAIN_GREY_LIGHT,
TR::fido__select_intro.into(),
))),
)
.with_menu_button()
.with_footer(TR::instructions__swipe_up.into(), None)
.with_swipe(Direction::Up, SwipeSettings::default())
.with_swipe(Direction::Right, SwipeSettings::immediate())
.map(|msg| matches!(msg, FrameMsg::Button(_)).then_some(FlowMsg::Info));
// Closure to lazy-load the information on given page index.
// Done like this to allow arbitrarily many pages without
// the need of any allocation here in Rust.
let label_fn = move |page_index| {
let account = unwrap!(accounts.get(page_index));
account
.try_into()
.unwrap_or_else(|_| TString::from_str("-"))
};
let content_choose_credential = Frame::left_aligned(
TR::fido__title_select_credential.into(),
SwipeContent::new(SwipePage::vertical(PagedVerticalMenu::new(
num_accounts,
label_fn,
))),
)
.with_subtitle(TR::fido__title_for_authentication.into())
.with_menu_button()
.with_footer_page_hint(
TR::fido__more_credentials.into(),
TR::buttons__go_back.into(),
TR::instructions__swipe_up.into(),
TR::instructions__swipe_down.into(),
)
.register_footer_update_fn(footer_update_fn)
.with_swipe(Direction::Down, SwipeSettings::default())
.with_swipe(Direction::Right, SwipeSettings::immediate())
.with_vertical_pages()
.map(|msg| match msg {
FrameMsg::Button(_) => Some(FlowMsg::Info),
FrameMsg::Content(VerticalMenuChoiceMsg::Selected(i)) => Some(FlowMsg::Choice(i)),
});
let get_account = move || {
let current = CRED_SELECTED.load(Ordering::Relaxed);
let account = unwrap!(accounts.get(current));
account.try_into().unwrap_or_else(|_| TString::from_str(""))
};
let content_details = Frame::left_aligned(
TR::fido__title_credential_details.into(),
SwipeContent::new(FidoCredential::new(icon_name, app_name, get_account)),
)
.with_footer(TR::instructions__swipe_up.into(), Some(title))
.with_swipe(Direction::Up, SwipeSettings::default())
.with_swipe(Direction::Right, SwipeSettings::immediate());
let content_details = if single_cred() {
content_details.with_menu_button()
} else {
content_details.with_cancel_button()
}
.map(|msg| match msg {
FrameMsg::Button(bm) => Some(bm),
_ => None,
});
fn new_obj(_args: &[Obj], kwargs: &Map) -> Result<Obj, error::Error> {
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
let app_name: TString = kwargs.get(Qstr::MP_QSTR_app_name)?.try_into()?;
let icon_name: Option<TString> = kwargs.get(Qstr::MP_QSTR_icon_name)?.try_into_option()?;
let accounts: Gc<List> = kwargs.get(Qstr::MP_QSTR_accounts)?.try_into()?;
let num_accounts = accounts.len();
SINGLE_CRED.store(num_accounts <= 1, Ordering::Relaxed);
CRED_SELECTED.store(0, Ordering::Relaxed);
let content_intro = Frame::left_aligned(
title,
SwipeContent::new(Paragraphs::new(Paragraph::new::<TString>(
&theme::TEXT_MAIN_GREY_LIGHT,
TR::fido__select_intro.into(),
))),
)
let content_tap = Frame::left_aligned(title, PromptScreen::new_tap_to_confirm())
.with_menu_button()
.with_footer(TR::instructions__swipe_up.into(), None)
.with_swipe(Direction::Up, SwipeSettings::default())
.with_swipe(Direction::Right, SwipeSettings::immediate())
.map(|msg| matches!(msg, FrameMsg::Button(_)).then_some(FlowMsg::Info));
// Closure to lazy-load the information on given page index.
// Done like this to allow arbitrarily many pages without
// the need of any allocation here in Rust.
let label_fn = move |page_index| {
let account = unwrap!(accounts.get(page_index));
account
.try_into()
.unwrap_or_else(|_| TString::from_str("-"))
};
let content_choose_credential = Frame::left_aligned(
TR::fido__title_select_credential.into(),
SwipeContent::new(SwipePage::vertical(PagedVerticalMenu::new(
num_accounts,
label_fn,
))),
)
.with_subtitle(TR::fido__title_for_authentication.into())
.with_menu_button()
.with_footer_page_hint(
TR::fido__more_credentials.into(),
TR::buttons__go_back.into(),
TR::instructions__swipe_up.into(),
TR::instructions__swipe_down.into(),
)
.register_footer_update_fn(footer_update_fn)
.with_footer(TR::instructions__tap_to_confirm.into(), None)
.with_swipe(Direction::Down, SwipeSettings::default())
.with_swipe(Direction::Right, SwipeSettings::immediate())
.with_vertical_pages()
.map(|msg| match msg {
FrameMsg::Content(PromptMsg::Confirmed) => Some(FlowMsg::Confirmed),
FrameMsg::Button(_) => Some(FlowMsg::Info),
FrameMsg::Content(VerticalMenuChoiceMsg::Selected(i)) => Some(FlowMsg::Choice(i)),
});
let get_account = move || {
let current = CRED_SELECTED.load(Ordering::Relaxed);
let account = unwrap!(accounts.get(current));
account.try_into().unwrap_or_else(|_| TString::from_str(""))
};
let content_details = Frame::left_aligned(
TR::fido__title_credential_details.into(),
SwipeContent::new(FidoCredential::new(icon_name, app_name, get_account)),
)
.with_footer(TR::instructions__swipe_up.into(), Some(title))
.with_swipe(Direction::Up, SwipeSettings::default())
.with_swipe(Direction::Right, SwipeSettings::immediate());
let content_details = if Self::single_cred() {
content_details.with_menu_button()
} else {
content_details.with_cancel_button()
}
.map(|msg| match msg {
FrameMsg::Button(bm) => Some(bm),
_ => None,
});
let content_tap = Frame::left_aligned(title, PromptScreen::new_tap_to_confirm())
.with_menu_button()
.with_footer(TR::instructions__tap_to_confirm.into(), None)
.with_swipe(Direction::Down, SwipeSettings::default())
.with_swipe(Direction::Right, SwipeSettings::immediate())
.map(|msg| match msg {
FrameMsg::Content(PromptMsg::Confirmed) => Some(FlowMsg::Confirmed),
FrameMsg::Button(_) => Some(FlowMsg::Info),
_ => None,
});
let content_menu = Frame::left_aligned(
"".into(),
VerticalMenu::empty().danger(theme::ICON_CANCEL, TR::buttons__cancel.into()),
)
.with_cancel_button()
.with_swipe(Direction::Right, SwipeSettings::immediate())
.map(|msg| match msg {
FrameMsg::Content(VerticalMenuChoiceMsg::Selected(i)) => Some(FlowMsg::Choice(i)),
FrameMsg::Button(_) => Some(FlowMsg::Cancelled),
});
let content_menu = Frame::left_aligned(
"".into(),
VerticalMenu::empty().danger(theme::ICON_CANCEL, TR::buttons__cancel.into()),
)
.with_cancel_button()
.with_swipe(Direction::Right, SwipeSettings::immediate())
.map(|msg| match msg {
FrameMsg::Content(VerticalMenuChoiceMsg::Selected(i)) => Some(FlowMsg::Choice(i)),
FrameMsg::Button(_) => Some(FlowMsg::Cancelled),
});
let initial_page = if Self::single_cred() {
&ConfirmFido::Details
} else {
&ConfirmFido::Intro
};
let res = SwipeFlow::new(initial_page)?
.with_page(&ConfirmFido::Intro, content_intro)?
.with_page(&ConfirmFido::ChooseCredential, content_choose_credential)?
.with_page(&ConfirmFido::Details, content_details)?
.with_page(&ConfirmFido::Tap, content_tap)?
.with_page(&ConfirmFido::Menu, content_menu)?;
Ok(LayoutObj::new_root(res)?.into())
}
let initial_page = if single_cred() {
&ConfirmFido::Details
} else {
&ConfirmFido::Intro
};
SwipeFlow::new(initial_page)?
.with_page(&ConfirmFido::Intro, content_intro)?
.with_page(&ConfirmFido::ChooseCredential, content_choose_credential)?
.with_page(&ConfirmFido::Details, content_details)?
.with_page(&ConfirmFido::Tap, content_tap)?
.with_page(&ConfirmFido::Menu, content_menu)
}

View File

@ -0,0 +1,108 @@
use crate::{
error,
strutil::TString,
translations::TR,
ui::{
component::{swipe_detect::SwipeSettings, CachedJpeg, ComponentExt},
flow::{
base::{Decision, DecisionBuilder},
FlowController, FlowMsg, SwipeFlow,
},
geometry::Direction,
model_mercury::{
component::{
Frame, FrameMsg, PromptMsg, PromptScreen, SwipeContent, VerticalMenu,
VerticalMenuChoiceMsg,
},
theme,
},
},
};
/// Flow for a setting of homescreen wallpaper showing a preview of the image,
/// menu to cancel and tap to confirm prompt.
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum ConfirmHomescreen {
Homescreen,
Menu,
Confirm,
}
impl FlowController for ConfirmHomescreen {
#[inline]
fn index(&'static self) -> usize {
*self as usize
}
fn handle_swipe(&'static self, direction: Direction) -> Decision {
match (self, direction) {
(Self::Homescreen, Direction::Left) => Self::Menu.swipe(direction),
(Self::Homescreen, Direction::Up) => Self::Confirm.swipe(direction),
(Self::Menu, Direction::Right) => Self::Homescreen.swipe(direction),
(Self::Confirm, Direction::Down) => Self::Homescreen.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::Homescreen, FlowMsg::Info) => Self::Menu.goto(),
(Self::Menu, FlowMsg::Cancelled) => Self::Homescreen.swipe_right(),
(Self::Menu, FlowMsg::Choice(0)) => self.return_msg(FlowMsg::Cancelled),
(Self::Confirm, FlowMsg::Confirmed) => self.return_msg(FlowMsg::Confirmed),
(Self::Confirm, FlowMsg::Info) => Self::Menu.goto(),
_ => self.do_nothing(),
}
}
}
pub fn new_confirm_homescreen(
title: TString<'static>,
image: CachedJpeg,
) -> Result<SwipeFlow, error::Error> {
let content_homescreen = Frame::left_aligned(title, SwipeContent::new(image))
.with_menu_button()
.with_footer(
TR::instructions__swipe_up.into(),
Some(TR::buttons__change.into()),
)
.with_swipe(Direction::Up, SwipeSettings::default())
// Homescreen + Tap to confirm
.with_pages(|_| 2)
.map(|msg| match msg {
FrameMsg::Button(_) => Some(FlowMsg::Info),
_ => None,
});
let content_menu = Frame::left_aligned(
TString::empty(),
VerticalMenu::empty().danger(theme::ICON_CANCEL, TR::buttons__cancel.into()),
)
.with_cancel_button()
.with_swipe(Direction::Right, SwipeSettings::immediate())
.map(|msg| match msg {
FrameMsg::Content(VerticalMenuChoiceMsg::Selected(i)) => Some(FlowMsg::Choice(i)),
FrameMsg::Button(_) => Some(FlowMsg::Cancelled),
});
let content_confirm = Frame::left_aligned(
TR::homescreen__title_set.into(),
SwipeContent::new(PromptScreen::new_tap_to_confirm()),
)
.with_menu_button()
.with_footer(TR::instructions__tap_to_confirm.into(), None)
.with_swipe(Direction::Down, SwipeSettings::default())
.with_swipe(Direction::Left, SwipeSettings::default())
.map(|msg| match msg {
FrameMsg::Content(PromptMsg::Confirmed) => Some(FlowMsg::Confirmed),
FrameMsg::Button(_) => Some(FlowMsg::Info),
_ => None,
});
let res = SwipeFlow::new(&ConfirmHomescreen::Homescreen)?
.with_page(&ConfirmHomescreen::Homescreen, content_homescreen)?
.with_page(&ConfirmHomescreen::Menu, content_menu)?
.with_page(&ConfirmHomescreen::Confirm, content_confirm)?;
Ok(res)
}

View File

@ -154,11 +154,11 @@ fn footer_update_fn(
footer.update_page_counter(ctx, current_page, total_pages);
}
pub fn new_continue_recovery(
first_screen: bool,
recovery_type: RecoveryType,
pub fn new_continue_recovery_homepage(
text: TString<'static>,
subtext: Option<TString<'static>>,
recovery_type: RecoveryType,
show_instructions: bool, // 1st screen of the recovery process
pages: Option<ParagraphVecLong<'static>>,
) -> Result<SwipeFlow, error::Error> {
let (title, cancel_btn, cancel_title, cancel_intro) = match recovery_type {
@ -179,7 +179,7 @@ pub fn new_continue_recovery(
let mut pars_main = ParagraphVecShort::new();
let footer_instruction;
let footer_description;
if first_screen {
if show_instructions {
pars_main.add(Paragraph::new(
&theme::TEXT_MAIN_GREY_EXTRA_LIGHT,
TR::recovery__enter_each_word,
@ -246,7 +246,7 @@ pub fn new_continue_recovery(
_ => None,
});
let res = if first_screen {
let res = if show_instructions {
let content_menu = Frame::left_aligned(
TString::empty(),
VerticalMenu::empty().danger(theme::ICON_CANCEL, cancel_btn.into()),

View File

@ -96,6 +96,7 @@ pub fn new_get_address(
account: Option<TString<'static>>,
path: Option<TString<'static>>,
xpubs: Obj, // TODO: get rid of Obj
title_success: TString<'static>,
br_code: u16,
br_name: TString<'static>,
) -> Result<SwipeFlow, error::Error> {
@ -141,7 +142,7 @@ pub fn new_get_address(
let content_confirmed = Frame::left_aligned(
TR::words__title_success.into(),
StatusScreen::new_success_timeout(TR::address__confirmed.into()),
StatusScreen::new_success_timeout(title_success),
)
.with_footer(TR::instructions__continue_in_app.into(), None)
.with_result_icon(theme::ICON_BULLET_CHECKMARK, theme::GREEN_LIGHT)

View File

@ -2,11 +2,12 @@ pub mod confirm_action;
#[cfg(feature = "universal_fw")]
pub mod confirm_fido;
pub mod confirm_firmware_update;
pub mod confirm_homescreen;
pub mod confirm_output;
pub mod confirm_reset;
pub mod confirm_set_new_pin;
pub mod confirm_summary;
pub mod continue_recovery;
pub mod continue_recovery_homepage;
pub mod get_address;
pub mod prompt_backup;
pub mod request_number;
@ -24,11 +25,12 @@ pub use confirm_action::{
#[cfg(feature = "universal_fw")]
pub use confirm_fido::new_confirm_fido;
pub use confirm_firmware_update::new_confirm_firmware_update;
pub use confirm_homescreen::new_confirm_homescreen;
pub use confirm_output::new_confirm_output;
pub use confirm_reset::new_confirm_reset;
pub use confirm_set_new_pin::SetNewPin;
pub use confirm_summary::new_confirm_summary;
pub use continue_recovery::new_continue_recovery;
pub use continue_recovery_homepage::new_continue_recovery_homepage;
pub use get_address::GetAddress;
pub use prompt_backup::PromptBackup;
pub use request_number::RequestNumber;

View File

@ -67,8 +67,6 @@ pub fn new_request_number(
max_count: u32,
description: TString<'static>,
info_closure: impl Fn(u32) -> TString<'static> + 'static,
br_code: u16,
br_name: TString<'static>,
) -> Result<SwipeFlow, error::Error> {
NUM_DISPLAYED.store(count as u16, Ordering::Relaxed);
@ -94,8 +92,7 @@ pub fn new_request_number(
NUM_DISPLAYED.store(n as u16, Ordering::Relaxed);
Some(FlowMsg::Choice(n as usize))
}
})
.one_button_request(ButtonRequest::from_num(br_code, br_name));
});
let content_menu = Frame::left_aligned(
TString::empty(),

View File

@ -78,15 +78,15 @@ fn footer_updating_func(
}
pub fn new_show_share_words(
title: TString<'static>,
subtitle: TString<'static>,
share_words_vec: Vec<TString<'static>, 33>,
description: Option<TString<'static>>,
subtitle: TString<'static>,
instructions_paragraphs: ParagraphVecShort<'static>,
text_footer: Option<TString<'static>>,
text_confirm: TString<'static>,
) -> Result<SwipeFlow, error::Error> {
let nwords = share_words_vec.len();
let paragraphs_spacing = 8;
let title = TR::reset__recovery_wallet_backup_title.into();
let content_instruction = Frame::left_aligned(
title,
@ -97,7 +97,7 @@ pub fn new_show_share_words(
),
)
.with_subtitle(TR::words__instructions.into())
.with_footer(TR::instructions__swipe_up.into(), description)
.with_footer(TR::instructions__swipe_up.into(), text_footer)
.with_swipe(Direction::Up, SwipeSettings::default())
.map(|msg| matches!(msg, FrameMsg::Content(_)).then_some(FlowMsg::Confirmed))
.one_button_request(ButtonRequestCode::ResetDevice.with_name("share_words"))

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -92,23 +92,24 @@ impl<'a> ShareWords<'a> {
fn render_words<'s>(&'s self, target: &mut impl Renderer<'s>) {
let mut y_offset = 0;
// Showing the word index and the words itself
for i in 0..WORDS_PER_PAGE {
for (word_idx, word) in self
.share_words
.iter()
.enumerate()
.skip(self.page_index * WORDS_PER_PAGE)
.take(WORDS_PER_PAGE)
{
let ordinal = word_idx + 1;
y_offset += NUMBER_FONT.line_height() + EXTRA_LINE_HEIGHT;
let index = self.word_index() + i;
if index >= self.share_words.len() {
break;
}
let word = &self.share_words[index];
let baseline = self.area.top_left() + Offset::y(y_offset);
let ordinal = uformat!("{}.", index + 1);
let base = self.area.top_left() + Offset::y(y_offset);
shape::Text::new(baseline + Offset::x(NUMBER_X_OFFSET), &ordinal)
let ordinal_txt = uformat!("{}.", ordinal);
shape::Text::new(base + Offset::x(NUMBER_X_OFFSET), &ordinal_txt)
.with_font(NUMBER_FONT)
.with_fg(theme::FG)
.render(target);
word.map(|w| {
shape::Text::new(baseline + Offset::x(WORD_X_OFFSET), w)
shape::Text::new(base + Offset::x(WORD_X_OFFSET), w)
.with_font(WORD_FONT)
.with_fg(theme::FG)
.render(target);
@ -170,13 +171,15 @@ impl<'a> crate::trace::Trace for ShareWords<'a> {
self.get_final_text()
} else {
let mut content = ShortString::new();
for i in 0..WORDS_PER_PAGE {
let index = self.word_index() + i;
if index >= self.share_words.len() {
break;
}
self.share_words[index]
.map(|word| unwrap!(uwrite!(content, "{}. {}\n", index + 1, word)));
for (word_idx, word) in self
.share_words
.iter()
.enumerate()
.skip(self.page_index * WORDS_PER_PAGE)
.take(WORDS_PER_PAGE)
{
let ordinal = word_idx + 1;
word.map(|w| unwrap!(uwrite!(content, "{}. {}\n", ordinal, w)));
}
content
};

File diff suppressed because it is too large Load Diff

View File

@ -12,6 +12,8 @@ mod screens;
pub mod theme;
pub struct ModelTRFeatures {}
#[cfg(feature = "micropython")]
pub mod ui_features_fw;
impl UIFeaturesCommon for ModelTRFeatures {

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,8 @@ mod progress;
mod result;
mod scroll;
mod set_brightness;
#[cfg(feature = "translations")]
mod share_words;
mod simple_page;
mod swipe;
mod welcome_screen;
@ -59,6 +61,8 @@ pub use progress::Progress;
pub use result::{ResultFooter, ResultScreen, ResultStyle};
pub use scroll::ScrollBar;
pub use set_brightness::SetBrightnessDialog;
#[cfg(feature = "translations")]
pub use share_words::ShareWords;
pub use simple_page::SimplePage;
pub use swipe::{Swipe, SwipeDirection};
pub use welcome_screen::WelcomeScreen;

View File

@ -17,8 +17,7 @@ use super::{
pub struct SetBrightnessDialog(NumberInputSliderDialog);
impl SetBrightnessDialog {
pub fn new(current: Option<u8>) -> Self {
let current = current.unwrap_or(theme::backlight::get_backlight_normal());
pub fn new(current: u8) -> Self {
Self(NumberInputSliderDialog::new(
theme::backlight::get_backlight_min() as u16,
theme::backlight::get_backlight_max() as u16,

View File

@ -0,0 +1,114 @@
use crate::{
strutil::TString,
ui::{
component::{Component, Event, EventCtx, Never, Paginate},
display::Font,
geometry::{Offset, Rect},
model_tt::theme,
shape::{self, Renderer},
},
};
use heapless::Vec;
use ufmt::uwrite;
const WORDS_PER_PAGE: usize = 4;
const TOP_PADDING_OFFSET: i16 = 13;
const WORD_FONT: Font = Font::MONO;
const MAX_WORDS: usize = 33; // super-shamir has 33 words, all other have less
/// Showing the given share words.
pub struct ShareWords<'a> {
area: Rect,
share_words: Vec<TString<'a>, MAX_WORDS>,
page_index: usize,
}
impl<'a> ShareWords<'a> {
pub fn new(share_words: Vec<TString<'a>, MAX_WORDS>) -> Self {
Self {
area: Rect::zero(),
share_words,
page_index: 0,
}
}
fn total_page_count(&self) -> usize {
(self.share_words.len() + WORDS_PER_PAGE - 1) / WORDS_PER_PAGE
}
}
impl<'a> Component for ShareWords<'a> {
type Msg = Never;
fn place(&mut self, bounds: Rect) -> Rect {
self.area = bounds;
bounds
}
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
None
}
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
let line_height = WORD_FONT.line_height();
let ordinal_largest_on_this_page =
(WORDS_PER_PAGE * (self.page_index + 1)).min(self.share_words.len());
let is_largest_double_digit = ordinal_largest_on_this_page >= 10;
let mut y_offset = self.area.top_left().y + TOP_PADDING_OFFSET;
for (word_idx, word) in self
.share_words
.iter()
.enumerate()
.skip(self.page_index * WORDS_PER_PAGE)
.take(WORDS_PER_PAGE)
{
let ordinal = word_idx + 1;
let base = self.area.top_left() + Offset::y(y_offset);
word.map(|w| {
let double_digit = ordinal >= 10;
let text_fmt = if double_digit || !is_largest_double_digit {
uformat!("{}. {}", ordinal, w)
} else {
uformat!(" {}. {}", ordinal, w)
};
shape::Text::new(base, &text_fmt)
.with_font(WORD_FONT)
.with_fg(theme::FG)
.render(target);
});
y_offset += line_height;
}
}
}
impl<'a> Paginate for ShareWords<'a> {
fn page_count(&self) -> usize {
self.total_page_count()
}
fn change_page(&mut self, active_page: usize) {
self.page_index = active_page;
}
}
// DEBUG-ONLY SECTION BELOW
#[cfg(feature = "ui_debug")]
impl<'a> crate::trace::Trace for ShareWords<'a> {
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
t.component("ShareWords");
let mut content = heapless::String::<64>::new();
for (word_idx, word) in self
.share_words
.iter()
.enumerate()
.skip(self.page_index * WORDS_PER_PAGE)
.take(WORDS_PER_PAGE)
{
let ordinal = word_idx + 1;
word.map(|w| unwrap!(uwrite!(content, "{}. {}\n", ordinal, w)));
}
t.string("screen_content", content.as_str().into());
}
}

File diff suppressed because it is too large Load Diff

View File

@ -19,6 +19,8 @@ use crate::ui::{
};
pub struct ModelTTFeatures;
#[cfg(feature = "micropython")]
pub mod ui_features_fw;
impl UIFeaturesCommon for ModelTTFeatures {

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,384 @@
use crate::{error::Error, micropython::gc::Gc, strutil::TString};
use crate::{
error::Error,
io::BinaryData,
micropython::{gc::Gc, list::List, obj::Obj},
strutil::TString,
};
use heapless::Vec;
use super::layout::obj::{LayoutMaybeTrace, LayoutObj};
use super::layout::{
obj::{LayoutMaybeTrace, LayoutObj},
util::RecoveryType,
};
pub trait UIFeaturesFirmware {
fn confirm_action(
title: TString<'static>,
action: Option<TString<'static>>,
description: Option<TString<'static>>,
subtitle: Option<TString<'static>>,
verb: Option<TString<'static>>,
verb_cancel: Option<TString<'static>>,
hold: bool,
hold_danger: bool,
reverse: bool,
prompt_screen: bool,
prompt_title: Option<TString<'static>>,
) -> Result<impl LayoutMaybeTrace, Error>;
fn confirm_address(
title: TString<'static>,
data: Obj, // TODO: replace Obj
description: Option<TString<'static>>,
extra: Option<TString<'static>>,
verb: Option<TString<'static>>,
chunkify: bool,
) -> Result<impl LayoutMaybeTrace, Error>;
fn confirm_blob(
title: TString<'static>,
data: Obj, // TODO: replace Obj
description: Option<TString<'static>>,
text_mono: bool,
extra: Option<TString<'static>>,
subtitle: Option<TString<'static>>,
verb: Option<TString<'static>>,
verb_cancel: Option<TString<'static>>,
verb_info: Option<TString<'static>>,
info: bool,
hold: bool,
chunkify: bool,
page_counter: bool,
prompt_screen: bool,
cancel: bool,
) -> Result<Gc<LayoutObj>, Error>; // TODO: return LayoutMaybeTrace
fn confirm_blob_intro(
title: TString<'static>,
data: Obj, // TODO: replace Obj
subtitle: Option<TString<'static>>,
verb: Option<TString<'static>>,
verb_cancel: Option<TString<'static>>,
chunkify: bool,
) -> Result<Gc<LayoutObj>, Error>; // TODO: return LayoutMaybeTrace
fn confirm_homescreen(
title: TString<'static>,
image: BinaryData<'static>,
) -> Result<impl LayoutMaybeTrace, Error>;
fn confirm_coinjoin(
max_rounds: TString<'static>,
max_feerate: TString<'static>,
) -> Result<impl LayoutMaybeTrace, Error>;
fn confirm_emphasized(
title: TString<'static>,
items: Obj, // TODO: replace Obj
verb: Option<TString<'static>>,
) -> Result<impl LayoutMaybeTrace, Error>;
fn confirm_fido(
title: TString<'static>,
app_name: TString<'static>,
icon: Option<TString<'static>>,
accounts: Gc<List>, // TODO: replace Gc<List>
) -> Result<impl LayoutMaybeTrace, Error>;
fn confirm_firmware_update(
description: TString<'static>,
fingerprint: TString<'static>,
) -> Result<impl LayoutMaybeTrace, Error>;
fn confirm_modify_fee(
title: TString<'static>,
sign: i32,
user_fee_change: TString<'static>,
total_fee_new: TString<'static>,
fee_rate_amount: Option<TString<'static>>,
) -> Result<impl LayoutMaybeTrace, Error>;
fn confirm_modify_output(
sign: i32,
amount_change: TString<'static>,
amount_new: TString<'static>,
) -> Result<impl LayoutMaybeTrace, Error>;
fn confirm_more(
title: TString<'static>,
button: TString<'static>,
button_style_confirm: bool,
items: Obj, // TODO: replace Obj
) -> Result<impl LayoutMaybeTrace, Error>;
fn confirm_properties(
title: TString<'static>,
items: Obj, // TODO: replace Obj`
hold: bool,
) -> Result<impl LayoutMaybeTrace, Error>;
fn confirm_reset_device(recovery: bool) -> Result<impl LayoutMaybeTrace, Error>;
fn confirm_summary(
amount: TString<'static>,
amount_label: TString<'static>,
fee: TString<'static>,
fee_label: TString<'static>,
title: Option<TString<'static>>,
account_items: Option<Obj>, // TODO: replace Obj
extra_items: Option<Obj>, // TODO: replace Obj
extra_title: Option<TString<'static>>,
verb_cancel: Option<TString<'static>>,
) -> Result<impl LayoutMaybeTrace, Error>;
fn confirm_value(
title: TString<'static>,
value: Obj, // TODO: replace Obj
description: Option<TString<'static>>,
subtitle: Option<TString<'static>>,
verb: Option<TString<'static>>,
verb_info: Option<TString<'static>>,
verb_cancel: Option<TString<'static>>,
info_button: bool,
hold: bool,
chunkify: bool,
text_mono: bool,
) -> Result<Gc<LayoutObj>, Error>; // TODO: return LayoutMaybeTrace
fn confirm_with_info(
title: TString<'static>,
button: TString<'static>,
info_button: TString<'static>,
verb_cancel: Option<TString<'static>>,
items: Obj, // TODO: replace Obj
) -> Result<impl LayoutMaybeTrace, Error>;
fn continue_recovery_homepage(
text: TString<'static>,
subtext: Option<TString<'static>>,
button: Option<TString<'static>>,
recovery_type: RecoveryType,
show_instructions: bool,
remaining_shares: Option<Obj>, // TODO: replace Obj
) -> Result<Gc<LayoutObj>, Error>; // TODO: return LayoutMaybeTrace
fn check_homescreen_format(image: BinaryData, accept_toif: bool) -> bool;
fn flow_confirm_output(
title: Option<TString<'static>>,
subtitle: Option<TString<'static>>,
message: Obj, // TODO: replace Obj
amount: Option<Obj>, // TODO: replace Obj
chunkify: bool,
text_mono: bool,
account: Option<TString<'static>>,
account_path: Option<TString<'static>>,
br_code: u16,
br_name: TString<'static>,
address: Option<Obj>, // TODO: replace Obj
address_title: Option<TString<'static>>,
summary_items: Option<Obj>, // TODO: replace Obj
fee_items: Option<Obj>, // TODO: replace Obj
summary_title: Option<TString<'static>>,
summary_br_code: Option<u16>,
summary_br_name: Option<TString<'static>>,
cancel_text: Option<TString<'static>>,
) -> Result<impl LayoutMaybeTrace, Error>;
fn flow_confirm_set_new_pin(
title: TString<'static>,
description: TString<'static>,
) -> Result<impl LayoutMaybeTrace, Error>;
fn flow_get_address(
address: Obj, // TODO: replace Obj
title: TString<'static>,
description: Option<TString<'static>>,
extra: Option<TString<'static>>,
chunkify: bool,
address_qr: TString<'static>,
case_sensitive: bool,
account: Option<TString<'static>>,
path: Option<TString<'static>>,
xpubs: Obj, // TODO: replace Obj
title_success: TString<'static>,
br_code: u16,
br_name: TString<'static>,
) -> Result<impl LayoutMaybeTrace, Error>;
// TODO: this is TR specific and used only in confirm_set_new_pin
fn multiple_pages_texts(
title: TString<'static>,
verb: TString<'static>,
items: Gc<List>,
) -> Result<impl LayoutMaybeTrace, Error>;
fn prompt_backup() -> Result<impl LayoutMaybeTrace, Error>;
fn request_bip39(
prompt: TString<'static>,
prefill_word: TString<'static>,
can_go_back: bool,
) -> Result<impl LayoutMaybeTrace, Error>;
fn request_slip39(
prompt: TString<'static>,
prefill_word: TString<'static>,
can_go_back: bool,
) -> Result<impl LayoutMaybeTrace, Error>;
fn request_number(
title: TString<'static>,
count: u32,
min_count: u32,
max_count: u32,
description: Option<TString<'static>>,
more_info_callback: Option<impl Fn(u32) -> TString<'static> + 'static>,
) -> Result<impl LayoutMaybeTrace, Error>;
fn request_pin(
prompt: TString<'static>,
subprompt: TString<'static>,
allow_cancel: bool,
warning: bool,
) -> Result<impl LayoutMaybeTrace, Error>;
fn request_passphrase(
prompt: TString<'static>,
max_len: u32,
) -> Result<impl LayoutMaybeTrace, Error>;
fn select_word(
title: TString<'static>,
description: TString<'static>,
words: [TString<'static>; 3],
) -> Result<impl LayoutMaybeTrace, Error>;
fn select_word_count(recovery_type: RecoveryType) -> Result<impl LayoutMaybeTrace, Error>;
fn set_brightness(current_brightness: Option<u8>) -> Result<impl LayoutMaybeTrace, Error>;
fn show_address_details(
qr_title: TString<'static>,
address: TString<'static>,
case_sensitive: bool,
details_title: TString<'static>,
account: Option<TString<'static>>,
path: Option<TString<'static>>,
xpubs: Obj, // TODO: replace Obj
) -> Result<impl LayoutMaybeTrace, Error>;
fn show_checklist(
title: TString<'static>,
button: TString<'static>,
active: usize,
items: [TString<'static>; 3],
) -> Result<impl LayoutMaybeTrace, Error>;
fn show_danger(
title: TString<'static>,
description: TString<'static>,
value: TString<'static>,
verb_cancel: Option<TString<'static>>,
) -> Result<impl LayoutMaybeTrace, Error>;
fn show_error(
title: TString<'static>,
button: TString<'static>,
description: TString<'static>,
allow_cancel: bool,
time_ms: u32,
) -> Result<Gc<LayoutObj>, Error>; // TODO: return LayoutMaybeTrace
fn show_group_share_success(
lines: [TString<'static>; 4],
) -> Result<impl LayoutMaybeTrace, Error>;
fn show_homescreen(
label: TString<'static>,
hold: bool,
notification: Option<TString<'static>>,
notification_level: u8,
) -> Result<impl LayoutMaybeTrace, Error>;
fn show_info(
title: TString<'static>,
description: TString<'static>,
button: TString<'static>,
time_ms: u32,
) -> Result<Gc<LayoutObj>, Error>;
) -> Result<Gc<LayoutObj>, Error>; // TODO: return LayoutMaybeTrace
fn show_info_with_cancel(
title: TString<'static>,
items: Obj, // TODO: replace Obj
horizontal: bool,
chunkify: bool,
) -> Result<impl LayoutMaybeTrace, Error>;
fn show_lockscreen(
label: TString<'static>,
bootscreen: bool,
coinjoin_authorized: bool,
) -> Result<impl LayoutMaybeTrace, Error>;
fn show_mismatch(title: TString<'static>) -> Result<impl LayoutMaybeTrace, Error>;
fn show_progress(
description: TString<'static>,
indeterminate: bool,
title: Option<TString<'static>>,
) -> Result<impl LayoutMaybeTrace, Error>;
fn show_progress_coinjoin(
title: TString<'static>,
indeterminate: bool,
time_ms: u32,
skip_first_paint: bool,
) -> Result<Gc<LayoutObj>, Error>; // TODO: return LayoutMaybeTrace
fn show_remaining_shares(
pages_iterable: Obj, // TODO: replace Obj
) -> Result<impl LayoutMaybeTrace, Error>;
fn show_share_words(
words: Vec<TString<'static>, 33>,
title: Option<TString<'static>>,
) -> Result<impl LayoutMaybeTrace, Error>;
// TODO: merge with `show_share_words` instead of having specific version for mercury
fn show_share_words_mercury(
words: Vec<TString<'static>, 33>,
subtitle: Option<TString<'static>>,
instructions: Obj, // TODO: replace Obj
text_footer: Option<TString<'static>>, // footer description at instruction screen
text_confirm: TString<'static>,
) -> Result<impl LayoutMaybeTrace, Error>;
fn show_simple(
text: TString<'static>,
title: Option<TString<'static>>,
button: Option<TString<'static>>,
) -> Result<Gc<LayoutObj>, Error>; // TODO: return LayoutMaybeTrace
fn show_success(
title: TString<'static>,
button: TString<'static>,
description: TString<'static>,
allow_cancel: bool,
time_ms: u32,
) -> Result<Gc<LayoutObj>, Error>; // TODO: return LayoutMaybeTrace
fn show_wait_text(text: TString<'static>) -> Result<impl LayoutMaybeTrace, Error>;
fn show_warning(
title: TString<'static>,
button: TString<'static>,
value: TString<'static>,
description: TString<'static>,
allow_cancel: bool,
time_ms: u32,
danger: bool,
) -> Result<Gc<LayoutObj>, Error>; // TODO: return LayoutMaybeTrace
fn tutorial() -> Result<impl LayoutMaybeTrace, Error>;
}

File diff suppressed because it is too large Load Diff

View File

@ -68,6 +68,466 @@ CANCELLED: UiResult
INFO: UiResult
# rust/src/ui/api/firmware_upy.rs
def check_homescreen_format(data: bytes) -> bool:
"""Check homescreen format and dimensions."""
# rust/src/ui/api/firmware_upy.rs
def disable_animation(disable: bool) -> None:
"""Disable animations, debug builds only."""
# rust/src/ui/api/firmware_upy.rs
def confirm_action(
*,
title: str,
action: str | None,
description: str | None,
subtitle: str | None = None,
verb: str | None = None,
verb_cancel: str | None = None,
hold: bool = False,
hold_danger: bool = False,
reverse: bool = False,
prompt_screen: bool = False,
prompt_title: str | None = None,
) -> LayoutObj[UiResult]:
"""Confirm action."""
# rust/src/ui/api/firmware_upy.rs
def confirm_address(
*,
title: str,
data: str | bytes,
description: str | None,
extra: str | None,
verb: str | None = None,
chunkify: bool = False,
) -> LayoutObj[UiResult]:
"""Confirm address."""
# rust/src/ui/api/firmware_upy.rs
def confirm_blob(
*,
title: str,
data: str | bytes,
description: str | None,
text_mono: bool = True,
extra: str | None = None,
subtitle: str | None = None,
verb: str | None = None,
verb_cancel: str | None = None,
verb_info: str | None = None,
info: bool = True,
hold: bool = False,
chunkify: bool = False,
page_counter: bool = False,
prompt_screen: bool = False,
cancel: bool = False,
) -> LayoutObj[UiResult]:
"""Confirm byte sequence data."""
# rust/src/ui/api/firmware_upy.rs
def confirm_blob_intro(
*,
title: str,
data: str | bytes,
subtitle: str | None = None,
verb: str | None = None,
verb_cancel: str | None = None,
chunkify: bool = False,
) -> LayoutObj[UiResult]:
"""Confirm byte sequence data by showing only the first page of the data
and instructing the user to access the menu in order to view all the data,
which can then be confirmed using confirm_blob."""
# rust/src/ui/api/firmware_upy.rs
def confirm_coinjoin(
*,
max_rounds: str,
max_feerate: str,
) -> LayoutObj[UiResult]:
"""Confirm coinjoin authorization."""
# rust/src/ui/api/firmware_upy.rs
def confirm_emphasized(
*,
title: str,
items: Iterable[str | tuple[bool, str]],
verb: str | None = None,
) -> LayoutObj[UiResult]:
"""Confirm formatted text that has been pre-split in python. For tuples
the first component is a bool indicating whether this part is emphasized."""
# rust/src/ui/api/firmware_upy.rs
def confirm_fido(
*,
title: str,
app_name: str,
icon_name: str | None,
accounts: list[str | None],
) -> LayoutObj[int | UiResult]:
"""FIDO confirmation.
Returns page index in case of confirmation and CANCELLED otherwise.
"""
# rust/src/ui/api/firmware_upy.rs
def confirm_firmware_update(
*,
description: str,
fingerprint: str,
) -> LayoutObj[UiResult]:
"""Ask whether to update firmware, optionally show fingerprint."""
# rust/src/ui/api/firmware_upy.rs
def confirm_homescreen(
*,
title: str,
image: bytes,
) -> LayoutObj[UiResult]:
"""Confirm homescreen."""
# rust/src/ui/api/firmware_upy.rs
def confirm_modify_fee(
*,
title: str,
sign: int,
user_fee_change: str,
total_fee_new: str,
fee_rate_amount: str | None,
) -> LayoutObj[UiResult]:
"""Decrease or increase transaction fee."""
# rust/src/ui/api/firmware_upy.rs
def confirm_modify_output(
*,
sign: int,
amount_change: str,
amount_new: str,
) -> LayoutObj[UiResult]:
"""Decrease or increase output amount."""
# rust/src/ui/api/firmware_upy.rs
def confirm_more(
*,
title: str,
button: str,
button_style_confirm: bool = False,
items: Iterable[tuple[int, str | bytes]],
) -> LayoutObj[UiResult]:
"""Confirm long content with the possibility to go back from any page.
Meant to be used with confirm_with_info on model TT and TR."""
# rust/src/ui/api/firmware_upy.rs
def confirm_properties(
*,
title: str,
items: list[tuple[str | None, str | bytes | None, bool]],
hold: bool = False,
) -> LayoutObj[UiResult]:
"""Confirm list of key-value pairs. The third component in the tuple should be True if
the value is to be rendered as binary with monospace font, False otherwise."""
# rust/src/ui/api/firmware_upy.rs
def confirm_reset_device(recovery: bool) -> LayoutObj[UiResult]:
"""Confirm TOS before creating wallet creation or wallet recovery."""
# rust/src/ui/api/firmware_upy.rs
def confirm_summary(
*,
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/api/firmware_upy.rs
def confirm_value(
*,
title: str,
value: str,
description: str | None,
subtitle: str | None,
verb: str | None = None,
verb_info: str | None = None,
verb_cancel: str | None = None,
info_button: bool = False,
hold: bool = False,
chunkify: bool = False,
text_mono: bool = True,
) -> LayoutObj[UiResult]:
"""Confirm value. Merge of confirm_total and confirm_output."""
# rust/src/ui/api/firmware_upy.rs
def confirm_with_info(
*,
title: str,
button: str,
info_button: str,
verb_cancel: str | None = None,
items: Iterable[tuple[int, str | bytes]],
) -> LayoutObj[UiResult]:
"""Confirm given items but with third button. Always single page
without scrolling. In mercury, the button is placed in
context menu."""
# rust/src/ui/api/firmware_upy.rs
def continue_recovery_homepage(
*,
text: str,
subtext: str | None,
button: str | None,
recovery_type: RecoveryType,
show_instructions: bool = False, # unused on TT
remaining_shares: Iterable[tuple[str, str]] | None = None,
) -> LayoutObj[UiResult]:
"""Device recovery homescreen."""
# rust/src/ui/api/firmware_upy.rs
def flow_confirm_output(
*,
title: str | None,
subtitle: str | None,
message: str,
amount: str | None,
chunkify: bool,
text_mono: bool,
account: str | None,
account_path: str | None,
br_code: ButtonRequestType,
br_name: str,
address: str | None,
address_title: str | None,
summary_items: Iterable[tuple[str, str]] | None = None,
fee_items: Iterable[tuple[str, str]] | None = None,
summary_title: str | None = None,
summary_br_code: ButtonRequestType | None = None,
summary_br_name: str | None = None,
cancel_text: str | None = None,
) -> LayoutObj[UiResult]:
"""Confirm the recipient, (optionally) confirm the amount and (optionally) confirm the summary and present a Hold to Sign page."""
# rust/src/ui/api/firmware_upy.rs
def flow_confirm_set_new_pin(
*,
title: str,
description: str,
) -> LayoutObj[UiResult]:
"""Confirm new PIN setup with an option to cancel action."""
# rust/src/ui/api/firmware_upy.rs
def flow_get_address(
*,
address: str | bytes,
title: str,
description: str | None,
extra: str | None,
chunkify: bool,
address_qr: str,
case_sensitive: bool,
account: str | None,
path: str | None,
xpubs: list[tuple[str, str]],
title_success: str,
br_code: ButtonRequestType,
br_name: str,
) -> LayoutObj[UiResult]:
"""Get address / receive funds."""
# rust/src/ui/api/firmware_upy.rs
def multiple_pages_texts(
*,
title: str,
verb: str,
items: list[str],
) -> LayoutObj[UiResult]:
"""Show multiple texts, each on its own page. TR specific."""
# rust/src/ui/api/firmware_upy.rs
def prompt_backup() -> LayoutObj[UiResult]:
"""Strongly recommend user to do a backup."""
# rust/src/ui/api/firmware_upy.rs
def request_bip39(
*,
prompt: str,
prefill_word: str,
can_go_back: bool,
) -> LayoutObj[str]:
"""BIP39 word input keyboard."""
# rust/src/ui/api/firmware_upy.rs
def request_slip39(
*,
prompt: str,
prefill_word: str,
can_go_back: bool,
) -> LayoutObj[str]:
"""SLIP39 word input keyboard."""
# rust/src/ui/api/firmware_upy.rs
def request_number(
*,
title: str,
count: int,
min_count: int,
max_count: int,
description: str | None = None,
more_info_callback: Callable[[int], str] | None = None,
) -> LayoutObj[tuple[UiResult, int]]:
"""Number input with + and - buttons, optional static description and optional dynamic
description."""
# rust/src/ui/api/firmware_upy.rs
def request_pin(
*,
prompt: str,
subprompt: str,
allow_cancel: bool = True,
wrong_pin: bool = False,
) -> LayoutObj[str | UiResult]:
"""Request pin on device."""
# rust/src/ui/api/firmware_upy.rs
def request_passphrase(
*,
prompt: str,
max_len: int,
) -> LayoutObj[str | UiResult]:
"""Passphrase input keyboard."""
# rust/src/ui/api/firmware_upy.rs
def select_word(
*,
title: str,
description: str,
words: Iterable[str],
) -> LayoutObj[int]:
"""Select mnemonic word from three possibilities - seed check after backup. The
iterable must be of exact size. Returns index in range `0..3`."""
# rust/src/ui/api/firmware_upy.rs
def select_word_count(
*,
recovery_type: RecoveryType,
) -> LayoutObj[int | str]: # TR returns str
"""Select a mnemonic word count from the options: 12, 18, 20, 24, or 33.
For unlocking a repeated backup, select from 20 or 33."""
# rust/src/ui/api/firmware_upy.rs
def set_brightness(
*,
current: int | None = None
) -> LayoutObj[UiResult]:
"""Show the brightness configuration dialog."""
# rust/src/ui/api/firmware_upy.rs
def show_address_details(
*,
qr_title: str,
address: str,
case_sensitive: bool,
details_title: str,
account: str | None,
path: str | None,
xpubs: list[tuple[str, str]],
) -> LayoutObj[UiResult]:
"""Show address details - QR code, account, path, cosigner xpubs."""
# rust/src/ui/api/firmware_upy.rs
def show_checklist(
*,
title: str,
items: Iterable[str],
active: int,
button: str,
) -> LayoutObj[UiResult]:
"""Checklist of backup steps. Active index is highlighted, previous items have check
mark next to them. Limited to 3 items."""
# rust/src/ui/api/firmware_upy.rs
def show_danger(
*,
title: str,
description: str,
value: str = "",
verb_cancel: str | None = None,
) -> LayoutObj[UiResult]:
"""Warning modal that makes it easier to cancel than to continue."""
# rust/src/ui/api/firmware_upy.rs
def show_error(
*,
title: str,
button: str,
description: str = "",
allow_cancel: bool = True,
time_ms: int = 0,
) -> LayoutObj[UiResult]:
"""Error modal. No buttons shown when `button` is empty string."""
# rust/src/ui/api/firmware_upy.rs
def show_group_share_success(
*,
lines: Iterable[str],
) -> LayoutObj[UiResult]:
"""Shown after successfully finishing a group."""
# rust/src/ui/api/firmware_upy.rs
def show_homescreen(
*,
label: str | None,
hold: bool,
notification: str | None,
notification_level: int = 0,
skip_first_paint: bool,
) -> LayoutObj[UiResult]:
"""Idle homescreen."""
# rust/src/ui/api/firmware_upy.rs
def show_info(
*,
@ -79,6 +539,133 @@ def show_info(
"""Info screen."""
# rust/src/ui/api/firmware_upy.rs
def show_info_with_cancel(
*,
title: str,
items: Iterable[Tuple[str, str]],
horizontal: bool = False,
chunkify: bool = False,
) -> LayoutObj[UiResult]:
"""Show metadata for outgoing transaction."""
# rust/src/ui/api/firmware_upy.rs
def show_lockscreen(
*,
label: str | None,
bootscreen: bool,
skip_first_paint: bool,
coinjoin_authorized: bool = False,
) -> LayoutObj[UiResult]:
"""Homescreen for locked device."""
# rust/src/ui/api/firmware_upy.rs
def show_mismatch(*, title: str) -> LayoutObj[UiResult]:
"""Warning of receiving address mismatch."""
# rust/src/ui/api/firmware_upy.rs
def show_progress(
*,
description: str,
indeterminate: bool = False,
title: str | None = None,
) -> LayoutObj[UiResult]:
"""Show progress loader. Please note that the number of lines reserved on screen for
description is determined at construction time. If you want multiline descriptions
make sure the initial description has at least that amount of lines."""
# rust/src/ui/api/firmware_upy.rs
def show_progress_coinjoin(
*,
title: str,
indeterminate: bool = False,
time_ms: int = 0,
skip_first_paint: bool = False,
) -> LayoutObj[UiResult]:
"""Show progress loader for coinjoin. Returns CANCELLED after a specified time when
time_ms timeout is passed."""
# rust/src/ui/api/firmware_upy.rs
def show_remaining_shares(
*,
pages: Iterable[tuple[str, str]],
) -> LayoutObj[UiResult]:
"""Shows SLIP39 state after info button is pressed on `confirm_recovery`."""
# rust/src/ui/api/firmware_upy.rs
def show_share_words(
*,
words: Iterable[str],
title: str | None = None,
) -> LayoutObj[UiResult]:
"""Show mnemonic for backup."""
# rust/src/ui/api/firmware_upy.rs
def show_share_words_mercury(
*,
words: Iterable[str],
subtitle: str | None,
instructions: Iterable[str],
text_footer: str | None,
text_confirm: str,
) -> LayoutObj[UiResult]:
"""Show mnemonic for wallet backup preceded by an instruction screen and followed by a
confirmation screen."""
# rust/src/ui/api/firmware_upy.rs
def show_simple(
*,
text: str,
title: str | None = None,
button: str | None = None,
) -> LayoutObj[UiResult]:
"""Simple dialog with text. TT: optional button."""
# rust/src/ui/api/firmware_upy.rs
def show_success(
*,
title: str,
button: str,
description: str = "",
allow_cancel: bool = True,
time_ms: int = 0,
) -> LayoutObj[UiResult]:
"""Success modal. No buttons shown when `button` is empty string."""
# rust/src/ui/api/firmware_upy.rs
def show_wait_text(message: str, /) -> LayoutObj[None]:
"""Show single-line text in the middle of the screen."""
# rust/src/ui/api/firmware_upy.rs
def show_warning(
*,
title: str,
button: str,
value: str = "",
description: str = "",
allow_cancel: bool = True,
time_ms: int = 0,
danger: bool = False, # unused on TT
) -> LayoutObj[UiResult]:
"""Warning modal. TT: No buttons shown when `button` is empty string. TR: middle button and centered text."""
# rust/src/ui/api/firmware_upy.rs
def tutorial() -> LayoutObj[UiResult]:
"""Show user how to interact with the device."""
# rust/src/ui/api/firmware_upy.rs
class BacklightLevels:
"""Backlight levels. Values dynamically update based on user settings."""

View File

@ -1,7 +1,7 @@
from typing import TYPE_CHECKING
import storage.device as storage_device
import trezorui2
import trezorui_api
from trezor import TR, utils
from trezor.enums import ButtonRequestType, DisplayRotation
from trezor.ui.layouts import confirm_action
@ -25,7 +25,7 @@ def _validate_homescreen(homescreen: bytes) -> None:
raise DataError(
f"Homescreen is too large, maximum size is {storage_device.HOMESCREEN_MAXSIZE} bytes"
)
if not trezorui2.check_homescreen_format(homescreen):
if not trezorui_api.check_homescreen_format(homescreen):
raise DataError("Wrong homescreen format")

View File

@ -67,7 +67,7 @@ async def recovery_device(msg: RecoveryDevice) -> Success:
return await recovery_process()
if recovery_type == RecoveryType.NormalRecovery:
await confirm_reset_device(TR.recovery__title_recover, recovery=True)
await confirm_reset_device(recovery=True)
# wipe storage to make sure the device is in a clear state
storage.reset()

View File

@ -55,7 +55,7 @@ async def reset_device(msg: ResetDevice) -> Success:
_validate_reset_device(msg)
# make sure user knows they're setting up a new wallet
await confirm_reset_device(TR.reset__title_create_wallet)
await confirm_reset_device()
# Rendering empty loader so users do not feel a freezing screen
render_empty_loader(config.StorageMessage.PROCESSING_MSG)

View File

@ -24,7 +24,9 @@ else:
if __debug__:
trezorui2.disable_animation(utils.DISABLE_ANIMATION)
from trezorui_api import disable_animation
disable_animation(utils.DISABLE_ANIMATION)
# all rendering is done through a singleton of `Display`

View File

@ -1,7 +1,6 @@
from typing import TYPE_CHECKING
import storage.cache as storage_cache
import trezorui2
import trezorui_api
from storage.cache_common import APP_COMMON_BUSY_DEADLINE_MS
from trezor import TR, ui
@ -57,7 +56,7 @@ class Homescreen(HomescreenBase):
level = 0
super().__init__(
layout=trezorui2.show_homescreen(
layout=trezorui_api.show_homescreen(
label=label,
notification=notification,
notification_level=level,
@ -97,7 +96,7 @@ class Lockscreen(HomescreenBase):
not bootscreen and storage_cache.homescreen_shown is self.RENDER_INDICATOR
)
super().__init__(
layout=trezorui2.show_lockscreen(
layout=trezorui_api.show_lockscreen(
label=label,
bootscreen=bootscreen,
skip_first_paint=skip,
@ -118,7 +117,7 @@ class Busyscreen(HomescreenBase):
def __init__(self, delay_ms: int) -> None:
super().__init__(
layout=trezorui2.show_progress_coinjoin(
layout=trezorui_api.show_progress_coinjoin(
title=TR.coinjoin__waiting_for_others,
indeterminate=True,
time_ms=delay_ms,

View File

@ -44,7 +44,7 @@ def confirm_action(
description = description.format(description_param)
return raise_if_not_confirmed(
trezorui2.confirm_action(
trezorui_api.confirm_action(
title=title,
action=action,
description=description,
@ -74,12 +74,11 @@ def confirm_single(
# Placeholders are coming from translations in form of {0}
template_str = "{0}"
if template_str not in description:
template_str = "{}"
assert template_str in description
begin, _separator, end = description.partition(template_str)
return raise_if_not_confirmed(
trezorui2.confirm_emphasized(
trezorui_api.confirm_emphasized(
title=title,
items=(begin, (True, description_param), end),
verb=verb,
@ -89,13 +88,15 @@ def confirm_single(
)
def confirm_reset_device(_title: str, recovery: bool = False) -> Awaitable[None]:
return raise_if_not_confirmed(trezorui2.flow_confirm_reset(recovery=recovery), None)
def confirm_reset_device(recovery: bool = False) -> Awaitable[None]:
return raise_if_not_confirmed(
trezorui_api.confirm_reset_device(recovery=recovery), None
)
async def show_wallet_created_success() -> None:
await interact(
trezorui2.show_success(title=TR.backup__new_wallet_created, description=""),
trezorui_api.show_success(title=TR.backup__new_wallet_created, button=""),
"backup_device",
ButtonRequestType.ResetDevice,
)
@ -103,7 +104,7 @@ async def show_wallet_created_success() -> None:
async def prompt_backup() -> bool:
result = await interact(
trezorui2.flow_prompt_backup(),
trezorui_api.prompt_backup(),
"backup_device",
ButtonRequestType.ResetDevice,
raise_on_cancel=None,
@ -140,7 +141,7 @@ def confirm_multisig_warning() -> Awaitable[None]:
def confirm_multisig_different_paths_warning() -> Awaitable[None]:
return raise_if_not_confirmed(
trezorui2.show_danger(
trezorui_api.show_danger(
title=f"{TR.words__important}!",
description="Using different paths for different XPUBs.",
),
@ -158,7 +159,7 @@ def confirm_homescreen(
workflow.close_others()
return raise_if_not_confirmed(
trezorui2.confirm_homescreen(
trezorui_api.confirm_homescreen(
title=TR.homescreen__title_set,
image=image,
),
@ -242,7 +243,7 @@ async def show_address(
)
await raise_if_not_confirmed(
trezorui2.flow_get_address(
trezorui_api.flow_get_address(
address=address,
title=title or TR.address__title_receive_address,
description=network or "",
@ -293,7 +294,7 @@ async def show_error_and_raise(
) -> NoReturn:
button = button or TR.buttons__try_again # def_arg
await interact(
trezorui2.show_error(
trezorui_api.show_error(
title=subheader or "",
description=content,
button=button,
@ -315,7 +316,7 @@ def show_warning(
) -> Awaitable[None]:
button = button or TR.buttons__continue # def_arg
return raise_if_not_confirmed(
trezorui2.show_warning(
trezorui_api.show_warning(
title=TR.words__important,
value=content,
button=subheader or TR.words__continue_anyway_question,
@ -337,7 +338,7 @@ def show_danger(
title = title or TR.words__warning
verb_cancel = verb_cancel or TR.buttons__cancel
return raise_if_not_confirmed(
trezorui2.show_danger(
trezorui_api.show_danger(
title=title,
description=content,
value=(value or ""),
@ -355,8 +356,9 @@ def show_success(
button: str | None = None,
) -> Awaitable[None]:
return raise_if_not_confirmed(
trezorui2.show_success(
trezorui_api.show_success(
title=content,
button="",
description=subheader if subheader else "",
),
br_name,
@ -387,7 +389,7 @@ async def confirm_output(
title = TR.send__title_sending_to
await raise_if_not_confirmed(
trezorui2.flow_confirm_output(
trezorui_api.flow_confirm_output(
title=TR.words__address,
subtitle=title,
message=address,
@ -422,7 +424,7 @@ async def should_show_payment_request_details(
Raises ActionCancelled if the user cancels.
"""
result = await interact(
trezorui2.confirm_with_info(
trezorui_api.confirm_with_info(
title=TR.send__title_sending,
items=[(ui.NORMAL, f"{amount} to\n{recipient_name}")]
+ [(ui.NORMAL, memo) for memo in memos],
@ -459,7 +461,7 @@ async def should_show_more(
confirm = TR.buttons__confirm
result = await interact(
trezorui2.confirm_with_info(
trezorui_api.confirm_with_info(
title=title,
items=para,
button=confirm,
@ -495,7 +497,7 @@ def confirm_blob(
prompt_screen: bool = True,
) -> Awaitable[None]:
if ask_pagination:
main_layout = trezorui2.confirm_blob_intro(
main_layout = trezorui_api.confirm_blob_intro(
title=title,
data=data,
subtitle=description,
@ -503,7 +505,7 @@ def confirm_blob(
verb_cancel=verb_cancel,
chunkify=chunkify,
)
info_layout = trezorui2.confirm_blob(
info_layout = trezorui_api.confirm_blob(
title=title,
data=data,
subtitle=description,
@ -527,7 +529,7 @@ def confirm_blob(
info_layout_can_confirm=True,
)
else:
layout = trezorui2.confirm_blob(
layout = trezorui_api.confirm_blob(
title=title,
data=data,
description=description,
@ -626,14 +628,14 @@ def confirm_value(
raise ValueError("Either verb or hold=True must be set")
info_items = info_items or []
info_layout = trezorui2.show_info_with_cancel(
info_layout = trezorui_api.show_info_with_cancel(
title=info_title if info_title else TR.words__title_information,
items=info_items,
chunkify=chunkify_info,
)
return with_info(
trezorui2.confirm_value(
trezorui_api.confirm_value(
title=title,
subtitle=subtitle,
description=description,
@ -661,7 +663,7 @@ def confirm_properties(
items = [(prop[0], prop[1], isinstance(prop[1], bytes)) for prop in props]
return raise_if_not_confirmed(
trezorui2.confirm_properties(
trezorui_api.confirm_properties(
title=title,
items=items,
hold=hold,
@ -697,7 +699,7 @@ def confirm_total(
fee_items.append((TR.confirm_total__fee_rate, fee_rate_amount))
return raise_if_not_confirmed(
trezorui2.confirm_summary(
trezorui_api.confirm_summary(
amount=total_amount,
amount_label=total_label,
fee=fee_amount,
@ -727,7 +729,7 @@ def _confirm_summary(
title = title or TR.words__title_summary # def_arg
return raise_if_not_confirmed(
trezorui2.confirm_summary(
trezorui_api.confirm_summary(
amount=amount,
amount_label=amount_label,
fee=fee,
@ -764,7 +766,7 @@ if not utils.BITCOIN_ONLY:
chunkify: bool = False,
) -> None:
await raise_if_not_confirmed(
trezorui2.flow_confirm_output(
trezorui_api.flow_confirm_output(
title=TR.words__address,
subtitle=(
TR.words__recipient
@ -817,7 +819,7 @@ if not utils.BITCOIN_ONLY:
(TR.send__maximum_fee, maximum_fee),
)
await raise_if_not_confirmed(
trezorui2.flow_confirm_output(
trezorui_api.flow_confirm_output(
title=verb,
subtitle=None,
message=intro_question,
@ -935,14 +937,14 @@ async def confirm_modify_output(
amount_change: str,
amount_new: str,
) -> None:
address_layout = trezorui2.confirm_blob(
address_layout = trezorui_api.confirm_blob(
title=TR.modify_amount__title,
data=address,
verb=TR.buttons__continue,
verb_cancel=None,
description=f"{TR.words__address}:",
)
modify_layout = trezorui2.confirm_modify_output(
modify_layout = trezorui_api.confirm_modify_output(
sign=sign,
amount_change=amount_change,
amount_new=amount_new,
@ -974,7 +976,7 @@ def confirm_modify_fee(
total_fee_new: str,
fee_rate_amount: str | None = None,
) -> Awaitable[None]:
fee_layout = trezorui2.confirm_modify_fee(
fee_layout = trezorui_api.confirm_modify_fee(
title=title,
sign=sign,
user_fee_change=user_fee_change,
@ -984,7 +986,7 @@ def confirm_modify_fee(
items: list[tuple[str, str]] = []
if fee_rate_amount:
items.append((TR.bitcoin__new_fee_rate, fee_rate_amount))
info_layout = trezorui2.show_info_with_cancel(
info_layout = trezorui_api.show_info_with_cancel(
title=TR.confirm_total__title_fee,
items=items,
)
@ -993,7 +995,7 @@ def confirm_modify_fee(
def confirm_coinjoin(max_rounds: int, max_fee_per_vbyte: str) -> Awaitable[None]:
return raise_if_not_confirmed(
trezorui2.confirm_coinjoin(
trezorui_api.confirm_coinjoin(
max_rounds=str(max_rounds),
max_feerate=max_fee_per_vbyte,
),
@ -1030,7 +1032,7 @@ async def confirm_signverify(
address_title = TR.sign_message__confirm_address
br_name = "sign_message"
address_layout = trezorui2.confirm_value(
address_layout = trezorui_api.confirm_value(
title=address_title,
subtitle=None,
description="",
@ -1053,17 +1055,18 @@ async def confirm_signverify(
)
)
info_layout = trezorui2.show_info_with_cancel(
info_layout = trezorui_api.show_info_with_cancel(
title=TR.words__title_information,
items=items,
horizontal=True,
)
message_layout = trezorui2.confirm_blob(
message_layout = trezorui_api.confirm_blob(
title=TR.sign_message__confirm_message,
description=None,
data=message,
extra=None,
prompt_screen=True,
hold=not verify,
info=False,
verb=TR.buttons__confirm if verify else None,
@ -1074,7 +1077,7 @@ async def confirm_signverify(
await with_info(address_layout, info_layout, br_name, br_code=BR_CODE_OTHER)
except ActionCancelled:
result = await interact(
trezorui2.show_mismatch(title=TR.addr_mismatch__mismatch),
trezorui_api.show_mismatch(title=TR.addr_mismatch__mismatch),
None,
raise_on_cancel=None,
)
@ -1103,7 +1106,7 @@ def error_popup(
if subtitle:
title += f"\n{subtitle}"
return trezorui2.show_error(
return trezorui_api.show_error(
title=title,
description=description.format(description_param),
button=button,
@ -1114,20 +1117,20 @@ def error_popup(
def request_passphrase_on_host() -> None:
draw_simple(
trezorui2.show_simple(
trezorui_api.show_simple(
title=None,
description=TR.passphrase__please_enter,
text=TR.passphrase__please_enter,
)
)
def show_wait_text(message: str) -> None:
draw_simple(trezorui2.show_wait_text(message))
draw_simple(trezorui_api.show_wait_text(message))
def request_passphrase_on_device(max_len: int) -> Awaitable[str]:
result = interact(
trezorui2.flow_request_passphrase(
trezorui_api.request_passphrase(
prompt=TR.passphrase__title_enter, max_len=max_len
),
"passphrase_device",
@ -1153,7 +1156,7 @@ def request_pin_on_device(
subprompt = f"{attempts_remaining} {TR.pin__tries_left}"
result = interact(
trezorui2.request_pin(
trezorui_api.request_pin(
prompt=prompt,
subprompt=subprompt,
allow_cancel=allow_cancel,
@ -1207,7 +1210,7 @@ def confirm_set_new_pin(
br_code: ButtonRequestType = BR_CODE_OTHER,
) -> Awaitable[None]:
return raise_if_not_confirmed(
trezorui2.flow_confirm_set_new_pin(title=title, description=description),
trezorui_api.flow_confirm_set_new_pin(title=title, description=description),
br_name,
br_code,
)
@ -1215,7 +1218,7 @@ def confirm_set_new_pin(
def confirm_firmware_update(description: str, fingerprint: str) -> Awaitable[None]:
return raise_if_not_confirmed(
trezorui2.confirm_firmware_update(
trezorui_api.confirm_firmware_update(
description=description, fingerprint=fingerprint
),
"firmware_update",
@ -1225,7 +1228,7 @@ def confirm_firmware_update(description: str, fingerprint: str) -> Awaitable[Non
def set_brightness(current: int | None = None) -> Awaitable[None]:
return raise_if_not_confirmed(
trezorui2.set_brightness(current=current),
trezorui_api.set_brightness(current=current),
"set_brightness",
BR_CODE_OTHER,
)
@ -1234,7 +1237,7 @@ def set_brightness(current: int | None = None) -> Awaitable[None]:
def tutorial(br_code: ButtonRequestType = BR_CODE_OTHER) -> Awaitable[None]:
"""Showing users how to interact with the device."""
return raise_if_not_confirmed(
trezorui2.tutorial(),
trezorui_api.tutorial(),
"tutorial",
br_code,
)

View File

@ -1,4 +1,3 @@
import trezorui2
import trezorui_api
from trezor import ui
from trezor.enums import ButtonRequestType
@ -13,7 +12,7 @@ async def confirm_fido(
accounts: list[str | None],
) -> int:
"""Webauthn confirmation for one or more credentials."""
confirm = trezorui2.confirm_fido(
confirm = trezorui_api.confirm_fido(
title=header,
app_name=app_name,
icon_name=icon_name,
@ -44,7 +43,7 @@ async def confirm_fido_reset() -> bool:
from trezor import TR
confirm = ui.Layout(
trezorui2.confirm_action(
trezorui_api.confirm_action(
title=TR.fido__title_reset,
action=TR.fido__erase_credentials,
description=TR.words__really_wanna,

View File

@ -17,9 +17,10 @@ if TYPE_CHECKING:
async def request_word_count(recovery_type: RecoveryType) -> int:
selector = trezorui2.select_word_count(recovery_type=recovery_type)
count = await interact(
selector, "recovery_word_count", ButtonRequestType.MnemonicWordCount
trezorui_api.select_word_count(recovery_type=recovery_type),
"recovery_word_count",
ButtonRequestType.MnemonicWordCount,
)
return int(count)
@ -34,11 +35,11 @@ async def request_word(
prompt = TR.recovery__word_x_of_y_template.format(word_index + 1, word_count)
can_go_back = word_index > 0
if is_slip39:
keyboard = trezorui2.request_slip39(
keyboard = trezorui_api.request_slip39(
prompt=prompt, prefill_word=prefill_word, can_go_back=can_go_back
)
else:
keyboard = trezorui2.request_bip39(
keyboard = trezorui_api.request_bip39(
prompt=prompt, prefill_word=prefill_word, can_go_back=can_go_back
)
@ -85,7 +86,7 @@ def format_remaining_shares_info(
async def show_group_share_success(share_index: int, group_index: int) -> None:
await raise_if_not_confirmed(
trezorui2.show_group_share_success(
trezorui_api.show_group_share_success(
lines=[
TR.recovery__you_have_entered,
TR.recovery__share_num_template.format(share_index + 1),
@ -99,7 +100,7 @@ async def show_group_share_success(share_index: int, group_index: int) -> None:
async def continue_recovery(
button_label: str, # unused on mercury
_button_label: str, # unused on mercury
text: str,
subtext: str | None,
recovery_type: RecoveryType,
@ -107,12 +108,13 @@ async def continue_recovery(
remaining_shares_info: "RemainingSharesInfo | None" = None,
) -> bool:
result = await interact(
trezorui2.flow_continue_recovery(
first_screen=show_instructions,
recovery_type=recovery_type,
trezorui_api.continue_recovery_homepage(
text=text,
subtext=subtext,
pages=(
button=None,
recovery_type=recovery_type,
show_instructions=show_instructions,
remaining_shares=(
format_remaining_shares_info(remaining_shares_info)
if remaining_shares_info
else None
@ -134,7 +136,7 @@ async def show_recovery_warning(
) -> None:
button = button or TR.buttons__try_again # def_arg
await raise_if_not_confirmed(
trezorui2.show_warning(
trezorui_api.show_warning(
title=content or TR.words__warning,
value=subheader or "",
button=button,

View File

@ -1,6 +1,5 @@
from typing import Awaitable, Callable, Sequence
import trezorui2
import trezorui_api
from trezor import TR, ui
from trezor.enums import ButtonRequestType
@ -17,9 +16,8 @@ def show_share_words(
share_index: int | None = None,
group_index: int | None = None,
) -> Awaitable[None]:
title = TR.reset__recovery_wallet_backup_title
if share_index is None:
subtitle = ""
subtitle = None
elif group_index is None:
subtitle = TR.reset__recovery_share_title_template.format(share_index + 1)
else:
@ -27,24 +25,24 @@ def show_share_words(
group_index + 1, share_index + 1
)
words_count = len(share_words)
description = ""
text_info = [TR.reset__write_down_words_template.format(words_count)]
description = None
instructions = [TR.reset__write_down_words_template.format(words_count)]
if words_count == 20 and share_index is None:
# 1-of-1 SLIP39: inform the user about repeated words
text_info.append(TR.reset__words_may_repeat)
instructions.append(TR.reset__words_may_repeat)
if share_index == 0:
# regular SLIP39, 1st share
description = TR.instructions__shares_start_with_1
text_info.append(TR.reset__repeat_for_all_shares)
instructions.append(TR.reset__repeat_for_all_shares)
assert len(instructions) < 3
text_confirm = TR.reset__words_written_down_template.format(words_count)
return raise_if_not_confirmed(
trezorui2.flow_show_share_words(
title=title,
subtitle=subtitle,
trezorui_api.show_share_words_mercury(
words=share_words,
description=description,
text_info=text_info,
subtitle=subtitle,
instructions=instructions,
text_footer=description,
text_confirm=text_confirm,
),
None,
@ -75,7 +73,7 @@ async def select_word(
words.append(words[-1])
result = await interact(
trezorui2.select_word(
trezorui_api.select_word(
title=title,
description=TR.reset__select_word_x_of_y_template.format(
checked_index + 1, count
@ -98,7 +96,7 @@ async def slip39_show_checklist(
) -> None:
items = _slip_39_checklist_items(step, advanced, count, threshold)
result = await interact(
trezorui2.show_checklist(
trezorui_api.show_checklist(
title=TR.reset__title_shamir_backup,
button=TR.buttons__continue,
active=step,
@ -155,17 +153,17 @@ async def _prompt_number(
br_name: str,
) -> int:
result = await interact(
trezorui2.flow_request_number(
trezorui_api.request_number(
title=title,
description=description,
count=count,
min_count=min_count,
max_count=max_count,
info=info,
br_code=ButtonRequestType.ResetDevice,
br_name=br_name,
description=description,
more_info_callback=info,
),
None,
br_name,
ButtonRequestType.ResetDevice,
raise_on_cancel=None,
)
if __debug__ and result is CONFIRMED:
@ -301,7 +299,7 @@ async def show_intro_backup(single_share: bool, num_of_words: int | None) -> Non
def show_warning_backup() -> Awaitable[ui.UiResult]:
return interact(
trezorui2.show_warning(
trezorui_api.show_warning(
title=TR.words__important,
value=TR.reset__never_make_digital_copy,
button="",
@ -328,7 +326,7 @@ def show_reset_warning(
br_code: ButtonRequestType = ButtonRequestType.Warning,
) -> Awaitable[None]:
return raise_if_not_confirmed(
trezorui2.show_warning(
trezorui_api.show_warning(
title=subheader or "",
description=content,
value="",

View File

@ -1,4 +1,4 @@
import trezorui2
import trezorui_api
from trezor import TR, config, ui, utils
@ -30,7 +30,7 @@ def progress(
description = TR.progress__please_wait # def_arg
return ui.ProgressLayout(
layout=trezorui2.show_progress(
layout=trezorui_api.show_progress(
description=description,
title=title,
indeterminate=indeterminate,
@ -44,7 +44,7 @@ def bitcoin_progress(message: str) -> ui.ProgressLayout:
def coinjoin_progress(message: str) -> ui.ProgressLayout:
return ui.ProgressLayout(
layout=trezorui2.show_progress_coinjoin(title=message, indeterminate=False)
layout=trezorui_api.show_progress_coinjoin(title=message, indeterminate=False)
)

View File

@ -70,7 +70,7 @@ def confirm_action(
description = description.format(description_param)
return raise_if_not_confirmed(
trezorui2.confirm_action(
trezorui_api.confirm_action(
title=title,
action=action,
description=description,
@ -109,19 +109,10 @@ def confirm_single(
def confirm_reset_device(
title: str,
recovery: bool = False,
) -> Awaitable[None]:
if recovery:
button = TR.reset__button_recover
else:
button = TR.reset__button_create
return raise_if_not_confirmed(
trezorui2.confirm_reset_device(
title=title,
button=button,
),
trezorui_api.confirm_reset_device(recovery=recovery),
"recover_device" if recovery else "setup_device",
ButtonRequestType.ProtectCall if recovery else ButtonRequestType.ResetDevice,
)
@ -137,7 +128,7 @@ async def prompt_backup() -> bool:
br_code = ButtonRequestType.ResetDevice
result = await interact(
trezorui2.confirm_backup(),
trezorui_api.prompt_backup(),
br_name,
br_code,
raise_on_cancel=None,
@ -146,7 +137,7 @@ async def prompt_backup() -> bool:
return True
result = await interact(
trezorui2.confirm_action(
trezorui_api.confirm_action(
title=TR.backup__title_skip,
action=None,
description=TR.backup__want_to_skip,
@ -192,7 +183,7 @@ def confirm_multisig_different_paths_warning() -> Awaitable[ui.UiResult]:
def confirm_homescreen(image: bytes) -> Awaitable[None]:
return raise_if_not_confirmed(
trezorui2.confirm_homescreen(
trezorui_api.confirm_homescreen(
title=TR.homescreen__title_set,
image=image,
),
@ -265,7 +256,7 @@ async def show_address(
while True:
result = await interact(
trezorui2.confirm_address(
trezorui_api.confirm_address(
title=title,
data=address,
description="", # unused on TR
@ -296,7 +287,7 @@ async def show_address(
return result
result = await interact(
trezorui2.show_address_details(
trezorui_api.show_address_details(
qr_title="", # unused on this model
address=address if address_qr is None else address_qr,
case_sensitive=case_sensitive,
@ -314,7 +305,7 @@ async def show_address(
# User pressed left cancel button, show mismatch dialogue.
else:
result = await interact(
trezorui2.show_mismatch(title=mismatch_title),
trezorui_api.show_mismatch(title=mismatch_title),
None,
raise_on_cancel=None,
)
@ -410,9 +401,10 @@ def show_warning(
content = content + "\n"
return interact(
trezorui2.show_warning( # type: ignore [Argument missing for parameter "title"]
trezorui_api.show_warning( # type: ignore [Argument missing for parameter "title"]
title="",
button=button,
warning=content, # type: ignore [No parameter named "warning"]
value=content,
description=subheader or "",
),
br_name,
@ -494,10 +486,13 @@ async def confirm_output(
while True:
await interact(
trezorui2.confirm_output_address(
address=address,
address_label=address_label or "",
address_title=address_title,
trezorui_api.confirm_blob(
title=address_title,
data=address,
description=address_label or "",
subtitle=None,
verb=TR.buttons__continue,
verb_cancel="",
chunkify=chunkify,
),
"confirm_output",
@ -506,9 +501,13 @@ async def confirm_output(
try:
await interact(
trezorui2.confirm_output_amount(
amount_title=amount_title,
amount=amount,
trezorui_api.confirm_blob(
title=amount_title,
data=amount,
description=None,
subtitle=None,
verb_cancel="^",
verb=TR.buttons__confirm,
),
"confirm_output",
br_code,
@ -522,7 +521,7 @@ async def confirm_output(
def tutorial(br_code: ButtonRequestType = BR_CODE_OTHER) -> Awaitable[ui.UiResult]:
"""Showing users how to interact with the device."""
return interact(trezorui2.tutorial(), "tutorial", br_code)
return interact(trezorui_api.tutorial(), "tutorial", br_code)
async def should_show_payment_request_details(
@ -559,11 +558,11 @@ async def should_show_more(
confirm = TR.buttons__confirm
result = await interact(
trezorui2.confirm_with_info(
trezorui_api.confirm_with_info(
title=title,
items=para,
button=confirm,
verb_cancel=verb_cancel, # type: ignore [No parameter named "verb_cancel"]
verb_cancel=verb_cancel,
info_button=button_text, # unused on TR
),
br_name,
@ -594,7 +593,7 @@ def confirm_blob(
prompt_screen: bool = True,
) -> Awaitable[None]:
verb = verb or TR.buttons__confirm # def_arg
layout = trezorui2.confirm_blob(
layout = trezorui_api.confirm_blob(
title=title,
description=description,
data=data,
@ -624,7 +623,7 @@ async def _confirm_ask_pagination(
data = hexlify(data).decode()
confirm_more_layout = trezorui2.confirm_more(
confirm_more_layout = trezorui_api.confirm_more(
title=title,
button=TR.buttons__confirm,
items=[(ui.NORMAL, description), (ui.MONO, data)],
@ -720,7 +719,7 @@ def confirm_properties(
return (key, value, bool(is_data))
return raise_if_not_confirmed(
trezorui2.confirm_properties(
trezorui_api.confirm_properties(
title=title,
items=map(handle_bytes, props), # type: ignore [cannot be assigned to parameter "items"]
hold=hold,
@ -749,11 +748,12 @@ async def confirm_value(
if info_items is None:
return await raise_if_not_confirmed(
trezorui2.confirm_value( # type: ignore [Argument missing for parameter "subtitle"]
trezorui_api.confirm_value( # type: ignore [Argument missing for parameter "subtitle"]
title=title,
description=description,
value=value,
verb=verb or TR.buttons__hold_to_confirm,
verb_cancel="",
hold=hold,
),
br_name,
@ -768,7 +768,7 @@ async def confirm_value(
send_button_request = True
while True:
result = await interact(
trezorui2.confirm_with_info(
trezorui_api.confirm_with_info(
title=title,
items=((ui.NORMAL, value),),
button=verb or TR.buttons__confirm,
@ -784,7 +784,7 @@ async def confirm_value(
elif result is INFO:
info_title, info_value = info_items_list[0]
await interact(
trezorui2.confirm_blob(
trezorui_api.confirm_blob(
title=info_title,
data=info_value,
description=description,
@ -824,7 +824,7 @@ def confirm_total(
account_info_items.append((TR.words__account_colon, source_account))
return raise_if_not_confirmed(
trezorui2.confirm_summary(
trezorui_api.confirm_summary(
amount=total_amount,
amount_label=total_label,
fee=fee_amount,
@ -880,7 +880,7 @@ if not utils.BITCOIN_ONLY:
amount_title = f"{TR.words__amount}:"
amount_value = total_amount
await raise_if_not_confirmed(
trezorui2.confirm_summary(
trezorui_api.confirm_summary(
amount=amount_value,
amount_label=amount_title,
fee=maximum_fee,
@ -906,7 +906,7 @@ if not utils.BITCOIN_ONLY:
) # def_arg
fee_title = fee_title or TR.words__fee # def_arg
return raise_if_not_confirmed(
trezorui2.confirm_summary(
trezorui_api.confirm_summary(
amount=amount,
amount_label=amount_title,
fee=fee,
@ -928,7 +928,7 @@ if not utils.BITCOIN_ONLY:
fee_title = TR.send__including_fee
return raise_if_not_confirmed(
trezorui2.confirm_summary(
trezorui_api.confirm_summary(
amount=amount,
amount_label=amount_title,
fee=fee,
@ -951,7 +951,7 @@ if not utils.BITCOIN_ONLY:
br_code: ButtonRequestType = ButtonRequestType.SignTx,
chunkify: bool = False,
) -> None:
summary_layout = trezorui2.confirm_summary(
summary_layout = trezorui_api.confirm_summary(
amount=total_amount,
amount_label=f"{TR.words__amount}:",
fee=maximum_fee,
@ -987,13 +987,15 @@ if not utils.BITCOIN_ONLY:
def confirm_joint_total(spending_amount: str, total_amount: str) -> Awaitable[None]:
return raise_if_not_confirmed(
trezorui2.confirm_joint_total(
spending_amount=spending_amount,
total_amount=total_amount,
),
return confirm_properties(
"confirm_joint_total",
ButtonRequestType.SignTx,
TR.joint__title,
[
(TR.joint__you_are_contributing, spending_amount),
(TR.joint__to_the_total_amount, total_amount),
],
hold=True,
br_code=ButtonRequestType.SignTx,
)
@ -1031,14 +1033,14 @@ async def confirm_modify_output(
amount_change: str,
amount_new: str,
) -> None:
address_layout = trezorui2.confirm_blob(
address_layout = trezorui_api.confirm_blob(
title=TR.modify_amount__title,
data=address,
verb=TR.buttons__continue,
description=f"{TR.words__address}:",
)
modify_layout = trezorui2.confirm_modify_output(
modify_layout = trezorui_api.confirm_modify_output(
sign=sign,
amount_change=amount_change,
amount_new=amount_new,
@ -1072,7 +1074,7 @@ def confirm_modify_fee(
fee_rate_amount: str | None = None,
) -> Awaitable[None]:
return raise_if_not_confirmed(
trezorui2.confirm_modify_fee(
trezorui_api.confirm_modify_fee(
title=title,
sign=sign,
user_fee_change=user_fee_change,
@ -1086,7 +1088,7 @@ def confirm_modify_fee(
def confirm_coinjoin(max_rounds: int, max_fee_per_vbyte: str) -> Awaitable[None]:
return raise_if_not_confirmed(
trezorui2.confirm_coinjoin(
trezorui_api.confirm_coinjoin(
max_rounds=str(max_rounds),
max_feerate=max_fee_per_vbyte,
),
@ -1133,7 +1135,7 @@ async def confirm_signverify(
)
try:
await raise_if_not_confirmed(
trezorui2.confirm_blob(
trezorui_api.confirm_blob(
title=TR.sign_message__confirm_message,
description=None,
data=message,
@ -1174,16 +1176,21 @@ def error_popup(
def request_passphrase_on_host() -> None:
draw_simple(trezorui2.show_passphrase())
draw_simple(
trezorui_api.show_simple(
title=None,
text=TR.passphrase__please_enter,
)
)
def show_wait_text(message: str) -> None:
draw_simple(trezorui2.show_wait_text(message))
draw_simple(trezorui_api.show_wait_text(message))
async def request_passphrase_on_device(max_len: int) -> str:
result = await interact(
trezorui2.request_passphrase(
trezorui_api.request_passphrase(
prompt=TR.passphrase__title_enter,
max_len=max_len,
),
@ -1213,7 +1220,7 @@ async def request_pin_on_device(
subprompt = f"{attempts_remaining} {TR.pin__tries_left}"
result = await interact(
trezorui2.request_pin(
trezorui_api.request_pin(
prompt=prompt,
subprompt=subprompt,
allow_cancel=allow_cancel,
@ -1252,7 +1259,7 @@ def _confirm_multiple_pages_texts(
br_code: ButtonRequestType = BR_CODE_OTHER,
) -> Awaitable[None]:
return raise_if_not_confirmed(
trezorui2.multiple_pages_texts(
trezorui_api.multiple_pages_texts(
title=title,
verb=verb,
items=items,
@ -1321,7 +1328,7 @@ async def confirm_set_new_pin(
def confirm_firmware_update(description: str, fingerprint: str) -> Awaitable[None]:
return raise_if_not_confirmed(
trezorui2.confirm_firmware_update(
trezorui_api.confirm_firmware_update(
description=description, fingerprint=fingerprint
),
"firmware_update",

View File

@ -1,4 +1,3 @@
import trezorui2
import trezorui_api
from trezor import ui
from trezor.enums import ButtonRequestType
@ -9,13 +8,14 @@ from ..common import interact
async def confirm_fido(
header: str,
app_name: str,
icon_name: str | None,
_icon_name: str | None, # unused on TR
accounts: list[str | None],
) -> int:
"""Webauthn confirmation for one or more credentials."""
confirm = trezorui2.confirm_fido( # type: ignore [Argument missing for parameter "icon_name"]
confirm = trezorui_api.confirm_fido( # type: ignore [Argument missing for parameter "icon_name"]
title=header,
app_name=app_name,
icon_name=None,
accounts=accounts,
)
result = await interact(confirm, "confirm_fido", ButtonRequestType.Other)
@ -34,7 +34,7 @@ async def confirm_fido(
async def confirm_fido_reset() -> bool:
from trezor import TR
confirm = trezorui2.confirm_action(
confirm = trezorui_api.confirm_action(
title=TR.fido__title_reset,
description=TR.fido__wanna_erase_credentials,
action=None,

View File

@ -16,7 +16,7 @@ if TYPE_CHECKING:
async def request_word_count(recovery_type: RecoveryType) -> int:
count = await interact(
trezorui2.select_word_count(recovery_type=recovery_type),
trezorui_api.select_word_count(recovery_type=recovery_type),
"recovery_word_count",
ButtonRequestType.MnemonicWordCount,
)
@ -36,12 +36,12 @@ async def request_word(
can_go_back = word_index > 0
if is_slip39:
keyboard = trezorui2.request_slip39(
keyboard = trezorui_api.request_slip39(
prompt=prompt, prefill_word=prefill_word, can_go_back=can_go_back
)
else:
keyboard = trezorui2.request_bip39(
keyboard = trezorui_api.request_bip39(
prompt=prompt, prefill_word=prefill_word, can_go_back=can_go_back
)
@ -65,7 +65,7 @@ def show_group_share_success(
share_index: int, group_index: int
) -> Awaitable[ui.UiResult]:
return interact(
trezorui2.show_group_share_success(
trezorui_api.show_group_share_success(
lines=[
TR.recovery__you_have_entered,
TR.recovery__share_num_template.format(share_index + 1),
@ -123,13 +123,13 @@ async def continue_recovery(
if subtext:
text += f"\n\n{subtext}"
homepage = trezorui2.confirm_recovery(
title="",
description=text,
homepage = trezorui_api.continue_recovery_homepage(
text=text,
subtext=None,
button=button_label,
recovery_type=recovery_type,
info_button=False,
show_instructions=show_instructions,
remaining_shares=None,
)
while True:
result = await interact(

View File

@ -1,6 +1,5 @@
from typing import TYPE_CHECKING
import trezorui2
from trezor import TR
from trezor.enums import ButtonRequestType
import trezorui_api
@ -50,8 +49,9 @@ async def show_share_words(
)
result = await interact(
trezorui2.show_share_words( # type: ignore [Arguments missing for parameters]
share_words=share_words, # type: ignore [No parameter named "share_words"]
trezorui_api.show_share_words(
words=share_words,
title=None,
),
br_name,
br_code,
@ -88,7 +88,7 @@ async def select_word(
word_ordinal = format_ordinal(checked_index + 1)
result = await interact(
trezorui2.select_word(
trezorui_api.select_word(
title="",
description=TR.reset__select_word_template.format(word_ordinal),
words=(words[0].lower(), words[1].lower(), words[2].lower()),
@ -122,7 +122,7 @@ def slip39_show_checklist(
)
return raise_if_not_confirmed(
trezorui2.show_checklist(
trezorui_api.show_checklist(
title=TR.reset__slip39_checklist_title,
button=TR.buttons__continue,
active=step,
@ -140,7 +140,7 @@ async def _prompt_number(
max_count: int,
br_name: str,
) -> int:
num_input = trezorui2.request_number(
num_input = trezorui_api.request_number(
title=title,
count=count,
min_count=min_count,

View File

@ -42,7 +42,7 @@ def confirm_action(
description = description.format(description_param)
return raise_if_not_confirmed(
trezorui2.confirm_action(
trezorui_api.confirm_action(
title=title,
action=action,
description=description,
@ -74,7 +74,7 @@ def confirm_single(
begin, _separator, end = description.partition(template_str)
return raise_if_not_confirmed(
trezorui2.confirm_emphasized(
trezorui_api.confirm_emphasized(
title=title,
items=(begin, (True, description_param), end),
verb=verb,
@ -84,17 +84,9 @@ def confirm_single(
)
def confirm_reset_device(title: str, recovery: bool = False) -> Awaitable[None]:
if recovery:
button = TR.reset__button_recover
else:
button = TR.reset__button_create
def confirm_reset_device(recovery: bool = False) -> Awaitable[None]:
return raise_if_not_confirmed(
trezorui2.confirm_reset_device(
title=title,
button=button,
),
trezorui_api.confirm_reset_device(recovery=recovery),
"recover_device" if recovery else "setup_device",
(ButtonRequestType.ProtectCall if recovery else ButtonRequestType.ResetDevice),
)
@ -108,7 +100,7 @@ async def show_wallet_created_success() -> None:
# TODO cleanup @ redesign
async def prompt_backup() -> bool:
result = await interact(
trezorui2.confirm_action(
trezorui_api.confirm_action(
title=TR.words__title_success,
action=TR.backup__new_wallet_successfully_created,
description=TR.backup__it_should_be_backed_up,
@ -123,7 +115,7 @@ async def prompt_backup() -> bool:
return True
result = await interact(
trezorui2.confirm_action(
trezorui_api.confirm_action(
title=TR.words__warning,
action=TR.backup__want_to_skip,
description=TR.backup__can_back_up_anytime,
@ -144,7 +136,7 @@ def confirm_path_warning(path: str, path_type: str | None = None) -> Awaitable[N
else f"{TR.words__unknown} {path_type.lower()}."
)
return raise_if_not_confirmed(
trezorui2.show_warning(
trezorui_api.show_warning(
title=title,
value=path,
description=TR.words__continue_anyway_question,
@ -173,7 +165,7 @@ def confirm_multisig_different_paths_warning() -> Awaitable[None]:
def confirm_homescreen(image: bytes) -> Awaitable[None]:
return raise_if_not_confirmed(
trezorui2.confirm_homescreen(
trezorui_api.confirm_homescreen(
title=TR.homescreen__title_set,
image=image,
),
@ -250,7 +242,7 @@ async def show_address(
while True:
result = await interact(
trezorui2.confirm_address(
trezorui_api.confirm_address(
title=title,
data=address,
description=network or "",
@ -281,7 +273,7 @@ async def show_address(
return result
result = await interact(
trezorui2.show_address_details(
trezorui_api.show_address_details(
qr_title=title,
address=address if address_qr is None else address_qr,
case_sensitive=case_sensitive,
@ -297,7 +289,7 @@ async def show_address(
else:
result = await interact(
trezorui2.show_mismatch(title=mismatch_title),
trezorui_api.show_mismatch(title=mismatch_title),
None,
raise_on_cancel=None,
)
@ -339,7 +331,7 @@ async def show_error_and_raise(
) -> NoReturn:
button = button or TR.buttons__try_again # def_arg
await interact(
trezorui2.show_error(
trezorui_api.show_error(
title=subheader or "",
description=content,
button=button,
@ -363,7 +355,7 @@ def show_warning(
) -> Awaitable[None]:
button = button or TR.buttons__continue # def_arg
return raise_if_not_confirmed(
trezorui2.show_warning(
trezorui_api.show_warning(
title=content,
description=subheader or "",
button=button,
@ -397,7 +389,7 @@ def show_success(
) -> Awaitable[None]:
button = button or TR.buttons__continue # def_arg
return raise_if_not_confirmed(
trezorui2.show_success(
trezorui_api.show_success(
title=content,
description=subheader or "",
button=button,
@ -436,7 +428,7 @@ async def confirm_output(
while True:
# if the user cancels here, raise ActionCancelled (by default)
await interact(
trezorui2.confirm_value(
trezorui_api.confirm_value(
title=recipient_title,
subtitle=address_label,
description=None,
@ -452,7 +444,7 @@ async def confirm_output(
try:
await interact(
trezorui2.confirm_value(
trezorui_api.confirm_value(
title=amount_title,
subtitle=None,
description=None,
@ -483,7 +475,7 @@ async def should_show_payment_request_details(
Raises ActionCancelled if the user cancels.
"""
result = await interact(
trezorui2.confirm_with_info(
trezorui_api.confirm_with_info(
title=TR.send__title_sending,
items=[(ui.NORMAL, f"{amount} to\n{recipient_name}")]
+ [(ui.NORMAL, memo) for memo in memos],
@ -520,7 +512,7 @@ async def should_show_more(
confirm = TR.buttons__confirm
result = await interact(
trezorui2.confirm_with_info(
trezorui_api.confirm_with_info(
title=title,
items=para,
button=confirm,
@ -551,7 +543,7 @@ async def _confirm_ask_pagination(
data = hexlify(data).decode()
confirm_more_layout = trezorui2.confirm_more(
confirm_more_layout = trezorui_api.confirm_more(
title=title,
button=TR.buttons__confirm,
button_style_confirm=True,
@ -592,7 +584,7 @@ def confirm_blob(
prompt_screen: bool = True,
) -> Awaitable[None]:
verb = verb or TR.buttons__confirm # def_arg
layout = trezorui2.confirm_blob(
layout = trezorui_api.confirm_blob(
title=title,
description=description,
text_mono=text_mono,
@ -691,14 +683,14 @@ def confirm_value(
raise ValueError("Either verb or hold=True must be set")
info_items = info_items or []
info_layout = trezorui2.show_info_with_cancel(
info_layout = trezorui_api.show_info_with_cancel(
title=info_title if info_title else TR.words__title_information,
items=info_items,
chunkify=chunkify_info,
)
return with_info(
trezorui2.confirm_value(
trezorui_api.confirm_value(
title=title,
subtitle=subtitle,
description=description,
@ -725,7 +717,7 @@ def confirm_properties(
items = [(prop[0], prop[1], isinstance(prop[1], bytes)) for prop in props]
return raise_if_not_confirmed(
trezorui2.confirm_properties(
trezorui_api.confirm_properties(
title=title,
items=items,
hold=hold,
@ -788,7 +780,7 @@ def _confirm_summary(
) -> Awaitable[None]:
title = title or TR.words__title_summary # def_arg
total_layout = trezorui2.confirm_summary(
total_layout = trezorui_api.confirm_summary(
amount=amount,
amount_label=amount_label,
fee=fee,
@ -804,7 +796,7 @@ def _confirm_summary(
info_items.extend(account_items)
if extra_items:
info_items.extend(extra_items)
info_layout = trezorui2.show_info_with_cancel(
info_layout = trezorui_api.show_info_with_cancel(
title=extra_title if extra_title else TR.words__title_information,
items=info_items,
)
@ -831,7 +823,7 @@ if not utils.BITCOIN_ONLY:
chunkify: bool = False,
) -> None:
# NOTE: fee_info used so that info button is shown
total_layout = trezorui2.confirm_summary(
total_layout = trezorui_api.confirm_summary(
amount=total_amount,
amount_label=f"{TR.words__amount}:",
fee=maximum_fee,
@ -841,7 +833,7 @@ if not utils.BITCOIN_ONLY:
extra_title=TR.confirm_total__title_fee,
verb_cancel="^",
)
info_layout = trezorui2.show_info_with_cancel(
info_layout = trezorui_api.show_info_with_cancel(
title=TR.confirm_total__title_fee,
items=[(f"{k}:", v) for (k, v) in fee_info_items],
)
@ -965,7 +957,7 @@ if not utils.BITCOIN_ONLY:
def confirm_joint_total(spending_amount: str, total_amount: str) -> Awaitable[None]:
return raise_if_not_confirmed(
# FIXME: arguments for amount/fee are misused here
trezorui2.confirm_summary(
trezorui_api.confirm_summary(
amount=spending_amount,
amount_label=TR.send__you_are_contributing,
fee=total_amount,
@ -1020,7 +1012,7 @@ async def confirm_modify_output(
while True:
# if the user cancels here, raise ActionCancelled (by default)
await interact(
trezorui2.confirm_blob(
trezorui_api.confirm_blob(
title="MODIFY AMOUNT",
data=address,
verb="CONTINUE",
@ -1033,7 +1025,7 @@ async def confirm_modify_output(
try:
await interact(
trezorui2.confirm_modify_output(
trezorui_api.confirm_modify_output(
sign=sign,
amount_change=amount_change,
amount_new=amount_new,
@ -1056,7 +1048,7 @@ def confirm_modify_fee(
total_fee_new: str,
fee_rate_amount: str | None = None,
) -> Awaitable[None]:
fee_layout = trezorui2.confirm_modify_fee(
fee_layout = trezorui_api.confirm_modify_fee(
title=title,
sign=sign,
user_fee_change=user_fee_change,
@ -1066,7 +1058,7 @@ def confirm_modify_fee(
items: list[tuple[str, str]] = []
if fee_rate_amount:
items.append((TR.bitcoin__new_fee_rate, fee_rate_amount))
info_layout = trezorui2.show_info_with_cancel(
info_layout = trezorui_api.show_info_with_cancel(
title=TR.confirm_total__title_fee,
items=items,
)
@ -1075,7 +1067,7 @@ def confirm_modify_fee(
def confirm_coinjoin(max_rounds: int, max_fee_per_vbyte: str) -> Awaitable[None]:
return raise_if_not_confirmed(
trezorui2.confirm_coinjoin(
trezorui_api.confirm_coinjoin(
max_rounds=str(max_rounds),
max_feerate=max_fee_per_vbyte,
),
@ -1112,7 +1104,7 @@ async def confirm_signverify(
address_title = TR.sign_message__confirm_address
br_name = "sign_message"
address_layout = trezorui2.confirm_address(
address_layout = trezorui_api.confirm_address(
title=address_title,
data=address,
description="",
@ -1133,13 +1125,13 @@ async def confirm_signverify(
)
)
info_layout = trezorui2.show_info_with_cancel(
info_layout = trezorui_api.show_info_with_cancel(
title=TR.words__title_information,
items=items,
horizontal=True,
)
message_layout = trezorui2.confirm_blob(
message_layout = trezorui_api.confirm_blob(
title=TR.sign_message__confirm_message,
description=None,
data=message,
@ -1152,7 +1144,7 @@ async def confirm_signverify(
await with_info(address_layout, info_layout, br_name, br_code=BR_CODE_OTHER)
except ActionCancelled:
result = await interact(
trezorui2.show_mismatch(title=TR.addr_mismatch__mismatch),
trezorui_api.show_mismatch(title=TR.addr_mismatch__mismatch),
None,
raise_on_cancel=None,
)
@ -1184,7 +1176,7 @@ def error_popup(
if subtitle:
title += f"\n{subtitle}"
layout = trezorui2.show_error(
layout = trezorui_api.show_error(
title=title,
description=description.format(description_param),
button=button,
@ -1196,20 +1188,22 @@ def error_popup(
def request_passphrase_on_host() -> None:
draw_simple(
trezorui2.show_simple(
trezorui_api.show_simple(
title=None,
description=TR.passphrase__please_enter,
text=TR.passphrase__please_enter,
)
)
def show_wait_text(message: str) -> None:
draw_simple(trezorui2.show_wait_text(message))
draw_simple(trezorui_api.show_wait_text(message))
async def request_passphrase_on_device(max_len: int) -> str:
result = await interact(
trezorui2.request_passphrase(prompt="Enter passphrase", max_len=max_len),
trezorui_api.request_passphrase(
prompt=TR.passphrase__title_enter, max_len=max_len
),
"passphrase_device",
ButtonRequestType.PassphraseEntry,
raise_on_cancel=ActionCancelled("Passphrase entry cancelled"),
@ -1234,7 +1228,7 @@ async def request_pin_on_device(
subprompt = f"{attempts_remaining} {TR.pin__tries_left}"
result = await interact(
trezorui2.request_pin(
trezorui_api.request_pin(
prompt=prompt,
subprompt=subprompt,
allow_cancel=allow_cancel,
@ -1290,7 +1284,7 @@ def confirm_set_new_pin(
br_code: ButtonRequestType = BR_CODE_OTHER,
) -> Awaitable[None]:
return raise_if_not_confirmed(
trezorui2.confirm_emphasized(
trezorui_api.confirm_emphasized(
title=title,
items=(
(True, description + "\n\n"),
@ -1305,7 +1299,7 @@ def confirm_set_new_pin(
def confirm_firmware_update(description: str, fingerprint: str) -> Awaitable[None]:
return raise_if_not_confirmed(
trezorui2.confirm_firmware_update(
trezorui_api.confirm_firmware_update(
description=description, fingerprint=fingerprint
),
"firmware_update",
@ -1315,7 +1309,7 @@ def confirm_firmware_update(description: str, fingerprint: str) -> Awaitable[Non
async def set_brightness(current: int | None = None) -> None:
await interact(
trezorui2.set_brightness(current=current),
trezorui_api.set_brightness(current=current),
"set_brightness",
BR_CODE_OTHER,
)

View File

@ -1,4 +1,3 @@
import trezorui2
import trezorui_api
from trezor import ui
from trezor.enums import ButtonRequestType
@ -13,7 +12,7 @@ async def confirm_fido(
accounts: list[str | None],
) -> int:
"""Webauthn confirmation for one or more credentials."""
confirm = trezorui2.confirm_fido(
confirm = trezorui_api.confirm_fido(
title=header,
app_name=app_name,
icon_name=icon_name,
@ -53,7 +52,7 @@ async def confirm_fido_reset() -> bool:
from trezor import TR
confirm = ui.Layout(
trezorui2.confirm_action(
trezorui_api.confirm_action(
title=TR.fido__title_reset,
action=TR.fido__erase_credentials,
description=TR.words__really_wanna,

View File

@ -17,7 +17,7 @@ if TYPE_CHECKING:
async def request_word_count(recovery_type: RecoveryType) -> int:
count = await interact(
trezorui2.select_word_count(recovery_type=recovery_type),
trezorui_api.select_word_count(recovery_type=recovery_type),
"recovery_word_count",
ButtonRequestType.MnemonicWordCount,
)
@ -34,12 +34,12 @@ async def request_word(
prompt = TR.recovery__type_word_x_of_y_template.format(word_index + 1, word_count)
can_go_back = word_index > 0
if is_slip39:
keyboard = trezorui2.request_slip39(
keyboard = trezorui_api.request_slip39(
prompt=prompt, prefill_word=prefill_word, can_go_back=can_go_back
)
else:
keyboard = trezorui2.request_bip39(
keyboard = trezorui_api.request_bip39(
prompt=prompt, prefill_word=prefill_word, can_go_back=can_go_back
)
@ -51,14 +51,14 @@ async def request_word(
return word
def show_remaining_shares(
groups: set[tuple[str, ...]],
shares_remaining: list[int],
group_threshold: int,
) -> Awaitable[trezorui_api.UiResult]:
def format_remaining_shares_info(
remaining_shares_info: "RemainingSharesInfo",
) -> list[tuple[str, str]]:
from trezor import strings
from trezor.crypto.slip39 import MAX_SHARE_COUNT
groups, shares_remaining, group_threshold = remaining_shares_info
pages: list[tuple[str, str]] = []
completed_groups = shares_remaining.count(0)
@ -81,8 +81,14 @@ def show_remaining_shares(
words = "\n".join(group)
pages.append((title, words))
return pages
def show_remaining_shares(
pages: list[tuple[str, str]],
) -> Awaitable[trezorui_api.UiResult]:
return interact(
trezorui2.show_remaining_shares(pages=pages),
trezorui_api.show_remaining_shares(pages=pages),
"show_shares",
ButtonRequestType.Other,
)
@ -92,7 +98,7 @@ def show_group_share_success(
share_index: int, group_index: int
) -> Awaitable[ui.UiResult]:
return interact(
trezorui2.show_group_share_success(
trezorui_api.show_group_share_success(
lines=[
TR.recovery__you_have_entered,
TR.recovery__share_num_template.format(share_index + 1),
@ -146,12 +152,17 @@ async def continue_recovery(
else:
description = subtext or ""
homepage = trezorui2.confirm_recovery(
title=text,
description=description,
remaining_shares = (
format_remaining_shares_info(remaining_shares_info)
if remaining_shares_info
else None
)
homepage = trezorui_api.continue_recovery_homepage(
text=text,
subtext=description,
button=button_label,
recovery_type=recovery_type,
info_button=remaining_shares_info is not None,
remaining_shares=remaining_shares,
)
while True:
@ -164,8 +175,8 @@ async def continue_recovery(
if result is trezorui_api.CONFIRMED:
return True
elif result is trezorui_api.INFO and remaining_shares_info is not None:
await show_remaining_shares(*remaining_shares_info)
elif result is trezorui_api.INFO and remaining_shares is not None:
await show_remaining_shares(remaining_shares)
else:
try:
await _confirm_abort(recovery_type != RecoveryType.NormalRecovery)
@ -185,7 +196,7 @@ def show_recovery_warning(
button = button or TR.buttons__try_again # def_arg
return interact(
trezorui2.show_warning(
trezorui_api.show_warning(
title=content,
description=subheader or "",
button=button,

View File

@ -1,6 +1,5 @@
from typing import Awaitable, Callable, Sequence
import trezorui2
import trezorui_api
from trezor import TR
from trezor.enums import ButtonRequestType
@ -10,30 +9,6 @@ from ..common import interact, raise_if_not_confirmed
CONFIRMED = trezorui_api.CONFIRMED # global_import_cache
def _split_share_into_pages(share_words: Sequence[str], per_page: int = 4) -> list[str]:
pages: list[str] = []
current = ""
fill = 2
for i, word in enumerate(share_words):
if i % per_page == 0:
if i != 0:
pages.append(current)
current = ""
# Align numbers to the right.
lastnum = i + per_page + 1
fill = 1 if lastnum < 10 else 2
else:
current += "\n"
current += f"{i + 1:>{fill}}. {word}"
if current:
pages.append(current)
return pages
def show_share_words(
share_words: Sequence[str],
share_index: int | None = None,
@ -48,12 +23,10 @@ def show_share_words(
group_index + 1, share_index + 1
)
pages = _split_share_into_pages(share_words)
return raise_if_not_confirmed(
trezorui2.show_share_words(
trezorui_api.show_share_words(
words=share_words,
title=title,
pages=pages,
),
"backup_words",
ButtonRequestType.ResetDevice,
@ -84,7 +57,7 @@ async def select_word(
words.append(words[-1])
result = await interact(
trezorui2.select_word(
trezorui_api.select_word(
title=title,
description=TR.reset__select_word_x_of_y_template.format(
checked_index + 1, count
@ -120,7 +93,7 @@ def slip39_show_checklist(
)
return raise_if_not_confirmed(
trezorui2.show_checklist(
trezorui_api.show_checklist(
title=TR.reset__slip39_checklist_title,
button=TR.buttons__continue,
active=step,
@ -140,12 +113,13 @@ async def _prompt_number(
max_count: int,
br_name: str,
) -> int:
num_input = trezorui2.request_number(
num_input = trezorui_api.request_number(
title=title,
description=description,
count=count,
min_count=min_count,
max_count=max_count,
description=None,
more_info_callback=description,
)
while True:
@ -167,9 +141,9 @@ async def _prompt_number(
return value
await interact(
trezorui2.show_simple(
trezorui_api.show_simple(
title=None,
description=info(value),
text=info(value),
button=TR.buttons__ok_i_understand,
),
None,
@ -354,7 +328,7 @@ def show_reset_warning(
) -> Awaitable[trezorui_api.UiResult]:
button = button or TR.buttons__try_again # def_arg
return interact(
trezorui2.show_warning(
trezorui_api.show_warning(
title=subheader or "",
description=content,
button=button,