From 5aeab554292d8e0aece72df49add368f35ac6e0d Mon Sep 17 00:00:00 2001 From: obrusvit Date: Mon, 28 Oct 2024 10:07:11 +0100 Subject: [PATCH] refactor(core): move selectors to UiFeatures --- core/embed/rust/src/ui/api/firmware_upy.rs | 43 +++++++++++- .../embed/rust/src/ui/model_mercury/layout.rs | 49 -------------- .../src/ui/model_mercury/ui_features_fw.rs | 32 ++++++++- core/embed/rust/src/ui/model_tr/layout.rs | 64 ------------------ .../rust/src/ui/model_tr/ui_features_fw.rs | 47 ++++++++++++- core/embed/rust/src/ui/model_tt/layout.rs | 66 ------------------- .../rust/src/ui/model_tt/ui_features_fw.rs | 52 +++++++++++++-- core/embed/rust/src/ui/ui_features_fw.rs | 14 +++- core/mocks/generated/trezorui2.pyi | 60 ----------------- core/mocks/generated/trezorui_api.pyi | 20 ++++++ .../src/trezor/ui/layouts/mercury/recovery.py | 5 +- core/src/trezor/ui/layouts/mercury/reset.py | 2 +- core/src/trezor/ui/layouts/tr/recovery.py | 2 +- core/src/trezor/ui/layouts/tr/reset.py | 2 +- core/src/trezor/ui/layouts/tt/recovery.py | 2 +- core/src/trezor/ui/layouts/tt/reset.py | 2 +- 16 files changed, 205 insertions(+), 257 deletions(-) diff --git a/core/embed/rust/src/ui/api/firmware_upy.rs b/core/embed/rust/src/ui/api/firmware_upy.rs index 3993b0efc2..11d262f076 100644 --- a/core/embed/rust/src/ui/api/firmware_upy.rs +++ b/core/embed/rust/src/ui/api/firmware_upy.rs @@ -14,7 +14,7 @@ use crate::{ base::LAYOUT_STATE, obj::{LayoutObj, ATTACH_TYPE_OBJ}, result::{CANCELLED, CONFIRMED, INFO}, - util::upy_disable_animation, + util::{upy_disable_animation, RecoveryType}, }, ui_features::ModelUI, ui_features_fw::UIFeaturesFirmware, @@ -118,6 +118,29 @@ extern "C" fn new_request_passphrase(n_args: usize, args: *const Obj, kwargs: *m unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } +extern "C" fn new_select_word(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { + let block = move |_args: &[Obj], kwargs: &Map| { + let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; + let description: TString = kwargs.get(Qstr::MP_QSTR_description)?.try_into()?; + let words_iterable: Obj = kwargs.get(Qstr::MP_QSTR_words)?; + let words: [TString<'static>; 3] = util::iter_into_array(words_iterable)?; + + let layout = ModelUI::select_word(title, description, words)?; + Ok(LayoutObj::new_root(layout)?.into()) + }; + unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } +} + +extern "C" fn new_select_word_count(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { + let block = move |_args: &[Obj], kwargs: &Map| { + let recovery_type: RecoveryType = kwargs.get(Qstr::MP_QSTR_recovery_type)?.try_into()?; + + let layout = ModelUI::select_word_count(recovery_type)?; + Ok(LayoutObj::new_root(layout)?.into()) + }; + unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } +} + extern "C" fn show_info(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { let block = move |_args: &[Obj], kwargs: &Map| { let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; @@ -299,6 +322,24 @@ pub static mp_module_trezorui_api: Module = obj_module! { /// """Passphrase input keyboard.""" Qstr::MP_QSTR_request_passphrase => obj_fn_kw!(0, new_request_passphrase).as_obj(), + /// def select_word( + /// *, + /// title: str, + /// description: str, + /// words: Iterable[str], + /// ) -> LayoutObj[int]: + /// """Select mnemonic word from three possibilities - seed check after backup. The + /// iterable must be of exact size. Returns index in range `0..3`.""" + Qstr::MP_QSTR_select_word => obj_fn_kw!(0, new_select_word).as_obj(), + + /// def select_word_count( + /// *, + /// recovery_type: RecoveryType, + /// ) -> LayoutObj[int | str]: # TR returns str + /// """Select a mnemonic word count from the options: 12, 18, 20, 24, or 33. + /// For unlocking a repeated backup, select from 20 or 33.""" + Qstr::MP_QSTR_select_word_count => obj_fn_kw!(0, new_select_word_count).as_obj(), + /// def show_info( /// *, /// title: str, diff --git a/core/embed/rust/src/ui/model_mercury/layout.rs b/core/embed/rust/src/ui/model_mercury/layout.rs index 46cf1e269c..73408b8e71 100644 --- a/core/embed/rust/src/ui/model_mercury/layout.rs +++ b/core/embed/rust/src/ui/model_mercury/layout.rs @@ -1162,20 +1162,6 @@ extern "C" fn new_request_number(n_args: usize, args: *const Obj, kwargs: *mut M unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } -extern "C" fn new_select_word(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { - let block = move |_args: &[Obj], kwargs: &Map| { - let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; - let description: TString = kwargs.get(Qstr::MP_QSTR_description)?.try_into()?; - let words_iterable: Obj = kwargs.get(Qstr::MP_QSTR_words)?; - let words: [TString; 3] = util::iter_into_array(words_iterable)?; - - let content = VerticalMenu::select_word(words); - let frame_with_menu = Frame::left_aligned(title, content).with_subtitle(description); - Ok(LayoutObj::new(frame_with_menu)?.into()) - }; - unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } -} - extern "C" fn new_show_checklist(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { let block = move |_args: &[Obj], kwargs: &Map| { let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; @@ -1226,23 +1212,6 @@ extern "C" fn new_show_tutorial() -> Obj { unsafe { util::try_or_raise(block) } } -extern "C" fn new_select_word_count(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { - let block = move |_args: &[Obj], kwargs: &Map| { - let recovery_type: RecoveryType = kwargs.get(Qstr::MP_QSTR_recovery_type)?.try_into()?; - let content = if matches!(recovery_type, RecoveryType::UnlockRepeatedBackup) { - SelectWordCount::new_multishare() - } else { - SelectWordCount::new_all() - }; - let obj = LayoutObj::new(Frame::left_aligned( - TR::recovery__num_of_words.into(), - content, - ))?; - Ok(obj.into()) - }; - unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } -} - extern "C" fn new_show_group_share_success( n_args: usize, args: *const Obj, @@ -1617,16 +1586,6 @@ pub static mp_module_trezorui2: Module = obj_module! { /// """Confirm coinjoin authorization.""" Qstr::MP_QSTR_confirm_coinjoin => obj_fn_kw!(0, new_confirm_coinjoin).as_obj(), - /// def select_word( - /// *, - /// title: str, - /// description: str, - /// words: Iterable[str], - /// ) -> LayoutObj[int]: - /// """Select mnemonic word from three possibilities - seed check after backup. The - /// iterable must be of exact size. Returns index in range `0..3`.""" - Qstr::MP_QSTR_select_word => obj_fn_kw!(0, new_select_word).as_obj(), - /// def flow_prompt_backup() -> LayoutObj[UiResult]: /// """Prompt a user to create backup with an option to skip.""" Qstr::MP_QSTR_flow_prompt_backup => obj_fn_0!(new_prompt_backup).as_obj(), @@ -1688,14 +1647,6 @@ pub static mp_module_trezorui2: Module = obj_module! { /// """Device recovery homescreen.""" Qstr::MP_QSTR_flow_continue_recovery => obj_fn_kw!(0, new_continue_recovery).as_obj(), - /// def select_word_count( - /// *, - /// recovery_type: RecoveryType, - /// ) -> LayoutObj[int | str]: # merucry returns int - /// """Select a mnemonic word count from the options: 12, 18, 20, 24, or 33. - /// For unlocking a repeated backup, select from 20 or 33.""" - Qstr::MP_QSTR_select_word_count => obj_fn_kw!(0, new_select_word_count).as_obj(), - /// def show_group_share_success( /// *, /// lines: Iterable[str] diff --git a/core/embed/rust/src/ui/model_mercury/ui_features_fw.rs b/core/embed/rust/src/ui/model_mercury/ui_features_fw.rs index be190a38ea..94cc2f9fff 100644 --- a/core/embed/rust/src/ui/model_mercury/ui_features_fw.rs +++ b/core/embed/rust/src/ui/model_mercury/ui_features_fw.rs @@ -10,14 +10,18 @@ use crate::{ text::paragraphs::{Paragraph, Paragraphs}, }, geometry::Direction, - layout::obj::{LayoutMaybeTrace, LayoutObj, RootComponent}, + layout::{ + obj::{LayoutMaybeTrace, LayoutObj, RootComponent}, + util::RecoveryType, + }, ui_features_fw::UIFeaturesFirmware, }, }; use super::{ component::{ - Bip39Input, Frame, MnemonicKeyboard, PinKeyboard, Slip39Input, SwipeContent, SwipeUpScreen, + Bip39Input, Frame, MnemonicKeyboard, PinKeyboard, SelectWordCount, Slip39Input, + SwipeContent, SwipeUpScreen, VerticalMenu, }, flow, theme, ModelMercuryFeatures, }; @@ -105,6 +109,30 @@ impl UIFeaturesFirmware for ModelMercuryFeatures { Ok(flow) } + fn select_word( + title: TString<'static>, + description: TString<'static>, + words: [TString<'static>; 3], + ) -> Result { + let content = VerticalMenu::select_word(words); + let layout = + RootComponent::new(Frame::left_aligned(title, content).with_subtitle(description)); + Ok(layout) + } + + fn select_word_count(recovery_type: RecoveryType) -> Result { + let content = if matches!(recovery_type, RecoveryType::UnlockRepeatedBackup) { + SelectWordCount::new_multishare() + } else { + SelectWordCount::new_all() + }; + let layout = RootComponent::new(Frame::left_aligned( + TR::recovery__num_of_words.into(), + content, + )); + Ok(layout) + } + fn show_info( title: TString<'static>, description: TString<'static>, diff --git a/core/embed/rust/src/ui/model_tr/layout.rs b/core/embed/rust/src/ui/model_tr/layout.rs index 22ed86459d..88d2b34fc6 100644 --- a/core/embed/rust/src/ui/model_tr/layout.rs +++ b/core/embed/rust/src/ui/model_tr/layout.rs @@ -1197,29 +1197,6 @@ extern "C" fn new_confirm_coinjoin(n_args: usize, args: *const Obj, kwargs: *mut unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } -extern "C" fn new_select_word(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { - let block = |_args: &[Obj], kwargs: &Map| { - // we ignore passed in `title` and use `description` in its place - let description: TString = kwargs.get(Qstr::MP_QSTR_description)?.try_into()?; - let words_iterable: Obj = kwargs.get(Qstr::MP_QSTR_words)?; - // There are only 3 words, but SimpleChoice requires 5 elements - let words: Vec, 5> = util::iter_into_vec(words_iterable)?; - - // Returning the index of the selected word, not the word itself - let obj = LayoutObj::new( - Frame::new( - description, - SimpleChoice::new(words, false) - .with_show_incomplete() - .with_return_index(), - ) - .with_title_centered(), - )?; - Ok(obj.into()) - }; - unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } -} - extern "C" fn new_show_share_words(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { let block = |_args: &[Obj], kwargs: &Map| { let share_words_obj: Obj = kwargs.get(Qstr::MP_QSTR_share_words)?; @@ -1332,29 +1309,6 @@ extern "C" fn new_confirm_recovery(n_args: usize, args: *const Obj, kwargs: *mut unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } -extern "C" fn new_select_word_count(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { - let block = |_args: &[Obj], kwargs: &Map| { - let title: TString = TR::word_count__title.into(); - let recovery_type: RecoveryType = kwargs.get(Qstr::MP_QSTR_recovery_type)?.try_into()?; - - let choices: Vec, 5> = { - let nums: &[&str] = if matches!(recovery_type, RecoveryType::UnlockRepeatedBackup) { - &["20", "33"] - } else { - &["12", "18", "20", "24", "33"] - }; - - nums.iter().map(|&num| num.into()).collect() - }; - - let obj = LayoutObj::new( - Frame::new(title, SimpleChoice::new(choices, false)).with_title_centered(), - )?; - Ok(obj.into()) - }; - unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } -} - extern "C" fn new_show_group_share_success( n_args: usize, args: *const Obj, @@ -1753,16 +1707,6 @@ pub static mp_module_trezorui2: Module = obj_module! { /// """Confirm coinjoin authorization.""" Qstr::MP_QSTR_confirm_coinjoin => obj_fn_kw!(0, new_confirm_coinjoin).as_obj(), - /// def select_word( - /// *, - /// title: str, # unused on TR - /// description: str, - /// words: Iterable[str], - /// ) -> LayoutObj[int]: - /// """Select mnemonic word from three possibilities - seed check after backup. The - /// iterable must be of exact size. Returns index in range `0..3`.""" - Qstr::MP_QSTR_select_word => obj_fn_kw!(0, new_select_word).as_obj(), - /// def show_share_words( /// *, /// share_words: Iterable[str], @@ -1804,14 +1748,6 @@ pub static mp_module_trezorui2: Module = obj_module! { /// """Device recovery homescreen.""" Qstr::MP_QSTR_confirm_recovery => obj_fn_kw!(0, new_confirm_recovery).as_obj(), - /// def select_word_count( - /// *, - /// recovery_type: RecoveryType, - /// ) -> LayoutObj[int | str]: # TR returns str - /// """Select a mnemonic word count from the options: 12, 18, 20, 24, or 33. - /// For unlocking a repeated backup, select from 20 or 33.""" - Qstr::MP_QSTR_select_word_count => obj_fn_kw!(0, new_select_word_count).as_obj(), - /// def show_group_share_success( /// *, /// lines: Iterable[str], diff --git a/core/embed/rust/src/ui/model_tr/ui_features_fw.rs b/core/embed/rust/src/ui/model_tr/ui_features_fw.rs index ff329af7b1..a8cf038d1c 100644 --- a/core/embed/rust/src/ui/model_tr/ui_features_fw.rs +++ b/core/embed/rust/src/ui/model_tr/ui_features_fw.rs @@ -4,24 +4,30 @@ use crate::{ maybe_trace::MaybeTrace, micropython::gc::Gc, strutil::TString, + translations::TR, ui::{ component::{ text::paragraphs::{Paragraph, ParagraphSource, ParagraphVecShort, Paragraphs, VecExt}, Component, ComponentExt, Paginate, Timeout, }, - layout::obj::{LayoutMaybeTrace, LayoutObj, RootComponent}, + layout::{ + obj::{LayoutMaybeTrace, LayoutObj, RootComponent}, + util::RecoveryType, + }, ui_features_fw::UIFeaturesFirmware, }, }; use super::{ component::{ - ButtonDetails, ButtonPage, Frame, PassphraseEntry, PinEntry, ScrollableFrame, + ButtonDetails, ButtonPage, Frame, PassphraseEntry, PinEntry, ScrollableFrame, SimpleChoice, WordlistEntry, WordlistType, }, theme, ModelTRFeatures, }; +use heapless::Vec; + impl UIFeaturesFirmware for ModelTRFeatures { fn confirm_action( title: TString<'static>, @@ -116,6 +122,43 @@ impl UIFeaturesFirmware for ModelTRFeatures { Ok(layout) } + fn select_word( + title: TString<'static>, + description: TString<'static>, + words: [TString<'static>; 3], + ) -> Result { + let words: Vec, 5> = Vec::from_iter(words); + // Returning the index of the selected word, not the word itself + let layout = RootComponent::new( + Frame::new( + description, + SimpleChoice::new(words, false) + .with_show_incomplete() + .with_return_index(), + ) + .with_title_centered(), + ); + Ok(layout) + } + + fn select_word_count(recovery_type: RecoveryType) -> Result { + let title: TString = TR::word_count__title.into(); + let choices: Vec, 5> = { + let nums: &[&str] = if matches!(recovery_type, RecoveryType::UnlockRepeatedBackup) { + &["20", "33"] + } else { + &["12", "18", "20", "24", "33"] + }; + + nums.iter().map(|&num| num.into()).collect() + }; + + let layout = RootComponent::new( + Frame::new(title, SimpleChoice::new(choices, false)).with_title_centered(), + ); + Ok(layout) + } + fn show_info( title: TString<'static>, description: TString<'static>, diff --git a/core/embed/rust/src/ui/model_tt/layout.rs b/core/embed/rust/src/ui/model_tt/layout.rs index bce5b3439e..29aabe66a4 100644 --- a/core/embed/rust/src/ui/model_tt/layout.rs +++ b/core/embed/rust/src/ui/model_tt/layout.rs @@ -1150,24 +1150,6 @@ extern "C" fn new_confirm_coinjoin(n_args: usize, args: *const Obj, kwargs: *mut unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } -extern "C" fn new_select_word(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { - let block = move |_args: &[Obj], kwargs: &Map| { - let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; - let description: TString = kwargs.get(Qstr::MP_QSTR_description)?.try_into()?; - let words_iterable: Obj = kwargs.get(Qstr::MP_QSTR_words)?; - let words: [TString<'static>; 3] = util::iter_into_array(words_iterable)?; - - let paragraphs = Paragraphs::new([Paragraph::new(&theme::TEXT_DEMIBOLD, description)]); - let obj = LayoutObj::new(Frame::left_aligned( - theme::label_title(), - title, - Dialog::new(paragraphs, Button::select_word(words)), - ))?; - Ok(obj.into()) - }; - unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } -} - extern "C" fn new_show_share_words(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { let block = move |_args: &[Obj], kwargs: &Map| { let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; @@ -1319,36 +1301,6 @@ extern "C" fn new_confirm_recovery(n_args: usize, args: *const Obj, kwargs: *mut unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } } -extern "C" fn new_select_word_count(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { - let block = move |_args: &[Obj], kwargs: &Map| { - let recovery_type: RecoveryType = kwargs.get(Qstr::MP_QSTR_recovery_type)?.try_into()?; - let title: TString = match recovery_type { - RecoveryType::DryRun => TR::recovery__title_dry_run.into(), - RecoveryType::UnlockRepeatedBackup => TR::recovery__title_dry_run.into(), - _ => TR::recovery__title.into(), - }; - - let paragraphs = Paragraphs::new(Paragraph::new( - &theme::TEXT_DEMIBOLD, - TR::recovery__num_of_words, - )); - - let content = if matches!(recovery_type, RecoveryType::UnlockRepeatedBackup) { - SelectWordCount::new_multishare() - } else { - SelectWordCount::new_all() - }; - - let obj = LayoutObj::new(Frame::left_aligned( - theme::label_title(), - title, - Dialog::new(paragraphs, content), - ))?; - Ok(obj.into()) - }; - unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } -} - extern "C" fn new_show_group_share_success( n_args: usize, args: *const Obj, @@ -1755,16 +1707,6 @@ pub static mp_module_trezorui2: Module = obj_module! { /// """Confirm coinjoin authorization.""" Qstr::MP_QSTR_confirm_coinjoin => obj_fn_kw!(0, new_confirm_coinjoin).as_obj(), - /// def select_word( - /// *, - /// title: str, - /// description: str, - /// words: Iterable[str], - /// ) -> LayoutObj[int]: - /// """Select mnemonic word from three possibilities - seed check after backup. The - /// iterable must be of exact size. Returns index in range `0..3`.""" - Qstr::MP_QSTR_select_word => obj_fn_kw!(0, new_select_word).as_obj(), - /// def show_share_words( /// *, /// title: str, @@ -1814,14 +1756,6 @@ pub static mp_module_trezorui2: Module = obj_module! { /// """Device recovery homescreen.""" Qstr::MP_QSTR_confirm_recovery => obj_fn_kw!(0, new_confirm_recovery).as_obj(), - /// def select_word_count( - /// *, - /// recovery_type: RecoveryType, - /// ) -> LayoutObj[int | str]: # TT returns int - /// """Select a mnemonic word count from the options: 12, 18, 20, 24, or 33. - /// For unlocking a repeated backup, select from 20 or 33.""" - Qstr::MP_QSTR_select_word_count => obj_fn_kw!(0, new_select_word_count).as_obj(), - /// def show_group_share_success( /// *, /// lines: Iterable[str] diff --git a/core/embed/rust/src/ui/model_tt/ui_features_fw.rs b/core/embed/rust/src/ui/model_tt/ui_features_fw.rs index 3bbc3f5ef3..36760c35e7 100644 --- a/core/embed/rust/src/ui/model_tt/ui_features_fw.rs +++ b/core/embed/rust/src/ui/model_tt/ui_features_fw.rs @@ -7,18 +7,22 @@ use crate::{ ui::{ component::{ image::BlendedImage, - text::paragraphs::{Paragraph, ParagraphSource, ParagraphVecShort, VecExt}, + text::paragraphs::{Paragraph, ParagraphSource, ParagraphVecShort, Paragraphs, VecExt}, ComponentExt, Empty, Timeout, }, - layout::obj::{LayoutMaybeTrace, LayoutObj, RootComponent}, + layout::{ + obj::{LayoutMaybeTrace, LayoutObj, RootComponent}, + util::RecoveryType, + }, ui_features_fw::UIFeaturesFirmware, }, }; use super::{ component::{ - Bip39Input, Button, ButtonMsg, ButtonPage, ButtonStyleSheet, CancelConfirmMsg, Frame, - IconDialog, MnemonicKeyboard, PassphraseKeyboard, PinKeyboard, Slip39Input, + Bip39Input, Button, ButtonMsg, ButtonPage, ButtonStyleSheet, CancelConfirmMsg, Dialog, + Frame, IconDialog, MnemonicKeyboard, PassphraseKeyboard, PinKeyboard, SelectWordCount, + Slip39Input, }, theme, ModelTTFeatures, }; @@ -119,6 +123,46 @@ impl UIFeaturesFirmware for ModelTTFeatures { Ok(layout) } + fn select_word( + title: TString<'static>, + description: TString<'static>, + words: [TString<'static>; 3], + ) -> Result { + let paragraphs = Paragraphs::new([Paragraph::new(&theme::TEXT_DEMIBOLD, description)]); + let layout = RootComponent::new(Frame::left_aligned( + theme::label_title(), + title, + Dialog::new(paragraphs, Button::select_word(words)), + )); + Ok(layout) + } + + fn select_word_count(recovery_type: RecoveryType) -> Result { + let title: TString = match recovery_type { + RecoveryType::DryRun => TR::recovery__title_dry_run.into(), + RecoveryType::UnlockRepeatedBackup => TR::recovery__title_dry_run.into(), + _ => TR::recovery__title.into(), + }; + + let paragraphs = Paragraphs::new(Paragraph::new( + &theme::TEXT_DEMIBOLD, + TR::recovery__num_of_words, + )); + + let content = if matches!(recovery_type, RecoveryType::UnlockRepeatedBackup) { + SelectWordCount::new_multishare() + } else { + SelectWordCount::new_all() + }; + + let layout = RootComponent::new(Frame::left_aligned( + theme::label_title(), + title, + Dialog::new(paragraphs, content), + )); + Ok(layout) + } + fn show_info( title: TString<'static>, description: TString<'static>, diff --git a/core/embed/rust/src/ui/ui_features_fw.rs b/core/embed/rust/src/ui/ui_features_fw.rs index 7679851cd2..a24a3729f1 100644 --- a/core/embed/rust/src/ui/ui_features_fw.rs +++ b/core/embed/rust/src/ui/ui_features_fw.rs @@ -1,7 +1,9 @@ use crate::{error::Error, io::BinaryData, micropython::gc::Gc, strutil::TString}; -use super::layout::obj::{LayoutMaybeTrace, LayoutObj}; - +use super::layout::{ + obj::{LayoutMaybeTrace, LayoutObj}, + util::RecoveryType, +}; pub trait UIFeaturesFirmware { fn confirm_action( @@ -44,6 +46,14 @@ pub trait UIFeaturesFirmware { max_len: u32, ) -> Result; + fn select_word( + title: TString<'static>, + description: TString<'static>, + words: [TString<'static>; 3], + ) -> Result; + + fn select_word_count(recovery_type: RecoveryType) -> Result; + fn show_info( title: TString<'static>, description: TString<'static>, diff --git a/core/mocks/generated/trezorui2.pyi b/core/mocks/generated/trezorui2.pyi index b8f9a955ea..117d5f9295 100644 --- a/core/mocks/generated/trezorui2.pyi +++ b/core/mocks/generated/trezorui2.pyi @@ -242,17 +242,6 @@ def confirm_coinjoin( """Confirm coinjoin authorization.""" -# rust/src/ui/model_mercury/layout.rs -def select_word( - *, - title: str, - description: str, - words: Iterable[str], -) -> LayoutObj[int]: - """Select mnemonic word from three possibilities - seed check after backup. The - iterable must be of exact size. Returns index in range `0..3`.""" - - # rust/src/ui/model_mercury/layout.rs def flow_prompt_backup() -> LayoutObj[UiResult]: """Prompt a user to create backup with an option to skip.""" @@ -320,15 +309,6 @@ def flow_continue_recovery( """Device recovery homescreen.""" -# rust/src/ui/model_mercury/layout.rs -def select_word_count( - *, - recovery_type: RecoveryType, -) -> LayoutObj[int | str]: # merucry returns int - """Select a mnemonic word count from the options: 12, 18, 20, 24, or 33. - For unlocking a repeated backup, select from 20 or 33.""" - - # rust/src/ui/model_mercury/layout.rs def show_group_share_success( *, @@ -728,17 +708,6 @@ def confirm_coinjoin( """Confirm coinjoin authorization.""" -# rust/src/ui/model_tr/layout.rs -def select_word( - *, - title: str, # unused on TR - description: str, - words: Iterable[str], -) -> LayoutObj[int]: - """Select mnemonic word from three possibilities - seed check after backup. The - iterable must be of exact size. Returns index in range `0..3`.""" - - # rust/src/ui/model_tr/layout.rs def show_share_words( *, @@ -784,15 +753,6 @@ def confirm_recovery( """Device recovery homescreen.""" -# rust/src/ui/model_tr/layout.rs -def select_word_count( - *, - recovery_type: RecoveryType, -) -> LayoutObj[int | str]: # TR returns str - """Select a mnemonic word count from the options: 12, 18, 20, 24, or 33. - For unlocking a repeated backup, select from 20 or 33.""" - - # rust/src/ui/model_tr/layout.rs def show_group_share_success( *, @@ -1113,17 +1073,6 @@ def confirm_coinjoin( """Confirm coinjoin authorization.""" -# rust/src/ui/model_tt/layout.rs -def select_word( - *, - title: str, - description: str, - words: Iterable[str], -) -> LayoutObj[int]: - """Select mnemonic word from three possibilities - seed check after backup. The - iterable must be of exact size. Returns index in range `0..3`.""" - - # rust/src/ui/model_tt/layout.rs def show_share_words( *, @@ -1178,15 +1127,6 @@ def confirm_recovery( """Device recovery homescreen.""" -# rust/src/ui/model_tt/layout.rs -def select_word_count( - *, - recovery_type: RecoveryType, -) -> LayoutObj[int | str]: # TT returns int - """Select a mnemonic word count from the options: 12, 18, 20, 24, or 33. - For unlocking a repeated backup, select from 20 or 33.""" - - # rust/src/ui/model_tt/layout.rs def show_group_share_success( *, diff --git a/core/mocks/generated/trezorui_api.pyi b/core/mocks/generated/trezorui_api.pyi index 840673ec93..a0febfc6ba 100644 --- a/core/mocks/generated/trezorui_api.pyi +++ b/core/mocks/generated/trezorui_api.pyi @@ -136,6 +136,26 @@ def request_passphrase( """Passphrase input keyboard.""" +# rust/src/ui/api/firmware_upy.rs +def select_word( + *, + title: str, + description: str, + words: Iterable[str], +) -> LayoutObj[int]: + """Select mnemonic word from three possibilities - seed check after backup. The + iterable must be of exact size. Returns index in range `0..3`.""" + + +# rust/src/ui/api/firmware_upy.rs +def select_word_count( + *, + recovery_type: RecoveryType, +) -> LayoutObj[int | str]: # TR returns str + """Select a mnemonic word count from the options: 12, 18, 20, 24, or 33. + For unlocking a repeated backup, select from 20 or 33.""" + + # rust/src/ui/api/firmware_upy.rs def show_info( *, diff --git a/core/src/trezor/ui/layouts/mercury/recovery.py b/core/src/trezor/ui/layouts/mercury/recovery.py index 71c45d7d1c..fb90b4c248 100644 --- a/core/src/trezor/ui/layouts/mercury/recovery.py +++ b/core/src/trezor/ui/layouts/mercury/recovery.py @@ -17,9 +17,10 @@ if TYPE_CHECKING: async def request_word_count(recovery_type: RecoveryType) -> int: - selector = trezorui2.select_word_count(recovery_type=recovery_type) count = await interact( - selector, "recovery_word_count", ButtonRequestType.MnemonicWordCount + trezorui_api.select_word_count(recovery_type=recovery_type), + "recovery_word_count", + ButtonRequestType.MnemonicWordCount, ) return int(count) diff --git a/core/src/trezor/ui/layouts/mercury/reset.py b/core/src/trezor/ui/layouts/mercury/reset.py index 1e9d853a82..de8ca557ea 100644 --- a/core/src/trezor/ui/layouts/mercury/reset.py +++ b/core/src/trezor/ui/layouts/mercury/reset.py @@ -75,7 +75,7 @@ async def select_word( words.append(words[-1]) result = await interact( - trezorui2.select_word( + trezorui_api.select_word( title=title, description=TR.reset__select_word_x_of_y_template.format( checked_index + 1, count diff --git a/core/src/trezor/ui/layouts/tr/recovery.py b/core/src/trezor/ui/layouts/tr/recovery.py index 1007e7d4b4..bcf6605a6f 100644 --- a/core/src/trezor/ui/layouts/tr/recovery.py +++ b/core/src/trezor/ui/layouts/tr/recovery.py @@ -16,7 +16,7 @@ if TYPE_CHECKING: async def request_word_count(recovery_type: RecoveryType) -> int: count = await interact( - trezorui2.select_word_count(recovery_type=recovery_type), + trezorui_api.select_word_count(recovery_type=recovery_type), "recovery_word_count", ButtonRequestType.MnemonicWordCount, ) diff --git a/core/src/trezor/ui/layouts/tr/reset.py b/core/src/trezor/ui/layouts/tr/reset.py index 787940b817..6b82a7efcc 100644 --- a/core/src/trezor/ui/layouts/tr/reset.py +++ b/core/src/trezor/ui/layouts/tr/reset.py @@ -88,7 +88,7 @@ async def select_word( word_ordinal = format_ordinal(checked_index + 1) result = await interact( - trezorui2.select_word( + trezorui_api.select_word( title="", description=TR.reset__select_word_template.format(word_ordinal), words=(words[0].lower(), words[1].lower(), words[2].lower()), diff --git a/core/src/trezor/ui/layouts/tt/recovery.py b/core/src/trezor/ui/layouts/tt/recovery.py index cf905352ba..2fa89e4f6d 100644 --- a/core/src/trezor/ui/layouts/tt/recovery.py +++ b/core/src/trezor/ui/layouts/tt/recovery.py @@ -17,7 +17,7 @@ if TYPE_CHECKING: async def request_word_count(recovery_type: RecoveryType) -> int: count = await interact( - trezorui2.select_word_count(recovery_type=recovery_type), + trezorui_api.select_word_count(recovery_type=recovery_type), "recovery_word_count", ButtonRequestType.MnemonicWordCount, ) diff --git a/core/src/trezor/ui/layouts/tt/reset.py b/core/src/trezor/ui/layouts/tt/reset.py index 2aa2a7a70a..aedef51eac 100644 --- a/core/src/trezor/ui/layouts/tt/reset.py +++ b/core/src/trezor/ui/layouts/tt/reset.py @@ -84,7 +84,7 @@ async def select_word( words.append(words[-1]) result = await interact( - trezorui2.select_word( + trezorui_api.select_word( title=title, description=TR.reset__select_word_x_of_y_template.format( checked_index + 1, count