mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-22 07:28:10 +00:00
refactor(core): move confirm_fido to UiFeatures
- still uses Gc<List> for now
This commit is contained in:
parent
0bc5dfac6a
commit
a7a12cf898
@ -1,6 +1,8 @@
|
||||
use crate::{
|
||||
io::BinaryData,
|
||||
micropython::{
|
||||
gc::Gc,
|
||||
list::List,
|
||||
macros::{obj_fn_1, obj_fn_kw, obj_module},
|
||||
map::Map,
|
||||
module::Module,
|
||||
@ -92,6 +94,19 @@ extern "C" fn new_confirm_coinjoin(n_args: usize, args: *const Obj, kwargs: *mut
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
|
||||
extern "C" fn new_confirm_fido(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||
let app_name: TString = kwargs.get(Qstr::MP_QSTR_app_name)?.try_into()?;
|
||||
let icon: 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 layout = ModelUI::confirm_fido(title, app_name, icon, accounts)?;
|
||||
Ok(LayoutObj::new_root(layout)?.into())
|
||||
};
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
|
||||
// TODO: there was `no_mangle` attribute in TT, should we apply it?
|
||||
extern "C" fn new_confirm_firmware_update(
|
||||
n_args: usize,
|
||||
@ -676,6 +691,19 @@ pub static mp_module_trezorui_api: Module = obj_module! {
|
||||
/// """Confirm coinjoin authorization."""
|
||||
Qstr::MP_QSTR_confirm_coinjoin => obj_fn_kw!(0, new_confirm_coinjoin).as_obj(),
|
||||
|
||||
/// 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.
|
||||
/// """
|
||||
Qstr::MP_QSTR_confirm_fido => obj_fn_kw!(0, new_confirm_fido).as_obj(),
|
||||
|
||||
/// def confirm_firmware_update(
|
||||
/// *,
|
||||
/// description: str,
|
||||
|
@ -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, Some(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)
|
||||
}
|
||||
|
@ -785,13 +785,6 @@ extern "C" fn new_prompt_backup() -> Obj {
|
||||
unsafe { util::try_or_raise(block) }
|
||||
}
|
||||
|
||||
extern "C" fn new_confirm_fido(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
#[cfg(feature = "universal_fw")]
|
||||
return flow::confirm_fido::new_confirm_fido(n_args, args, kwargs);
|
||||
#[cfg(not(feature = "universal_fw"))]
|
||||
panic!();
|
||||
}
|
||||
|
||||
extern "C" fn new_warning_hi_prio(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||
@ -914,19 +907,6 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
||||
/// """Transaction summary. Always hold to confirm."""
|
||||
Qstr::MP_QSTR_confirm_total => obj_fn_kw!(0, new_confirm_total).as_obj(),
|
||||
|
||||
/// 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.
|
||||
/// """
|
||||
Qstr::MP_QSTR_confirm_fido => obj_fn_kw!(0, new_confirm_fido).as_obj(),
|
||||
|
||||
/// def confirm_with_info(
|
||||
/// *,
|
||||
/// title: str,
|
||||
|
@ -3,7 +3,7 @@ use core::cmp::Ordering;
|
||||
use crate::{
|
||||
error::{value_error, Error},
|
||||
io::BinaryData,
|
||||
micropython::{gc::Gc, util},
|
||||
micropython::{gc::Gc, list::List, util},
|
||||
strutil::TString,
|
||||
translations::TR,
|
||||
ui::{
|
||||
@ -125,6 +125,22 @@ impl UIFeaturesFirmware for ModelMercuryFeatures {
|
||||
Ok(flow)
|
||||
}
|
||||
|
||||
fn confirm_fido(
|
||||
title: TString<'static>,
|
||||
app_name: TString<'static>,
|
||||
icon: Option<TString<'static>>,
|
||||
accounts: Gc<List>,
|
||||
) -> Result<impl LayoutMaybeTrace, Error> {
|
||||
#[cfg(feature = "universal_fw")]
|
||||
return Ok(flow::confirm_fido::new_confirm_fido(
|
||||
title, app_name, icon, accounts,
|
||||
)?);
|
||||
#[cfg(not(feature = "universal_fw"))]
|
||||
Err::<RootComponent<Empty, ModelMercuryFeatures>, Error>(Error::ValueError(
|
||||
c"confirm_fido not used in bitcoin-only firmware",
|
||||
))
|
||||
}
|
||||
|
||||
fn confirm_firmware_update(
|
||||
description: TString<'static>,
|
||||
fingerprint: TString<'static>,
|
||||
|
@ -778,70 +778,6 @@ extern "C" fn new_multiple_pages_texts(n_args: usize, args: *const Obj, kwargs:
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
|
||||
extern "C" fn new_confirm_fido(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||
let app_name: TString = kwargs.get(Qstr::MP_QSTR_app_name)?.try_into()?;
|
||||
let accounts: Gc<List> = kwargs.get(Qstr::MP_QSTR_accounts)?.try_into()?;
|
||||
|
||||
// Cache the page count so that we can move `accounts` into the closure.
|
||||
let page_count = accounts.len();
|
||||
|
||||
// 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 get_page = move |page_index| {
|
||||
let account_obj = unwrap!(accounts.get(page_index));
|
||||
let account = TString::try_from(account_obj).unwrap_or_else(|_| TString::empty());
|
||||
|
||||
let (btn_layout, btn_actions) = if page_count == 1 {
|
||||
// There is only one page
|
||||
(
|
||||
ButtonLayout::cancel_none_text(TR::buttons__confirm.into()),
|
||||
ButtonActions::cancel_none_confirm(),
|
||||
)
|
||||
} else if page_index == 0 {
|
||||
// First page
|
||||
(
|
||||
ButtonLayout::cancel_armed_arrow(TR::buttons__select.into()),
|
||||
ButtonActions::cancel_confirm_next(),
|
||||
)
|
||||
} else if page_index == page_count - 1 {
|
||||
// Last page
|
||||
(
|
||||
ButtonLayout::arrow_armed_none(TR::buttons__select.into()),
|
||||
ButtonActions::prev_confirm_none(),
|
||||
)
|
||||
} else {
|
||||
// Page in the middle
|
||||
(
|
||||
ButtonLayout::arrow_armed_arrow(TR::buttons__select.into()),
|
||||
ButtonActions::prev_confirm_next(),
|
||||
)
|
||||
};
|
||||
|
||||
let ops = OpTextLayout::new(theme::TEXT_NORMAL)
|
||||
.newline()
|
||||
.text_normal(app_name)
|
||||
.newline()
|
||||
.text_bold(account);
|
||||
let formatted = FormattedText::new(ops);
|
||||
|
||||
Page::new(btn_layout, btn_actions, formatted)
|
||||
};
|
||||
|
||||
let pages = FlowPages::new(get_page, page_count);
|
||||
// Returning the page index in case of confirmation.
|
||||
let obj = LayoutObj::new(
|
||||
Flow::new(pages)
|
||||
.with_common_title(title)
|
||||
.with_return_confirmed_index(),
|
||||
)?;
|
||||
Ok(obj.into())
|
||||
};
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
|
||||
extern "C" fn new_confirm_with_info(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||
@ -1050,19 +986,6 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
||||
/// """Confirm details about altcoin transaction."""
|
||||
Qstr::MP_QSTR_altcoin_tx_summary => obj_fn_kw!(0, new_altcoin_tx_summary).as_obj(),
|
||||
|
||||
/// def confirm_fido(
|
||||
/// *,
|
||||
/// title: str,
|
||||
/// app_name: str,
|
||||
/// icon_name: str | None, # unused on TR
|
||||
/// accounts: list[str | None],
|
||||
/// ) -> LayoutObj[int | UiResult]:
|
||||
/// """FIDO confirmation.
|
||||
///
|
||||
/// Returns page index in case of confirmation and CANCELLED otherwise.
|
||||
/// """
|
||||
Qstr::MP_QSTR_confirm_fido => obj_fn_kw!(0, new_confirm_fido).as_obj(),
|
||||
|
||||
/// def multiple_pages_texts(
|
||||
/// *,
|
||||
/// title: str,
|
||||
|
@ -4,7 +4,7 @@ use crate::{
|
||||
error::Error,
|
||||
io::BinaryData,
|
||||
maybe_trace::MaybeTrace,
|
||||
micropython::gc::Gc,
|
||||
micropython::{gc::Gc, list::List},
|
||||
strutil::TString,
|
||||
translations::TR,
|
||||
ui::{
|
||||
@ -113,6 +113,68 @@ impl UIFeaturesFirmware for ModelTRFeatures {
|
||||
)
|
||||
}
|
||||
|
||||
fn confirm_fido(
|
||||
title: TString<'static>,
|
||||
app_name: TString<'static>,
|
||||
icon: Option<TString<'static>>,
|
||||
accounts: Gc<List>,
|
||||
) -> Result<impl LayoutMaybeTrace, Error> {
|
||||
// Cache the page count so that we can move `accounts` into the closure.
|
||||
let page_count = accounts.len();
|
||||
|
||||
// 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 get_page = move |page_index| {
|
||||
let account_obj = unwrap!(accounts.get(page_index));
|
||||
let account = TString::try_from(account_obj).unwrap_or_else(|_| TString::empty());
|
||||
|
||||
let (btn_layout, btn_actions) = if page_count == 1 {
|
||||
// There is only one page
|
||||
(
|
||||
ButtonLayout::cancel_none_text(TR::buttons__confirm.into()),
|
||||
ButtonActions::cancel_none_confirm(),
|
||||
)
|
||||
} else if page_index == 0 {
|
||||
// First page
|
||||
(
|
||||
ButtonLayout::cancel_armed_arrow(TR::buttons__select.into()),
|
||||
ButtonActions::cancel_confirm_next(),
|
||||
)
|
||||
} else if page_index == page_count - 1 {
|
||||
// Last page
|
||||
(
|
||||
ButtonLayout::arrow_armed_none(TR::buttons__select.into()),
|
||||
ButtonActions::prev_confirm_none(),
|
||||
)
|
||||
} else {
|
||||
// Page in the middle
|
||||
(
|
||||
ButtonLayout::arrow_armed_arrow(TR::buttons__select.into()),
|
||||
ButtonActions::prev_confirm_next(),
|
||||
)
|
||||
};
|
||||
|
||||
let ops = OpTextLayout::new(theme::TEXT_NORMAL)
|
||||
.newline()
|
||||
.text_normal(app_name)
|
||||
.newline()
|
||||
.text_bold(account);
|
||||
let formatted = FormattedText::new(ops);
|
||||
|
||||
Page::new(btn_layout, btn_actions, formatted)
|
||||
};
|
||||
|
||||
let pages = FlowPages::new(get_page, page_count);
|
||||
// Returning the page index in case of confirmation.
|
||||
let obj = RootComponent::new(
|
||||
Flow::new(pages)
|
||||
.with_common_title(title)
|
||||
.with_return_confirmed_index(),
|
||||
);
|
||||
Ok(obj)
|
||||
}
|
||||
|
||||
fn confirm_firmware_update(
|
||||
description: TString<'static>,
|
||||
fingerprint: TString<'static>,
|
||||
|
@ -702,37 +702,6 @@ extern "C" fn new_confirm_total(n_args: usize, args: *const Obj, kwargs: *mut Ma
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
|
||||
extern "C" fn new_confirm_fido(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||
let app_name: TString = kwargs.get(Qstr::MP_QSTR_app_name)?.try_into()?;
|
||||
let icon: Option<TString> = kwargs.get(Qstr::MP_QSTR_icon_name)?.try_into_option()?;
|
||||
let accounts: Gc<List> = kwargs.get(Qstr::MP_QSTR_accounts)?.try_into()?;
|
||||
|
||||
// Cache the page count so that we can move `accounts` into the closure.
|
||||
let page_count = accounts.len();
|
||||
// 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 get_page = move |page_index| {
|
||||
let account = unwrap!(accounts.get(page_index));
|
||||
account.try_into().unwrap_or_else(|_| "".into())
|
||||
};
|
||||
|
||||
let controls = Button::cancel_confirm(
|
||||
Button::with_icon(theme::ICON_CANCEL),
|
||||
Button::with_text(TR::buttons__confirm.into()).styled(theme::button_confirm()),
|
||||
true,
|
||||
);
|
||||
|
||||
let fido_page = FidoConfirm::new(app_name, get_page, page_count, icon, controls);
|
||||
|
||||
let obj = LayoutObj::new(Frame::centered(theme::label_title(), title, fido_page))?;
|
||||
Ok(obj.into())
|
||||
};
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
|
||||
extern "C" fn new_confirm_with_info(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||
@ -929,19 +898,6 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
||||
/// """Transaction summary. Always hold to confirm."""
|
||||
Qstr::MP_QSTR_confirm_total => obj_fn_kw!(0, new_confirm_total).as_obj(),
|
||||
|
||||
/// 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.
|
||||
/// """
|
||||
Qstr::MP_QSTR_confirm_fido => obj_fn_kw!(0, new_confirm_fido).as_obj(),
|
||||
|
||||
/// def confirm_with_info(
|
||||
/// *,
|
||||
/// title: str,
|
||||
|
@ -3,7 +3,7 @@ use core::cmp::Ordering;
|
||||
use crate::{
|
||||
error::{value_error, Error},
|
||||
io::BinaryData,
|
||||
micropython::gc::Gc,
|
||||
micropython::{gc::Gc, list::List},
|
||||
strutil::TString,
|
||||
translations::TR,
|
||||
ui::{
|
||||
@ -27,8 +27,8 @@ use crate::{
|
||||
use super::{
|
||||
component::{
|
||||
check_homescreen_format, Bip39Input, Button, ButtonMsg, ButtonPage, ButtonStyleSheet,
|
||||
CancelConfirmMsg, CoinJoinProgress, Dialog, Frame, Homescreen, IconDialog, Lockscreen,
|
||||
MnemonicKeyboard, NumberInputDialog, PassphraseKeyboard, PinKeyboard, Progress,
|
||||
CancelConfirmMsg, CoinJoinProgress, Dialog, FidoConfirm, Frame, Homescreen, IconDialog,
|
||||
Lockscreen, MnemonicKeyboard, NumberInputDialog, PassphraseKeyboard, PinKeyboard, Progress,
|
||||
SelectWordCount, SetBrightnessDialog, Slip39Input,
|
||||
},
|
||||
theme, ModelTTFeatures,
|
||||
@ -118,6 +118,34 @@ impl UIFeaturesFirmware for ModelTTFeatures {
|
||||
Ok(layout)
|
||||
}
|
||||
|
||||
fn confirm_fido(
|
||||
title: TString<'static>,
|
||||
app_name: TString<'static>,
|
||||
icon: Option<TString<'static>>,
|
||||
accounts: Gc<List>,
|
||||
) -> Result<impl LayoutMaybeTrace, Error> {
|
||||
// Cache the page count so that we can move `accounts` into the closure.
|
||||
let page_count = accounts.len();
|
||||
// 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 get_page = move |page_index| {
|
||||
let account = unwrap!(accounts.get(page_index));
|
||||
account.try_into().unwrap_or_else(|_| "".into())
|
||||
};
|
||||
|
||||
let controls = Button::cancel_confirm(
|
||||
Button::with_icon(theme::ICON_CANCEL),
|
||||
Button::with_text(TR::buttons__confirm.into()).styled(theme::button_confirm()),
|
||||
true,
|
||||
);
|
||||
|
||||
let fido_page = FidoConfirm::new(app_name, get_page, page_count, icon, controls);
|
||||
|
||||
let layout = RootComponent::new(Frame::centered(theme::label_title(), title, fido_page));
|
||||
Ok(layout)
|
||||
}
|
||||
|
||||
fn confirm_firmware_update(
|
||||
description: TString<'static>,
|
||||
fingerprint: TString<'static>,
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
error::Error,
|
||||
io::BinaryData,
|
||||
micropython::{gc::Gc, obj::Obj},
|
||||
micropython::{gc::Gc, list::List, obj::Obj},
|
||||
strutil::TString,
|
||||
};
|
||||
|
||||
@ -35,6 +35,13 @@ pub trait UIFeaturesFirmware {
|
||||
max_feerate: 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>,
|
||||
|
@ -108,19 +108,6 @@ def confirm_total(
|
||||
"""Transaction summary. Always hold to confirm."""
|
||||
|
||||
|
||||
# rust/src/ui/model_mercury/layout.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/model_mercury/layout.rs
|
||||
def confirm_with_info(
|
||||
*,
|
||||
@ -367,19 +354,6 @@ def altcoin_tx_summary(
|
||||
"""Confirm details about altcoin transaction."""
|
||||
|
||||
|
||||
# rust/src/ui/model_tr/layout.rs
|
||||
def confirm_fido(
|
||||
*,
|
||||
title: str,
|
||||
app_name: str,
|
||||
icon_name: str | None, # unused on TR
|
||||
accounts: list[str | None],
|
||||
) -> LayoutObj[int | UiResult]:
|
||||
"""FIDO confirmation.
|
||||
Returns page index in case of confirmation and CANCELLED otherwise.
|
||||
"""
|
||||
|
||||
|
||||
# rust/src/ui/model_tr/layout.rs
|
||||
def multiple_pages_texts(
|
||||
*,
|
||||
@ -534,19 +508,6 @@ def confirm_total(
|
||||
"""Transaction summary. Always hold to confirm."""
|
||||
|
||||
|
||||
# rust/src/ui/model_tt/layout.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/model_tt/layout.rs
|
||||
def confirm_with_info(
|
||||
*,
|
||||
|
@ -105,6 +105,19 @@ def confirm_coinjoin(
|
||||
"""Confirm coinjoin authorization."""
|
||||
|
||||
|
||||
# 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(
|
||||
*,
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user