mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-24 07:18:09 +00:00
feat(core/ui): T3T1 receive flow
[no changelog]
This commit is contained in:
parent
1028c3500f
commit
5020868c2c
@ -30,14 +30,21 @@ static void _librust_qstrs(void) {
|
|||||||
MP_QSTR_addr_mismatch__wrong_derivation_path;
|
MP_QSTR_addr_mismatch__wrong_derivation_path;
|
||||||
MP_QSTR_addr_mismatch__xpub_mismatch;
|
MP_QSTR_addr_mismatch__xpub_mismatch;
|
||||||
MP_QSTR_address;
|
MP_QSTR_address;
|
||||||
|
MP_QSTR_address__cancel_contact_support;
|
||||||
|
MP_QSTR_address__cancel_receive;
|
||||||
|
MP_QSTR_address__confirmed;
|
||||||
MP_QSTR_address__public_key;
|
MP_QSTR_address__public_key;
|
||||||
|
MP_QSTR_address__qr_code;
|
||||||
MP_QSTR_address__title_cosigner;
|
MP_QSTR_address__title_cosigner;
|
||||||
MP_QSTR_address__title_receive_address;
|
MP_QSTR_address__title_receive_address;
|
||||||
MP_QSTR_address__title_yours;
|
MP_QSTR_address__title_yours;
|
||||||
|
MP_QSTR_address_details__account_info;
|
||||||
MP_QSTR_address_details__derivation_path;
|
MP_QSTR_address_details__derivation_path;
|
||||||
|
MP_QSTR_address_details__derivation_path_colon;
|
||||||
MP_QSTR_address_details__title_receive_address;
|
MP_QSTR_address_details__title_receive_address;
|
||||||
MP_QSTR_address_details__title_receiving_to;
|
MP_QSTR_address_details__title_receiving_to;
|
||||||
MP_QSTR_address_label;
|
MP_QSTR_address_label;
|
||||||
|
MP_QSTR_address_qr;
|
||||||
MP_QSTR_address_title;
|
MP_QSTR_address_title;
|
||||||
MP_QSTR_allow_cancel;
|
MP_QSTR_allow_cancel;
|
||||||
MP_QSTR_altcoin_tx_summary;
|
MP_QSTR_altcoin_tx_summary;
|
||||||
@ -210,6 +217,7 @@ static void _librust_qstrs(void) {
|
|||||||
MP_QSTR_flow_get_address;
|
MP_QSTR_flow_get_address;
|
||||||
MP_QSTR_flow_prompt_backup;
|
MP_QSTR_flow_prompt_backup;
|
||||||
MP_QSTR_flow_show_share_words;
|
MP_QSTR_flow_show_share_words;
|
||||||
|
MP_QSTR_flow_warning_hi_prio;
|
||||||
MP_QSTR_get_language;
|
MP_QSTR_get_language;
|
||||||
MP_QSTR_hold;
|
MP_QSTR_hold;
|
||||||
MP_QSTR_hold_danger;
|
MP_QSTR_hold_danger;
|
||||||
@ -237,6 +245,7 @@ static void _librust_qstrs(void) {
|
|||||||
MP_QSTR_inputs__return;
|
MP_QSTR_inputs__return;
|
||||||
MP_QSTR_inputs__show;
|
MP_QSTR_inputs__show;
|
||||||
MP_QSTR_inputs__space;
|
MP_QSTR_inputs__space;
|
||||||
|
MP_QSTR_instructions__continue_in_app;
|
||||||
MP_QSTR_instructions__hold_to_confirm;
|
MP_QSTR_instructions__hold_to_confirm;
|
||||||
MP_QSTR_instructions__swipe_up;
|
MP_QSTR_instructions__swipe_up;
|
||||||
MP_QSTR_instructions__tap_to_confirm;
|
MP_QSTR_instructions__tap_to_confirm;
|
||||||
@ -623,6 +632,7 @@ static void _librust_qstrs(void) {
|
|||||||
MP_QSTR_words__array_of;
|
MP_QSTR_words__array_of;
|
||||||
MP_QSTR_words__blockhash;
|
MP_QSTR_words__blockhash;
|
||||||
MP_QSTR_words__buying;
|
MP_QSTR_words__buying;
|
||||||
|
MP_QSTR_words__cancel_and_exit;
|
||||||
MP_QSTR_words__confirm;
|
MP_QSTR_words__confirm;
|
||||||
MP_QSTR_words__confirm_fee;
|
MP_QSTR_words__confirm_fee;
|
||||||
MP_QSTR_words__contains;
|
MP_QSTR_words__contains;
|
||||||
|
@ -20,7 +20,7 @@ pub enum TranslatedString {
|
|||||||
address__title_cosigner = 7, // "Cosigner"
|
address__title_cosigner = 7, // "Cosigner"
|
||||||
address__title_receive_address = 8, // "Receive address"
|
address__title_receive_address = 8, // "Receive address"
|
||||||
address__title_yours = 9, // "Yours"
|
address__title_yours = 9, // "Yours"
|
||||||
address_details__derivation_path = 10, // "Derivation path:"
|
address_details__derivation_path_colon = 10, // "Derivation path:"
|
||||||
address_details__title_receive_address = 11, // "Receive address"
|
address_details__title_receive_address = 11, // "Receive address"
|
||||||
address_details__title_receiving_to = 12, // "Receiving to"
|
address_details__title_receiving_to = 12, // "Receiving to"
|
||||||
authenticate__confirm_template = 13, // "Allow connected computer to confirm your {0} is genuine?"
|
authenticate__confirm_template = 13, // "Allow connected computer to confirm your {0} is genuine?"
|
||||||
@ -1260,6 +1260,14 @@ pub enum TranslatedString {
|
|||||||
reset__check_backup_instructions = 859, // "Let's do a quick check of your backup."
|
reset__check_backup_instructions = 859, // "Let's do a quick check of your backup."
|
||||||
words__instructions = 860, // "Instructions"
|
words__instructions = 860, // "Instructions"
|
||||||
words__not_recommended = 861, // "Not recommended!"
|
words__not_recommended = 861, // "Not recommended!"
|
||||||
|
address_details__account_info = 862, // "Account info"
|
||||||
|
address__cancel_contact_support = 863, // "If receive address doesn't match, contact Trezor Support at trezor.io/support."
|
||||||
|
address__cancel_receive = 864, // "Cancel receive"
|
||||||
|
address__qr_code = 865, // "QR code"
|
||||||
|
address_details__derivation_path = 866, // "Derivation path"
|
||||||
|
instructions__continue_in_app = 867, // "Continue in the app"
|
||||||
|
words__cancel_and_exit = 868, // "Cancel and exit"
|
||||||
|
address__confirmed = 869, // "Receive address confirmed"
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TranslatedString {
|
impl TranslatedString {
|
||||||
@ -1275,7 +1283,7 @@ impl TranslatedString {
|
|||||||
Self::address__title_cosigner => "Cosigner",
|
Self::address__title_cosigner => "Cosigner",
|
||||||
Self::address__title_receive_address => "Receive address",
|
Self::address__title_receive_address => "Receive address",
|
||||||
Self::address__title_yours => "Yours",
|
Self::address__title_yours => "Yours",
|
||||||
Self::address_details__derivation_path => "Derivation path:",
|
Self::address_details__derivation_path_colon => "Derivation path:",
|
||||||
Self::address_details__title_receive_address => "Receive address",
|
Self::address_details__title_receive_address => "Receive address",
|
||||||
Self::address_details__title_receiving_to => "Receiving to",
|
Self::address_details__title_receiving_to => "Receiving to",
|
||||||
Self::authenticate__confirm_template => "Allow connected computer to confirm your {0} is genuine?",
|
Self::authenticate__confirm_template => "Allow connected computer to confirm your {0} is genuine?",
|
||||||
@ -2515,6 +2523,14 @@ impl TranslatedString {
|
|||||||
Self::reset__check_backup_instructions => "Let's do a quick check of your backup.",
|
Self::reset__check_backup_instructions => "Let's do a quick check of your backup.",
|
||||||
Self::words__instructions => "Instructions",
|
Self::words__instructions => "Instructions",
|
||||||
Self::words__not_recommended => "Not recommended!",
|
Self::words__not_recommended => "Not recommended!",
|
||||||
|
Self::address_details__account_info => "Account info",
|
||||||
|
Self::address__cancel_contact_support => "If receive address doesn't match, contact Trezor Support at trezor.io/support.",
|
||||||
|
Self::address__cancel_receive => "Cancel receive",
|
||||||
|
Self::address__qr_code => "QR code",
|
||||||
|
Self::address_details__derivation_path => "Derivation path",
|
||||||
|
Self::instructions__continue_in_app => "Continue in the app",
|
||||||
|
Self::words__cancel_and_exit => "Cancel and exit",
|
||||||
|
Self::address__confirmed => "Receive address confirmed",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2531,7 +2547,7 @@ impl TranslatedString {
|
|||||||
Qstr::MP_QSTR_address__title_cosigner => Some(Self::address__title_cosigner),
|
Qstr::MP_QSTR_address__title_cosigner => Some(Self::address__title_cosigner),
|
||||||
Qstr::MP_QSTR_address__title_receive_address => Some(Self::address__title_receive_address),
|
Qstr::MP_QSTR_address__title_receive_address => Some(Self::address__title_receive_address),
|
||||||
Qstr::MP_QSTR_address__title_yours => Some(Self::address__title_yours),
|
Qstr::MP_QSTR_address__title_yours => Some(Self::address__title_yours),
|
||||||
Qstr::MP_QSTR_address_details__derivation_path => Some(Self::address_details__derivation_path),
|
Qstr::MP_QSTR_address_details__derivation_path_colon => Some(Self::address_details__derivation_path_colon),
|
||||||
Qstr::MP_QSTR_address_details__title_receive_address => Some(Self::address_details__title_receive_address),
|
Qstr::MP_QSTR_address_details__title_receive_address => Some(Self::address_details__title_receive_address),
|
||||||
Qstr::MP_QSTR_address_details__title_receiving_to => Some(Self::address_details__title_receiving_to),
|
Qstr::MP_QSTR_address_details__title_receiving_to => Some(Self::address_details__title_receiving_to),
|
||||||
Qstr::MP_QSTR_authenticate__confirm_template => Some(Self::authenticate__confirm_template),
|
Qstr::MP_QSTR_authenticate__confirm_template => Some(Self::authenticate__confirm_template),
|
||||||
@ -3771,6 +3787,14 @@ impl TranslatedString {
|
|||||||
Qstr::MP_QSTR_reset__check_backup_instructions => Some(Self::reset__check_backup_instructions),
|
Qstr::MP_QSTR_reset__check_backup_instructions => Some(Self::reset__check_backup_instructions),
|
||||||
Qstr::MP_QSTR_words__instructions => Some(Self::words__instructions),
|
Qstr::MP_QSTR_words__instructions => Some(Self::words__instructions),
|
||||||
Qstr::MP_QSTR_words__not_recommended => Some(Self::words__not_recommended),
|
Qstr::MP_QSTR_words__not_recommended => Some(Self::words__not_recommended),
|
||||||
|
Qstr::MP_QSTR_address_details__account_info => Some(Self::address_details__account_info),
|
||||||
|
Qstr::MP_QSTR_address__cancel_contact_support => Some(Self::address__cancel_contact_support),
|
||||||
|
Qstr::MP_QSTR_address__cancel_receive => Some(Self::address__cancel_receive),
|
||||||
|
Qstr::MP_QSTR_address__qr_code => Some(Self::address__qr_code),
|
||||||
|
Qstr::MP_QSTR_address_details__derivation_path => Some(Self::address_details__derivation_path),
|
||||||
|
Qstr::MP_QSTR_instructions__continue_in_app => Some(Self::instructions__continue_in_app),
|
||||||
|
Qstr::MP_QSTR_words__cancel_and_exit => Some(Self::words__cancel_and_exit),
|
||||||
|
Qstr::MP_QSTR_address__confirmed => Some(Self::address__confirmed),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ pub struct Child<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Child<T> {
|
impl<T> Child<T> {
|
||||||
pub fn new(component: T) -> Self {
|
pub const fn new(component: T) -> Self {
|
||||||
Self {
|
Self {
|
||||||
component,
|
component,
|
||||||
marked_for_paint: true,
|
marked_for_paint: true,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use super::{Component, Event, EventCtx, Never};
|
use super::{Component, Event, EventCtx, Never};
|
||||||
use crate::ui::{geometry::Rect, shape::Renderer};
|
use crate::ui::{geometry::Rect, shape::Renderer};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Empty;
|
pub struct Empty;
|
||||||
|
|
||||||
impl Component for Empty {
|
impl Component for Empty {
|
||||||
|
@ -18,7 +18,7 @@ pub struct Label<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Label<'a> {
|
impl<'a> Label<'a> {
|
||||||
pub fn new(text: TString<'a>, align: Alignment, style: TextStyle) -> Self {
|
pub const fn new(text: TString<'a>, align: Alignment, style: TextStyle) -> Self {
|
||||||
Self {
|
Self {
|
||||||
text,
|
text,
|
||||||
layout: TextLayout::new(style).with_align(align),
|
layout: TextLayout::new(style).with_align(align),
|
||||||
@ -26,34 +26,34 @@ impl<'a> Label<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn left_aligned(text: TString<'a>, style: TextStyle) -> Self {
|
pub const fn left_aligned(text: TString<'a>, style: TextStyle) -> Self {
|
||||||
Self::new(text, Alignment::Start, style)
|
Self::new(text, Alignment::Start, style)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn right_aligned(text: TString<'a>, style: TextStyle) -> Self {
|
pub const fn right_aligned(text: TString<'a>, style: TextStyle) -> Self {
|
||||||
Self::new(text, Alignment::End, style)
|
Self::new(text, Alignment::End, style)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn centered(text: TString<'a>, style: TextStyle) -> Self {
|
pub const fn centered(text: TString<'a>, style: TextStyle) -> Self {
|
||||||
Self::new(text, Alignment::Center, style)
|
Self::new(text, Alignment::Center, style)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn top_aligned(mut self) -> Self {
|
pub const fn top_aligned(mut self) -> Self {
|
||||||
self.vertical = Alignment::Start;
|
self.vertical = Alignment::Start;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vertically_centered(mut self) -> Self {
|
pub const fn vertically_centered(mut self) -> Self {
|
||||||
self.vertical = Alignment::Center;
|
self.vertical = Alignment::Center;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bottom_aligned(mut self) -> Self {
|
pub const fn bottom_aligned(mut self) -> Self {
|
||||||
self.vertical = Alignment::End;
|
self.vertical = Alignment::End;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn styled(mut self, style: TextStyle) -> Self {
|
pub const fn styled(mut self, style: TextStyle) -> Self {
|
||||||
self.layout.style = style;
|
self.layout.style = style;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -74,7 +74,7 @@ impl<'a> Label<'a> {
|
|||||||
self.layout.bounds
|
self.layout.bounds
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn alignment(&self) -> Alignment {
|
pub const fn alignment(&self) -> Alignment {
|
||||||
self.layout.align
|
self.layout.align
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ impl TextStyle {
|
|||||||
impl TextLayout {
|
impl TextLayout {
|
||||||
/// Create a new text layout, with empty size and default text parameters
|
/// Create a new text layout, with empty size and default text parameters
|
||||||
/// filled from `T`.
|
/// filled from `T`.
|
||||||
pub fn new(style: TextStyle) -> Self {
|
pub const fn new(style: TextStyle) -> Self {
|
||||||
Self {
|
Self {
|
||||||
bounds: Rect::zero(),
|
bounds: Rect::zero(),
|
||||||
padding_top: 0,
|
padding_top: 0,
|
||||||
@ -210,12 +210,12 @@ impl TextLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_bounds(mut self, bounds: Rect) -> Self {
|
pub const fn with_bounds(mut self, bounds: Rect) -> Self {
|
||||||
self.bounds = bounds;
|
self.bounds = bounds;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_align(mut self, align: Alignment) -> Self {
|
pub const fn with_align(mut self, align: Alignment) -> Self {
|
||||||
self.align = align;
|
self.align = align;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ use crate::{
|
|||||||
/// consumption and conversion time.
|
/// consumption and conversion time.
|
||||||
pub const MAX_HEX_CHARS_ON_SCREEN: usize = 256;
|
pub const MAX_HEX_CHARS_ON_SCREEN: usize = 256;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub enum StrOrBytes {
|
pub enum StrOrBytes {
|
||||||
Str(TString<'static>),
|
Str(TString<'static>),
|
||||||
Bytes(Obj),
|
Bytes(Obj),
|
||||||
@ -55,6 +56,7 @@ impl TryFrom<Obj> for StrOrBytes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct ConfirmBlob {
|
pub struct ConfirmBlob {
|
||||||
pub description: TString<'static>,
|
pub description: TString<'static>,
|
||||||
pub extra: TString<'static>,
|
pub extra: TString<'static>,
|
||||||
|
@ -7,7 +7,7 @@ use crate::{
|
|||||||
ui::{
|
ui::{
|
||||||
component::{
|
component::{
|
||||||
text::paragraphs::{Paragraph, ParagraphSource, ParagraphVecShort, Paragraphs, VecExt},
|
text::paragraphs::{Paragraph, ParagraphSource, ParagraphVecShort, Paragraphs, VecExt},
|
||||||
Component, Event, EventCtx, Paginate, Qr,
|
Component, Event, EventCtx, Paginate,
|
||||||
},
|
},
|
||||||
geometry::Rect,
|
geometry::Rect,
|
||||||
shape::Renderer,
|
shape::Renderer,
|
||||||
@ -18,8 +18,8 @@ use super::{theme, Frame, FrameMsg};
|
|||||||
|
|
||||||
const MAX_XPUBS: usize = 16;
|
const MAX_XPUBS: usize = 16;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct AddressDetails {
|
pub struct AddressDetails {
|
||||||
qr_code: Frame<Qr>,
|
|
||||||
details: Frame<Paragraphs<ParagraphVecShort<'static>>>,
|
details: Frame<Paragraphs<ParagraphVecShort<'static>>>,
|
||||||
xpub_view: Frame<Paragraphs<Paragraph<'static>>>,
|
xpub_view: Frame<Paragraphs<Paragraph<'static>>>,
|
||||||
xpubs: Vec<(TString<'static>, TString<'static>), MAX_XPUBS>,
|
xpubs: Vec<(TString<'static>, TString<'static>), MAX_XPUBS>,
|
||||||
@ -29,43 +29,38 @@ pub struct AddressDetails {
|
|||||||
|
|
||||||
impl AddressDetails {
|
impl AddressDetails {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
qr_title: TString<'static>,
|
|
||||||
qr_address: TString<'static>,
|
|
||||||
case_sensitive: bool,
|
|
||||||
details_title: TString<'static>,
|
details_title: TString<'static>,
|
||||||
account: Option<TString<'static>>,
|
account: Option<TString<'static>>,
|
||||||
path: Option<TString<'static>>,
|
path: Option<TString<'static>>,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let mut para = ParagraphVecShort::new();
|
let mut para = ParagraphVecShort::new();
|
||||||
if let Some(a) = account {
|
if let Some(a) = account {
|
||||||
para.add(Paragraph::new(
|
para.add(Paragraph::new::<TString>(
|
||||||
&theme::TEXT_NORMAL,
|
&theme::TEXT_SUB_GREY,
|
||||||
TR::words__account_colon,
|
TR::words__account.into(),
|
||||||
|
));
|
||||||
|
para.add(Paragraph::new(&theme::TEXT_MONO_GREY_LIGHT, a));
|
||||||
|
}
|
||||||
|
if account.is_some() & path.is_some() {
|
||||||
|
para.add(Paragraph::new(
|
||||||
|
&theme::TEXT_SUB_GREY,
|
||||||
|
TString::from_str(" "),
|
||||||
));
|
));
|
||||||
para.add(Paragraph::new(&theme::TEXT_MONO, a));
|
|
||||||
}
|
}
|
||||||
if let Some(p) = path {
|
if let Some(p) = path {
|
||||||
para.add(Paragraph::new(
|
para.add(Paragraph::new::<TString>(
|
||||||
&theme::TEXT_NORMAL,
|
&theme::TEXT_SUB_GREY,
|
||||||
TR::address_details__derivation_path,
|
TR::address_details__derivation_path.into(),
|
||||||
));
|
));
|
||||||
para.add(Paragraph::new(&theme::TEXT_MONO, p));
|
para.add(Paragraph::new(&theme::TEXT_MONO_GREY_LIGHT, p));
|
||||||
}
|
}
|
||||||
let result = Self {
|
let result = Self {
|
||||||
qr_code: Frame::left_aligned(
|
|
||||||
qr_title,
|
|
||||||
qr_address
|
|
||||||
.map(|s| Qr::new(s, case_sensitive))?
|
|
||||||
.with_border(7),
|
|
||||||
)
|
|
||||||
.with_cancel_button()
|
|
||||||
.with_border(theme::borders_horizontal_scroll()),
|
|
||||||
details: Frame::left_aligned(details_title, para.into_paragraphs())
|
details: Frame::left_aligned(details_title, para.into_paragraphs())
|
||||||
.with_cancel_button()
|
.with_cancel_button()
|
||||||
.with_border(theme::borders_horizontal_scroll()),
|
.with_border(theme::borders_horizontal_scroll()),
|
||||||
xpub_view: Frame::left_aligned(
|
xpub_view: Frame::left_aligned(
|
||||||
" \n ".into(),
|
" \n ".into(),
|
||||||
Paragraph::new(&theme::TEXT_MONO, "").into_paragraphs(),
|
Paragraph::new(&theme::TEXT_MONO_GREY_LIGHT, "").into_paragraphs(),
|
||||||
)
|
)
|
||||||
.with_cancel_button()
|
.with_cancel_button()
|
||||||
.with_border(theme::borders_horizontal_scroll()),
|
.with_border(theme::borders_horizontal_scroll()),
|
||||||
@ -121,13 +116,13 @@ impl AddressDetails {
|
|||||||
impl Paginate for AddressDetails {
|
impl Paginate for AddressDetails {
|
||||||
fn page_count(&mut self) -> usize {
|
fn page_count(&mut self) -> usize {
|
||||||
let total_xpub_pages: u8 = self.xpub_page_count.iter().copied().sum();
|
let total_xpub_pages: u8 = self.xpub_page_count.iter().copied().sum();
|
||||||
2usize.saturating_add(total_xpub_pages.into())
|
1usize.saturating_add(total_xpub_pages.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_page(&mut self, to_page: usize) {
|
fn change_page(&mut self, to_page: usize) {
|
||||||
self.current_page = to_page;
|
self.current_page = to_page;
|
||||||
if to_page > 1 {
|
if to_page > 0 {
|
||||||
let i = to_page - 2;
|
let i = to_page - 1;
|
||||||
let (xpub_index, xpub_page) = self.lookup(i);
|
let (xpub_index, xpub_page) = self.lookup(i);
|
||||||
self.switch_xpub(xpub_index, xpub_page);
|
self.switch_xpub(xpub_index, xpub_page);
|
||||||
}
|
}
|
||||||
@ -138,7 +133,6 @@ impl Component for AddressDetails {
|
|||||||
type Msg = ();
|
type Msg = ();
|
||||||
|
|
||||||
fn place(&mut self, bounds: Rect) -> Rect {
|
fn place(&mut self, bounds: Rect) -> Rect {
|
||||||
self.qr_code.place(bounds);
|
|
||||||
self.details.place(bounds);
|
self.details.place(bounds);
|
||||||
self.xpub_view.place(bounds);
|
self.xpub_view.place(bounds);
|
||||||
|
|
||||||
@ -153,8 +147,7 @@ impl Component for AddressDetails {
|
|||||||
|
|
||||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
||||||
let msg = match self.current_page {
|
let msg = match self.current_page {
|
||||||
0 => self.qr_code.event(ctx, event),
|
0 => self.details.event(ctx, event),
|
||||||
1 => self.details.event(ctx, event),
|
|
||||||
_ => self.xpub_view.event(ctx, event),
|
_ => self.xpub_view.event(ctx, event),
|
||||||
};
|
};
|
||||||
match msg {
|
match msg {
|
||||||
@ -165,16 +158,14 @@ impl Component for AddressDetails {
|
|||||||
|
|
||||||
fn paint(&mut self) {
|
fn paint(&mut self) {
|
||||||
match self.current_page {
|
match self.current_page {
|
||||||
0 => self.qr_code.paint(),
|
0 => self.details.paint(),
|
||||||
1 => self.details.paint(),
|
|
||||||
_ => self.xpub_view.paint(),
|
_ => self.xpub_view.paint(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||||
match self.current_page {
|
match self.current_page {
|
||||||
0 => self.qr_code.render(target),
|
0 => self.details.render(target),
|
||||||
1 => self.details.render(target),
|
|
||||||
_ => self.xpub_view.render(target),
|
_ => self.xpub_view.render(target),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,8 +173,7 @@ impl Component for AddressDetails {
|
|||||||
#[cfg(feature = "ui_bounds")]
|
#[cfg(feature = "ui_bounds")]
|
||||||
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
|
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
|
||||||
match self.current_page {
|
match self.current_page {
|
||||||
0 => self.qr_code.bounds(sink),
|
0 => self.details.bounds(sink),
|
||||||
1 => self.details.bounds(sink),
|
|
||||||
_ => self.xpub_view.bounds(sink),
|
_ => self.xpub_view.bounds(sink),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -194,8 +184,7 @@ impl crate::trace::Trace for AddressDetails {
|
|||||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||||
t.component("AddressDetails");
|
t.component("AddressDetails");
|
||||||
match self.current_page {
|
match self.current_page {
|
||||||
0 => t.child("qr_code", &self.qr_code),
|
0 => t.child("details", &self.details),
|
||||||
1 => t.child("details", &self.details),
|
|
||||||
_ => t.child("xpub_view", &self.xpub_view),
|
_ => t.child("xpub_view", &self.xpub_view),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ impl<T> Frame<T>
|
|||||||
where
|
where
|
||||||
T: Component,
|
T: Component,
|
||||||
{
|
{
|
||||||
pub fn new(alignment: Alignment, title: TString<'static>, content: T) -> Self {
|
pub const fn new(alignment: Alignment, title: TString<'static>, content: T) -> Self {
|
||||||
Self {
|
Self {
|
||||||
title: Child::new(
|
title: Child::new(
|
||||||
Label::new(title, alignment, theme::label_title_main()).vertically_centered(),
|
Label::new(title, alignment, theme::label_title_main()).vertically_centered(),
|
||||||
@ -49,19 +49,19 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn left_aligned(title: TString<'static>, content: T) -> Self {
|
pub const fn left_aligned(title: TString<'static>, content: T) -> Self {
|
||||||
Self::new(Alignment::Start, title, content)
|
Self::new(Alignment::Start, title, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn right_aligned(title: TString<'static>, content: T) -> Self {
|
pub const fn right_aligned(title: TString<'static>, content: T) -> Self {
|
||||||
Self::new(Alignment::End, title, content)
|
Self::new(Alignment::End, title, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn centered(title: TString<'static>, content: T) -> Self {
|
pub const fn centered(title: TString<'static>, content: T) -> Self {
|
||||||
Self::new(Alignment::Center, title, content)
|
Self::new(Alignment::Center, title, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_border(mut self, border: Insets) -> Self {
|
pub const fn with_border(mut self, border: Insets) -> Self {
|
||||||
self.border = border;
|
self.border = border;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -130,6 +130,11 @@ where
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_danger(self) -> Self {
|
||||||
|
self.button_styled(theme::button_danger())
|
||||||
|
.title_styled(theme::label_title_danger())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn inner(&self) -> &T {
|
pub fn inner(&self) -> &T {
|
||||||
self.content.inner()
|
self.content.inner()
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ use super::{theme, Swipe, SwipeDirection};
|
|||||||
|
|
||||||
/// Component showing status of an operation. Most typically embedded as a
|
/// Component showing status of an operation. Most typically embedded as a
|
||||||
/// content of a Frame and showing success (checkmark with a circle around).
|
/// content of a Frame and showing success (checkmark with a circle around).
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct StatusScreen {
|
pub struct StatusScreen {
|
||||||
area: Rect,
|
area: Rect,
|
||||||
icon: Icon,
|
icon: Icon,
|
||||||
@ -18,6 +19,7 @@ pub struct StatusScreen {
|
|||||||
dismiss_type: DismissType,
|
dismiss_type: DismissType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
enum DismissType {
|
enum DismissType {
|
||||||
SwipeUp(Swipe),
|
SwipeUp(Swipe),
|
||||||
Timeout(Timeout),
|
Timeout(Timeout),
|
||||||
@ -62,6 +64,15 @@ impl StatusScreen {
|
|||||||
DismissType::SwipeUp(Swipe::new().up()),
|
DismissType::SwipeUp(Swipe::new().up()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_neutral_timeout() -> Self {
|
||||||
|
Self::new(
|
||||||
|
theme::ICON_SIMPLE_CHECKMARK,
|
||||||
|
theme::GREY_EXTRA_LIGHT,
|
||||||
|
theme::GREY_DARK,
|
||||||
|
DismissType::Timeout(Timeout::new(TIMEOUT_MS)),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for StatusScreen {
|
impl Component for StatusScreen {
|
||||||
|
@ -10,6 +10,7 @@ use super::theme;
|
|||||||
|
|
||||||
pub use crate::ui::component::SwipeDirection;
|
pub use crate::ui::component::SwipeDirection;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Swipe {
|
pub struct Swipe {
|
||||||
pub area: Rect,
|
pub area: Rect,
|
||||||
pub allow_up: bool,
|
pub allow_up: bool,
|
||||||
|
@ -1,33 +1,41 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error,
|
error,
|
||||||
|
micropython::{iter::IterBuf, qstr::Qstr},
|
||||||
|
strutil::TString,
|
||||||
|
translations::TR,
|
||||||
ui::{
|
ui::{
|
||||||
component::{
|
component::{
|
||||||
image::BlendedImage,
|
text::paragraphs::{Paragraph, ParagraphSource, Paragraphs},
|
||||||
text::paragraphs::{Paragraph, Paragraphs},
|
ComponentExt, Qr, SwipeDirection,
|
||||||
ComponentExt, Qr, SwipeDirection, Timeout,
|
|
||||||
},
|
},
|
||||||
flow::{
|
flow::{
|
||||||
base::Decision, flow_store, FlowMsg, FlowState, FlowStore, IgnoreSwipe, SwipeFlow,
|
base::Decision, flow_store, FlowMsg, FlowState, FlowStore, IgnoreSwipe, SwipeFlow,
|
||||||
SwipePage,
|
SwipePage,
|
||||||
},
|
},
|
||||||
|
layout::util::ConfirmBlob,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::super::{
|
use super::super::{
|
||||||
component::{Frame, FrameMsg, IconDialog, VerticalMenu, VerticalMenuChoiceMsg},
|
component::{
|
||||||
|
AddressDetails, CancelInfoConfirmMsg, Frame, FrameMsg, PromptScreen, StatusScreen,
|
||||||
|
VerticalMenu, VerticalMenuChoiceMsg,
|
||||||
|
},
|
||||||
theme,
|
theme,
|
||||||
};
|
};
|
||||||
|
|
||||||
const LONGSTRING: &'static str = "https://youtu.be/iFkEs4GNgfc?si=Jl4UZSIAYGVcLQKohttps://youtu.be/iFkEs4GNgfc?si=Jl4UZSIAYGVcLQKohttps://youtu.be/iFkEs4GNgfc?si=Jl4UZSIAYGVcLQKohttps://youtu.be/iFkEs4GNgfc?si=Jl4UZSIAYGVcLQKohttps://youtu.be/iFkEs4GNgfc?si=Jl4UZSIAYGVcLQKo";
|
const QR_BORDER: i16 = 4;
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, ToPrimitive)]
|
#[derive(Copy, Clone, PartialEq, Eq, ToPrimitive)]
|
||||||
pub enum GetAddress {
|
pub enum GetAddress {
|
||||||
Address,
|
Address,
|
||||||
|
Tap,
|
||||||
|
Confirmed,
|
||||||
Menu,
|
Menu,
|
||||||
QrCode,
|
QrCode,
|
||||||
AccountInfo,
|
AccountInfo,
|
||||||
Cancel,
|
Cancel,
|
||||||
Success,
|
CancelTap,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlowState for GetAddress {
|
impl FlowState for GetAddress {
|
||||||
@ -36,8 +44,9 @@ impl FlowState for GetAddress {
|
|||||||
(GetAddress::Address, SwipeDirection::Left) => {
|
(GetAddress::Address, SwipeDirection::Left) => {
|
||||||
Decision::Goto(GetAddress::Menu, direction)
|
Decision::Goto(GetAddress::Menu, direction)
|
||||||
}
|
}
|
||||||
(GetAddress::Address, SwipeDirection::Up) => {
|
(GetAddress::Address, SwipeDirection::Up) => Decision::Goto(GetAddress::Tap, direction),
|
||||||
Decision::Goto(GetAddress::Success, direction)
|
(GetAddress::Tap, SwipeDirection::Down) => {
|
||||||
|
Decision::Goto(GetAddress::Address, direction)
|
||||||
}
|
}
|
||||||
(GetAddress::Menu, SwipeDirection::Right) => {
|
(GetAddress::Menu, SwipeDirection::Right) => {
|
||||||
Decision::Goto(GetAddress::Address, direction)
|
Decision::Goto(GetAddress::Address, direction)
|
||||||
@ -48,7 +57,15 @@ impl FlowState for GetAddress {
|
|||||||
(GetAddress::AccountInfo, SwipeDirection::Right) => {
|
(GetAddress::AccountInfo, SwipeDirection::Right) => {
|
||||||
Decision::Goto(GetAddress::Menu, direction)
|
Decision::Goto(GetAddress::Menu, direction)
|
||||||
}
|
}
|
||||||
(GetAddress::Cancel, SwipeDirection::Up) => Decision::Return(FlowMsg::Cancelled),
|
(GetAddress::Cancel, SwipeDirection::Up) => {
|
||||||
|
Decision::Goto(GetAddress::CancelTap, direction)
|
||||||
|
}
|
||||||
|
(GetAddress::Cancel, SwipeDirection::Right) => {
|
||||||
|
Decision::Goto(GetAddress::Menu, direction)
|
||||||
|
}
|
||||||
|
(GetAddress::CancelTap, SwipeDirection::Down) => {
|
||||||
|
Decision::Goto(GetAddress::Cancel, direction)
|
||||||
|
}
|
||||||
_ => Decision::Nothing,
|
_ => Decision::Nothing,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,6 +76,12 @@ impl FlowState for GetAddress {
|
|||||||
Decision::Goto(GetAddress::Menu, SwipeDirection::Left)
|
Decision::Goto(GetAddress::Menu, SwipeDirection::Left)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(GetAddress::Tap, FlowMsg::Confirmed) => {
|
||||||
|
Decision::Goto(GetAddress::Confirmed, SwipeDirection::Up)
|
||||||
|
}
|
||||||
|
|
||||||
|
(GetAddress::Confirmed, _) => Decision::Return(FlowMsg::Confirmed),
|
||||||
|
|
||||||
(GetAddress::Menu, FlowMsg::Choice(0)) => {
|
(GetAddress::Menu, FlowMsg::Choice(0)) => {
|
||||||
Decision::Goto(GetAddress::QrCode, SwipeDirection::Left)
|
Decision::Goto(GetAddress::QrCode, SwipeDirection::Left)
|
||||||
}
|
}
|
||||||
@ -87,14 +110,19 @@ impl FlowState for GetAddress {
|
|||||||
Decision::Goto(GetAddress::Menu, SwipeDirection::Right)
|
Decision::Goto(GetAddress::Menu, SwipeDirection::Right)
|
||||||
}
|
}
|
||||||
|
|
||||||
(GetAddress::Success, _) => Decision::Return(FlowMsg::Confirmed),
|
(GetAddress::CancelTap, FlowMsg::Confirmed) => Decision::Return(FlowMsg::Cancelled),
|
||||||
|
|
||||||
|
(GetAddress::CancelTap, FlowMsg::Cancelled) => {
|
||||||
|
Decision::Goto(GetAddress::Menu, SwipeDirection::Right)
|
||||||
|
}
|
||||||
|
|
||||||
_ => Decision::Nothing,
|
_ => Decision::Nothing,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
micropython::{buffer::StrBuffer, map::Map, obj::Obj, util},
|
micropython::{map::Map, obj::Obj, util},
|
||||||
ui::layout::obj::LayoutObj,
|
ui::layout::obj::LayoutObj,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -103,83 +131,132 @@ pub extern "C" fn new_get_address(n_args: usize, args: *const Obj, kwargs: *mut
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl GetAddress {
|
impl GetAddress {
|
||||||
fn new(_args: &[Obj], _kwargs: &Map) -> Result<Obj, error::Error> {
|
fn new(_args: &[Obj], kwargs: &Map) -> Result<Obj, error::Error> {
|
||||||
let store = flow_store()
|
let title: TString = "Receive address".into(); // TODO: address__title_receive_address w/o uppercase
|
||||||
.add(
|
let description: Option<TString> =
|
||||||
Frame::left_aligned(
|
kwargs.get(Qstr::MP_QSTR_description)?.try_into_option()?;
|
||||||
"Receive".into(),
|
let extra: Option<TString> = kwargs.get(Qstr::MP_QSTR_extra)?.try_into_option()?;
|
||||||
SwipePage::vertical(Paragraphs::new(Paragraph::new(
|
let address: Obj = kwargs.get(Qstr::MP_QSTR_address)?;
|
||||||
&theme::TEXT_MONO,
|
let chunkify: bool = kwargs.get_or(Qstr::MP_QSTR_chunkify, false)?;
|
||||||
StrBuffer::from(LONGSTRING),
|
|
||||||
))),
|
let address_qr: TString = kwargs.get(Qstr::MP_QSTR_address_qr)?.try_into()?;
|
||||||
)
|
let case_sensitive: bool = kwargs.get(Qstr::MP_QSTR_case_sensitive)?.try_into()?;
|
||||||
.with_subtitle("address".into())
|
|
||||||
|
let account: Option<TString> = kwargs.get(Qstr::MP_QSTR_account)?.try_into_option()?;
|
||||||
|
let path: Option<TString> = kwargs.get(Qstr::MP_QSTR_path)?.try_into_option()?;
|
||||||
|
let xpubs: Obj = kwargs.get(Qstr::MP_QSTR_xpubs)?;
|
||||||
|
|
||||||
|
// Address
|
||||||
|
let data_style = if chunkify {
|
||||||
|
let address: TString = address.try_into()?;
|
||||||
|
theme::get_chunkified_text_style(address.len())
|
||||||
|
} else {
|
||||||
|
&theme::TEXT_MONO
|
||||||
|
};
|
||||||
|
let paragraphs = ConfirmBlob {
|
||||||
|
description: description.unwrap_or("".into()),
|
||||||
|
extra: extra.unwrap_or("".into()),
|
||||||
|
data: address.try_into()?,
|
||||||
|
description_font: &theme::TEXT_NORMAL,
|
||||||
|
extra_font: &theme::TEXT_DEMIBOLD,
|
||||||
|
data_font: data_style,
|
||||||
|
}
|
||||||
|
.into_paragraphs();
|
||||||
|
let content_address = Frame::left_aligned(title, SwipePage::vertical(paragraphs))
|
||||||
.with_menu_button()
|
.with_menu_button()
|
||||||
.map(|msg| matches!(msg, FrameMsg::Button(_)).then_some(FlowMsg::Info)),
|
.with_footer(TR::instructions__swipe_up.into(), None)
|
||||||
)?
|
.map(|msg| matches!(msg, FrameMsg::Button(_)).then_some(FlowMsg::Info));
|
||||||
.add(
|
// .one_button_request(ButtonRequestCode::Address, "show_address");
|
||||||
|
|
||||||
|
// Tap
|
||||||
|
let content_tap = Frame::left_aligned(title, PromptScreen::new_tap_to_confirm())
|
||||||
|
.with_footer(TR::instructions__tap_to_confirm.into(), None)
|
||||||
|
.map(|msg| match msg {
|
||||||
|
FrameMsg::Content(()) => Some(FlowMsg::Confirmed),
|
||||||
|
FrameMsg::Button(CancelInfoConfirmMsg::Cancelled) => Some(FlowMsg::Cancelled),
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
|
|
||||||
|
let content_confirmed = IgnoreSwipe::new(
|
||||||
Frame::left_aligned(
|
Frame::left_aligned(
|
||||||
|
TR::address__confirmed.into(),
|
||||||
|
StatusScreen::new_success_timeout(),
|
||||||
|
)
|
||||||
|
.with_footer(TR::instructions__continue_in_app.into(), None),
|
||||||
|
)
|
||||||
|
.map(|_| Some(FlowMsg::Confirmed));
|
||||||
|
|
||||||
|
// Menu
|
||||||
|
let content_menu = Frame::left_aligned(
|
||||||
"".into(),
|
"".into(),
|
||||||
VerticalMenu::empty()
|
VerticalMenu::empty()
|
||||||
.item(theme::ICON_QR_CODE, "Address QR code".into())
|
.item(theme::ICON_QR_CODE, TR::address__qr_code.into())
|
||||||
.item(theme::ICON_CHEVRON_RIGHT, "Account info".into())
|
.item(
|
||||||
.danger(theme::ICON_CANCEL, "Cancel operation".into()),
|
theme::ICON_CHEVRON_RIGHT,
|
||||||
|
TR::address_details__account_info.into(),
|
||||||
|
)
|
||||||
|
.danger(theme::ICON_CANCEL, TR::address__cancel_receive.into()),
|
||||||
)
|
)
|
||||||
.with_cancel_button()
|
.with_cancel_button()
|
||||||
.map(|msg| match msg {
|
.map(|msg| match msg {
|
||||||
FrameMsg::Content(VerticalMenuChoiceMsg::Selected(i)) => {
|
FrameMsg::Content(VerticalMenuChoiceMsg::Selected(i)) => Some(FlowMsg::Choice(i)),
|
||||||
Some(FlowMsg::Choice(i))
|
|
||||||
}
|
|
||||||
FrameMsg::Button(_) => Some(FlowMsg::Cancelled),
|
FrameMsg::Button(_) => Some(FlowMsg::Cancelled),
|
||||||
}),
|
});
|
||||||
)?
|
|
||||||
.add(
|
// QrCode
|
||||||
Frame::left_aligned(
|
let content_qr = Frame::left_aligned(
|
||||||
"Receive address".into(),
|
title,
|
||||||
IgnoreSwipe::new(Qr::new(
|
IgnoreSwipe::new(
|
||||||
"https://youtu.be/iFkEs4GNgfc?si=Jl4UZSIAYGVcLQKo",
|
address_qr
|
||||||
true,
|
.map(|s| Qr::new(s, case_sensitive))?
|
||||||
)?),
|
.with_border(QR_BORDER),
|
||||||
)
|
|
||||||
.with_cancel_button()
|
|
||||||
.map(|msg| matches!(msg, FrameMsg::Button(_)).then_some(FlowMsg::Cancelled)),
|
|
||||||
)?
|
|
||||||
.add(
|
|
||||||
Frame::left_aligned(
|
|
||||||
"Account info".into(),
|
|
||||||
SwipePage::vertical(Paragraphs::new(Paragraph::new(
|
|
||||||
&theme::TEXT_NORMAL,
|
|
||||||
StrBuffer::from("taproot xp"),
|
|
||||||
))),
|
|
||||||
)
|
|
||||||
.with_cancel_button()
|
|
||||||
.map(|msg| matches!(msg, FrameMsg::Button(_)).then_some(FlowMsg::Cancelled)),
|
|
||||||
)?
|
|
||||||
.add(
|
|
||||||
Frame::left_aligned(
|
|
||||||
"Cancel receive".into(),
|
|
||||||
SwipePage::vertical(Paragraphs::new(Paragraph::new(
|
|
||||||
&theme::TEXT_NORMAL,
|
|
||||||
StrBuffer::from("O rly?"),
|
|
||||||
))),
|
|
||||||
)
|
|
||||||
.with_cancel_button()
|
|
||||||
.map(|msg| matches!(msg, FrameMsg::Button(_)).then_some(FlowMsg::Cancelled)),
|
|
||||||
)?
|
|
||||||
.add(
|
|
||||||
IconDialog::new(
|
|
||||||
BlendedImage::new(
|
|
||||||
theme::IMAGE_BG_CIRCLE,
|
|
||||||
theme::IMAGE_FG_WARN,
|
|
||||||
theme::SUCCESS_COLOR,
|
|
||||||
theme::FG,
|
|
||||||
theme::BG,
|
|
||||||
),
|
),
|
||||||
StrBuffer::from("Confirmed"),
|
|
||||||
Timeout::new(100),
|
|
||||||
)
|
)
|
||||||
.map(|_| Some(FlowMsg::Confirmed)),
|
.with_cancel_button()
|
||||||
)?;
|
.map(|msg| matches!(msg, FrameMsg::Button(_)).then_some(FlowMsg::Cancelled));
|
||||||
|
|
||||||
|
// AccountInfo
|
||||||
|
let mut ad = AddressDetails::new(TR::address_details__account_info.into(), account, path)?;
|
||||||
|
for i in IterBuf::new().try_iterate(xpubs)? {
|
||||||
|
let [xtitle, text]: [TString; 2] = util::iter_into_array(i)?;
|
||||||
|
ad.add_xpub(xtitle, text)?;
|
||||||
|
}
|
||||||
|
let content_account = SwipePage::vertical(ad).map(|_| Some(FlowMsg::Cancelled));
|
||||||
|
|
||||||
|
// Cancel
|
||||||
|
let content_cancel_info = Frame::left_aligned(
|
||||||
|
TR::address__cancel_receive.into(),
|
||||||
|
SwipePage::vertical(Paragraphs::new(Paragraph::new(
|
||||||
|
&theme::TEXT_MAIN_GREY_LIGHT,
|
||||||
|
TR::address__cancel_contact_support,
|
||||||
|
))),
|
||||||
|
)
|
||||||
|
.with_cancel_button()
|
||||||
|
.with_footer(TR::instructions__swipe_up.into(), None)
|
||||||
|
.map(|msg| matches!(msg, FrameMsg::Button(_)).then_some(FlowMsg::Cancelled));
|
||||||
|
|
||||||
|
// CancelTap
|
||||||
|
let content_cancel_tap = Frame::left_aligned(
|
||||||
|
TR::address__cancel_receive.into(),
|
||||||
|
PromptScreen::new_tap_to_cancel(),
|
||||||
|
)
|
||||||
|
.with_cancel_button()
|
||||||
|
.with_footer(TR::instructions__tap_to_confirm.into(), None)
|
||||||
|
.map(|msg| match msg {
|
||||||
|
FrameMsg::Content(()) => Some(FlowMsg::Confirmed),
|
||||||
|
FrameMsg::Button(CancelInfoConfirmMsg::Cancelled) => Some(FlowMsg::Cancelled),
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
|
|
||||||
|
let store = flow_store()
|
||||||
|
.add(content_address)?
|
||||||
|
.add(content_tap)?
|
||||||
|
.add(content_confirmed)?
|
||||||
|
.add(content_menu)?
|
||||||
|
.add(content_qr)?
|
||||||
|
.add(content_account)?
|
||||||
|
.add(content_cancel_info)?
|
||||||
|
.add(content_cancel_tap)?;
|
||||||
let res = SwipeFlow::new(GetAddress::Address, store)?;
|
let res = SwipeFlow::new(GetAddress::Address, store)?;
|
||||||
Ok(LayoutObj::new(res)?.into())
|
Ok(LayoutObj::new(res)?.into())
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,11 @@ pub mod confirm_reset_recover;
|
|||||||
pub mod get_address;
|
pub mod get_address;
|
||||||
pub mod prompt_backup;
|
pub mod prompt_backup;
|
||||||
pub mod show_share_words;
|
pub mod show_share_words;
|
||||||
|
pub mod warning_hi_prio;
|
||||||
|
|
||||||
pub use confirm_reset_create::ConfirmResetCreate;
|
pub use confirm_reset_create::ConfirmResetCreate;
|
||||||
pub use confirm_reset_recover::ConfirmResetRecover;
|
pub use confirm_reset_recover::ConfirmResetRecover;
|
||||||
pub use get_address::GetAddress;
|
pub use get_address::GetAddress;
|
||||||
pub use prompt_backup::PromptBackup;
|
pub use prompt_backup::PromptBackup;
|
||||||
pub use show_share_words::ShowShareWords;
|
pub use show_share_words::ShowShareWords;
|
||||||
|
pub use warning_hi_prio::WarningHiPrio;
|
||||||
|
125
core/embed/rust/src/ui/model_mercury/flow/warning_hi_prio.rs
Normal file
125
core/embed/rust/src/ui/model_mercury/flow/warning_hi_prio.rs
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
use crate::{
|
||||||
|
error,
|
||||||
|
micropython::qstr::Qstr,
|
||||||
|
strutil::TString,
|
||||||
|
translations::TR,
|
||||||
|
ui::{
|
||||||
|
component::{
|
||||||
|
text::paragraphs::{Paragraph, ParagraphSource},
|
||||||
|
ComponentExt, SwipeDirection,
|
||||||
|
},
|
||||||
|
flow::{
|
||||||
|
base::Decision, flow_store, FlowMsg, FlowState, FlowStore, IgnoreSwipe, SwipeFlow,
|
||||||
|
SwipePage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::super::{
|
||||||
|
component::{Frame, FrameMsg, StatusScreen, VerticalMenu, VerticalMenuChoiceMsg},
|
||||||
|
theme,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, ToPrimitive)]
|
||||||
|
pub enum WarningHiPrio {
|
||||||
|
Message,
|
||||||
|
Menu,
|
||||||
|
Cancelled,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FlowState for WarningHiPrio {
|
||||||
|
fn handle_swipe(&self, direction: SwipeDirection) -> Decision<Self> {
|
||||||
|
match (self, direction) {
|
||||||
|
(WarningHiPrio::Message, SwipeDirection::Left) => {
|
||||||
|
Decision::Goto(WarningHiPrio::Menu, direction)
|
||||||
|
}
|
||||||
|
(WarningHiPrio::Message, SwipeDirection::Up) => {
|
||||||
|
Decision::Goto(WarningHiPrio::Cancelled, direction)
|
||||||
|
}
|
||||||
|
(WarningHiPrio::Menu, SwipeDirection::Right) => {
|
||||||
|
Decision::Goto(WarningHiPrio::Message, direction)
|
||||||
|
}
|
||||||
|
_ => Decision::Nothing,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_event(&self, msg: FlowMsg) -> Decision<Self> {
|
||||||
|
match (self, msg) {
|
||||||
|
(WarningHiPrio::Message, FlowMsg::Info) => {
|
||||||
|
Decision::Goto(WarningHiPrio::Menu, SwipeDirection::Left)
|
||||||
|
}
|
||||||
|
(WarningHiPrio::Menu, FlowMsg::Choice(1)) => Decision::Return(FlowMsg::Confirmed),
|
||||||
|
(WarningHiPrio::Menu, FlowMsg::Choice(_)) => {
|
||||||
|
Decision::Goto(WarningHiPrio::Cancelled, SwipeDirection::Up)
|
||||||
|
}
|
||||||
|
(WarningHiPrio::Menu, FlowMsg::Cancelled) => {
|
||||||
|
Decision::Goto(WarningHiPrio::Message, SwipeDirection::Right)
|
||||||
|
}
|
||||||
|
(WarningHiPrio::Cancelled, _) => Decision::Return(FlowMsg::Cancelled),
|
||||||
|
_ => Decision::Nothing,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
micropython::{map::Map, obj::Obj, util},
|
||||||
|
ui::layout::obj::LayoutObj,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub extern "C" fn new_warning_hi_prio(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||||
|
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, WarningHiPrio::new) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WarningHiPrio {
|
||||||
|
const EXTRA_PADDING: i16 = 6;
|
||||||
|
|
||||||
|
fn new(_args: &[Obj], kwargs: &Map) -> Result<Obj, error::Error> {
|
||||||
|
let title: TString = kwargs.get_or(Qstr::MP_QSTR_title, TR::words__warning.try_into()?)?;
|
||||||
|
let description: TString = kwargs.get(Qstr::MP_QSTR_description)?.try_into()?;
|
||||||
|
let value: TString = kwargs.get_or(Qstr::MP_QSTR_value, "".into())?;
|
||||||
|
let cancel: TString = TR::words__cancel_and_exit.into();
|
||||||
|
let confirm: TString = "Continue anyway".into(); // FIXME: en.json has punctuation
|
||||||
|
let done_title: TString = "Operation cancelled".into();
|
||||||
|
|
||||||
|
// Message
|
||||||
|
let paragraphs = [
|
||||||
|
Paragraph::new(&theme::TEXT_MAIN_GREY_LIGHT, description),
|
||||||
|
Paragraph::new(&theme::TEXT_MAIN_GREY_EXTRA_LIGHT, value)
|
||||||
|
.with_top_padding(Self::EXTRA_PADDING),
|
||||||
|
]
|
||||||
|
.into_paragraphs();
|
||||||
|
let content_message = Frame::left_aligned(title, SwipePage::vertical(paragraphs))
|
||||||
|
.with_menu_button()
|
||||||
|
.with_footer(TR::instructions__swipe_up.into(), Some(cancel))
|
||||||
|
.with_danger()
|
||||||
|
.map(|msg| matches!(msg, FrameMsg::Button(_)).then_some(FlowMsg::Info));
|
||||||
|
// .one_button_request(ButtonRequestCode::Warning, br_type);
|
||||||
|
|
||||||
|
// Menu
|
||||||
|
let content_menu = Frame::left_aligned(
|
||||||
|
"".into(),
|
||||||
|
VerticalMenu::empty()
|
||||||
|
.item(theme::ICON_CANCEL, "Cancel".into()) // TODO: button__cancel after it's lowercase
|
||||||
|
.danger(theme::ICON_CHEVRON_RIGHT, confirm),
|
||||||
|
)
|
||||||
|
.with_cancel_button()
|
||||||
|
.map(|msg| match msg {
|
||||||
|
FrameMsg::Content(VerticalMenuChoiceMsg::Selected(i)) => Some(FlowMsg::Choice(i)),
|
||||||
|
FrameMsg::Button(_) => Some(FlowMsg::Cancelled),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Cancelled
|
||||||
|
let content_cancelled = IgnoreSwipe::new(
|
||||||
|
Frame::left_aligned(done_title, StatusScreen::new_neutral_timeout())
|
||||||
|
.with_footer(TR::instructions__continue_in_app.into(), None),
|
||||||
|
)
|
||||||
|
.map(|_| Some(FlowMsg::Cancelled));
|
||||||
|
|
||||||
|
let store = flow_store()
|
||||||
|
.add(content_message)?
|
||||||
|
.add(content_menu)?
|
||||||
|
.add(content_cancelled)?;
|
||||||
|
let res = SwipeFlow::new(WarningHiPrio::Message, store)?;
|
||||||
|
Ok(LayoutObj::new(res)?.into())
|
||||||
|
}
|
||||||
|
}
|
@ -684,38 +684,6 @@ extern "C" fn new_confirm_homescreen(n_args: usize, args: *const Obj, kwargs: *m
|
|||||||
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_show_address_details(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
|
||||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
|
||||||
let qr_title: TString = kwargs.get(Qstr::MP_QSTR_qr_title)?.try_into()?;
|
|
||||||
let details_title: TString = kwargs.get(Qstr::MP_QSTR_details_title)?.try_into()?;
|
|
||||||
let address: TString = kwargs.get(Qstr::MP_QSTR_address)?.try_into()?;
|
|
||||||
let case_sensitive: bool = kwargs.get(Qstr::MP_QSTR_case_sensitive)?.try_into()?;
|
|
||||||
let account: Option<TString> = kwargs.get(Qstr::MP_QSTR_account)?.try_into_option()?;
|
|
||||||
let path: Option<TString> = kwargs.get(Qstr::MP_QSTR_path)?.try_into_option()?;
|
|
||||||
|
|
||||||
let xpubs: Obj = kwargs.get(Qstr::MP_QSTR_xpubs)?;
|
|
||||||
|
|
||||||
let mut ad = AddressDetails::new(
|
|
||||||
qr_title,
|
|
||||||
address,
|
|
||||||
case_sensitive,
|
|
||||||
details_title,
|
|
||||||
account,
|
|
||||||
path,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
for i in IterBuf::new().try_iterate(xpubs)? {
|
|
||||||
let [xtitle, text]: [TString; 2] = util::iter_into_array(i)?;
|
|
||||||
ad.add_xpub(xtitle, text)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let obj =
|
|
||||||
LayoutObj::new(SimplePage::horizontal(ad, theme::BG).with_swipe_right_to_go_back())?;
|
|
||||||
Ok(obj.into())
|
|
||||||
};
|
|
||||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" fn new_show_info_with_cancel(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
extern "C" fn new_show_info_with_cancel(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||||
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||||
@ -1012,12 +980,13 @@ extern "C" fn new_confirm_fido(n_args: usize, args: *const Obj, kwargs: *mut Map
|
|||||||
extern "C" fn new_show_warning(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
extern "C" fn new_show_warning(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||||
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||||
|
let description: TString = kwargs.get_or(Qstr::MP_QSTR_description, "".into())?;
|
||||||
let value: TString = kwargs.get_or(Qstr::MP_QSTR_value, "".into())?;
|
let value: TString = kwargs.get_or(Qstr::MP_QSTR_value, "".into())?;
|
||||||
|
|
||||||
let content = SwipeUpScreen::new(Paragraphs::new([Paragraph::new(
|
let content = SwipeUpScreen::new(Paragraphs::new([
|
||||||
&theme::TEXT_MAIN_GREY_LIGHT,
|
Paragraph::new(&theme::TEXT_MAIN_GREY_LIGHT, description),
|
||||||
value,
|
Paragraph::new(&theme::TEXT_MAIN_GREY_EXTRA_LIGHT, value),
|
||||||
)]));
|
]));
|
||||||
let obj = LayoutObj::new(
|
let obj = LayoutObj::new(
|
||||||
Frame::left_aligned(title, content)
|
Frame::left_aligned(title, content)
|
||||||
.with_warning_button()
|
.with_warning_button()
|
||||||
@ -1753,19 +1722,6 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
|||||||
/// """Confirm TOS before creating a wallet and have a user hold to confirm creation."""
|
/// """Confirm TOS before creating a wallet and have a user hold to confirm creation."""
|
||||||
Qstr::MP_QSTR_flow_confirm_reset_create => obj_fn_kw!(0, flow::confirm_reset_create::new_confirm_reset_create).as_obj(),
|
Qstr::MP_QSTR_flow_confirm_reset_create => obj_fn_kw!(0, flow::confirm_reset_create::new_confirm_reset_create).as_obj(),
|
||||||
|
|
||||||
/// def show_address_details(
|
|
||||||
/// *,
|
|
||||||
/// qr_title: str,
|
|
||||||
/// address: str,
|
|
||||||
/// case_sensitive: bool,
|
|
||||||
/// details_title: str,
|
|
||||||
/// account: str | None,
|
|
||||||
/// path: str | None,
|
|
||||||
/// xpubs: list[tuple[str, str]],
|
|
||||||
/// ) -> LayoutObj[UiResult]:
|
|
||||||
/// """Show address details - QR code, account, path, cosigner xpubs."""
|
|
||||||
Qstr::MP_QSTR_show_address_details => obj_fn_kw!(0, new_show_address_details).as_obj(),
|
|
||||||
|
|
||||||
/// def show_info_with_cancel(
|
/// def show_info_with_cancel(
|
||||||
/// *,
|
/// *,
|
||||||
/// title: str,
|
/// title: str,
|
||||||
@ -2092,9 +2048,29 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
|||||||
/// """Show single-line text in the middle of the screen."""
|
/// """Show single-line text in the middle of the screen."""
|
||||||
Qstr::MP_QSTR_show_wait_text => obj_fn_1!(new_show_wait_text).as_obj(),
|
Qstr::MP_QSTR_show_wait_text => obj_fn_1!(new_show_wait_text).as_obj(),
|
||||||
|
|
||||||
/// def flow_get_address() -> LayoutObj[UiResult]:
|
/// def flow_get_address(
|
||||||
|
/// *,
|
||||||
|
/// address: str | bytes,
|
||||||
|
/// description: str | None,
|
||||||
|
/// extra: str | None,
|
||||||
|
/// chunkify: bool,
|
||||||
|
/// address_qr: str | None,
|
||||||
|
/// case_sensitive: bool,
|
||||||
|
/// account: str | None,
|
||||||
|
/// path: str | None,
|
||||||
|
/// xpubs: list[tuple[str, str]],
|
||||||
|
/// ) -> LayoutObj[UiResult]:
|
||||||
/// """Get address / receive funds."""
|
/// """Get address / receive funds."""
|
||||||
Qstr::MP_QSTR_flow_get_address => obj_fn_kw!(0, flow::get_address::new_get_address).as_obj(),
|
Qstr::MP_QSTR_flow_get_address => obj_fn_kw!(0, flow::get_address::new_get_address).as_obj(),
|
||||||
|
|
||||||
|
/// def flow_warning_hi_prio(
|
||||||
|
/// *,
|
||||||
|
/// title: str,
|
||||||
|
/// description: str,
|
||||||
|
/// value: str = "",
|
||||||
|
/// ) -> LayoutObj[UiResult]:
|
||||||
|
/// """Warning modal with multiple steps to confirm."""
|
||||||
|
Qstr::MP_QSTR_flow_warning_hi_prio => obj_fn_kw!(0, flow::warning_hi_prio::new_warning_hi_prio).as_obj(),
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -215,6 +215,16 @@ pub const fn label_title_main() -> TextStyle {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const fn label_title_danger() -> TextStyle {
|
||||||
|
TextStyle::new(
|
||||||
|
Font::NORMAL,
|
||||||
|
ORANGE_LIGHT,
|
||||||
|
GREY_DARK,
|
||||||
|
GREY_LIGHT,
|
||||||
|
GREY_LIGHT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub const fn label_title_sub() -> TextStyle {
|
pub const fn label_title_sub() -> TextStyle {
|
||||||
TextStyle::new(Font::SUB, GREY, GREY_DARK, GREY_LIGHT, GREY_LIGHT)
|
TextStyle::new(Font::SUB, GREY, GREY_DARK, GREY_LIGHT, GREY_LIGHT)
|
||||||
}
|
}
|
||||||
@ -355,9 +365,30 @@ pub const fn button_cancel() -> ButtonStyleSheet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: delete
|
|
||||||
pub const fn button_danger() -> ButtonStyleSheet {
|
pub const fn button_danger() -> ButtonStyleSheet {
|
||||||
button_cancel()
|
ButtonStyleSheet {
|
||||||
|
normal: &ButtonStyle {
|
||||||
|
font: Font::DEMIBOLD,
|
||||||
|
text_color: ORANGE_LIGHT,
|
||||||
|
button_color: BG,
|
||||||
|
icon_color: ORANGE_LIGHT,
|
||||||
|
background_color: BG,
|
||||||
|
},
|
||||||
|
active: &ButtonStyle {
|
||||||
|
font: Font::DEMIBOLD,
|
||||||
|
text_color: ORANGE_LIGHT,
|
||||||
|
button_color: BG,
|
||||||
|
icon_color: ORANGE_LIGHT,
|
||||||
|
background_color: BG,
|
||||||
|
},
|
||||||
|
disabled: &ButtonStyle {
|
||||||
|
font: Font::DEMIBOLD,
|
||||||
|
text_color: ORANGE_LIGHT,
|
||||||
|
button_color: BG,
|
||||||
|
icon_color: ORANGE_LIGHT,
|
||||||
|
background_color: BG,
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn button_reset() -> ButtonStyleSheet {
|
pub const fn button_reset() -> ButtonStyleSheet {
|
||||||
@ -591,6 +622,10 @@ pub const TEXT_MONO: TextStyle = TextStyle::new(Font::MONO, GREY_EXTRA_LIGHT, BG
|
|||||||
.with_page_breaking(PageBreaking::CutAndInsertEllipsisBoth)
|
.with_page_breaking(PageBreaking::CutAndInsertEllipsisBoth)
|
||||||
.with_ellipsis_icon(ICON_PAGE_NEXT, 0)
|
.with_ellipsis_icon(ICON_PAGE_NEXT, 0)
|
||||||
.with_prev_page_icon(ICON_PAGE_PREV, 0);
|
.with_prev_page_icon(ICON_PAGE_PREV, 0);
|
||||||
|
pub const TEXT_MONO_GREY_LIGHT: TextStyle = TextStyle {
|
||||||
|
text_color: GREY_LIGHT,
|
||||||
|
..TEXT_MONO
|
||||||
|
};
|
||||||
/// Makes sure that the displayed text (usually address) will get divided into
|
/// Makes sure that the displayed text (usually address) will get divided into
|
||||||
/// smaller chunks.
|
/// smaller chunks.
|
||||||
pub const TEXT_MONO_ADDRESS_CHUNKS: TextStyle = TEXT_MONO
|
pub const TEXT_MONO_ADDRESS_CHUNKS: TextStyle = TEXT_MONO
|
||||||
@ -656,6 +691,7 @@ pub const MNEMONIC_BUTTON_HEIGHT: i16 = 52;
|
|||||||
pub const RESULT_PADDING: i16 = 6;
|
pub const RESULT_PADDING: i16 = 6;
|
||||||
pub const RESULT_FOOTER_START: i16 = 171;
|
pub const RESULT_FOOTER_START: i16 = 171;
|
||||||
pub const RESULT_FOOTER_HEIGHT: i16 = 62;
|
pub const RESULT_FOOTER_HEIGHT: i16 = 62;
|
||||||
|
pub const DETAILS_SPACING: i16 = 8;
|
||||||
|
|
||||||
// checklist settings
|
// checklist settings
|
||||||
pub const CHECKLIST_CHECK_WIDTH: i16 = 16;
|
pub const CHECKLIST_CHECK_WIDTH: i16 = 16;
|
||||||
|
@ -52,7 +52,7 @@ impl AddressDetails {
|
|||||||
if let Some(path) = path {
|
if let Some(path) = path {
|
||||||
para.add(Paragraph::new(
|
para.add(Paragraph::new(
|
||||||
&theme::TEXT_BOLD,
|
&theme::TEXT_BOLD,
|
||||||
TR::address_details__derivation_path,
|
TR::address_details__derivation_path_colon,
|
||||||
));
|
));
|
||||||
para.add(Paragraph::new(&theme::TEXT_MONO, path));
|
para.add(Paragraph::new(&theme::TEXT_MONO, path));
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ impl AddressDetails {
|
|||||||
if let Some(p) = path {
|
if let Some(p) = path {
|
||||||
para.add(Paragraph::new(
|
para.add(Paragraph::new(
|
||||||
&theme::TEXT_NORMAL,
|
&theme::TEXT_NORMAL,
|
||||||
TR::address_details__derivation_path,
|
TR::address_details__derivation_path_colon,
|
||||||
));
|
));
|
||||||
para.add(Paragraph::new(&theme::TEXT_MONO, p));
|
para.add(Paragraph::new(&theme::TEXT_MONO, p));
|
||||||
}
|
}
|
||||||
|
@ -155,20 +155,6 @@ def flow_confirm_reset_create() -> LayoutObj[UiResult]:
|
|||||||
"""Confirm TOS before creating a wallet and have a user hold to confirm creation."""
|
"""Confirm TOS before creating a wallet and have a user hold to confirm creation."""
|
||||||
|
|
||||||
|
|
||||||
# rust/src/ui/model_mercury/layout.rs
|
|
||||||
def show_address_details(
|
|
||||||
*,
|
|
||||||
qr_title: str,
|
|
||||||
address: str,
|
|
||||||
case_sensitive: bool,
|
|
||||||
details_title: str,
|
|
||||||
account: str | None,
|
|
||||||
path: str | None,
|
|
||||||
xpubs: list[tuple[str, str]],
|
|
||||||
) -> LayoutObj[UiResult]:
|
|
||||||
"""Show address details - QR code, account, path, cosigner xpubs."""
|
|
||||||
|
|
||||||
|
|
||||||
# rust/src/ui/model_mercury/layout.rs
|
# rust/src/ui/model_mercury/layout.rs
|
||||||
def show_info_with_cancel(
|
def show_info_with_cancel(
|
||||||
*,
|
*,
|
||||||
@ -529,8 +515,29 @@ def show_wait_text(message: str, /) -> LayoutObj[None]:
|
|||||||
|
|
||||||
|
|
||||||
# rust/src/ui/model_mercury/layout.rs
|
# rust/src/ui/model_mercury/layout.rs
|
||||||
def flow_get_address() -> LayoutObj[UiResult]:
|
def flow_get_address(
|
||||||
|
*,
|
||||||
|
address: str | bytes,
|
||||||
|
description: str | None,
|
||||||
|
extra: str | None,
|
||||||
|
chunkify: bool,
|
||||||
|
address_qr: str | None,
|
||||||
|
case_sensitive: bool,
|
||||||
|
account: str | None,
|
||||||
|
path: str | None,
|
||||||
|
xpubs: list[tuple[str, str]],
|
||||||
|
) -> LayoutObj[UiResult]:
|
||||||
"""Get address / receive funds."""
|
"""Get address / receive funds."""
|
||||||
|
|
||||||
|
|
||||||
|
# rust/src/ui/model_mercury/layout.rs
|
||||||
|
def flow_warning_hi_prio(
|
||||||
|
*,
|
||||||
|
title: str,
|
||||||
|
description: str,
|
||||||
|
value: str = "",
|
||||||
|
) -> LayoutObj[UiResult]:
|
||||||
|
"""Warning modal with multiple steps to confirm."""
|
||||||
CONFIRMED: UiResult
|
CONFIRMED: UiResult
|
||||||
CANCELLED: UiResult
|
CANCELLED: UiResult
|
||||||
INFO: UiResult
|
INFO: UiResult
|
||||||
|
@ -8,11 +8,17 @@ class TR:
|
|||||||
addr_mismatch__support_url: str = "trezor.io/support"
|
addr_mismatch__support_url: str = "trezor.io/support"
|
||||||
addr_mismatch__wrong_derivation_path: str = "Wrong derivation path for selected account."
|
addr_mismatch__wrong_derivation_path: str = "Wrong derivation path for selected account."
|
||||||
addr_mismatch__xpub_mismatch: str = "XPUB mismatch?"
|
addr_mismatch__xpub_mismatch: str = "XPUB mismatch?"
|
||||||
|
address__cancel_contact_support: str = "If receive address doesn't match, contact Trezor Support at trezor.io/support."
|
||||||
|
address__cancel_receive: str = "Cancel receive"
|
||||||
|
address__confirmed: str = "Receive address confirmed"
|
||||||
address__public_key: str = "Public key"
|
address__public_key: str = "Public key"
|
||||||
|
address__qr_code: str = "QR code"
|
||||||
address__title_cosigner: str = "Cosigner"
|
address__title_cosigner: str = "Cosigner"
|
||||||
address__title_receive_address: str = "Receive address"
|
address__title_receive_address: str = "Receive address"
|
||||||
address__title_yours: str = "Yours"
|
address__title_yours: str = "Yours"
|
||||||
address_details__derivation_path: str = "Derivation path:"
|
address_details__account_info: str = "Account info"
|
||||||
|
address_details__derivation_path: str = "Derivation path"
|
||||||
|
address_details__derivation_path_colon: str = "Derivation path:"
|
||||||
address_details__title_receive_address: str = "Receive address"
|
address_details__title_receive_address: str = "Receive address"
|
||||||
address_details__title_receiving_to: str = "Receiving to"
|
address_details__title_receiving_to: str = "Receiving to"
|
||||||
authenticate__confirm_template: str = "Allow connected computer to confirm your {0} is genuine?"
|
authenticate__confirm_template: str = "Allow connected computer to confirm your {0} is genuine?"
|
||||||
@ -356,6 +362,7 @@ class TR:
|
|||||||
inputs__return: str = "RETURN"
|
inputs__return: str = "RETURN"
|
||||||
inputs__show: str = "SHOW"
|
inputs__show: str = "SHOW"
|
||||||
inputs__space: str = "SPACE"
|
inputs__space: str = "SPACE"
|
||||||
|
instructions__continue_in_app: str = "Continue in the app"
|
||||||
instructions__hold_to_confirm: str = "Hold to confirm"
|
instructions__hold_to_confirm: str = "Hold to confirm"
|
||||||
instructions__swipe_up: str = "Swipe up"
|
instructions__swipe_up: str = "Swipe up"
|
||||||
instructions__tap_to_confirm: str = "Tap to confirm"
|
instructions__tap_to_confirm: str = "Tap to confirm"
|
||||||
@ -828,6 +835,7 @@ class TR:
|
|||||||
words__array_of: str = "Array of"
|
words__array_of: str = "Array of"
|
||||||
words__blockhash: str = "Blockhash"
|
words__blockhash: str = "Blockhash"
|
||||||
words__buying: str = "Buying"
|
words__buying: str = "Buying"
|
||||||
|
words__cancel_and_exit: str = "Cancel and exit"
|
||||||
words__confirm: str = "Confirm"
|
words__confirm: str = "Confirm"
|
||||||
words__confirm_fee: str = "Confirm fee"
|
words__confirm_fee: str = "Confirm fee"
|
||||||
words__contains: str = "Contains"
|
words__contains: str = "Contains"
|
||||||
|
@ -31,10 +31,9 @@ def _get_xpubs(
|
|||||||
|
|
||||||
@with_keychain
|
@with_keychain
|
||||||
async def get_address(msg: GetAddress, keychain: Keychain, coin: CoinInfo) -> Address:
|
async def get_address(msg: GetAddress, keychain: Keychain, coin: CoinInfo) -> Address:
|
||||||
from trezor import TR
|
|
||||||
from trezor.enums import InputScriptType
|
from trezor.enums import InputScriptType
|
||||||
from trezor.messages import Address
|
from trezor.messages import Address
|
||||||
from trezor.ui.layouts import show_address, show_warning
|
from trezor.ui.layouts import confirm_multisig_warning, show_address
|
||||||
|
|
||||||
from apps.common.address_mac import get_address_mac
|
from apps.common.address_mac import get_address_mac
|
||||||
from apps.common.paths import address_n_to_str, validate_path
|
from apps.common.paths import address_n_to_str, validate_path
|
||||||
@ -104,11 +103,7 @@ async def get_address(msg: GetAddress, keychain: Keychain, coin: CoinInfo) -> Ad
|
|||||||
pubnodes = [hd.node for hd in multisig.pubkeys]
|
pubnodes = [hd.node for hd in multisig.pubkeys]
|
||||||
multisig_index = multisig_pubkey_index(multisig, node.public_key())
|
multisig_index = multisig_pubkey_index(multisig, node.public_key())
|
||||||
|
|
||||||
await show_warning(
|
await confirm_multisig_warning()
|
||||||
"warning_multisig",
|
|
||||||
TR.send__receiving_to_multisig,
|
|
||||||
TR.words__continue_anyway,
|
|
||||||
)
|
|
||||||
|
|
||||||
await show_address(
|
await show_address(
|
||||||
address_short,
|
address_short,
|
||||||
|
@ -279,17 +279,6 @@ async def confirm_action(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def flow_demo() -> None:
|
|
||||||
await raise_if_not_confirmed(
|
|
||||||
interact(
|
|
||||||
RustLayout(trezorui2.flow_get_address()),
|
|
||||||
"get_address",
|
|
||||||
BR_TYPE_OTHER,
|
|
||||||
),
|
|
||||||
ActionCancelled,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def confirm_single(
|
async def confirm_single(
|
||||||
br_type: str,
|
br_type: str,
|
||||||
title: str,
|
title: str,
|
||||||
@ -362,7 +351,7 @@ async def confirm_path_warning(
|
|||||||
path: str,
|
path: str,
|
||||||
path_type: str | None = None,
|
path_type: str | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
title = (
|
description = (
|
||||||
TR.addr_mismatch__wrong_derivation_path
|
TR.addr_mismatch__wrong_derivation_path
|
||||||
if not path_type
|
if not path_type
|
||||||
else f"{TR.words__unknown} {path_type.lower()}."
|
else f"{TR.words__unknown} {path_type.lower()}."
|
||||||
@ -370,11 +359,8 @@ async def confirm_path_warning(
|
|||||||
await raise_if_not_confirmed(
|
await raise_if_not_confirmed(
|
||||||
interact(
|
interact(
|
||||||
RustLayout(
|
RustLayout(
|
||||||
trezorui2.show_warning(
|
trezorui2.flow_warning_hi_prio(
|
||||||
title=title,
|
title=f"{TR.words__warning}!", description=description, value=path
|
||||||
value=path,
|
|
||||||
description=TR.words__continue_anyway,
|
|
||||||
button=TR.buttons__continue,
|
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
"path_warning",
|
"path_warning",
|
||||||
@ -383,6 +369,21 @@ async def confirm_path_warning(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def confirm_multisig_warning() -> None:
|
||||||
|
await raise_if_not_confirmed(
|
||||||
|
interact(
|
||||||
|
RustLayout(
|
||||||
|
trezorui2.flow_warning_hi_prio(
|
||||||
|
title=f"{TR.words__important}!",
|
||||||
|
description=TR.send__receiving_to_multisig,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"warning_multisig",
|
||||||
|
br_code=ButtonRequestType.Warning,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def confirm_homescreen(
|
async def confirm_homescreen(
|
||||||
image: bytes,
|
image: bytes,
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -417,77 +418,34 @@ async def show_address(
|
|||||||
br_code: ButtonRequestType = ButtonRequestType.Address,
|
br_code: ButtonRequestType = ButtonRequestType.Address,
|
||||||
chunkify: bool = False,
|
chunkify: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
mismatch_title = mismatch_title or TR.addr_mismatch__mismatch # def_arg
|
|
||||||
send_button_request = True
|
|
||||||
|
|
||||||
if title is None:
|
|
||||||
title = TR.address__title_receive_address
|
|
||||||
if multisig_index is not None:
|
|
||||||
title = f"{title}\n(MULTISIG)"
|
|
||||||
details_title = TR.send__title_receiving_to
|
|
||||||
elif details_title is None:
|
|
||||||
details_title = title
|
|
||||||
|
|
||||||
layout = RustLayout(
|
|
||||||
trezorui2.confirm_address(
|
|
||||||
title=title,
|
|
||||||
data=address,
|
|
||||||
description=network or "",
|
|
||||||
extra=None,
|
|
||||||
chunkify=chunkify,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
while True:
|
|
||||||
if send_button_request:
|
|
||||||
send_button_request = False
|
|
||||||
await button_request(
|
|
||||||
br_type,
|
|
||||||
br_code,
|
|
||||||
pages=layout.page_count(),
|
|
||||||
)
|
|
||||||
layout.request_complete_repaint()
|
|
||||||
result = await ctx_wait(layout)
|
|
||||||
|
|
||||||
# User pressed right button.
|
|
||||||
if result is CONFIRMED:
|
|
||||||
break
|
|
||||||
|
|
||||||
# User pressed corner button or swiped left, go to address details.
|
|
||||||
elif result is INFO:
|
|
||||||
|
|
||||||
def xpub_title(i: int) -> str:
|
def xpub_title(i: int) -> str:
|
||||||
result = f"MULTISIG XPUB #{i + 1}\n"
|
result = f"Multisig XPUB #{i + 1}\n"
|
||||||
result += (
|
result += (
|
||||||
f"({TR.address__title_yours})"
|
f"({TR.address__title_yours.lower()})"
|
||||||
if i == multisig_index
|
if i == multisig_index
|
||||||
else f"({TR.address__title_cosigner})"
|
else f"({TR.address__title_cosigner.lower()})"
|
||||||
)
|
)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
result = await ctx_wait(
|
await raise_if_not_confirmed(
|
||||||
|
interact(
|
||||||
RustLayout(
|
RustLayout(
|
||||||
trezorui2.show_address_details(
|
trezorui2.flow_get_address(
|
||||||
qr_title=title,
|
address=address,
|
||||||
address=address if address_qr is None else address_qr,
|
description=network or "",
|
||||||
|
extra=None,
|
||||||
|
chunkify=chunkify,
|
||||||
|
address_qr=address if address_qr is None else address_qr,
|
||||||
case_sensitive=case_sensitive,
|
case_sensitive=case_sensitive,
|
||||||
details_title=details_title,
|
|
||||||
account=account,
|
account=account,
|
||||||
path=path,
|
path=path,
|
||||||
xpubs=[(xpub_title(i), xpub) for i, xpub in enumerate(xpubs)],
|
xpubs=[(xpub_title(i), xpub) for i, xpub in enumerate(xpubs)],
|
||||||
)
|
)
|
||||||
|
),
|
||||||
|
br_type,
|
||||||
|
br_code,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
assert result is CANCELLED
|
|
||||||
|
|
||||||
else:
|
|
||||||
result = await ctx_wait(
|
|
||||||
RustLayout(trezorui2.show_mismatch(title=mismatch_title))
|
|
||||||
)
|
|
||||||
assert result in (CONFIRMED, CANCELLED)
|
|
||||||
# Right button aborts action, left goes back to showing address.
|
|
||||||
if result is CONFIRMED:
|
|
||||||
raise ActionCancelled
|
|
||||||
|
|
||||||
|
|
||||||
def show_pubkey(
|
def show_pubkey(
|
||||||
@ -1305,7 +1263,7 @@ async def confirm_signverify(
|
|||||||
|
|
||||||
items: list[tuple[str, str]] = []
|
items: list[tuple[str, str]] = []
|
||||||
if account is not None:
|
if account is not None:
|
||||||
items.append((f"{TR.words__account}:", account))
|
items.append((TR.words__account, account))
|
||||||
if path is not None:
|
if path is not None:
|
||||||
items.append((TR.address_details__derivation_path, path))
|
items.append((TR.address_details__derivation_path, path))
|
||||||
items.append(
|
items.append(
|
||||||
|
@ -492,6 +492,14 @@ def confirm_path_warning(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def confirm_multisig_warning() -> Awaitable[None]:
|
||||||
|
return show_warning(
|
||||||
|
"warning_multisig",
|
||||||
|
TR.send__receiving_to_multisig,
|
||||||
|
TR.words__continue_anyway,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def confirm_homescreen(image: bytes) -> Awaitable[None]:
|
def confirm_homescreen(image: bytes) -> Awaitable[None]:
|
||||||
return raise_if_not_confirmed(
|
return raise_if_not_confirmed(
|
||||||
interact(
|
interact(
|
||||||
|
@ -431,6 +431,14 @@ def confirm_path_warning(path: str, path_type: str | None = None) -> Awaitable[N
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def confirm_multisig_warning() -> Awaitable[None]:
|
||||||
|
return show_warning(
|
||||||
|
"warning_multisig",
|
||||||
|
TR.send__receiving_to_multisig,
|
||||||
|
TR.words__continue_anyway,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def confirm_homescreen(image: bytes) -> Awaitable[None]:
|
def confirm_homescreen(image: bytes) -> Awaitable[None]:
|
||||||
return raise_if_not_confirmed(
|
return raise_if_not_confirmed(
|
||||||
interact(
|
interact(
|
||||||
@ -1349,7 +1357,7 @@ async def confirm_signverify(
|
|||||||
if account is not None:
|
if account is not None:
|
||||||
items.append((f"{TR.words__account}:", account))
|
items.append((f"{TR.words__account}:", account))
|
||||||
if path is not None:
|
if path is not None:
|
||||||
items.append((TR.address_details__derivation_path, path))
|
items.append((TR.address_details__derivation_path_colon, path))
|
||||||
items.append(
|
items.append(
|
||||||
(
|
(
|
||||||
TR.sign_message__message_size,
|
TR.sign_message__message_size,
|
||||||
|
@ -46,7 +46,8 @@
|
|||||||
"address__title_cosigner": "Další podepisující",
|
"address__title_cosigner": "Další podepisující",
|
||||||
"address__title_receive_address": "Přijímací adresa",
|
"address__title_receive_address": "Přijímací adresa",
|
||||||
"address__title_yours": "Vaše",
|
"address__title_yours": "Vaše",
|
||||||
"address_details__derivation_path": "Derivační cesta:",
|
"address_details__derivation_path": "Derivační cesta",
|
||||||
|
"address_details__derivation_path_colon": "Derivační cesta:",
|
||||||
"address_details__title_receive_address": "Přijímací adresa",
|
"address_details__title_receive_address": "Přijímací adresa",
|
||||||
"address_details__title_receiving_to": "Příjem",
|
"address_details__title_receiving_to": "Příjem",
|
||||||
"authenticate__confirm_template": "Povolit připojenému počítači potvrdit pravost vašeho {0}?",
|
"authenticate__confirm_template": "Povolit připojenému počítači potvrdit pravost vašeho {0}?",
|
||||||
|
@ -46,7 +46,8 @@
|
|||||||
"address__title_cosigner": "Mitunterzeich.",
|
"address__title_cosigner": "Mitunterzeich.",
|
||||||
"address__title_receive_address": "Empfäng-adresse",
|
"address__title_receive_address": "Empfäng-adresse",
|
||||||
"address__title_yours": "Deiner",
|
"address__title_yours": "Deiner",
|
||||||
"address_details__derivation_path": "Ableitungspfad:",
|
"address_details__derivation_path": "Ableitungspfad",
|
||||||
|
"address_details__derivation_path_colon": "Ableitungspfad:",
|
||||||
"address_details__title_receive_address": "Empfäng-adresse",
|
"address_details__title_receive_address": "Empfäng-adresse",
|
||||||
"address_details__title_receiving_to": "Empfänger",
|
"address_details__title_receiving_to": "Empfänger",
|
||||||
"authenticate__confirm_template": "Darf verbundener Computer bestätigen, dass {0} echt ist?",
|
"authenticate__confirm_template": "Darf verbundener Computer bestätigen, dass {0} echt ist?",
|
||||||
|
@ -10,11 +10,17 @@
|
|||||||
"addr_mismatch__support_url": "trezor.io/support",
|
"addr_mismatch__support_url": "trezor.io/support",
|
||||||
"addr_mismatch__wrong_derivation_path": "Wrong derivation path for selected account.",
|
"addr_mismatch__wrong_derivation_path": "Wrong derivation path for selected account.",
|
||||||
"addr_mismatch__xpub_mismatch": "XPUB mismatch?",
|
"addr_mismatch__xpub_mismatch": "XPUB mismatch?",
|
||||||
|
"address__cancel_contact_support": "If receive address doesn't match, contact Trezor Support at trezor.io/support.",
|
||||||
|
"address__cancel_receive": "Cancel receive",
|
||||||
|
"address__confirmed": "Receive address confirmed",
|
||||||
"address__public_key": "Public key",
|
"address__public_key": "Public key",
|
||||||
|
"address__qr_code": "QR code",
|
||||||
"address__title_cosigner": "Cosigner",
|
"address__title_cosigner": "Cosigner",
|
||||||
"address__title_receive_address": "Receive address",
|
"address__title_receive_address": "Receive address",
|
||||||
"address__title_yours": "Yours",
|
"address__title_yours": "Yours",
|
||||||
"address_details__derivation_path": "Derivation path:",
|
"address_details__derivation_path": "Derivation path",
|
||||||
|
"address_details__derivation_path_colon": "Derivation path:",
|
||||||
|
"address_details__account_info": "Account info",
|
||||||
"address_details__title_receive_address": "Receive address",
|
"address_details__title_receive_address": "Receive address",
|
||||||
"address_details__title_receiving_to": "Receiving to",
|
"address_details__title_receiving_to": "Receiving to",
|
||||||
"authenticate__confirm_template": "Allow connected computer to confirm your {0} is genuine?",
|
"authenticate__confirm_template": "Allow connected computer to confirm your {0} is genuine?",
|
||||||
@ -358,6 +364,7 @@
|
|||||||
"inputs__previous": "PREVIOUS",
|
"inputs__previous": "PREVIOUS",
|
||||||
"inputs__show": "SHOW",
|
"inputs__show": "SHOW",
|
||||||
"inputs__space": "SPACE",
|
"inputs__space": "SPACE",
|
||||||
|
"instructions__continue_in_app": "Continue in the app",
|
||||||
"instructions__swipe_up": "Swipe up",
|
"instructions__swipe_up": "Swipe up",
|
||||||
"instructions__tap_to_confirm": "Tap to confirm",
|
"instructions__tap_to_confirm": "Tap to confirm",
|
||||||
"instructions__hold_to_confirm": "Hold to confirm",
|
"instructions__hold_to_confirm": "Hold to confirm",
|
||||||
@ -830,6 +837,7 @@
|
|||||||
"words__array_of": "Array of",
|
"words__array_of": "Array of",
|
||||||
"words__blockhash": "Blockhash",
|
"words__blockhash": "Blockhash",
|
||||||
"words__buying": "Buying",
|
"words__buying": "Buying",
|
||||||
|
"words__cancel_and_exit": "Cancel and exit",
|
||||||
"words__confirm": "Confirm",
|
"words__confirm": "Confirm",
|
||||||
"words__confirm_fee": "Confirm fee",
|
"words__confirm_fee": "Confirm fee",
|
||||||
"words__contains": "Contains",
|
"words__contains": "Contains",
|
||||||
|
@ -46,7 +46,8 @@
|
|||||||
"address__title_cosigner": "Cofirmante",
|
"address__title_cosigner": "Cofirmante",
|
||||||
"address__title_receive_address": "Dirección destino",
|
"address__title_receive_address": "Dirección destino",
|
||||||
"address__title_yours": "Tuyo",
|
"address__title_yours": "Tuyo",
|
||||||
"address_details__derivation_path": "Ruta de derivación:",
|
"address_details__derivation_path": "Ruta de derivación",
|
||||||
|
"address_details__derivation_path_colon": "Ruta de derivación:",
|
||||||
"address_details__title_receive_address": "Dirección destino",
|
"address_details__title_receive_address": "Dirección destino",
|
||||||
"address_details__title_receiving_to": "Recibir en",
|
"address_details__title_receiving_to": "Recibir en",
|
||||||
"authenticate__confirm_template": "¿Confirmar con el ordenador conectado que tu {0} es original?",
|
"authenticate__confirm_template": "¿Confirmar con el ordenador conectado que tu {0} es original?",
|
||||||
|
@ -46,7 +46,8 @@
|
|||||||
"address__title_cosigner": "Cosignataire",
|
"address__title_cosigner": "Cosignataire",
|
||||||
"address__title_receive_address": "Adr. de récep.",
|
"address__title_receive_address": "Adr. de récep.",
|
||||||
"address__title_yours": "La vôtre",
|
"address__title_yours": "La vôtre",
|
||||||
"address_details__derivation_path": "Chemin de dérivation :",
|
"address_details__derivation_path": "Chemin de dérivation",
|
||||||
|
"address_details__derivation_path_colon": "Chemin de dérivation :",
|
||||||
"address_details__title_receive_address": "Adr. de récep.",
|
"address_details__title_receive_address": "Adr. de récep.",
|
||||||
"address_details__title_receiving_to": "Récep. sur",
|
"address_details__title_receiving_to": "Récep. sur",
|
||||||
"authenticate__confirm_template": "Autoriser l'ord. connecté à conf. que votre {0} est auth. ?",
|
"authenticate__confirm_template": "Autoriser l'ord. connecté à conf. que votre {0} est auth. ?",
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
"7": "address__title_cosigner",
|
"7": "address__title_cosigner",
|
||||||
"8": "address__title_receive_address",
|
"8": "address__title_receive_address",
|
||||||
"9": "address__title_yours",
|
"9": "address__title_yours",
|
||||||
"10": "address_details__derivation_path",
|
"10": "address_details__derivation_path_colon",
|
||||||
"11": "address_details__title_receive_address",
|
"11": "address_details__title_receive_address",
|
||||||
"12": "address_details__title_receiving_to",
|
"12": "address_details__title_receiving_to",
|
||||||
"13": "authenticate__confirm_template",
|
"13": "authenticate__confirm_template",
|
||||||
@ -860,5 +860,13 @@
|
|||||||
"858": "backup__create_backup_to_prevent_loss",
|
"858": "backup__create_backup_to_prevent_loss",
|
||||||
"859": "reset__check_backup_instructions",
|
"859": "reset__check_backup_instructions",
|
||||||
"860": "words__instructions",
|
"860": "words__instructions",
|
||||||
"861": "words__not_recommended"
|
"861": "words__not_recommended",
|
||||||
|
"862": "address_details__account_info",
|
||||||
|
"863": "address__cancel_contact_support",
|
||||||
|
"864": "address__cancel_receive",
|
||||||
|
"865": "address__qr_code",
|
||||||
|
"866": "address_details__derivation_path",
|
||||||
|
"867": "instructions__continue_in_app",
|
||||||
|
"868": "words__cancel_and_exit",
|
||||||
|
"869": "address__confirmed"
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"current": {
|
"current": {
|
||||||
"merkle_root": "5261bdad43d4e3cda9263ec6ce080218a0d897e02307ca8cafa2525d6a8d3d6b",
|
"merkle_root": "d2a00bb90ebc87448eb0786432129db7c4e67316de7c491bf854d8429d2db9b8",
|
||||||
"datetime": "2024-05-17T10:18:14.246905",
|
"datetime": "2024-05-17T10:29:37.039056",
|
||||||
"commit": "58db509b926fd99b3a36eb3bd550945bf1a139c4"
|
"commit": "b3379e14e0658ab2327bffdfff5227f6079c8f74"
|
||||||
},
|
},
|
||||||
"history": [
|
"history": [
|
||||||
{
|
{
|
||||||
|
@ -434,7 +434,7 @@ class InputFlowShowMultisigXPUBs(InputFlowBase):
|
|||||||
layout = self.debug.swipe_left(wait=True)
|
layout = self.debug.swipe_left(wait=True)
|
||||||
# address details
|
# address details
|
||||||
assert "Multisig 2 of 3" in layout.screen_content()
|
assert "Multisig 2 of 3" in layout.screen_content()
|
||||||
TR.assert_in(layout.screen_content(), "address_details__derivation_path")
|
TR.assert_in(layout.screen_content(), "address_details__derivation_path_colon")
|
||||||
|
|
||||||
# Three xpub pages with the same testing logic
|
# Three xpub pages with the same testing logic
|
||||||
for xpub_num in range(3):
|
for xpub_num in range(3):
|
||||||
@ -508,7 +508,7 @@ class InputFlowShowMultisigXPUBs(InputFlowBase):
|
|||||||
layout = self.debug.swipe_left(wait=True)
|
layout = self.debug.swipe_left(wait=True)
|
||||||
# address details
|
# address details
|
||||||
assert "Multisig 2 of 3" in layout.screen_content()
|
assert "Multisig 2 of 3" in layout.screen_content()
|
||||||
TR.assert_in(layout.screen_content(), "address_details__derivation_path")
|
TR.assert_in(layout.screen_content(), "address_details__derivation_path_colon")
|
||||||
|
|
||||||
# Three xpub pages with the same testing logic
|
# Three xpub pages with the same testing logic
|
||||||
for xpub_num in range(3):
|
for xpub_num in range(3):
|
||||||
|
Loading…
Reference in New Issue
Block a user