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
|
- firmware-T2T1-btconly-production-*.*.*-$CI_COMMIT_SHORT_SHA.bin
|
||||||
expire_in: 1 week
|
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:
|
core fw R btconly debug build:
|
||||||
stage: build
|
stage: build
|
||||||
<<: *gitlab_caching
|
<<: *gitlab_caching
|
||||||
@ -370,22 +354,6 @@ core unix frozen debug build arm:
|
|||||||
tags:
|
tags:
|
||||||
- docker_darwin_arm
|
- 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:
|
core macos frozen regular build:
|
||||||
stage: build
|
stage: build
|
||||||
<<: *gitlab_caching
|
<<: *gitlab_caching
|
||||||
|
@ -120,6 +120,7 @@ static void _librust_qstrs(void) {
|
|||||||
MP_QSTR_time_ms;
|
MP_QSTR_time_ms;
|
||||||
MP_QSTR_app_name;
|
MP_QSTR_app_name;
|
||||||
MP_QSTR_icon_name;
|
MP_QSTR_icon_name;
|
||||||
|
MP_QSTR_account;
|
||||||
MP_QSTR_accounts;
|
MP_QSTR_accounts;
|
||||||
MP_QSTR_indeterminate;
|
MP_QSTR_indeterminate;
|
||||||
MP_QSTR_notification;
|
MP_QSTR_notification;
|
||||||
|
@ -9,8 +9,6 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use heapless::String;
|
|
||||||
|
|
||||||
use super::theme;
|
use super::theme;
|
||||||
|
|
||||||
const HALF_SCREEN_BUTTON_WIDTH: i16 = constant::WIDTH / 2 - 1;
|
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)]
|
#[derive(PartialEq, Eq)]
|
||||||
enum State {
|
enum State {
|
||||||
Released,
|
Released,
|
||||||
@ -453,7 +439,7 @@ impl ButtonDetails {
|
|||||||
self
|
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 {
|
pub fn with_default_duration(mut self) -> Self {
|
||||||
self.duration = Some(Duration::from_millis(1000));
|
self.duration = Some(Duration::from_millis(1000));
|
||||||
self
|
self
|
||||||
@ -511,11 +497,11 @@ impl ButtonLayout {
|
|||||||
|
|
||||||
/// Default button layout for all three buttons - icons.
|
/// Default button layout for all three buttons - icons.
|
||||||
pub fn default_three_icons() -> Self {
|
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.
|
/// 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(
|
Self::new(
|
||||||
Some(ButtonDetails::left_arrow_icon()),
|
Some(ButtonDetails::left_arrow_icon()),
|
||||||
Some(ButtonDetails::armed_text(middle_text)),
|
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.
|
/// 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(
|
Self::new(
|
||||||
Some(ButtonDetails::text(text_left)),
|
Some(ButtonDetails::text(text_left)),
|
||||||
None,
|
None,
|
||||||
@ -533,12 +546,12 @@ impl ButtonLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Only right text.
|
/// 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)))
|
Self::new(None, None, Some(ButtonDetails::text(text_right)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Left and right arrow icons for navigation.
|
/// Left and right arrow icons for navigation.
|
||||||
pub fn left_right_arrows() -> Self {
|
pub fn arrow_none_arrow() -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
Some(ButtonDetails::left_arrow_icon()),
|
Some(ButtonDetails::left_arrow_icon()),
|
||||||
None,
|
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.
|
/// Cancel cross on left and right arrow.
|
||||||
pub fn cancel_and_arrow() -> Self {
|
pub fn cancel_none_arrow() -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
Some(ButtonDetails::cancel_icon()),
|
Some(ButtonDetails::cancel_icon()),
|
||||||
None,
|
None,
|
||||||
@ -556,7 +587,7 @@ impl ButtonLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Cancel cross on left and right arrow facing down.
|
/// 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(
|
Self::new(
|
||||||
Some(ButtonDetails::cancel_icon()),
|
Some(ButtonDetails::cancel_icon()),
|
||||||
None,
|
None,
|
||||||
@ -565,7 +596,7 @@ impl ButtonLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Cancel cross on left and text on the right.
|
/// 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(
|
Self::new(
|
||||||
Some(ButtonDetails::cancel_icon()),
|
Some(ButtonDetails::cancel_icon()),
|
||||||
None,
|
None,
|
||||||
@ -574,39 +605,30 @@ impl ButtonLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Cancel cross on left and hold-to-confirm text on the right.
|
/// 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(
|
Self::new(
|
||||||
Some(ButtonDetails::cancel_icon()),
|
Some(ButtonDetails::cancel_icon()),
|
||||||
None,
|
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.
|
/// 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(
|
Self::new(
|
||||||
Some(ButtonDetails::left_arrow_icon()),
|
Some(ButtonDetails::left_arrow_icon()),
|
||||||
None,
|
None,
|
||||||
Some(ButtonDetails::text(text).with_duration(duration)),
|
Some(ButtonDetails::text(text).with_default_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)),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Only armed text in the middle.
|
/// 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)
|
Self::new(None, Some(ButtonDetails::armed_text(text)), None)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Only hold-to-confirm with text on the right.
|
/// 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(
|
Self::new(
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
@ -614,30 +636,14 @@ impl ButtonLayout {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Only right arrow facing down.
|
/// Only left arrow.
|
||||||
pub fn only_arrow_down() -> Self {
|
pub fn arrow_none_none() -> Self {
|
||||||
Self::new(None, None, Some(ButtonDetails::down_arrow_icon_wide()))
|
Self::new(Some(ButtonDetails::left_arrow_icon()), None, None)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
/// Only right arrow facing down.
|
||||||
impl crate::trace::Trace for ButtonDetails {
|
pub fn none_none_arrow_wide() -> Self {
|
||||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
Self::new(None, None, Some(ButtonDetails::down_arrow_icon_wide()))
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -667,6 +673,195 @@ pub enum ButtonAction {
|
|||||||
Action(&'static str),
|
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")]
|
#[cfg(feature = "ui_debug")]
|
||||||
impl ButtonAction {
|
impl ButtonAction {
|
||||||
/// Describing the action as a string. Debug-only.
|
/// Describing the action as a string. Debug-only.
|
||||||
@ -697,126 +892,3 @@ impl ButtonAction {
|
|||||||
"None".into()
|
"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.
|
/// All possible states buttons (left and right) can be at.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
enum ButtonState {
|
enum ButtonState {
|
||||||
@ -435,8 +433,12 @@ impl Component for ButtonController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEBUG-ONLY SECTION BELOW
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
#[cfg(feature = "ui_debug")]
|
||||||
use super::ButtonContent;
|
use super::ButtonContent;
|
||||||
|
#[cfg(feature = "ui_debug")]
|
||||||
|
use heapless::String;
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
#[cfg(feature = "ui_debug")]
|
||||||
impl crate::trace::Trace for ButtonContainer {
|
impl crate::trace::Trace for ButtonContainer {
|
||||||
|
@ -14,6 +14,7 @@ use super::{
|
|||||||
/// To be returned directly from Flow.
|
/// To be returned directly from Flow.
|
||||||
pub enum FlowMsg {
|
pub enum FlowMsg {
|
||||||
Confirmed,
|
Confirmed,
|
||||||
|
ConfirmedIndex(u8),
|
||||||
Cancelled,
|
Cancelled,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,6 +31,7 @@ pub struct Flow<F, const M: usize> {
|
|||||||
pad: Pad,
|
pad: Pad,
|
||||||
buttons: Child<ButtonController>,
|
buttons: Child<ButtonController>,
|
||||||
page_counter: u8,
|
page_counter: u8,
|
||||||
|
return_confirmed_index: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F, const M: usize> Flow<F, M>
|
impl<F, const M: usize> Flow<F, M>
|
||||||
@ -51,6 +53,7 @@ where
|
|||||||
// `content.page_count()`.
|
// `content.page_count()`.
|
||||||
buttons: Child::new(ButtonController::new(ButtonLayout::empty())),
|
buttons: Child::new(ButtonController::new(ButtonLayout::empty())),
|
||||||
page_counter: 0,
|
page_counter: 0,
|
||||||
|
return_confirmed_index: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,6 +64,12 @@ where
|
|||||||
self
|
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.
|
/// Getting new current page according to page counter.
|
||||||
/// Also updating the possible title and moving the scrollbar to correct
|
/// Also updating the possible title and moving the scrollbar to correct
|
||||||
/// position.
|
/// position.
|
||||||
@ -222,7 +231,13 @@ where
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
ButtonAction::Cancel => return Some(FlowMsg::Cancelled),
|
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::Select => {}
|
||||||
ButtonAction::Action(_) => {}
|
ButtonAction::Action(_) => {}
|
||||||
}
|
}
|
||||||
@ -247,6 +262,8 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEBUG-ONLY SECTION BELOW
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
#[cfg(feature = "ui_debug")]
|
||||||
use heapless::String;
|
use heapless::String;
|
||||||
|
|
||||||
|
@ -332,6 +332,8 @@ impl<const M: usize> Paginate for Page<M> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEBUG-ONLY SECTION BELOW
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
#[cfg(feature = "ui_debug")]
|
||||||
pub mod trace {
|
pub mod trace {
|
||||||
use crate::ui::model_tr::component::flow_pages_poc_helpers::TraceSink;
|
use crate::ui::model_tr::component::flow_pages_poc_helpers::TraceSink;
|
||||||
|
@ -96,6 +96,8 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEBUG-ONLY SECTION BELOW
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
#[cfg(feature = "ui_debug")]
|
||||||
impl<T> crate::trace::Trace for Frame<T>
|
impl<T> crate::trace::Trace for Frame<T>
|
||||||
where
|
where
|
||||||
|
@ -108,6 +108,8 @@ impl Component for HoldToConfirm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEBUG-ONLY SECTION BELOW
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
#[cfg(feature = "ui_debug")]
|
||||||
impl crate::trace::Trace for HoldToConfirm {
|
impl crate::trace::Trace for HoldToConfirm {
|
||||||
fn trace(&self, d: &mut dyn crate::trace::Tracer) {
|
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 {
|
pub struct Lockscreen {
|
||||||
label: StrBuffer,
|
label: StrBuffer,
|
||||||
bootscreen: bool,
|
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")]
|
#[cfg(feature = "ui_debug")]
|
||||||
impl crate::trace::Trace for Lockscreen {
|
impl crate::trace::Trace for Lockscreen {
|
||||||
fn trace(&self, d: &mut dyn crate::trace::Tracer) {
|
fn trace(&self, d: &mut dyn crate::trace::Tracer) {
|
||||||
|
@ -58,11 +58,8 @@ impl ChoiceFactory for ChoiceFactoryBIP39 {
|
|||||||
match self {
|
match self {
|
||||||
Self::Letters(letter_choices) => {
|
Self::Letters(letter_choices) => {
|
||||||
if choice_index >= letter_choices.len() as u8 {
|
if choice_index >= letter_choices.len() as u8 {
|
||||||
ChoiceItem::new(
|
ChoiceItem::new("DELETE", ButtonLayout::arrow_armed_icon("CONFIRM".into()))
|
||||||
"DELETE",
|
.with_icon(Icon::new(theme::ICON_DELETE))
|
||||||
ButtonLayout::three_icons_middle_text("CONFIRM".into()),
|
|
||||||
)
|
|
||||||
.with_icon(Icon::new(theme::ICON_DELETE))
|
|
||||||
} else {
|
} else {
|
||||||
let letter = letter_choices[choice_index as usize];
|
let letter = letter_choices[choice_index as usize];
|
||||||
ChoiceItem::new(
|
ChoiceItem::new(
|
||||||
@ -73,11 +70,9 @@ impl ChoiceFactory for ChoiceFactoryBIP39 {
|
|||||||
}
|
}
|
||||||
Self::Words(word_choices) => {
|
Self::Words(word_choices) => {
|
||||||
if choice_index >= word_choices.len() as u8 {
|
if choice_index >= word_choices.len() as u8 {
|
||||||
let mut item = ChoiceItem::new(
|
let mut item =
|
||||||
"DELETE",
|
ChoiceItem::new("DELETE", ButtonLayout::arrow_armed_icon("CONFIRM".into()))
|
||||||
ButtonLayout::three_icons_middle_text("CONFIRM".into()),
|
.with_icon(Icon::new(theme::ICON_DELETE));
|
||||||
)
|
|
||||||
.with_icon(Icon::new(theme::ICON_DELETE));
|
|
||||||
item.set_right_btn(None);
|
item.set_right_btn(None);
|
||||||
item
|
item
|
||||||
} else {
|
} else {
|
||||||
@ -223,6 +218,8 @@ impl Component for Bip39Entry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEBUG-ONLY SECTION BELOW
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
#[cfg(feature = "ui_debug")]
|
||||||
use super::super::{ButtonAction, ButtonPos};
|
use super::super::{ButtonAction, ButtonPos};
|
||||||
#[cfg(feature = "ui_debug")]
|
#[cfg(feature = "ui_debug")]
|
||||||
|
@ -421,6 +421,8 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEBUG-ONLY SECTION BELOW
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
#[cfg(feature = "ui_debug")]
|
||||||
impl<F> crate::trace::Trace for ChoicePage<F>
|
impl<F> crate::trace::Trace for ChoicePage<F>
|
||||||
where
|
where
|
||||||
|
@ -198,6 +198,8 @@ impl Choice for ChoiceItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEBUG-ONLY SECTION BELOW
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
#[cfg(feature = "ui_debug")]
|
||||||
impl crate::trace::Trace for ChoiceItem {
|
impl crate::trace::Trace for ChoiceItem {
|
||||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||||
|
@ -135,10 +135,7 @@ impl ChoiceFactoryPassphrase {
|
|||||||
/// return back
|
/// return back
|
||||||
fn get_character_item(&self, choice_index: u8) -> ChoiceItem {
|
fn get_character_item(&self, choice_index: u8) -> ChoiceItem {
|
||||||
if is_menu_choice(&self.current_category, choice_index) {
|
if is_menu_choice(&self.current_category, choice_index) {
|
||||||
ChoiceItem::new(
|
ChoiceItem::new("MENU", ButtonLayout::arrow_armed_icon("RETURN".into()))
|
||||||
"MENU",
|
|
||||||
ButtonLayout::three_icons_middle_text("RETURN".into()),
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
let ch = get_char(&self.current_category, choice_index);
|
let ch = get_char(&self.current_category, choice_index);
|
||||||
ChoiceItem::new(char_to_string::<1>(ch), ButtonLayout::default_three_icons())
|
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")]
|
#[cfg(feature = "ui_debug")]
|
||||||
use super::super::{ButtonAction, ButtonPos};
|
use super::super::{ButtonAction, ButtonPos};
|
||||||
#[cfg(feature = "ui_debug")]
|
#[cfg(feature = "ui_debug")]
|
||||||
|
@ -215,6 +215,8 @@ impl Component for PinEntry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEBUG-ONLY SECTION BELOW
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
#[cfg(feature = "ui_debug")]
|
||||||
use super::super::{ButtonAction, ButtonPos};
|
use super::super::{ButtonAction, ButtonPos};
|
||||||
|
|
||||||
|
@ -9,9 +9,6 @@ use crate::{
|
|||||||
use super::super::{ButtonLayout, ChoiceFactory, ChoiceItem, ChoicePage, ChoicePageMsg};
|
use super::super::{ButtonLayout, ChoiceFactory, ChoiceItem, ChoicePage, ChoicePageMsg};
|
||||||
use heapless::{String, Vec};
|
use heapless::{String, Vec};
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
|
||||||
use super::super::{ButtonAction, ButtonPos};
|
|
||||||
|
|
||||||
pub enum SimpleChoiceMsg {
|
pub enum SimpleChoiceMsg {
|
||||||
Result(String<50>),
|
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")]
|
#[cfg(feature = "ui_debug")]
|
||||||
impl<const N: usize> crate::trace::Trace for SimpleChoice<N> {
|
impl<const N: usize> crate::trace::Trace for SimpleChoice<N> {
|
||||||
fn get_btn_action(&self, pos: ButtonPos) -> String<25> {
|
fn get_btn_action(&self, pos: ButtonPos) -> String<25> {
|
||||||
|
@ -241,6 +241,8 @@ impl LoaderStyleSheet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEBUG-ONLY SECTION BELOW
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
#[cfg(feature = "ui_debug")]
|
||||||
impl crate::trace::Trace for Loader {
|
impl crate::trace::Trace for Loader {
|
||||||
fn trace(&self, d: &mut dyn crate::trace::Tracer) {
|
fn trace(&self, d: &mut dyn crate::trace::Tracer) {
|
||||||
|
@ -13,7 +13,6 @@ mod loader;
|
|||||||
mod no_btn_dialog;
|
mod no_btn_dialog;
|
||||||
mod page;
|
mod page;
|
||||||
mod progress;
|
mod progress;
|
||||||
mod qr_code;
|
|
||||||
mod result_anim;
|
mod result_anim;
|
||||||
mod result_popup;
|
mod result_popup;
|
||||||
mod scrollbar;
|
mod scrollbar;
|
||||||
@ -45,7 +44,6 @@ pub use loader::{Loader, LoaderMsg, LoaderStyle, LoaderStyleSheet};
|
|||||||
pub use no_btn_dialog::{NoBtnDialog, NoBtnDialogMsg};
|
pub use no_btn_dialog::{NoBtnDialog, NoBtnDialogMsg};
|
||||||
pub use page::ButtonPage;
|
pub use page::ButtonPage;
|
||||||
pub use progress::Progress;
|
pub use progress::Progress;
|
||||||
pub use qr_code::{QRCodePage, QRCodePageMessage};
|
|
||||||
pub use result_anim::{ResultAnim, ResultAnimMsg};
|
pub use result_anim::{ResultAnim, ResultAnimMsg};
|
||||||
pub use result_popup::{ResultPopup, ResultPopupMsg};
|
pub use result_popup::{ResultPopup, ResultPopupMsg};
|
||||||
pub use scrollbar::ScrollBar;
|
pub use scrollbar::ScrollBar;
|
||||||
|
@ -55,6 +55,8 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEBUG-ONLY SECTION BELOW
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
#[cfg(feature = "ui_debug")]
|
||||||
impl<T, U> crate::trace::Trace for NoBtnDialog<T, U>
|
impl<T, U> crate::trace::Trace for NoBtnDialog<T, U>
|
||||||
where
|
where
|
||||||
|
@ -217,6 +217,8 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEBUG-ONLY SECTION BELOW
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
#[cfg(feature = "ui_debug")]
|
||||||
use super::ButtonAction;
|
use super::ButtonAction;
|
||||||
#[cfg(feature = "ui_debug")]
|
#[cfg(feature = "ui_debug")]
|
||||||
|
@ -120,6 +120,8 @@ impl Component for Progress {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEBUG-ONLY SECTION BELOW
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
#[cfg(feature = "ui_debug")]
|
||||||
impl crate::trace::Trace for Progress {
|
impl crate::trace::Trace for Progress {
|
||||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
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")]
|
#[cfg(feature = "ui_debug")]
|
||||||
impl crate::trace::Trace for ResultAnim {
|
impl crate::trace::Trace for ResultAnim {
|
||||||
fn trace(&self, d: &mut dyn crate::trace::Tracer) {
|
fn trace(&self, d: &mut dyn crate::trace::Tracer) {
|
||||||
|
@ -49,7 +49,7 @@ impl ResultPopup {
|
|||||||
.with_placement(LinearPlacement::vertical().align_at_center());
|
.with_placement(LinearPlacement::vertical().align_at_center());
|
||||||
|
|
||||||
let buttons = button_text.map(|text| {
|
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))
|
Child::new(ButtonController::new(btn_layout))
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -155,6 +155,8 @@ impl Component for ResultPopup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEBUG-ONLY SECTION BELOW
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
#[cfg(feature = "ui_debug")]
|
||||||
impl crate::trace::Trace for ResultPopup {
|
impl crate::trace::Trace for ResultPopup {
|
||||||
fn trace(&self, d: &mut dyn crate::trace::Tracer) {
|
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")]
|
#[cfg(feature = "ui_debug")]
|
||||||
impl<const N: usize> crate::trace::Trace for ShareWords<N> {
|
impl<const N: usize> crate::trace::Trace for ShareWords<N> {
|
||||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||||
|
@ -6,14 +6,15 @@ use crate::{
|
|||||||
error::Error,
|
error::Error,
|
||||||
micropython::{
|
micropython::{
|
||||||
buffer::StrBuffer,
|
buffer::StrBuffer,
|
||||||
|
gc::Gc,
|
||||||
iter::{Iter, IterBuf},
|
iter::{Iter, IterBuf},
|
||||||
|
list::List,
|
||||||
map::Map,
|
map::Map,
|
||||||
module::Module,
|
module::Module,
|
||||||
obj::Obj,
|
obj::Obj,
|
||||||
qstr::Qstr,
|
qstr::Qstr,
|
||||||
util,
|
util,
|
||||||
},
|
},
|
||||||
time::Duration,
|
|
||||||
ui::{
|
ui::{
|
||||||
component::{
|
component::{
|
||||||
base::Component,
|
base::Component,
|
||||||
@ -38,7 +39,7 @@ use super::{
|
|||||||
Bip39Entry, Bip39EntryMsg, ButtonActions, ButtonDetails, ButtonLayout, ButtonPage, Flow,
|
Bip39Entry, Bip39EntryMsg, ButtonActions, ButtonDetails, ButtonLayout, ButtonPage, Flow,
|
||||||
FlowMsg, FlowPages, Frame, Homescreen, HomescreenMsg, Lockscreen, NoBtnDialog,
|
FlowMsg, FlowPages, Frame, Homescreen, HomescreenMsg, Lockscreen, NoBtnDialog,
|
||||||
NoBtnDialogMsg, Page, PassphraseEntry, PassphraseEntryMsg, PinEntry, PinEntryMsg, Progress,
|
NoBtnDialogMsg, Page, PassphraseEntry, PassphraseEntryMsg, PinEntry, PinEntryMsg, Progress,
|
||||||
QRCodePage, QRCodePageMessage, ShareWords, SimpleChoice, SimpleChoiceMsg,
|
ShareWords, SimpleChoice, SimpleChoiceMsg,
|
||||||
},
|
},
|
||||||
constant, theme,
|
constant, theme,
|
||||||
};
|
};
|
||||||
@ -94,18 +95,7 @@ where
|
|||||||
match msg {
|
match msg {
|
||||||
FlowMsg::Confirmed => Ok(CONFIRMED.as_obj()),
|
FlowMsg::Confirmed => Ok(CONFIRMED.as_obj()),
|
||||||
FlowMsg::Cancelled => Ok(CANCELLED.as_obj()),
|
FlowMsg::Cancelled => Ok(CANCELLED.as_obj()),
|
||||||
}
|
FlowMsg::ConfirmedIndex(page) => Ok(page.into()),
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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 action: Option<StrBuffer> = kwargs.get(Qstr::MP_QSTR_action)?.try_into_option()?;
|
||||||
let description: Option<StrBuffer> =
|
let description: Option<StrBuffer> =
|
||||||
kwargs.get(Qstr::MP_QSTR_description)?.try_into_option()?;
|
kwargs.get(Qstr::MP_QSTR_description)?.try_into_option()?;
|
||||||
let verb: Option<StrBuffer> = kwargs.get(Qstr::MP_QSTR_verb)?.try_into_option()?;
|
let verb: StrBuffer = kwargs.get_or(Qstr::MP_QSTR_verb, "CONFIRM".into())?;
|
||||||
let verb_cancel: Option<StrBuffer> =
|
let verb_cancel: Option<StrBuffer> = kwargs
|
||||||
kwargs.get(Qstr::MP_QSTR_verb_cancel)?.try_into_option()?;
|
.get(Qstr::MP_QSTR_verb_cancel)
|
||||||
let reverse: bool = kwargs.get(Qstr::MP_QSTR_reverse)?.try_into()?;
|
.unwrap_or_else(|_| Obj::const_none())
|
||||||
let hold: bool = kwargs.get(Qstr::MP_QSTR_hold)?.try_into()?;
|
.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 paragraphs = {
|
||||||
let action = action.unwrap_or_default();
|
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.
|
// Right button - text or nothing.
|
||||||
let verb = verb.unwrap_or_default();
|
|
||||||
let mut confirm_btn = if verb.len() > 0 {
|
let mut confirm_btn = if verb.len() > 0 {
|
||||||
Some(ButtonDetails::text(verb))
|
Some(ButtonDetails::text(verb))
|
||||||
} else {
|
} else {
|
||||||
@ -293,24 +284,16 @@ extern "C" fn new_confirm_output(n_args: usize, args: *const Obj, kwargs: *mut M
|
|||||||
match page_index {
|
match page_index {
|
||||||
0 => {
|
0 => {
|
||||||
// RECIPIENT + address
|
// RECIPIENT + address
|
||||||
let btn_layout = ButtonLayout::new(
|
let btn_layout = ButtonLayout::cancel_none_text("CONFIRM".into());
|
||||||
Some(ButtonDetails::cancel_icon()),
|
let btn_actions = ButtonActions::cancel_none_next();
|
||||||
None,
|
|
||||||
Some(ButtonDetails::text("CONFIRM".into())),
|
|
||||||
);
|
|
||||||
let btn_actions = ButtonActions::cancel_next();
|
|
||||||
Page::<10>::new(btn_layout, btn_actions, Font::MONO)
|
Page::<10>::new(btn_layout, btn_actions, Font::MONO)
|
||||||
.with_title(address_title)
|
.with_title(address_title)
|
||||||
.text_mono(address)
|
.text_mono(address)
|
||||||
}
|
}
|
||||||
1 => {
|
1 => {
|
||||||
// AMOUNT + amount
|
// AMOUNT + amount
|
||||||
let btn_layout = ButtonLayout::new(
|
let btn_layout = ButtonLayout::up_arrow_none_text("CONFIRM".into());
|
||||||
Some(ButtonDetails::up_arrow_icon()),
|
let btn_actions = ButtonActions::prev_none_confirm();
|
||||||
None,
|
|
||||||
Some(ButtonDetails::text("CONFIRM".into())),
|
|
||||||
);
|
|
||||||
let btn_actions = ButtonActions::cancel_confirm();
|
|
||||||
Page::<10>::new(btn_layout, btn_actions, Font::MONO)
|
Page::<10>::new(btn_layout, btn_actions, Font::MONO)
|
||||||
.with_title(amount_title)
|
.with_title(amount_title)
|
||||||
.newline()
|
.newline()
|
||||||
@ -341,12 +324,8 @@ extern "C" fn new_confirm_total(n_args: usize, args: *const Obj, kwargs: *mut Ma
|
|||||||
// Total amount + fee
|
// Total amount + fee
|
||||||
assert!(page_index == 0);
|
assert!(page_index == 0);
|
||||||
|
|
||||||
let btn_layout = ButtonLayout::new(
|
let btn_layout = ButtonLayout::cancel_none_htc("HOLD TO CONFIRM".into());
|
||||||
Some(ButtonDetails::cancel_icon()),
|
let btn_actions = ButtonActions::cancel_none_confirm();
|
||||||
None,
|
|
||||||
Some(ButtonDetails::text("HOLD TO CONFIRM".into()).with_default_duration()),
|
|
||||||
);
|
|
||||||
let btn_actions = ButtonActions::cancel_confirm();
|
|
||||||
|
|
||||||
let mut flow_page = Page::<15>::new(btn_layout, btn_actions, Font::MONO)
|
let mut flow_page = Page::<15>::new(btn_layout, btn_actions, Font::MONO)
|
||||||
.text_bold(total_label)
|
.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 {
|
match page_index {
|
||||||
0 => {
|
0 => {
|
||||||
// RECEIVE ADDRESS
|
// RECEIVE ADDRESS
|
||||||
let btn_layout = ButtonLayout::new(
|
let btn_layout = ButtonLayout::cancel_armed_text("CONFIRM".into(), "i".into());
|
||||||
Some(ButtonDetails::cancel_icon()),
|
|
||||||
Some(ButtonDetails::armed_text("CONFIRM".into())),
|
|
||||||
Some(ButtonDetails::text("i".into())),
|
|
||||||
);
|
|
||||||
let btn_actions = ButtonActions::last_confirm_next();
|
let btn_actions = ButtonActions::last_confirm_next();
|
||||||
Page::<15>::new(btn_layout, btn_actions, Font::BOLD)
|
Page::<15>::new(btn_layout, btn_actions, Font::BOLD)
|
||||||
.text_bold(title)
|
.text_bold(title)
|
||||||
@ -400,12 +375,8 @@ extern "C" fn new_show_receive_address(n_args: usize, args: *const Obj, kwargs:
|
|||||||
}
|
}
|
||||||
1 => {
|
1 => {
|
||||||
// QR CODE
|
// QR CODE
|
||||||
let btn_layout = ButtonLayout::new(
|
let btn_layout = ButtonLayout::arrow_none_arrow();
|
||||||
Some(ButtonDetails::left_arrow_icon()),
|
let btn_actions = ButtonActions::prev_none_next();
|
||||||
None,
|
|
||||||
Some(ButtonDetails::right_arrow_icon()),
|
|
||||||
);
|
|
||||||
let btn_actions = ButtonActions::prev_next();
|
|
||||||
Page::<15>::new(btn_layout, btn_actions, Font::MONO).qr_code(
|
Page::<15>::new(btn_layout, btn_actions, Font::MONO).qr_code(
|
||||||
address_qr,
|
address_qr,
|
||||||
theme::QR_SIDE_MAX,
|
theme::QR_SIDE_MAX,
|
||||||
@ -415,9 +386,8 @@ extern "C" fn new_show_receive_address(n_args: usize, args: *const Obj, kwargs:
|
|||||||
}
|
}
|
||||||
2 => {
|
2 => {
|
||||||
// ADDRESS INFO
|
// ADDRESS INFO
|
||||||
let btn_layout =
|
let btn_layout = ButtonLayout::arrow_none_none();
|
||||||
ButtonLayout::new(Some(ButtonDetails::left_arrow_icon()), None, None);
|
let btn_actions = ButtonActions::prev_none_none();
|
||||||
let btn_actions = ButtonActions::only_prev();
|
|
||||||
Page::<15>::new(btn_layout, btn_actions, Font::MONO)
|
Page::<15>::new(btn_layout, btn_actions, Font::MONO)
|
||||||
.text_bold("Account:".into())
|
.text_bold("Account:".into())
|
||||||
.newline()
|
.newline()
|
||||||
@ -429,12 +399,8 @@ extern "C" fn new_show_receive_address(n_args: usize, args: *const Obj, kwargs:
|
|||||||
}
|
}
|
||||||
3 => {
|
3 => {
|
||||||
// ADDRESS MISMATCH
|
// ADDRESS MISMATCH
|
||||||
let btn_layout = ButtonLayout::new(
|
let btn_layout = ButtonLayout::arrow_none_text("QUIT".into());
|
||||||
Some(ButtonDetails::left_arrow_icon()),
|
let btn_actions = ButtonActions::beginning_none_cancel();
|
||||||
None,
|
|
||||||
Some(ButtonDetails::text("QUIT".into())),
|
|
||||||
);
|
|
||||||
let btn_actions = ButtonActions::beginning_cancel();
|
|
||||||
Page::<15>::new(btn_layout, btn_actions, Font::MONO)
|
Page::<15>::new(btn_layout, btn_actions, Font::MONO)
|
||||||
.text_bold("ADDRESS MISMATCH?".into())
|
.text_bold("ADDRESS MISMATCH?".into())
|
||||||
.newline()
|
.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) }
|
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.
|
/// General pattern of most tutorial screens.
|
||||||
/// (title, text, btn_layout, btn_actions)
|
/// (title, text, btn_layout, btn_actions)
|
||||||
fn tutorial_screen(
|
fn tutorial_screen(
|
||||||
@ -523,47 +556,47 @@ extern "C" fn tutorial(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj
|
|||||||
tutorial_screen(
|
tutorial_screen(
|
||||||
"HELLO".into(),
|
"HELLO".into(),
|
||||||
"Welcome to Trezor.\nPress right to continue.".into(),
|
"Welcome to Trezor.\nPress right to continue.".into(),
|
||||||
ButtonLayout::cancel_and_arrow(),
|
ButtonLayout::cancel_none_arrow(),
|
||||||
ButtonActions::last_next(),
|
ButtonActions::last_none_next(),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
1 => {
|
1 => {
|
||||||
tutorial_screen(
|
tutorial_screen(
|
||||||
"".into(),
|
"".into(),
|
||||||
"Use Trezor by clicking left and right.\n\nContinue right.".into(),
|
"Use Trezor by clicking left and right.\n\nContinue right.".into(),
|
||||||
ButtonLayout::left_right_arrows(),
|
ButtonLayout::arrow_none_arrow(),
|
||||||
ButtonActions::prev_next(),
|
ButtonActions::prev_none_next(),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
2 => {
|
2 => {
|
||||||
tutorial_screen(
|
tutorial_screen(
|
||||||
"HOLD TO CONFIRM".into(),
|
"HOLD TO CONFIRM".into(),
|
||||||
"Press and hold right to approve important operations.".into(),
|
"Press and hold right to approve important operations.".into(),
|
||||||
ButtonLayout::back_and_htc_text("HOLD TO CONFIRM".into(), Duration::from_millis(1000)),
|
ButtonLayout::arrow_none_htc("HOLD TO CONFIRM".into()),
|
||||||
ButtonActions::prev_next(),
|
ButtonActions::prev_none_next(),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
3 => {
|
3 => {
|
||||||
tutorial_screen(
|
tutorial_screen(
|
||||||
"SCREEN SCROLL".into(),
|
"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(),
|
"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()),
|
ButtonLayout::arrow_none_text("GOT IT".into()),
|
||||||
ButtonActions::prev_next(),
|
ButtonActions::prev_none_next(),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
4 => {
|
4 => {
|
||||||
tutorial_screen(
|
tutorial_screen(
|
||||||
"CONFIRM".into(),
|
"CONFIRM".into(),
|
||||||
"Press both left and right at the same time to confirm.".into(),
|
"Press both left and right at the same time to confirm.".into(),
|
||||||
ButtonLayout::middle_armed_text("CONFIRM".into()),
|
ButtonLayout::none_armed_none("CONFIRM".into()),
|
||||||
ButtonActions::prev_next_with_middle(),
|
ButtonActions::prev_next_none(),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
// This page is special
|
// This page is special
|
||||||
5 => {
|
5 => {
|
||||||
Page::<10>::new(
|
Page::<10>::new(
|
||||||
ButtonLayout::left_right_text("AGAIN".into(), "FINISH".into()),
|
ButtonLayout::text_none_text("AGAIN".into(), "FINISH".into()),
|
||||||
ButtonActions::beginning_confirm(),
|
ButtonActions::beginning_none_confirm(),
|
||||||
Font::MONO,
|
Font::MONO,
|
||||||
)
|
)
|
||||||
.newline()
|
.newline()
|
||||||
@ -577,8 +610,8 @@ extern "C" fn tutorial(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj
|
|||||||
tutorial_screen(
|
tutorial_screen(
|
||||||
"SKIP TUTORIAL".into(),
|
"SKIP TUTORIAL".into(),
|
||||||
"Are you sure you want to skip the tutorial?".into(),
|
"Are you sure you want to skip the tutorial?".into(),
|
||||||
ButtonLayout::cancel_and_text("SKIP".into()),
|
ButtonLayout::cancel_none_text("SKIP".into()),
|
||||||
ButtonActions::beginning_cancel(),
|
ButtonActions::beginning_none_cancel(),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
@ -773,9 +806,9 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
|||||||
/// def confirm_action(
|
/// def confirm_action(
|
||||||
/// *,
|
/// *,
|
||||||
/// title: str,
|
/// title: str,
|
||||||
/// action: str | None = None,
|
/// action: str | None,
|
||||||
/// description: str | None = None,
|
/// description: str | None,
|
||||||
/// verb: str | None = None,
|
/// verb: str = "CONFIRM",
|
||||||
/// verb_cancel: str | None = None,
|
/// verb_cancel: str | None = None,
|
||||||
/// hold: bool = False,
|
/// hold: bool = False,
|
||||||
/// hold_danger: bool = False, # unused on TR
|
/// hold_danger: bool = False, # unused on TR
|
||||||
@ -837,6 +870,17 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
|||||||
/// """Info modal."""
|
/// """Info modal."""
|
||||||
Qstr::MP_QSTR_show_info => obj_fn_kw!(0, new_show_info).as_obj(),
|
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:
|
/// def tutorial() -> object:
|
||||||
/// """Show user how to interact with the device."""
|
/// """Show user how to interact with the device."""
|
||||||
Qstr::MP_QSTR_tutorial => obj_fn_kw!(0, tutorial).as_obj(),
|
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,
|
/// title: str,
|
||||||
/// action: str | None,
|
/// action: str | None,
|
||||||
/// description: str | None,
|
/// description: str | None,
|
||||||
/// verb: str | None = None,
|
/// verb: str = "CONFIRM",
|
||||||
/// verb_cancel: str | None = None,
|
/// verb_cancel: str | None = None,
|
||||||
/// hold: bool = False,
|
/// hold: bool = False,
|
||||||
/// hold_danger: bool = False,
|
/// hold_danger: bool = False,
|
||||||
|
@ -13,9 +13,9 @@ def disable_animation(disable: bool) -> None:
|
|||||||
def confirm_action(
|
def confirm_action(
|
||||||
*,
|
*,
|
||||||
title: str,
|
title: str,
|
||||||
action: str | None = None,
|
action: str | None,
|
||||||
description: str | None = None,
|
description: str | None,
|
||||||
verb: str | None = None,
|
verb: str = "CONFIRM",
|
||||||
verb_cancel: str | None = None,
|
verb_cancel: str | None = None,
|
||||||
hold: bool = False,
|
hold: bool = False,
|
||||||
hold_danger: bool = False, # unused on TR
|
hold_danger: bool = False, # unused on TR
|
||||||
@ -82,6 +82,17 @@ def show_info(
|
|||||||
"""Info modal."""
|
"""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
|
# rust/src/ui/model_tr/layout.rs
|
||||||
def tutorial() -> object:
|
def tutorial() -> object:
|
||||||
"""Show user how to interact with the device."""
|
"""Show user how to interact with the device."""
|
||||||
@ -197,7 +208,7 @@ def confirm_action(
|
|||||||
title: str,
|
title: str,
|
||||||
action: str | None,
|
action: str | None,
|
||||||
description: str | None,
|
description: str | None,
|
||||||
verb: str | None = None,
|
verb: str = "CONFIRM",
|
||||||
verb_cancel: str | None = None,
|
verb_cancel: str | None = None,
|
||||||
hold: bool = False,
|
hold: bool = False,
|
||||||
hold_danger: bool = False,
|
hold_danger: bool = False,
|
||||||
|
@ -115,7 +115,7 @@ class Approver:
|
|||||||
self,
|
self,
|
||||||
txo: TxOutput,
|
txo: TxOutput,
|
||||||
script_pubkey: bytes,
|
script_pubkey: bytes,
|
||||||
index: int | None,
|
index: int | None = None,
|
||||||
orig_txo: TxOutput | None = None,
|
orig_txo: TxOutput | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
self._add_output(txo, script_pubkey)
|
self._add_output(txo, script_pubkey)
|
||||||
@ -169,7 +169,7 @@ class BasicApprover(Approver):
|
|||||||
self,
|
self,
|
||||||
txo: TxOutput,
|
txo: TxOutput,
|
||||||
script_pubkey: bytes,
|
script_pubkey: bytes,
|
||||||
index: int | None,
|
index: int | None = None,
|
||||||
orig_txo: TxOutput | None = None,
|
orig_txo: TxOutput | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
from trezor.enums import OutputScriptType
|
from trezor.enums import OutputScriptType
|
||||||
|
@ -469,7 +469,7 @@ async def get_bool(
|
|||||||
title: str,
|
title: str,
|
||||||
data: str | None = None,
|
data: str | None = None,
|
||||||
description: str | None = None,
|
description: str | None = None,
|
||||||
verb: str | None = "CONFIRM",
|
verb: str = "CONFIRM",
|
||||||
verb_cancel: str | None = "",
|
verb_cancel: str | None = "",
|
||||||
hold: bool = False,
|
hold: bool = False,
|
||||||
reverse: bool = False,
|
reverse: bool = False,
|
||||||
@ -723,7 +723,7 @@ async def _show_modal(
|
|||||||
title=header.upper(),
|
title=header.upper(),
|
||||||
action=subheader,
|
action=subheader,
|
||||||
description=content,
|
description=content,
|
||||||
verb=button_confirm,
|
verb=button_confirm or "",
|
||||||
verb_cancel=button_cancel,
|
verb_cancel=button_cancel,
|
||||||
exc=exc,
|
exc=exc,
|
||||||
)
|
)
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from trezor.enums import ButtonRequestType
|
||||||
|
|
||||||
|
import trezorui2
|
||||||
|
|
||||||
|
from ..common import interact
|
||||||
|
from . import RustLayout
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from trezor.wire import GenericContext
|
from trezor.wire import GenericContext
|
||||||
|
|
||||||
@ -14,8 +21,37 @@ async def confirm_fido(
|
|||||||
accounts: list[str | None],
|
accounts: list[str | None],
|
||||||
) -> int:
|
) -> int:
|
||||||
"""Webauthn confirmation for one or more credentials."""
|
"""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:
|
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),
|
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||||
|
|
||||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN),
|
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0),
|
||||||
True,
|
True,
|
||||||
|
|
||||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||||
TxAckOutput(tx=TxAckOutputWrapper(output=out2)),
|
TxAckOutput(tx=TxAckOutputWrapper(output=out2)),
|
||||||
|
|
||||||
helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN),
|
helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN, 1),
|
||||||
True,
|
True,
|
||||||
|
|
||||||
helpers.UiConfirmTotal(12300000, 11000, fee_rate, coin, AmountUnit.BITCOIN),
|
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),
|
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||||
|
|
||||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN),
|
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0),
|
||||||
True,
|
True,
|
||||||
|
|
||||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
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),
|
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||||
|
|
||||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN),
|
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0),
|
||||||
True,
|
True,
|
||||||
|
|
||||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||||
TxAckOutput(tx=TxAckOutputWrapper(output=out2)),
|
TxAckOutput(tx=TxAckOutputWrapper(output=out2)),
|
||||||
|
|
||||||
helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN),
|
helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN, 1),
|
||||||
True,
|
True,
|
||||||
|
|
||||||
helpers.UiConfirmNonDefaultLocktime(tx.lock_time, lock_time_disabled=False),
|
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),
|
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||||
|
|
||||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN),
|
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0),
|
||||||
True,
|
True,
|
||||||
|
|
||||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
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),
|
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||||
|
|
||||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN),
|
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0),
|
||||||
True,
|
True,
|
||||||
|
|
||||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||||
TxAckOutput(tx=TxAckOutputWrapper(output=out2)),
|
TxAckOutput(tx=TxAckOutputWrapper(output=out2)),
|
||||||
|
|
||||||
helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN),
|
helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN, 1),
|
||||||
True,
|
True,
|
||||||
|
|
||||||
helpers.UiConfirmTotal(123445789 + 11000, 11000, fee_rate, coin, AmountUnit.BITCOIN),
|
helpers.UiConfirmTotal(123445789 + 11000, 11000, fee_rate, coin, AmountUnit.BITCOIN),
|
||||||
@ -223,7 +223,7 @@ class TestSignSegwitTxP2WPKHInP2SH(unittest.TestCase):
|
|||||||
|
|
||||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||||
|
|
||||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN),
|
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0),
|
||||||
True,
|
True,
|
||||||
|
|
||||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
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),
|
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||||
|
|
||||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN),
|
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0),
|
||||||
True,
|
True,
|
||||||
|
|
||||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
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),
|
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||||
|
|
||||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN),
|
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0),
|
||||||
True,
|
True,
|
||||||
|
|
||||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||||
TxAckOutput(tx=TxAckOutputWrapper(output=out2)),
|
TxAckOutput(tx=TxAckOutputWrapper(output=out2)),
|
||||||
|
|
||||||
helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN),
|
helpers.UiConfirmOutput(out2, coin, AmountUnit.BITCOIN, 1),
|
||||||
True,
|
True,
|
||||||
|
|
||||||
helpers.UiConfirmNonDefaultLocktime(tx.lock_time, lock_time_disabled=False),
|
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),
|
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||||
|
|
||||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN),
|
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0),
|
||||||
True,
|
True,
|
||||||
|
|
||||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=1, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
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)),
|
TxAckPrevOutput(tx=TxAckPrevOutputWrapper(output=pout1)),
|
||||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=None),
|
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=None),
|
||||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||||
helpers.UiConfirmOutput(out1, coin_bitcoin, AmountUnit.BITCOIN),
|
helpers.UiConfirmOutput(out1, coin_bitcoin, AmountUnit.BITCOIN, 0),
|
||||||
True,
|
True,
|
||||||
helpers.UiConfirmFeeOverThreshold(100000, coin_bitcoin),
|
helpers.UiConfirmFeeOverThreshold(100000, coin_bitcoin),
|
||||||
True,
|
True,
|
||||||
@ -146,7 +146,7 @@ class TestSignTxFeeThreshold(unittest.TestCase):
|
|||||||
True,
|
True,
|
||||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||||
helpers.UiConfirmOutput(out1, coin_bitcoin, AmountUnit.BITCOIN),
|
helpers.UiConfirmOutput(out1, coin_bitcoin, AmountUnit.BITCOIN, 0),
|
||||||
True,
|
True,
|
||||||
helpers.UiConfirmTotal(300000 + 90000, 90000, fee_rate, coin_bitcoin, AmountUnit.BITCOIN),
|
helpers.UiConfirmTotal(300000 + 90000, 90000, fee_rate, coin_bitcoin, AmountUnit.BITCOIN),
|
||||||
True,
|
True,
|
||||||
|
@ -111,7 +111,7 @@ class TestSignTx(unittest.TestCase):
|
|||||||
serialized=EMPTY_SERIALIZED,
|
serialized=EMPTY_SERIALIZED,
|
||||||
),
|
),
|
||||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||||
helpers.UiConfirmOutput(out1, coin_bitcoin, AmountUnit.BITCOIN),
|
helpers.UiConfirmOutput(out1, coin_bitcoin, AmountUnit.BITCOIN, 0),
|
||||||
True,
|
True,
|
||||||
helpers.UiConfirmTotal(3_801_747, 50_000, fee_rate, coin_bitcoin, AmountUnit.BITCOIN),
|
helpers.UiConfirmTotal(3_801_747, 50_000, fee_rate, coin_bitcoin, AmountUnit.BITCOIN),
|
||||||
True,
|
True,
|
||||||
|
@ -109,7 +109,7 @@ class TestSignTxDecred(unittest.TestCase):
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||||
helpers.UiConfirmOutput(out1, coin_decred, AmountUnit.BITCOIN),
|
helpers.UiConfirmOutput(out1, coin_decred, AmountUnit.BITCOIN, 0),
|
||||||
True,
|
True,
|
||||||
helpers.UiConfirmTotal(
|
helpers.UiConfirmTotal(
|
||||||
200_000_000, 100_000, fee_rate, coin_decred, AmountUnit.BITCOIN
|
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)),
|
TxAckInput(tx=TxAckInputWrapper(input=inp1)),
|
||||||
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
TxRequest(request_type=TXOUTPUT, details=TxRequestDetailsType(request_index=0, tx_hash=None), serialized=EMPTY_SERIALIZED),
|
||||||
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
TxAckOutput(tx=TxAckOutputWrapper(output=out1)),
|
||||||
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN),
|
helpers.UiConfirmOutput(out1, coin, AmountUnit.BITCOIN, 0),
|
||||||
True,
|
True,
|
||||||
helpers.UiConfirmTotal(210016, 192, fee_rate, coin, AmountUnit.BITCOIN),
|
helpers.UiConfirmTotal(210016, 192, fee_rate, coin, AmountUnit.BITCOIN),
|
||||||
True,
|
True,
|
||||||
|
@ -30,9 +30,6 @@ RK_CAPACITY = 100
|
|||||||
@pytest.mark.altcoin
|
@pytest.mark.altcoin
|
||||||
@pytest.mark.setup_client(mnemonic=MNEMONIC12)
|
@pytest.mark.setup_client(mnemonic=MNEMONIC12)
|
||||||
def test_add_remove(client: Client):
|
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.
|
# Remove index 0 should fail.
|
||||||
with pytest.raises(TrezorFailure):
|
with pytest.raises(TrezorFailure):
|
||||||
fido.remove_credential(client, 0)
|
fido.remove_credential(client, 0)
|
||||||
|
Loading…
Reference in New Issue
Block a user