mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-08-04 21:05:29 +00:00
WIP - FIDO and various fixes
This commit is contained in:
parent
416f76a033
commit
d4dce3d67f
32
ci/build.yml
32
ci/build.yml
@ -133,22 +133,6 @@ core fw btconly production build:
|
||||
- firmware-T2T1-btconly-production-*.*.*-$CI_COMMIT_SHORT_SHA.bin
|
||||
expire_in: 1 week
|
||||
|
||||
core fw btconly t1 build:
|
||||
stage: build
|
||||
<<: *gitlab_caching
|
||||
needs: []
|
||||
variables:
|
||||
BITCOIN_ONLY: "1"
|
||||
TREZOR_MODEL: "1"
|
||||
script:
|
||||
- nix-shell --run "poetry run make -C core build_firmware"
|
||||
- cp core/build/firmware/firmware.bin firmware-T1B1-btconly-t1-$CORE_VERSION-$CI_COMMIT_SHORT_SHA.bin
|
||||
artifacts:
|
||||
name: "$CI_JOB_NAME-$CI_COMMIT_SHORT_SHA"
|
||||
paths:
|
||||
- firmware-T1B1-btconly-t1-*.*.*-$CI_COMMIT_SHORT_SHA.bin
|
||||
expire_in: 1 week
|
||||
|
||||
core fw R btconly debug build:
|
||||
stage: build
|
||||
<<: *gitlab_caching
|
||||
@ -370,22 +354,6 @@ core unix frozen debug build arm:
|
||||
tags:
|
||||
- docker_darwin_arm
|
||||
|
||||
core unix frozen btconly debug t1 build:
|
||||
stage: build
|
||||
<<: *gitlab_caching
|
||||
needs: []
|
||||
variables:
|
||||
BITCOIN_ONLY: "1"
|
||||
TREZOR_MODEL: "1"
|
||||
script:
|
||||
- nix-shell --run "poetry run make -C core build_unix_frozen"
|
||||
- mv core/build/unix/trezor-emu-core core/build/unix/trezor-emu-core-bitcoinonly
|
||||
artifacts:
|
||||
name: "$CI_JOB_NAME-$CI_COMMIT_SHORT_SHA"
|
||||
paths:
|
||||
- core/build/unix # most of it needed by test_rust
|
||||
expire_in: 1 week
|
||||
|
||||
core macos frozen regular build:
|
||||
stage: build
|
||||
<<: *gitlab_caching
|
||||
|
@ -120,6 +120,7 @@ static void _librust_qstrs(void) {
|
||||
MP_QSTR_time_ms;
|
||||
MP_QSTR_app_name;
|
||||
MP_QSTR_icon_name;
|
||||
MP_QSTR_account;
|
||||
MP_QSTR_accounts;
|
||||
MP_QSTR_indeterminate;
|
||||
MP_QSTR_notification;
|
||||
|
@ -9,8 +9,6 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
use heapless::String;
|
||||
|
||||
use super::theme;
|
||||
|
||||
const HALF_SCREEN_BUTTON_WIDTH: i16 = constant::WIDTH / 2 - 1;
|
||||
@ -262,18 +260,6 @@ impl Component for Button {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl crate::trace::Trace for Button {
|
||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||
t.open("Button");
|
||||
match &self.content {
|
||||
ButtonContent::Text(text) => t.field("text", text),
|
||||
ButtonContent::Icon(icon) => t.field("icon", icon),
|
||||
}
|
||||
t.close();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
enum State {
|
||||
Released,
|
||||
@ -453,7 +439,7 @@ impl ButtonDetails {
|
||||
self
|
||||
}
|
||||
|
||||
/// Default duration of the hold-to-confirm.
|
||||
/// Default duration of the hold-to-confirm - 1 second.
|
||||
pub fn with_default_duration(mut self) -> Self {
|
||||
self.duration = Some(Duration::from_millis(1000));
|
||||
self
|
||||
@ -511,11 +497,11 @@ impl ButtonLayout {
|
||||
|
||||
/// Default button layout for all three buttons - icons.
|
||||
pub fn default_three_icons() -> Self {
|
||||
Self::three_icons_middle_text("SELECT".into())
|
||||
Self::arrow_armed_icon("SELECT".into())
|
||||
}
|
||||
|
||||
/// Special middle text for default icon layout.
|
||||
pub fn three_icons_middle_text(middle_text: StrBuffer) -> Self {
|
||||
pub fn arrow_armed_icon(middle_text: StrBuffer) -> Self {
|
||||
Self::new(
|
||||
Some(ButtonDetails::left_arrow_icon()),
|
||||
Some(ButtonDetails::armed_text(middle_text)),
|
||||
@ -523,8 +509,35 @@ impl ButtonLayout {
|
||||
)
|
||||
}
|
||||
|
||||
/// Left cancel, armed text and next right arrow.
|
||||
pub fn cancel_armed_arrow(middle_text: StrBuffer) -> Self {
|
||||
Self::new(
|
||||
Some(ButtonDetails::cancel_icon()),
|
||||
Some(ButtonDetails::armed_text(middle_text)),
|
||||
Some(ButtonDetails::right_arrow_icon()),
|
||||
)
|
||||
}
|
||||
|
||||
/// Left cancel, armed text and right text.
|
||||
pub fn cancel_armed_text(middle_text: StrBuffer, right_text: StrBuffer) -> Self {
|
||||
Self::new(
|
||||
Some(ButtonDetails::cancel_icon()),
|
||||
Some(ButtonDetails::armed_text(middle_text)),
|
||||
Some(ButtonDetails::text(right_text)),
|
||||
)
|
||||
}
|
||||
|
||||
/// Left back arrow and middle armed text.
|
||||
pub fn arrow_armed_none(middle_text: StrBuffer) -> Self {
|
||||
Self::new(
|
||||
Some(ButtonDetails::left_arrow_icon()),
|
||||
Some(ButtonDetails::armed_text(middle_text)),
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
/// Left and right texts.
|
||||
pub fn left_right_text(text_left: StrBuffer, text_right: StrBuffer) -> Self {
|
||||
pub fn text_none_text(text_left: StrBuffer, text_right: StrBuffer) -> Self {
|
||||
Self::new(
|
||||
Some(ButtonDetails::text(text_left)),
|
||||
None,
|
||||
@ -533,12 +546,12 @@ impl ButtonLayout {
|
||||
}
|
||||
|
||||
/// Only right text.
|
||||
pub fn only_right_text(text_right: StrBuffer) -> Self {
|
||||
pub fn none_none_text(text_right: StrBuffer) -> Self {
|
||||
Self::new(None, None, Some(ButtonDetails::text(text_right)))
|
||||
}
|
||||
|
||||
/// Left and right arrow icons for navigation.
|
||||
pub fn left_right_arrows() -> Self {
|
||||
pub fn arrow_none_arrow() -> Self {
|
||||
Self::new(
|
||||
Some(ButtonDetails::left_arrow_icon()),
|
||||
None,
|
||||
@ -546,8 +559,26 @@ impl ButtonLayout {
|
||||
)
|
||||
}
|
||||
|
||||
/// Left arrow and right text.
|
||||
pub fn arrow_none_text(text_right: StrBuffer) -> Self {
|
||||
Self::new(
|
||||
Some(ButtonDetails::left_arrow_icon()),
|
||||
None,
|
||||
Some(ButtonDetails::text(text_right)),
|
||||
)
|
||||
}
|
||||
|
||||
/// Up arrow left and right text.
|
||||
pub fn up_arrow_none_text(text_right: StrBuffer) -> Self {
|
||||
Self::new(
|
||||
Some(ButtonDetails::up_arrow_icon()),
|
||||
None,
|
||||
Some(ButtonDetails::text(text_right)),
|
||||
)
|
||||
}
|
||||
|
||||
/// Cancel cross on left and right arrow.
|
||||
pub fn cancel_and_arrow() -> Self {
|
||||
pub fn cancel_none_arrow() -> Self {
|
||||
Self::new(
|
||||
Some(ButtonDetails::cancel_icon()),
|
||||
None,
|
||||
@ -556,7 +587,7 @@ impl ButtonLayout {
|
||||
}
|
||||
|
||||
/// Cancel cross on left and right arrow facing down.
|
||||
pub fn cancel_and_arrow_down() -> Self {
|
||||
pub fn cancel_none_arrow_wide() -> Self {
|
||||
Self::new(
|
||||
Some(ButtonDetails::cancel_icon()),
|
||||
None,
|
||||
@ -565,7 +596,7 @@ impl ButtonLayout {
|
||||
}
|
||||
|
||||
/// Cancel cross on left and text on the right.
|
||||
pub fn cancel_and_text(text: StrBuffer) -> Self {
|
||||
pub fn cancel_none_text(text: StrBuffer) -> Self {
|
||||
Self::new(
|
||||
Some(ButtonDetails::cancel_icon()),
|
||||
None,
|
||||
@ -574,39 +605,30 @@ impl ButtonLayout {
|
||||
}
|
||||
|
||||
/// Cancel cross on left and hold-to-confirm text on the right.
|
||||
pub fn cancel_and_htc_text(text: StrBuffer, duration: Duration) -> Self {
|
||||
pub fn cancel_none_htc(text: StrBuffer) -> Self {
|
||||
Self::new(
|
||||
Some(ButtonDetails::cancel_icon()),
|
||||
None,
|
||||
Some(ButtonDetails::text(text).with_duration(duration)),
|
||||
Some(ButtonDetails::text(text).with_default_duration()),
|
||||
)
|
||||
}
|
||||
|
||||
/// Arrow back on left and hold-to-confirm text on the right.
|
||||
pub fn back_and_htc_text(text: StrBuffer, duration: Duration) -> Self {
|
||||
pub fn arrow_none_htc(text: StrBuffer) -> Self {
|
||||
Self::new(
|
||||
Some(ButtonDetails::left_arrow_icon()),
|
||||
None,
|
||||
Some(ButtonDetails::text(text).with_duration(duration)),
|
||||
)
|
||||
}
|
||||
|
||||
/// Arrow back on left and text on the right.
|
||||
pub fn back_and_text(text: StrBuffer) -> Self {
|
||||
Self::new(
|
||||
Some(ButtonDetails::left_arrow_icon()),
|
||||
None,
|
||||
Some(ButtonDetails::text(text)),
|
||||
Some(ButtonDetails::text(text).with_default_duration()),
|
||||
)
|
||||
}
|
||||
|
||||
/// Only armed text in the middle.
|
||||
pub fn middle_armed_text(text: StrBuffer) -> Self {
|
||||
pub fn none_armed_none(text: StrBuffer) -> Self {
|
||||
Self::new(None, Some(ButtonDetails::armed_text(text)), None)
|
||||
}
|
||||
|
||||
/// Only hold-to-confirm with text on the right.
|
||||
pub fn htc_only(text: StrBuffer, duration: Duration) -> Self {
|
||||
pub fn none_none_htc(text: StrBuffer, duration: Duration) -> Self {
|
||||
Self::new(
|
||||
None,
|
||||
None,
|
||||
@ -614,30 +636,14 @@ impl ButtonLayout {
|
||||
)
|
||||
}
|
||||
|
||||
/// Only right arrow facing down.
|
||||
pub fn only_arrow_down() -> Self {
|
||||
Self::new(None, None, Some(ButtonDetails::down_arrow_icon_wide()))
|
||||
/// Only left arrow.
|
||||
pub fn arrow_none_none() -> Self {
|
||||
Self::new(Some(ButtonDetails::left_arrow_icon()), None, None)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl crate::trace::Trace for ButtonDetails {
|
||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||
t.open("ButtonDetails");
|
||||
let mut btn_text: String<30> = String::new();
|
||||
if let Some(text) = &self.text {
|
||||
btn_text.push_str(text.as_ref()).unwrap();
|
||||
} else if let Some(icon) = &self.icon {
|
||||
btn_text.push_str("Icon:").unwrap();
|
||||
btn_text.push_str(icon.text.as_ref()).unwrap();
|
||||
}
|
||||
if let Some(duration) = &self.duration {
|
||||
btn_text.push_str(" (HTC:").unwrap();
|
||||
btn_text.push_str(inttostr!(duration.to_millis())).unwrap();
|
||||
btn_text.push_str(")").unwrap();
|
||||
}
|
||||
t.button(btn_text.as_ref());
|
||||
t.close();
|
||||
/// Only right arrow facing down.
|
||||
pub fn none_none_arrow_wide() -> Self {
|
||||
Self::new(None, None, Some(ButtonDetails::down_arrow_icon_wide()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -667,6 +673,195 @@ pub enum ButtonAction {
|
||||
Action(&'static str),
|
||||
}
|
||||
|
||||
/// Storing actions for all three possible buttons.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ButtonActions {
|
||||
pub left: Option<ButtonAction>,
|
||||
pub middle: Option<ButtonAction>,
|
||||
pub right: Option<ButtonAction>,
|
||||
}
|
||||
|
||||
impl ButtonActions {
|
||||
pub fn new(
|
||||
left: Option<ButtonAction>,
|
||||
middle: Option<ButtonAction>,
|
||||
right: Option<ButtonAction>,
|
||||
) -> Self {
|
||||
Self {
|
||||
left,
|
||||
middle,
|
||||
right,
|
||||
}
|
||||
}
|
||||
|
||||
/// Going back with left, going further with right
|
||||
pub fn prev_none_next() -> Self {
|
||||
Self::new(
|
||||
Some(ButtonAction::PrevPage),
|
||||
None,
|
||||
Some(ButtonAction::NextPage),
|
||||
)
|
||||
}
|
||||
|
||||
/// Going back with left, going further with middle
|
||||
pub fn prev_next_none() -> Self {
|
||||
Self::new(
|
||||
Some(ButtonAction::PrevPage),
|
||||
Some(ButtonAction::NextPage),
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
/// Previous with left, confirming with right
|
||||
pub fn prev_none_confirm() -> Self {
|
||||
Self::new(
|
||||
Some(ButtonAction::PrevPage),
|
||||
None,
|
||||
Some(ButtonAction::Confirm),
|
||||
)
|
||||
}
|
||||
|
||||
/// Previous with left, confirming with middle
|
||||
pub fn prev_confirm_none() -> Self {
|
||||
Self::new(
|
||||
Some(ButtonAction::PrevPage),
|
||||
Some(ButtonAction::Confirm),
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
/// Going to last page with left, to the next page with right
|
||||
pub fn last_none_next() -> Self {
|
||||
Self::new(
|
||||
Some(ButtonAction::GoToIndex(-1)),
|
||||
None,
|
||||
Some(ButtonAction::NextPage),
|
||||
)
|
||||
}
|
||||
|
||||
/// Going to last page with left, to the next page with right and confirm
|
||||
/// with middle
|
||||
pub fn last_confirm_next() -> Self {
|
||||
Self::new(
|
||||
Some(ButtonAction::GoToIndex(-1)),
|
||||
Some(ButtonAction::Confirm),
|
||||
Some(ButtonAction::NextPage),
|
||||
)
|
||||
}
|
||||
|
||||
/// Going to previous page with left, to the next page with right and
|
||||
/// confirm with middle
|
||||
pub fn prev_confirm_next() -> Self {
|
||||
Self::new(
|
||||
Some(ButtonAction::PrevPage),
|
||||
Some(ButtonAction::Confirm),
|
||||
Some(ButtonAction::NextPage),
|
||||
)
|
||||
}
|
||||
|
||||
/// Cancelling with left, going to the next page with right
|
||||
pub fn cancel_none_next() -> Self {
|
||||
Self::new(
|
||||
Some(ButtonAction::Cancel),
|
||||
None,
|
||||
Some(ButtonAction::NextPage),
|
||||
)
|
||||
}
|
||||
|
||||
/// Only going to the next page with right
|
||||
pub fn none_none_next() -> Self {
|
||||
Self::new(None, None, Some(ButtonAction::NextPage))
|
||||
}
|
||||
|
||||
/// Only going to the prev page with left
|
||||
pub fn prev_none_none() -> Self {
|
||||
Self::new(Some(ButtonAction::PrevPage), None, None)
|
||||
}
|
||||
|
||||
/// Cancelling with left, confirming with right
|
||||
pub fn cancel_none_confirm() -> Self {
|
||||
Self::new(
|
||||
Some(ButtonAction::Cancel),
|
||||
None,
|
||||
Some(ButtonAction::Confirm),
|
||||
)
|
||||
}
|
||||
|
||||
/// Cancelling with left, confirming with middle and next with right
|
||||
pub fn cancel_confirm_next() -> Self {
|
||||
Self::new(
|
||||
Some(ButtonAction::Cancel),
|
||||
Some(ButtonAction::Confirm),
|
||||
Some(ButtonAction::NextPage),
|
||||
)
|
||||
}
|
||||
|
||||
/// Going to the beginning with left, confirming with right
|
||||
pub fn beginning_none_confirm() -> Self {
|
||||
Self::new(
|
||||
Some(ButtonAction::GoToIndex(0)),
|
||||
None,
|
||||
Some(ButtonAction::Confirm),
|
||||
)
|
||||
}
|
||||
|
||||
/// Going to the beginning with left, cancelling with right
|
||||
pub fn beginning_none_cancel() -> Self {
|
||||
Self::new(
|
||||
Some(ButtonAction::GoToIndex(0)),
|
||||
None,
|
||||
Some(ButtonAction::Cancel),
|
||||
)
|
||||
}
|
||||
|
||||
/// Having access to appropriate action based on the `ButtonPos`
|
||||
pub fn get_action(&self, pos: ButtonPos) -> Option<ButtonAction> {
|
||||
match pos {
|
||||
ButtonPos::Left => self.left,
|
||||
ButtonPos::Middle => self.middle,
|
||||
ButtonPos::Right => self.right,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG-ONLY SECTION BELOW
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl crate::trace::Trace for Button {
|
||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||
t.open("Button");
|
||||
match &self.content {
|
||||
ButtonContent::Text(text) => t.field("text", text),
|
||||
ButtonContent::Icon(icon) => t.field("icon", icon),
|
||||
}
|
||||
t.close();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
use heapless::String;
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl crate::trace::Trace for ButtonDetails {
|
||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||
t.open("ButtonDetails");
|
||||
let mut btn_text: String<30> = String::new();
|
||||
if let Some(text) = &self.text {
|
||||
btn_text.push_str(text.as_ref()).unwrap();
|
||||
} else if let Some(icon) = &self.icon {
|
||||
btn_text.push_str("Icon:").unwrap();
|
||||
btn_text.push_str(icon.text.as_ref()).unwrap();
|
||||
}
|
||||
if let Some(duration) = &self.duration {
|
||||
btn_text.push_str(" (HTC:").unwrap();
|
||||
btn_text.push_str(inttostr!(duration.to_millis())).unwrap();
|
||||
btn_text.push_str(")").unwrap();
|
||||
}
|
||||
t.button(btn_text.as_ref());
|
||||
t.close();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl ButtonAction {
|
||||
/// Describing the action as a string. Debug-only.
|
||||
@ -697,126 +892,3 @@ impl ButtonAction {
|
||||
"None".into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Storing actions for all three possible buttons.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ButtonActions {
|
||||
pub left: Option<ButtonAction>,
|
||||
pub middle: Option<ButtonAction>,
|
||||
pub right: Option<ButtonAction>,
|
||||
}
|
||||
|
||||
impl ButtonActions {
|
||||
pub fn new(
|
||||
left: Option<ButtonAction>,
|
||||
middle: Option<ButtonAction>,
|
||||
right: Option<ButtonAction>,
|
||||
) -> Self {
|
||||
Self {
|
||||
left,
|
||||
middle,
|
||||
right,
|
||||
}
|
||||
}
|
||||
|
||||
/// Going back with left, going further with right
|
||||
pub fn prev_next() -> Self {
|
||||
Self::new(
|
||||
Some(ButtonAction::PrevPage),
|
||||
None,
|
||||
Some(ButtonAction::NextPage),
|
||||
)
|
||||
}
|
||||
|
||||
/// Going back with left, going further with middle
|
||||
pub fn prev_next_with_middle() -> Self {
|
||||
Self::new(
|
||||
Some(ButtonAction::PrevPage),
|
||||
Some(ButtonAction::NextPage),
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
/// Previous with left, confirming with right
|
||||
pub fn prev_confirm() -> Self {
|
||||
Self::new(
|
||||
Some(ButtonAction::PrevPage),
|
||||
None,
|
||||
Some(ButtonAction::Confirm),
|
||||
)
|
||||
}
|
||||
|
||||
/// Going to last page with left, to the next page with right
|
||||
pub fn last_next() -> Self {
|
||||
Self::new(
|
||||
Some(ButtonAction::GoToIndex(-1)),
|
||||
None,
|
||||
Some(ButtonAction::NextPage),
|
||||
)
|
||||
}
|
||||
|
||||
/// Going to last page with left, to the next page with right and confirm
|
||||
/// with middle
|
||||
pub fn last_confirm_next() -> Self {
|
||||
Self::new(
|
||||
Some(ButtonAction::GoToIndex(-1)),
|
||||
Some(ButtonAction::Confirm),
|
||||
Some(ButtonAction::NextPage),
|
||||
)
|
||||
}
|
||||
|
||||
/// Cancelling with left, going to the next page with right
|
||||
pub fn cancel_next() -> Self {
|
||||
Self::new(
|
||||
Some(ButtonAction::Cancel),
|
||||
None,
|
||||
Some(ButtonAction::NextPage),
|
||||
)
|
||||
}
|
||||
|
||||
/// Only going to the next page with right
|
||||
pub fn only_next() -> Self {
|
||||
Self::new(None, None, Some(ButtonAction::NextPage))
|
||||
}
|
||||
|
||||
/// Only going to the prev page with left
|
||||
pub fn only_prev() -> Self {
|
||||
Self::new(Some(ButtonAction::PrevPage), None, None)
|
||||
}
|
||||
|
||||
/// Cancelling with left, confirming with right
|
||||
pub fn cancel_confirm() -> Self {
|
||||
Self::new(
|
||||
Some(ButtonAction::Cancel),
|
||||
None,
|
||||
Some(ButtonAction::Confirm),
|
||||
)
|
||||
}
|
||||
|
||||
/// Going to the beginning with left, confirming with right
|
||||
pub fn beginning_confirm() -> Self {
|
||||
Self::new(
|
||||
Some(ButtonAction::GoToIndex(0)),
|
||||
None,
|
||||
Some(ButtonAction::Confirm),
|
||||
)
|
||||
}
|
||||
|
||||
/// Going to the beginning with left, cancelling with right
|
||||
pub fn beginning_cancel() -> Self {
|
||||
Self::new(
|
||||
Some(ButtonAction::GoToIndex(0)),
|
||||
None,
|
||||
Some(ButtonAction::Cancel),
|
||||
)
|
||||
}
|
||||
|
||||
/// Having access to appropriate action based on the `ButtonPos`
|
||||
pub fn get_action(&self, pos: ButtonPos) -> Option<ButtonAction> {
|
||||
match pos {
|
||||
ButtonPos::Left => self.left,
|
||||
ButtonPos::Middle => self.middle,
|
||||
ButtonPos::Right => self.right,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,6 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
use heapless::String;
|
||||
|
||||
/// All possible states buttons (left and right) can be at.
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
enum ButtonState {
|
||||
@ -435,8 +433,12 @@ impl Component for ButtonController {
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG-ONLY SECTION BELOW
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
use super::ButtonContent;
|
||||
#[cfg(feature = "ui_debug")]
|
||||
use heapless::String;
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl crate::trace::Trace for ButtonContainer {
|
||||
|
@ -14,6 +14,7 @@ use super::{
|
||||
/// To be returned directly from Flow.
|
||||
pub enum FlowMsg {
|
||||
Confirmed,
|
||||
ConfirmedIndex(u8),
|
||||
Cancelled,
|
||||
}
|
||||
|
||||
@ -30,6 +31,7 @@ pub struct Flow<F, const M: usize> {
|
||||
pad: Pad,
|
||||
buttons: Child<ButtonController>,
|
||||
page_counter: u8,
|
||||
return_confirmed_index: bool,
|
||||
}
|
||||
|
||||
impl<F, const M: usize> Flow<F, M>
|
||||
@ -51,6 +53,7 @@ where
|
||||
// `content.page_count()`.
|
||||
buttons: Child::new(ButtonController::new(ButtonLayout::empty())),
|
||||
page_counter: 0,
|
||||
return_confirmed_index: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,6 +64,12 @@ where
|
||||
self
|
||||
}
|
||||
|
||||
/// Causing the Flow to return the index of the page that was confirmed.
|
||||
pub fn with_return_confirmed_index(mut self) -> Self {
|
||||
self.return_confirmed_index = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Getting new current page according to page counter.
|
||||
/// Also updating the possible title and moving the scrollbar to correct
|
||||
/// position.
|
||||
@ -222,7 +231,13 @@ where
|
||||
return None;
|
||||
}
|
||||
ButtonAction::Cancel => return Some(FlowMsg::Cancelled),
|
||||
ButtonAction::Confirm => return Some(FlowMsg::Confirmed),
|
||||
ButtonAction::Confirm => {
|
||||
if self.return_confirmed_index {
|
||||
return Some(FlowMsg::ConfirmedIndex(self.page_counter));
|
||||
} else {
|
||||
return Some(FlowMsg::Confirmed);
|
||||
}
|
||||
}
|
||||
ButtonAction::Select => {}
|
||||
ButtonAction::Action(_) => {}
|
||||
}
|
||||
@ -247,6 +262,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG-ONLY SECTION BELOW
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
use heapless::String;
|
||||
|
||||
|
@ -332,6 +332,8 @@ impl<const M: usize> Paginate for Page<M> {
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG-ONLY SECTION BELOW
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
pub mod trace {
|
||||
use crate::ui::model_tr::component::flow_pages_poc_helpers::TraceSink;
|
||||
|
@ -96,6 +96,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG-ONLY SECTION BELOW
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl<T> crate::trace::Trace for Frame<T>
|
||||
where
|
||||
|
@ -108,6 +108,8 @@ impl Component for HoldToConfirm {
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG-ONLY SECTION BELOW
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl crate::trace::Trace for HoldToConfirm {
|
||||
fn trace(&self, d: &mut dyn crate::trace::Tracer) {
|
||||
|
@ -85,17 +85,6 @@ impl Component for Homescreen {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl crate::trace::Trace for Homescreen {
|
||||
fn trace(&self, d: &mut dyn crate::trace::Tracer) {
|
||||
d.open("Homescreen");
|
||||
d.kw_pair("active_page", "0");
|
||||
d.kw_pair("page_count", "1");
|
||||
d.field("label", &self.label.as_ref());
|
||||
d.close();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Lockscreen {
|
||||
label: StrBuffer,
|
||||
bootscreen: bool,
|
||||
@ -137,6 +126,19 @@ impl Component for Lockscreen {
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG-ONLY SECTION BELOW
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl crate::trace::Trace for Homescreen {
|
||||
fn trace(&self, d: &mut dyn crate::trace::Tracer) {
|
||||
d.open("Homescreen");
|
||||
d.kw_pair("active_page", "0");
|
||||
d.kw_pair("page_count", "1");
|
||||
d.field("label", &self.label.as_ref());
|
||||
d.close();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl crate::trace::Trace for Lockscreen {
|
||||
fn trace(&self, d: &mut dyn crate::trace::Tracer) {
|
||||
|
@ -58,11 +58,8 @@ impl ChoiceFactory for ChoiceFactoryBIP39 {
|
||||
match self {
|
||||
Self::Letters(letter_choices) => {
|
||||
if choice_index >= letter_choices.len() as u8 {
|
||||
ChoiceItem::new(
|
||||
"DELETE",
|
||||
ButtonLayout::three_icons_middle_text("CONFIRM".into()),
|
||||
)
|
||||
.with_icon(Icon::new(theme::ICON_DELETE))
|
||||
ChoiceItem::new("DELETE", ButtonLayout::arrow_armed_icon("CONFIRM".into()))
|
||||
.with_icon(Icon::new(theme::ICON_DELETE))
|
||||
} else {
|
||||
let letter = letter_choices[choice_index as usize];
|
||||
ChoiceItem::new(
|
||||
@ -73,11 +70,9 @@ impl ChoiceFactory for ChoiceFactoryBIP39 {
|
||||
}
|
||||
Self::Words(word_choices) => {
|
||||
if choice_index >= word_choices.len() as u8 {
|
||||
let mut item = ChoiceItem::new(
|
||||
"DELETE",
|
||||
ButtonLayout::three_icons_middle_text("CONFIRM".into()),
|
||||
)
|
||||
.with_icon(Icon::new(theme::ICON_DELETE));
|
||||
let mut item =
|
||||
ChoiceItem::new("DELETE", ButtonLayout::arrow_armed_icon("CONFIRM".into()))
|
||||
.with_icon(Icon::new(theme::ICON_DELETE));
|
||||
item.set_right_btn(None);
|
||||
item
|
||||
} else {
|
||||
@ -223,6 +218,8 @@ impl Component for Bip39Entry {
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG-ONLY SECTION BELOW
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
use super::super::{ButtonAction, ButtonPos};
|
||||
#[cfg(feature = "ui_debug")]
|
||||
|
@ -421,6 +421,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG-ONLY SECTION BELOW
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl<F> crate::trace::Trace for ChoicePage<F>
|
||||
where
|
||||
|
@ -198,6 +198,8 @@ impl Choice for ChoiceItem {
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG-ONLY SECTION BELOW
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl crate::trace::Trace for ChoiceItem {
|
||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||
|
@ -135,10 +135,7 @@ impl ChoiceFactoryPassphrase {
|
||||
/// return back
|
||||
fn get_character_item(&self, choice_index: u8) -> ChoiceItem {
|
||||
if is_menu_choice(&self.current_category, choice_index) {
|
||||
ChoiceItem::new(
|
||||
"MENU",
|
||||
ButtonLayout::three_icons_middle_text("RETURN".into()),
|
||||
)
|
||||
ChoiceItem::new("MENU", ButtonLayout::arrow_armed_icon("RETURN".into()))
|
||||
} else {
|
||||
let ch = get_char(&self.current_category, choice_index);
|
||||
ChoiceItem::new(char_to_string::<1>(ch), ButtonLayout::default_three_icons())
|
||||
@ -304,6 +301,8 @@ impl Component for PassphraseEntry {
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG-ONLY SECTION BELOW
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
use super::super::{ButtonAction, ButtonPos};
|
||||
#[cfg(feature = "ui_debug")]
|
||||
|
@ -215,6 +215,8 @@ impl Component for PinEntry {
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG-ONLY SECTION BELOW
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
use super::super::{ButtonAction, ButtonPos};
|
||||
|
||||
|
@ -9,9 +9,6 @@ use crate::{
|
||||
use super::super::{ButtonLayout, ChoiceFactory, ChoiceItem, ChoicePage, ChoicePageMsg};
|
||||
use heapless::{String, Vec};
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
use super::super::{ButtonAction, ButtonPos};
|
||||
|
||||
pub enum SimpleChoiceMsg {
|
||||
Result(String<50>),
|
||||
}
|
||||
@ -95,6 +92,11 @@ impl<const N: usize> Component for SimpleChoice<N> {
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG-ONLY SECTION BELOW
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
use super::super::{ButtonAction, ButtonPos};
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl<const N: usize> crate::trace::Trace for SimpleChoice<N> {
|
||||
fn get_btn_action(&self, pos: ButtonPos) -> String<25> {
|
||||
|
@ -241,6 +241,8 @@ impl LoaderStyleSheet {
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG-ONLY SECTION BELOW
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl crate::trace::Trace for Loader {
|
||||
fn trace(&self, d: &mut dyn crate::trace::Tracer) {
|
||||
|
@ -13,7 +13,6 @@ mod loader;
|
||||
mod no_btn_dialog;
|
||||
mod page;
|
||||
mod progress;
|
||||
mod qr_code;
|
||||
mod result_anim;
|
||||
mod result_popup;
|
||||
mod scrollbar;
|
||||
@ -45,7 +44,6 @@ pub use loader::{Loader, LoaderMsg, LoaderStyle, LoaderStyleSheet};
|
||||
pub use no_btn_dialog::{NoBtnDialog, NoBtnDialogMsg};
|
||||
pub use page::ButtonPage;
|
||||
pub use progress::Progress;
|
||||
pub use qr_code::{QRCodePage, QRCodePageMessage};
|
||||
pub use result_anim::{ResultAnim, ResultAnimMsg};
|
||||
pub use result_popup::{ResultPopup, ResultPopupMsg};
|
||||
pub use scrollbar::ScrollBar;
|
||||
|
@ -55,6 +55,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG-ONLY SECTION BELOW
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl<T, U> crate::trace::Trace for NoBtnDialog<T, U>
|
||||
where
|
||||
|
@ -217,6 +217,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG-ONLY SECTION BELOW
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
use super::ButtonAction;
|
||||
#[cfg(feature = "ui_debug")]
|
||||
|
@ -120,6 +120,8 @@ impl Component for Progress {
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG-ONLY SECTION BELOW
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl crate::trace::Trace for Progress {
|
||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||
|
@ -1,109 +0,0 @@
|
||||
use crate::{
|
||||
micropython::buffer::StrBuffer,
|
||||
ui::{
|
||||
component::{Child, Component, Event, EventCtx},
|
||||
display::{self, Font},
|
||||
geometry::Rect,
|
||||
},
|
||||
};
|
||||
|
||||
use super::{theme, ButtonController, ButtonControllerMsg, ButtonLayout, ButtonPos};
|
||||
|
||||
pub enum QRCodePageMessage {
|
||||
Confirmed,
|
||||
Cancelled,
|
||||
}
|
||||
|
||||
pub struct QRCodePage<T> {
|
||||
title: StrBuffer,
|
||||
title_area: Rect,
|
||||
qr_code: T,
|
||||
buttons: Child<ButtonController>,
|
||||
}
|
||||
|
||||
impl<T> QRCodePage<T> {
|
||||
pub fn new(title: StrBuffer, qr_code: T, btn_layout: ButtonLayout) -> Self {
|
||||
Self {
|
||||
title,
|
||||
title_area: Rect::zero(),
|
||||
qr_code,
|
||||
buttons: Child::new(ButtonController::new(btn_layout)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Component for QRCodePage<T>
|
||||
where
|
||||
T: Component,
|
||||
{
|
||||
type Msg = QRCodePageMessage;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
let (content_area, button_area) = bounds.split_bottom(theme::BUTTON_HEIGHT);
|
||||
let (qr_code_area, title_area) = content_area.split_left(theme::QR_SIDE_MAX);
|
||||
self.title_area = title_area;
|
||||
self.qr_code.place(qr_code_area);
|
||||
self.buttons.place(button_area);
|
||||
bounds
|
||||
}
|
||||
|
||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
||||
let button_event = self.buttons.event(ctx, event);
|
||||
|
||||
if let Some(ButtonControllerMsg::Triggered(pos)) = button_event {
|
||||
match pos {
|
||||
ButtonPos::Left => {
|
||||
return Some(QRCodePageMessage::Cancelled);
|
||||
}
|
||||
ButtonPos::Right => {
|
||||
return Some(QRCodePageMessage::Confirmed);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.qr_code.paint();
|
||||
// TODO: add the Label from Suite
|
||||
display::text_multiline(
|
||||
self.title_area,
|
||||
self.title.as_ref(),
|
||||
Font::MONO,
|
||||
theme::FG,
|
||||
theme::BG,
|
||||
);
|
||||
self.buttons.paint();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
use super::ButtonAction;
|
||||
#[cfg(feature = "ui_debug")]
|
||||
use heapless::String;
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl<T> crate::trace::Trace for QRCodePage<T> {
|
||||
fn get_btn_action(&self, pos: ButtonPos) -> String<25> {
|
||||
match pos {
|
||||
ButtonPos::Left => ButtonAction::Cancel.string(),
|
||||
ButtonPos::Right => ButtonAction::Confirm.string(),
|
||||
ButtonPos::Middle => ButtonAction::empty(),
|
||||
}
|
||||
}
|
||||
|
||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||
t.open("QRCodePage");
|
||||
t.kw_pair("active_page", "0");
|
||||
t.kw_pair("page_count", "1");
|
||||
self.report_btn_actions(t);
|
||||
t.content_flag();
|
||||
t.string("QR CODE");
|
||||
t.string(self.title.as_ref());
|
||||
t.content_flag();
|
||||
t.field("buttons", &self.buttons);
|
||||
t.close();
|
||||
}
|
||||
}
|
@ -140,6 +140,8 @@ impl Component for ResultAnim {
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG-ONLY SECTION BELOW
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl crate::trace::Trace for ResultAnim {
|
||||
fn trace(&self, d: &mut dyn crate::trace::Tracer) {
|
||||
|
@ -49,7 +49,7 @@ impl ResultPopup {
|
||||
.with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let buttons = button_text.map(|text| {
|
||||
let btn_layout = ButtonLayout::only_right_text(text.into());
|
||||
let btn_layout = ButtonLayout::none_none_text(text.into());
|
||||
Child::new(ButtonController::new(btn_layout))
|
||||
});
|
||||
|
||||
@ -155,6 +155,8 @@ impl Component for ResultPopup {
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG-ONLY SECTION BELOW
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl crate::trace::Trace for ResultPopup {
|
||||
fn trace(&self, d: &mut dyn crate::trace::Tracer) {
|
||||
|
@ -142,6 +142,8 @@ impl<const N: usize> Paginate for ShareWords<N> {
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG-ONLY SECTION BELOW
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl<const N: usize> crate::trace::Trace for ShareWords<N> {
|
||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||
|
@ -6,14 +6,15 @@ use crate::{
|
||||
error::Error,
|
||||
micropython::{
|
||||
buffer::StrBuffer,
|
||||
gc::Gc,
|
||||
iter::{Iter, IterBuf},
|
||||
list::List,
|
||||
map::Map,
|
||||
module::Module,
|
||||
obj::Obj,
|
||||
qstr::Qstr,
|
||||
util,
|
||||
},
|
||||
time::Duration,
|
||||
ui::{
|
||||
component::{
|
||||
base::Component,
|
||||
@ -38,7 +39,7 @@ use super::{
|
||||
Bip39Entry, Bip39EntryMsg, ButtonActions, ButtonDetails, ButtonLayout, ButtonPage, Flow,
|
||||
FlowMsg, FlowPages, Frame, Homescreen, HomescreenMsg, Lockscreen, NoBtnDialog,
|
||||
NoBtnDialogMsg, Page, PassphraseEntry, PassphraseEntryMsg, PinEntry, PinEntryMsg, Progress,
|
||||
QRCodePage, QRCodePageMessage, ShareWords, SimpleChoice, SimpleChoiceMsg,
|
||||
ShareWords, SimpleChoice, SimpleChoiceMsg,
|
||||
},
|
||||
constant, theme,
|
||||
};
|
||||
@ -94,18 +95,7 @@ where
|
||||
match msg {
|
||||
FlowMsg::Confirmed => Ok(CONFIRMED.as_obj()),
|
||||
FlowMsg::Cancelled => Ok(CANCELLED.as_obj()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ComponentMsgObj for QRCodePage<T>
|
||||
where
|
||||
T: Component,
|
||||
{
|
||||
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
|
||||
match msg {
|
||||
QRCodePageMessage::Confirmed => Ok(CONFIRMED.as_obj()),
|
||||
QRCodePageMessage::Cancelled => Ok(CANCELLED.as_obj()),
|
||||
FlowMsg::ConfirmedIndex(page) => Ok(page.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -181,11 +171,13 @@ extern "C" fn new_confirm_action(n_args: usize, args: *const Obj, kwargs: *mut M
|
||||
let action: Option<StrBuffer> = kwargs.get(Qstr::MP_QSTR_action)?.try_into_option()?;
|
||||
let description: Option<StrBuffer> =
|
||||
kwargs.get(Qstr::MP_QSTR_description)?.try_into_option()?;
|
||||
let verb: Option<StrBuffer> = kwargs.get(Qstr::MP_QSTR_verb)?.try_into_option()?;
|
||||
let verb_cancel: Option<StrBuffer> =
|
||||
kwargs.get(Qstr::MP_QSTR_verb_cancel)?.try_into_option()?;
|
||||
let reverse: bool = kwargs.get(Qstr::MP_QSTR_reverse)?.try_into()?;
|
||||
let hold: bool = kwargs.get(Qstr::MP_QSTR_hold)?.try_into()?;
|
||||
let verb: StrBuffer = kwargs.get_or(Qstr::MP_QSTR_verb, "CONFIRM".into())?;
|
||||
let verb_cancel: Option<StrBuffer> = kwargs
|
||||
.get(Qstr::MP_QSTR_verb_cancel)
|
||||
.unwrap_or_else(|_| Obj::const_none())
|
||||
.try_into_option()?;
|
||||
let reverse: bool = kwargs.get_or(Qstr::MP_QSTR_reverse, false)?;
|
||||
let hold: bool = kwargs.get_or(Qstr::MP_QSTR_hold, false)?;
|
||||
|
||||
let paragraphs = {
|
||||
let action = action.unwrap_or_default();
|
||||
@ -215,7 +207,6 @@ extern "C" fn new_confirm_action(n_args: usize, args: *const Obj, kwargs: *mut M
|
||||
};
|
||||
|
||||
// Right button - text or nothing.
|
||||
let verb = verb.unwrap_or_default();
|
||||
let mut confirm_btn = if verb.len() > 0 {
|
||||
Some(ButtonDetails::text(verb))
|
||||
} else {
|
||||
@ -293,24 +284,16 @@ extern "C" fn new_confirm_output(n_args: usize, args: *const Obj, kwargs: *mut M
|
||||
match page_index {
|
||||
0 => {
|
||||
// RECIPIENT + address
|
||||
let btn_layout = ButtonLayout::new(
|
||||
Some(ButtonDetails::cancel_icon()),
|
||||
None,
|
||||
Some(ButtonDetails::text("CONFIRM".into())),
|
||||
);
|
||||
let btn_actions = ButtonActions::cancel_next();
|
||||
let btn_layout = ButtonLayout::cancel_none_text("CONFIRM".into());
|
||||
let btn_actions = ButtonActions::cancel_none_next();
|
||||
Page::<10>::new(btn_layout, btn_actions, Font::MONO)
|
||||
.with_title(address_title)
|
||||
.text_mono(address)
|
||||
}
|
||||
1 => {
|
||||
// AMOUNT + amount
|
||||
let btn_layout = ButtonLayout::new(
|
||||
Some(ButtonDetails::up_arrow_icon()),
|
||||
None,
|
||||
Some(ButtonDetails::text("CONFIRM".into())),
|
||||
);
|
||||
let btn_actions = ButtonActions::cancel_confirm();
|
||||
let btn_layout = ButtonLayout::up_arrow_none_text("CONFIRM".into());
|
||||
let btn_actions = ButtonActions::prev_none_confirm();
|
||||
Page::<10>::new(btn_layout, btn_actions, Font::MONO)
|
||||
.with_title(amount_title)
|
||||
.newline()
|
||||
@ -341,12 +324,8 @@ extern "C" fn new_confirm_total(n_args: usize, args: *const Obj, kwargs: *mut Ma
|
||||
// Total amount + fee
|
||||
assert!(page_index == 0);
|
||||
|
||||
let btn_layout = ButtonLayout::new(
|
||||
Some(ButtonDetails::cancel_icon()),
|
||||
None,
|
||||
Some(ButtonDetails::text("HOLD TO CONFIRM".into()).with_default_duration()),
|
||||
);
|
||||
let btn_actions = ButtonActions::cancel_confirm();
|
||||
let btn_layout = ButtonLayout::cancel_none_htc("HOLD TO CONFIRM".into());
|
||||
let btn_actions = ButtonActions::cancel_none_confirm();
|
||||
|
||||
let mut flow_page = Page::<15>::new(btn_layout, btn_actions, Font::MONO)
|
||||
.text_bold(total_label)
|
||||
@ -386,11 +365,7 @@ extern "C" fn new_show_receive_address(n_args: usize, args: *const Obj, kwargs:
|
||||
match page_index {
|
||||
0 => {
|
||||
// RECEIVE ADDRESS
|
||||
let btn_layout = ButtonLayout::new(
|
||||
Some(ButtonDetails::cancel_icon()),
|
||||
Some(ButtonDetails::armed_text("CONFIRM".into())),
|
||||
Some(ButtonDetails::text("i".into())),
|
||||
);
|
||||
let btn_layout = ButtonLayout::cancel_armed_text("CONFIRM".into(), "i".into());
|
||||
let btn_actions = ButtonActions::last_confirm_next();
|
||||
Page::<15>::new(btn_layout, btn_actions, Font::BOLD)
|
||||
.text_bold(title)
|
||||
@ -400,12 +375,8 @@ extern "C" fn new_show_receive_address(n_args: usize, args: *const Obj, kwargs:
|
||||
}
|
||||
1 => {
|
||||
// QR CODE
|
||||
let btn_layout = ButtonLayout::new(
|
||||
Some(ButtonDetails::left_arrow_icon()),
|
||||
None,
|
||||
Some(ButtonDetails::right_arrow_icon()),
|
||||
);
|
||||
let btn_actions = ButtonActions::prev_next();
|
||||
let btn_layout = ButtonLayout::arrow_none_arrow();
|
||||
let btn_actions = ButtonActions::prev_none_next();
|
||||
Page::<15>::new(btn_layout, btn_actions, Font::MONO).qr_code(
|
||||
address_qr,
|
||||
theme::QR_SIDE_MAX,
|
||||
@ -415,9 +386,8 @@ extern "C" fn new_show_receive_address(n_args: usize, args: *const Obj, kwargs:
|
||||
}
|
||||
2 => {
|
||||
// ADDRESS INFO
|
||||
let btn_layout =
|
||||
ButtonLayout::new(Some(ButtonDetails::left_arrow_icon()), None, None);
|
||||
let btn_actions = ButtonActions::only_prev();
|
||||
let btn_layout = ButtonLayout::arrow_none_none();
|
||||
let btn_actions = ButtonActions::prev_none_none();
|
||||
Page::<15>::new(btn_layout, btn_actions, Font::MONO)
|
||||
.text_bold("Account:".into())
|
||||
.newline()
|
||||
@ -429,12 +399,8 @@ extern "C" fn new_show_receive_address(n_args: usize, args: *const Obj, kwargs:
|
||||
}
|
||||
3 => {
|
||||
// ADDRESS MISMATCH
|
||||
let btn_layout = ButtonLayout::new(
|
||||
Some(ButtonDetails::left_arrow_icon()),
|
||||
None,
|
||||
Some(ButtonDetails::text("QUIT".into())),
|
||||
);
|
||||
let btn_actions = ButtonActions::beginning_cancel();
|
||||
let btn_layout = ButtonLayout::arrow_none_text("QUIT".into());
|
||||
let btn_actions = ButtonActions::beginning_none_cancel();
|
||||
Page::<15>::new(btn_layout, btn_actions, Font::MONO)
|
||||
.text_bold("ADDRESS MISMATCH?".into())
|
||||
.newline()
|
||||
@ -482,6 +448,73 @@ extern "C" fn new_show_info(n_args: usize, args: *const Obj, kwargs: *mut Map) -
|
||||
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 app_name: StrBuffer = 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();
|
||||
|
||||
let title: StrBuffer = if page_count > 1 {
|
||||
"IMPORT".into()
|
||||
} else {
|
||||
"IMPORT CREDENTIAL".into()
|
||||
};
|
||||
|
||||
// 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 as usize));
|
||||
let account = account_obj.try_into().unwrap_or_else(|_| "".into());
|
||||
|
||||
let (btn_layout, btn_actions) = if page_count == 1 {
|
||||
// There is only one page
|
||||
(
|
||||
ButtonLayout::cancel_none_text("CONFIRM".into()),
|
||||
ButtonActions::cancel_none_confirm(),
|
||||
)
|
||||
} else if page_index == 0 {
|
||||
// First page
|
||||
(
|
||||
ButtonLayout::cancel_armed_arrow("SELECT".into()),
|
||||
ButtonActions::cancel_confirm_next(),
|
||||
)
|
||||
} else if page_index as usize == page_count - 1 {
|
||||
// Last page
|
||||
(
|
||||
ButtonLayout::arrow_armed_none("SELECT".into()),
|
||||
ButtonActions::prev_confirm_none(),
|
||||
)
|
||||
} else {
|
||||
// Page in the middle
|
||||
(
|
||||
ButtonLayout::arrow_armed_icon("SELECT".into()),
|
||||
ButtonActions::prev_confirm_next(),
|
||||
)
|
||||
};
|
||||
|
||||
Page::<10>::new(btn_layout, btn_actions, Font::MONO)
|
||||
.newline()
|
||||
.text_mono(app_name)
|
||||
.newline()
|
||||
.text_bold(account)
|
||||
};
|
||||
|
||||
let pages = FlowPages::new(get_page, page_count as u8);
|
||||
|
||||
// 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) }
|
||||
}
|
||||
|
||||
/// General pattern of most tutorial screens.
|
||||
/// (title, text, btn_layout, btn_actions)
|
||||
fn tutorial_screen(
|
||||
@ -523,47 +556,47 @@ extern "C" fn tutorial(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj
|
||||
tutorial_screen(
|
||||
"HELLO".into(),
|
||||
"Welcome to Trezor.\nPress right to continue.".into(),
|
||||
ButtonLayout::cancel_and_arrow(),
|
||||
ButtonActions::last_next(),
|
||||
ButtonLayout::cancel_none_arrow(),
|
||||
ButtonActions::last_none_next(),
|
||||
)
|
||||
},
|
||||
1 => {
|
||||
tutorial_screen(
|
||||
"".into(),
|
||||
"Use Trezor by clicking left and right.\n\nContinue right.".into(),
|
||||
ButtonLayout::left_right_arrows(),
|
||||
ButtonActions::prev_next(),
|
||||
ButtonLayout::arrow_none_arrow(),
|
||||
ButtonActions::prev_none_next(),
|
||||
)
|
||||
},
|
||||
2 => {
|
||||
tutorial_screen(
|
||||
"HOLD TO CONFIRM".into(),
|
||||
"Press and hold right to approve important operations.".into(),
|
||||
ButtonLayout::back_and_htc_text("HOLD TO CONFIRM".into(), Duration::from_millis(1000)),
|
||||
ButtonActions::prev_next(),
|
||||
ButtonLayout::arrow_none_htc("HOLD TO CONFIRM".into()),
|
||||
ButtonActions::prev_none_next(),
|
||||
)
|
||||
},
|
||||
3 => {
|
||||
tutorial_screen(
|
||||
"SCREEN SCROLL".into(),
|
||||
"Press right to scroll down to read all content when text\ndoesn't fit on one screen. Press left to scroll up.".into(),
|
||||
ButtonLayout::back_and_text("GOT IT".into()),
|
||||
ButtonActions::prev_next(),
|
||||
ButtonLayout::arrow_none_text("GOT IT".into()),
|
||||
ButtonActions::prev_none_next(),
|
||||
)
|
||||
},
|
||||
4 => {
|
||||
tutorial_screen(
|
||||
"CONFIRM".into(),
|
||||
"Press both left and right at the same time to confirm.".into(),
|
||||
ButtonLayout::middle_armed_text("CONFIRM".into()),
|
||||
ButtonActions::prev_next_with_middle(),
|
||||
ButtonLayout::none_armed_none("CONFIRM".into()),
|
||||
ButtonActions::prev_next_none(),
|
||||
)
|
||||
},
|
||||
// This page is special
|
||||
5 => {
|
||||
Page::<10>::new(
|
||||
ButtonLayout::left_right_text("AGAIN".into(), "FINISH".into()),
|
||||
ButtonActions::beginning_confirm(),
|
||||
ButtonLayout::text_none_text("AGAIN".into(), "FINISH".into()),
|
||||
ButtonActions::beginning_none_confirm(),
|
||||
Font::MONO,
|
||||
)
|
||||
.newline()
|
||||
@ -577,8 +610,8 @@ extern "C" fn tutorial(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj
|
||||
tutorial_screen(
|
||||
"SKIP TUTORIAL".into(),
|
||||
"Are you sure you want to skip the tutorial?".into(),
|
||||
ButtonLayout::cancel_and_text("SKIP".into()),
|
||||
ButtonActions::beginning_cancel(),
|
||||
ButtonLayout::cancel_none_text("SKIP".into()),
|
||||
ButtonActions::beginning_none_cancel(),
|
||||
)
|
||||
},
|
||||
_ => unreachable!(),
|
||||
@ -773,9 +806,9 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
||||
/// def confirm_action(
|
||||
/// *,
|
||||
/// title: str,
|
||||
/// action: str | None = None,
|
||||
/// description: str | None = None,
|
||||
/// verb: str | None = None,
|
||||
/// action: str | None,
|
||||
/// description: str | None,
|
||||
/// verb: str = "CONFIRM",
|
||||
/// verb_cancel: str | None = None,
|
||||
/// hold: bool = False,
|
||||
/// hold_danger: bool = False, # unused on TR
|
||||
@ -837,6 +870,17 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
||||
/// """Info modal."""
|
||||
Qstr::MP_QSTR_show_info => obj_fn_kw!(0, new_show_info).as_obj(),
|
||||
|
||||
/// def confirm_fido(
|
||||
/// *,
|
||||
/// app_name: str,
|
||||
/// accounts: list[str | None],
|
||||
/// ) -> int | object:
|
||||
/// """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 tutorial() -> object:
|
||||
/// """Show user how to interact with the device."""
|
||||
Qstr::MP_QSTR_tutorial => obj_fn_kw!(0, tutorial).as_obj(),
|
||||
|
@ -1330,7 +1330,7 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
||||
/// title: str,
|
||||
/// action: str | None,
|
||||
/// description: str | None,
|
||||
/// verb: str | None = None,
|
||||
/// verb: str = "CONFIRM",
|
||||
/// verb_cancel: str | None = None,
|
||||
/// hold: bool = False,
|
||||
/// hold_danger: bool = False,
|
||||
|
@ -13,9 +13,9 @@ def disable_animation(disable: bool) -> None:
|
||||
def confirm_action(
|
||||
*,
|
||||
title: str,
|
||||
action: str | None = None,
|
||||
description: str | None = None,
|
||||
verb: str | None = None,
|
||||
action: str | None,
|
||||
description: str | None,
|
||||
verb: str = "CONFIRM",
|
||||
verb_cancel: str | None = None,
|
||||
hold: bool = False,
|
||||
hold_danger: bool = False, # unused on TR
|
||||
@ -82,6 +82,17 @@ def show_info(
|
||||
"""Info modal."""
|
||||
|
||||
|
||||
# rust/src/ui/model_tr/layout.rs
|
||||
def confirm_fido(
|
||||
*,
|
||||
app_name: str,
|
||||
accounts: list[str | None],
|
||||
) -> int | object:
|
||||
"""FIDO confirmation.
|
||||
Returns page index in case of confirmation and CANCELLED otherwise.
|
||||
"""
|
||||
|
||||
|
||||
# rust/src/ui/model_tr/layout.rs
|
||||
def tutorial() -> object:
|
||||
"""Show user how to interact with the device."""
|
||||
@ -197,7 +208,7 @@ def confirm_action(
|
||||
title: str,
|
||||
action: str | None,
|
||||
description: str | None,
|
||||
verb: str | None = None,
|
||||
verb: str = "CONFIRM",
|
||||
verb_cancel: str | None = None,
|
||||
hold: bool = False,
|
||||
hold_danger: bool = False,
|
||||
|
@ -115,7 +115,7 @@ class Approver:
|
||||
self,
|
||||
txo: TxOutput,
|
||||
script_pubkey: bytes,
|
||||
index: int | None,
|
||||
index: int | None = None,
|
||||
orig_txo: TxOutput | None = None,
|
||||
) -> None:
|
||||
self._add_output(txo, script_pubkey)
|
||||
@ -169,7 +169,7 @@ class BasicApprover(Approver):
|
||||
self,
|
||||
txo: TxOutput,
|
||||
script_pubkey: bytes,
|
||||
index: int | None,
|
||||
index: int | None = None,
|
||||
orig_txo: TxOutput | None = None,
|
||||
) -> None:
|
||||
from trezor.enums import OutputScriptType
|
||||
|
@ -469,7 +469,7 @@ async def get_bool(
|
||||
title: str,
|
||||
data: str | None = None,
|
||||
description: str | None = None,
|
||||
verb: str | None = "CONFIRM",
|
||||
verb: str = "CONFIRM",
|
||||
verb_cancel: str | None = "",
|
||||
hold: bool = False,
|
||||
reverse: bool = False,
|
||||
@ -723,7 +723,7 @@ async def _show_modal(
|
||||
title=header.upper(),
|
||||
action=subheader,
|
||||
description=content,
|
||||
verb=button_confirm,
|
||||
verb=button_confirm or "",
|
||||
verb_cancel=button_cancel,
|
||||
exc=exc,
|
||||
)
|
||||
|
@ -1,5 +1,12 @@
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from trezor.enums import ButtonRequestType
|
||||
|
||||
import trezorui2
|
||||
|
||||
from ..common import interact
|
||||
from . import RustLayout
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from trezor.wire import GenericContext
|
||||
|
||||
@ -14,8 +21,37 @@ async def confirm_fido(
|
||||
accounts: list[str | None],
|
||||
) -> int:
|
||||
"""Webauthn confirmation for one or more credentials."""
|
||||
raise NotImplementedError
|
||||
confirm = RustLayout(
|
||||
trezorui2.confirm_fido( # type: ignore [Arguments missing]
|
||||
app_name=app_name,
|
||||
accounts=accounts,
|
||||
)
|
||||
)
|
||||
|
||||
if ctx is None:
|
||||
result = await confirm
|
||||
else:
|
||||
result = await interact(ctx, confirm, "confirm_fido", ButtonRequestType.Other)
|
||||
|
||||
# The Rust side returns either an int or `CANCELLED`. We detect the int situation
|
||||
# and assume cancellation otherwise.
|
||||
if isinstance(result, int):
|
||||
return result
|
||||
|
||||
# Late import won't get executed on the happy path.
|
||||
from trezor.wire import ActionCancelled
|
||||
|
||||
raise ActionCancelled
|
||||
|
||||
|
||||
async def confirm_fido_reset() -> bool:
|
||||
raise NotImplementedError
|
||||
confirm = RustLayout(
|
||||
trezorui2.confirm_action(
|
||||
title="FIDO2 RESET",
|
||||
description="Do you really want to erase all credentials?",
|
||||
action=None,
|
||||
verb_cancel="",
|
||||
verb="CONFIRM",
|
||||
)
|
||||
)
|
||||
return (await confirm) is trezorui2.CONFIRMED
|
||||
|
@ -95,13 +95,13 @@ class TestSignSegwitTxNativeP2WPKH(unittest.TestCase):
|
||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||
|
||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN),
|
||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0),
|
||||
True,
|
||||
|
||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||
TxAckOutput(tx=TxAckOutputWrapper(output=out2)),
|
||||
|
||||
helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN),
|
||||
helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN, 1),
|
||||
True,
|
||||
|
||||
helpers.UiConfirmTotal(12300000, 11000, fee_rate, coin, AmountUnit.BITCOIN),
|
||||
@ -229,7 +229,7 @@ class TestSignSegwitTxNativeP2WPKH(unittest.TestCase):
|
||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||
|
||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN),
|
||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0),
|
||||
True,
|
||||
|
||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||
|
@ -93,13 +93,13 @@ class TestSignSegwitTxNativeP2WPKH_GRS(unittest.TestCase):
|
||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||
|
||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN),
|
||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0),
|
||||
True,
|
||||
|
||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||
TxAckOutput(tx=TxAckOutputWrapper(output=out2)),
|
||||
|
||||
helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN),
|
||||
helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN, 1),
|
||||
True,
|
||||
|
||||
helpers.UiConfirmNonDefaultLocktime(tx.lock_time, lock_time_disabled=False),
|
||||
@ -227,7 +227,7 @@ class TestSignSegwitTxNativeP2WPKH_GRS(unittest.TestCase):
|
||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||
|
||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN),
|
||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0),
|
||||
True,
|
||||
|
||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||
|
@ -92,13 +92,13 @@ class TestSignSegwitTxP2WPKHInP2SH(unittest.TestCase):
|
||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||
|
||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN),
|
||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0),
|
||||
True,
|
||||
|
||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||
TxAckOutput(tx=TxAckOutputWrapper(output=out2)),
|
||||
|
||||
helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN),
|
||||
helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN, 1),
|
||||
True,
|
||||
|
||||
helpers.UiConfirmTotal(123445789 + 11000, 11000, fee_rate, coin, AmountUnit.BITCOIN),
|
||||
@ -223,7 +223,7 @@ class TestSignSegwitTxP2WPKHInP2SH(unittest.TestCase):
|
||||
|
||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||
|
||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN),
|
||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0),
|
||||
True,
|
||||
|
||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||
@ -371,7 +371,7 @@ class TestSignSegwitTxP2WPKHInP2SH(unittest.TestCase):
|
||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||
|
||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN),
|
||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0),
|
||||
True,
|
||||
|
||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||
|
@ -93,13 +93,13 @@ class TestSignSegwitTxP2WPKHInP2SH_GRS(unittest.TestCase):
|
||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||
|
||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN),
|
||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0),
|
||||
True,
|
||||
|
||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||
TxAckOutput(tx=TxAckOutputWrapper(output=out2)),
|
||||
|
||||
helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN),
|
||||
helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN, 1),
|
||||
True,
|
||||
|
||||
helpers.UiConfirmNonDefaultLocktime(tx.lock_time, lock_time_disabled=False),
|
||||
@ -226,7 +226,7 @@ class TestSignSegwitTxP2WPKHInP2SH_GRS(unittest.TestCase):
|
||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||
|
||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN),
|
||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0),
|
||||
True,
|
||||
|
||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||
|
@ -85,7 +85,7 @@ class TestSignTxFeeThreshold(unittest.TestCase):
|
||||
TxAckPrevOutput(tx=TxAckPrevOutputWrapper(output=pout1)),
|
||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=None),
|
||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||
helpers.UiConfirmOutput(out1, coin_bitcoin, AmountUnit.BITCOIN),
|
||||
helpers.UiConfirmOutput(out1, coin_bitcoin, AmountUnit.BITCOIN, 0),
|
||||
True,
|
||||
helpers.UiConfirmFeeOverThreshold(100000, coin_bitcoin),
|
||||
True,
|
||||
@ -146,7 +146,7 @@ class TestSignTxFeeThreshold(unittest.TestCase):
|
||||
True,
|
||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||
helpers.UiConfirmOutput(out1, coin_bitcoin, AmountUnit.BITCOIN),
|
||||
helpers.UiConfirmOutput(out1, coin_bitcoin, AmountUnit.BITCOIN, 0),
|
||||
True,
|
||||
helpers.UiConfirmTotal(300000 + 90000, 90000, fee_rate, coin_bitcoin, AmountUnit.BITCOIN),
|
||||
True,
|
||||
|
@ -111,7 +111,7 @@ class TestSignTx(unittest.TestCase):
|
||||
serialized=EMPTY_SERIALIZED,
|
||||
),
|
||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||
helpers.UiConfirmOutput(out1, coin_bitcoin, AmountUnit.BITCOIN),
|
||||
helpers.UiConfirmOutput(out1, coin_bitcoin, AmountUnit.BITCOIN, 0),
|
||||
True,
|
||||
helpers.UiConfirmTotal(3_801_747, 50_000, fee_rate, coin_bitcoin, AmountUnit.BITCOIN),
|
||||
True,
|
||||
|
@ -109,7 +109,7 @@ class TestSignTxDecred(unittest.TestCase):
|
||||
),
|
||||
),
|
||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||
helpers.UiConfirmOutput(out1, coin_decred, AmountUnit.BITCOIN),
|
||||
helpers.UiConfirmOutput(out1, coin_decred, AmountUnit.BITCOIN, 0),
|
||||
True,
|
||||
helpers.UiConfirmTotal(
|
||||
200_000_000, 100_000, fee_rate, coin_decred, AmountUnit.BITCOIN
|
||||
|
@ -70,7 +70,7 @@ class TestSignTx_GRS(unittest.TestCase):
|
||||
TxAckInput(tx=TxAckInputWrapper(input=inp1)),
|
||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN),
|
||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0),
|
||||
True,
|
||||
helpers.UiConfirmTotal(210016, 192, fee_rate, coin, AmountUnit.BITCOIN),
|
||||
True,
|
||||
|
@ -30,9 +30,6 @@ RK_CAPACITY = 100
|
||||
@pytest.mark.altcoin
|
||||
@pytest.mark.setup_client(mnemonic=MNEMONIC12)
|
||||
def test_add_remove(client: Client):
|
||||
if client.features.model == "R":
|
||||
pytest.skip("Webauthn is not supported on model R")
|
||||
|
||||
# Remove index 0 should fail.
|
||||
with pytest.raises(TrezorFailure):
|
||||
fido.remove_credential(client, 0)
|
||||
|
Loading…
Reference in New Issue
Block a user