mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-01-11 07:50:57 +00:00
feat(core/rust/ui): return Layout results as singleton objects
[no changelog]
This commit is contained in:
parent
4cf917c7cb
commit
38f4ab0983
@ -23,104 +23,6 @@
|
||||
|
||||
#include "librust.h"
|
||||
|
||||
/// def layout_new_confirm_action(
|
||||
/// *,
|
||||
/// title: str,
|
||||
/// action: str | None = None,
|
||||
/// description: str | None = None,
|
||||
/// verb: str | None = None,
|
||||
/// verb_cancel: str | None = None,
|
||||
/// hold: bool | None = None,
|
||||
/// reverse: bool = False,
|
||||
/// ) -> object:
|
||||
/// """Example layout."""
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_trezorui2_layout_new_confirm_action_obj,
|
||||
0, ui_layout_new_confirm_action);
|
||||
|
||||
#if TREZOR_MODEL == T
|
||||
/// def layout_new_example(text: str) -> object:
|
||||
/// """Example layout."""
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorui2_layout_new_example_obj,
|
||||
ui_layout_new_example);
|
||||
|
||||
/// def layout_new_pin(
|
||||
/// *,
|
||||
/// prompt: str,
|
||||
/// subprompt: str,
|
||||
/// allow_cancel: bool,
|
||||
/// warning: str | None,
|
||||
/// ) -> object:
|
||||
/// """PIN keyboard."""
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_trezorui2_layout_new_pin_obj, 0,
|
||||
ui_layout_new_pin);
|
||||
|
||||
/// def layout_new_passphrase(
|
||||
/// *,
|
||||
/// prompt: str,
|
||||
/// max_len: int,
|
||||
/// ) -> object:
|
||||
/// """Passphrase keyboard."""
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_trezorui2_layout_new_passphrase_obj, 0,
|
||||
ui_layout_new_passphrase);
|
||||
|
||||
/// def layout_new_bip39(
|
||||
/// *,
|
||||
/// prompt: str,
|
||||
/// ) -> object:
|
||||
/// """BIP39 keyboard."""
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_trezorui2_layout_new_bip39_obj, 0,
|
||||
ui_layout_new_bip39);
|
||||
|
||||
/// def layout_new_slip39(
|
||||
/// *,
|
||||
/// prompt: str,
|
||||
/// ) -> object:
|
||||
/// """BIP39 keyboard."""
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_trezorui2_layout_new_slip39_obj, 0,
|
||||
ui_layout_new_slip39);
|
||||
#elif TREZOR_MODEL == 1
|
||||
/// def layout_new_confirm_text(
|
||||
/// *,
|
||||
/// title: str,
|
||||
/// data: str,
|
||||
/// description: str | None,
|
||||
/// ) -> object:
|
||||
/// """Example layout."""
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_trezorui2_layout_new_confirm_text_obj, 0,
|
||||
ui_layout_new_confirm_text);
|
||||
#endif
|
||||
|
||||
STATIC const mp_rom_map_elem_t mp_module_trezorui2_globals_table[] = {
|
||||
{MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_trezorui2)},
|
||||
|
||||
{MP_ROM_QSTR(MP_QSTR_layout_new_confirm_action),
|
||||
MP_ROM_PTR(&mod_trezorui2_layout_new_confirm_action_obj)},
|
||||
#if TREZOR_MODEL == T
|
||||
{MP_ROM_QSTR(MP_QSTR_layout_new_example),
|
||||
MP_ROM_PTR(&mod_trezorui2_layout_new_example_obj)},
|
||||
{MP_ROM_QSTR(MP_QSTR_layout_new_pin),
|
||||
MP_ROM_PTR(&mod_trezorui2_layout_new_pin_obj)},
|
||||
{MP_ROM_QSTR(MP_QSTR_layout_new_passphrase),
|
||||
MP_ROM_PTR(&mod_trezorui2_layout_new_passphrase_obj)},
|
||||
{MP_ROM_QSTR(MP_QSTR_layout_new_bip39),
|
||||
MP_ROM_PTR(&mod_trezorui2_layout_new_bip39_obj)},
|
||||
{MP_ROM_QSTR(MP_QSTR_layout_new_slip39),
|
||||
MP_ROM_PTR(&mod_trezorui2_layout_new_slip39_obj)},
|
||||
#elif TREZOR_MODEL == 1
|
||||
{MP_ROM_QSTR(MP_QSTR_layout_new_confirm_text),
|
||||
MP_ROM_PTR(&mod_trezorui2_layout_new_confirm_text_obj)},
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_trezorui2_globals,
|
||||
mp_module_trezorui2_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_trezorui2 = {
|
||||
.base = {&mp_type_module},
|
||||
.globals = (mp_obj_dict_t *)&mp_module_trezorui2_globals,
|
||||
};
|
||||
|
||||
MP_REGISTER_MODULE(MP_QSTR_trezorui2, mp_module_trezorui2,
|
||||
MICROPY_PY_TREZORUI2);
|
||||
|
||||
|
@ -60,6 +60,7 @@ fn generate_micropython_bindings() {
|
||||
.allowlist_function("mp_obj_new_int_from_uint")
|
||||
.allowlist_function("mp_obj_new_bytes")
|
||||
.allowlist_function("mp_obj_new_str")
|
||||
.allowlist_function("mp_obj_new_tuple")
|
||||
.allowlist_function("mp_obj_get_int_maybe")
|
||||
.allowlist_function("mp_obj_is_true")
|
||||
.allowlist_function("mp_call_function_n_kw")
|
||||
|
@ -12,19 +12,7 @@ mp_obj_t protobuf_debug_msg_type();
|
||||
mp_obj_t protobuf_debug_msg_def_type();
|
||||
#endif
|
||||
|
||||
mp_obj_t ui_layout_new_example(mp_obj_t);
|
||||
mp_obj_t ui_layout_new_confirm_action(size_t n_args, const mp_obj_t *args,
|
||||
mp_map_t *kwargs);
|
||||
mp_obj_t ui_layout_new_confirm_text(size_t n_args, const mp_obj_t *args,
|
||||
mp_map_t *kwargs);
|
||||
mp_obj_t ui_layout_new_pin(size_t n_args, const mp_obj_t *args,
|
||||
mp_map_t *kwargs);
|
||||
mp_obj_t ui_layout_new_passphrase(size_t n_args, const mp_obj_t *args,
|
||||
mp_map_t *kwargs);
|
||||
mp_obj_t ui_layout_new_bip39(size_t n_args, const mp_obj_t *args,
|
||||
mp_map_t *kwargs);
|
||||
mp_obj_t ui_layout_new_slip39(size_t n_args, const mp_obj_t *args,
|
||||
mp_map_t *kwargs);
|
||||
extern mp_obj_module_t mp_module_trezorui2;
|
||||
|
||||
#ifdef TREZOR_EMULATOR
|
||||
mp_obj_t ui_debug_layout_type();
|
||||
|
@ -10,7 +10,18 @@ static void _librust_qstrs(void) {
|
||||
MP_QSTR_MESSAGE_NAME;
|
||||
|
||||
// layout
|
||||
MP_QSTR___name__;
|
||||
MP_QSTR_trezorui2;
|
||||
MP_QSTR_Layout;
|
||||
MP_QSTR_CONFIRMED;
|
||||
MP_QSTR_CANCELLED;
|
||||
MP_QSTR_confirm_action;
|
||||
MP_QSTR_confirm_text;
|
||||
MP_QSTR_request_pin;
|
||||
MP_QSTR_request_passphrase;
|
||||
MP_QSTR_request_bip39;
|
||||
MP_QSTR_request_slip39;
|
||||
|
||||
MP_QSTR_set_timer_fn;
|
||||
MP_QSTR_touch_event;
|
||||
MP_QSTR_button_event;
|
||||
|
@ -175,6 +175,7 @@ macro_rules! obj_type {
|
||||
macro_rules! obj_module {
|
||||
($($key:expr => $val:expr),*) => ({
|
||||
#[allow(unused_unsafe)]
|
||||
#[allow(unused_doc_comments)]
|
||||
unsafe {
|
||||
use $crate::micropython::ffi;
|
||||
|
||||
|
@ -289,6 +289,23 @@ impl TryFrom<&'static CStr> for Obj {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<(Obj, Obj)> for Obj {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(val: (Obj, Obj)) -> Result<Self, Self::Error> {
|
||||
// SAFETY:
|
||||
// - Should work with any micropython objects.
|
||||
// EXCEPTION: Will raise if allocation fails.
|
||||
let values = [val.0, val.1];
|
||||
let obj = catch_exception(|| unsafe { ffi::mp_obj_new_tuple(2, values.as_ptr()) })?;
|
||||
if obj.is_null() {
|
||||
Err(Error::AllocationFailed)
|
||||
} else {
|
||||
Ok(obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// # Additional conversions based on the methods above.
|
||||
//
|
||||
|
@ -447,7 +447,7 @@ impl Grid {
|
||||
}
|
||||
|
||||
pub fn cells(&self, cells: GridCellSpan) -> Rect {
|
||||
let from = self.row_col(cells.from.0, cells.to.1);
|
||||
let from = self.row_col(cells.from.0, cells.from.1);
|
||||
let to = self.row_col(cells.to.0, cells.to.1);
|
||||
from.union(to)
|
||||
}
|
||||
|
@ -1 +1,2 @@
|
||||
pub mod obj;
|
||||
pub mod result;
|
||||
|
@ -14,7 +14,7 @@ use crate::{
|
||||
},
|
||||
time::Duration,
|
||||
ui::{
|
||||
component::{Child, Component, Event, EventCtx, Never, PageMsg, TimerToken},
|
||||
component::{Child, Component, Event, EventCtx, Never, TimerToken},
|
||||
geometry::Rect,
|
||||
},
|
||||
util,
|
||||
@ -38,13 +38,12 @@ pub trait ComponentMsgObj: Component {
|
||||
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error>;
|
||||
}
|
||||
|
||||
impl<T> ComponentMsgObj for T
|
||||
impl<T> ComponentMsgObj for Child<T>
|
||||
where
|
||||
T: Component,
|
||||
T::Msg: TryInto<Obj, Error = Error>,
|
||||
T: ComponentMsgObj,
|
||||
{
|
||||
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
|
||||
msg.try_into()
|
||||
self.inner().msg_try_into_obj(msg)
|
||||
}
|
||||
}
|
||||
|
||||
@ -333,17 +332,6 @@ impl TryFrom<Duration> for Obj {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TryFrom<PageMsg<T, bool>> for Obj {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(val: PageMsg<T, bool>) -> Result<Self, Self::Error> {
|
||||
match val {
|
||||
PageMsg::Content(_) => Err(Error::TypeError),
|
||||
PageMsg::Controls(c) => Ok(c.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Never> for Obj {
|
||||
fn from(_: Never) -> Self {
|
||||
unreachable!()
|
||||
|
34
core/embed/rust/src/ui/layout/result.rs
Normal file
34
core/embed/rust/src/ui/layout/result.rs
Normal file
@ -0,0 +1,34 @@
|
||||
use crate::micropython::{
|
||||
obj::{Obj, ObjBase},
|
||||
qstr::Qstr,
|
||||
typ::Type,
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ResultObj {
|
||||
base: ObjBase,
|
||||
}
|
||||
|
||||
impl ResultObj {
|
||||
/// Convert ResultObj to a MicroPython object.
|
||||
pub const fn as_obj(&'static self) -> Obj {
|
||||
// SAFETY:
|
||||
// - We are an object struct with a base and a type.
|
||||
// - 'static lifetime holds us in place.
|
||||
// - There's nothing to mutate.
|
||||
unsafe { Obj::from_ptr(self as *const _ as *mut _) }
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY: We are in a single-threaded environment.
|
||||
unsafe impl Sync for ResultObj {}
|
||||
|
||||
static CONFIRMED_TYPE: Type = obj_type! { name: Qstr::MP_QSTR_CONFIRMED, };
|
||||
static CANCELLED_TYPE: Type = obj_type! { name: Qstr::MP_QSTR_CANCELLED, };
|
||||
|
||||
pub static CONFIRMED: ResultObj = ResultObj {
|
||||
base: CONFIRMED_TYPE.as_base(),
|
||||
};
|
||||
pub static CANCELLED: ResultObj = ResultObj {
|
||||
base: CANCELLED_TYPE.as_base(),
|
||||
};
|
@ -31,6 +31,10 @@ where
|
||||
right_btn: right.map(Child::new),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inner(&self) -> &T {
|
||||
self.content.inner()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> Component for Dialog<T, U>
|
||||
|
@ -23,6 +23,10 @@ where
|
||||
content: Child::new(content),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inner(&self) -> &T {
|
||||
self.content.inner()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> Component for Frame<T, U>
|
||||
|
@ -1,26 +1,52 @@
|
||||
use core::convert::TryInto;
|
||||
|
||||
use crate::{
|
||||
micropython::{buffer::Buffer, map::Map, obj::Obj, qstr::Qstr},
|
||||
error::Error,
|
||||
micropython::{buffer::Buffer, map::Map, module::Module, obj::Obj, qstr::Qstr},
|
||||
ui::{
|
||||
component::{text::paragraphs::Paragraphs, FormattedText},
|
||||
layout::obj::LayoutObj,
|
||||
model_t1::component::ButtonPos,
|
||||
component::{
|
||||
base::Component,
|
||||
paginated::{PageMsg, Paginate},
|
||||
text::paragraphs::Paragraphs,
|
||||
FormattedText,
|
||||
},
|
||||
layout::{
|
||||
obj::{ComponentMsgObj, LayoutObj},
|
||||
result::{CANCELLED, CONFIRMED},
|
||||
},
|
||||
},
|
||||
util,
|
||||
};
|
||||
|
||||
use super::{
|
||||
component::{Button, ButtonPage, Dialog, DialogMsg, Frame},
|
||||
constant, theme,
|
||||
component::{Button, ButtonPage, ButtonPos, Frame},
|
||||
theme,
|
||||
};
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn ui_layout_new_confirm_action(
|
||||
n_args: usize,
|
||||
args: *const Obj,
|
||||
kwargs: *const Map,
|
||||
) -> Obj {
|
||||
impl<T> ComponentMsgObj for ButtonPage<T>
|
||||
where
|
||||
T: Component + Paginate,
|
||||
{
|
||||
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
|
||||
match msg {
|
||||
PageMsg::Content(_) => Err(Error::TypeError),
|
||||
PageMsg::Controls(true) => Ok(CONFIRMED.as_obj()),
|
||||
PageMsg::Controls(false) => Ok(CANCELLED.as_obj()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> ComponentMsgObj for Frame<T, U>
|
||||
where
|
||||
T: ComponentMsgObj,
|
||||
U: AsRef<[u8]>,
|
||||
{
|
||||
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
|
||||
self.inner().msg_try_into_obj(msg)
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn new_confirm_action(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = |_args: &[Obj], kwargs: &Map| {
|
||||
let title: Buffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||
let action: Option<Buffer> = kwargs.get(Qstr::MP_QSTR_action)?.try_into_option()?;
|
||||
@ -39,9 +65,9 @@ extern "C" fn ui_layout_new_confirm_action(
|
||||
_ => "",
|
||||
};
|
||||
|
||||
let left = verb_cancel
|
||||
let _left = verb_cancel
|
||||
.map(|label| Button::with_text(ButtonPos::Left, label, theme::button_cancel()));
|
||||
let right =
|
||||
let _right =
|
||||
verb.map(|label| Button::with_text(ButtonPos::Right, label, theme::button_default()));
|
||||
|
||||
let obj = LayoutObj::new(Frame::new(
|
||||
@ -58,12 +84,7 @@ extern "C" fn ui_layout_new_confirm_action(
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn ui_layout_new_confirm_text(
|
||||
n_args: usize,
|
||||
args: *const Obj,
|
||||
kwargs: *const Map,
|
||||
) -> Obj {
|
||||
extern "C" fn new_confirm_text(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = |_args: &[Obj], kwargs: &Map| {
|
||||
let title: Buffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||
let data: Buffer = kwargs.get(Qstr::MP_QSTR_data)?.try_into()?;
|
||||
@ -87,15 +108,49 @@ extern "C" fn ui_layout_new_confirm_text(
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub static mp_module_trezorui2: Module = obj_module! {
|
||||
Qstr::MP_QSTR___name__ => Qstr::MP_QSTR_trezorui2.to_obj(),
|
||||
|
||||
/// CONFIRMED: object
|
||||
Qstr::MP_QSTR_CONFIRMED => CONFIRMED.as_obj(),
|
||||
|
||||
/// CANCELLED: object
|
||||
Qstr::MP_QSTR_CANCELLED => CANCELLED.as_obj(),
|
||||
|
||||
/// def confirm_action(
|
||||
/// *,
|
||||
/// title: str,
|
||||
/// action: str | None = None,
|
||||
/// description: str | None = None,
|
||||
/// verb: str | None = None,
|
||||
/// verb_cancel: str | None = None,
|
||||
/// hold: bool | None = None,
|
||||
/// reverse: bool = False,
|
||||
/// ) -> object:
|
||||
/// """Confirm action."""
|
||||
Qstr::MP_QSTR_confirm_action => obj_fn_kw!(0, new_confirm_action).as_obj(),
|
||||
|
||||
/// def confirm_text(
|
||||
/// *,
|
||||
/// title: str,
|
||||
/// data: str,
|
||||
/// description: str | None,
|
||||
/// ) -> object:
|
||||
/// """Confirm text."""
|
||||
Qstr::MP_QSTR_confirm_text => obj_fn_kw!(0, new_confirm_text).as_obj(),
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
error::Error,
|
||||
trace::Trace,
|
||||
ui::{
|
||||
component::Component,
|
||||
display,
|
||||
model_t1::component::{Dialog, DialogMsg},
|
||||
model_t1::{
|
||||
component::{Dialog, DialogMsg},
|
||||
constant,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -107,18 +162,16 @@ mod tests {
|
||||
String::from_utf8(t).unwrap()
|
||||
}
|
||||
|
||||
impl<T> TryFrom<DialogMsg<T>> for Obj
|
||||
impl<T, U> ComponentMsgObj for Dialog<T, U>
|
||||
where
|
||||
Obj: TryFrom<T>,
|
||||
Error: From<<T as TryInto<Obj>>::Error>,
|
||||
T: ComponentMsgObj,
|
||||
U: AsRef<[u8]>,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(val: DialogMsg<T>) -> Result<Self, Self::Error> {
|
||||
match val {
|
||||
DialogMsg::Content(c) => Ok(c.try_into()?),
|
||||
DialogMsg::LeftClicked => 1.try_into(),
|
||||
DialogMsg::RightClicked => 2.try_into(),
|
||||
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
|
||||
match msg {
|
||||
DialogMsg::Content(c) => self.inner().msg_try_into_obj(c),
|
||||
DialogMsg::LeftClicked => Ok(CANCELLED.as_obj()),
|
||||
DialogMsg::RightClicked => Ok(CONFIRMED.as_obj()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,8 @@ use super::{theme, Button, ButtonMsg, Loader, LoaderMsg};
|
||||
|
||||
pub enum HoldToConfirmMsg<T> {
|
||||
Content(T),
|
||||
Cancelled,
|
||||
Confirmed,
|
||||
Cancelled,
|
||||
}
|
||||
|
||||
pub struct HoldToConfirm<T> {
|
||||
@ -36,6 +36,10 @@ where
|
||||
pad: Pad::with_background(theme::BG),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inner(&self) -> &T {
|
||||
self.content.inner()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Component for HoldToConfirm<T>
|
||||
|
@ -10,9 +10,9 @@ pub enum DialogMsg<T, L, R> {
|
||||
}
|
||||
|
||||
pub struct Dialog<T, L, R> {
|
||||
pub content: Child<T>,
|
||||
pub left: Child<L>,
|
||||
pub right: Child<R>,
|
||||
content: Child<T>,
|
||||
left: Child<L>,
|
||||
right: Child<R>,
|
||||
}
|
||||
|
||||
impl<T, L, R> Dialog<T, L, R>
|
||||
@ -28,6 +28,10 @@ where
|
||||
right: Child::new(right),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inner(&self) -> &T {
|
||||
self.content.inner()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, L, R> Component for Dialog<T, L, R>
|
||||
|
@ -23,6 +23,10 @@ where
|
||||
content: Child::new(content),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inner(&self) -> &T {
|
||||
&self.content.inner()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> Component for Frame<T, U>
|
||||
|
@ -64,6 +64,10 @@ impl MnemonicInput for Bip39Input {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.textbox.is_empty()
|
||||
}
|
||||
|
||||
fn mnemonic(&self) -> Option<&'static str> {
|
||||
self.suggested_word
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Bip39Input {
|
||||
|
@ -1,3 +1,5 @@
|
||||
use core::ops::Deref;
|
||||
|
||||
use crate::ui::{
|
||||
component::{Child, Component, Event, EventCtx, Label, Maybe},
|
||||
geometry::{Alignment, Grid, Rect},
|
||||
@ -13,9 +15,9 @@ pub enum MnemonicKeyboardMsg {
|
||||
Confirmed,
|
||||
}
|
||||
|
||||
pub struct MnemonicKeyboard<T> {
|
||||
pub struct MnemonicKeyboard<T, U> {
|
||||
/// Initial prompt, displayed on empty input.
|
||||
prompt: Child<Maybe<Label<&'static [u8]>>>,
|
||||
prompt: Child<Maybe<Label<U>>>,
|
||||
/// Backspace button.
|
||||
back: Child<Maybe<Button<&'static [u8]>>>,
|
||||
/// Input area, acting as the auto-complete and confirm button.
|
||||
@ -24,11 +26,12 @@ pub struct MnemonicKeyboard<T> {
|
||||
keys: [Child<Button<&'static [u8]>>; MNEMONIC_KEY_COUNT],
|
||||
}
|
||||
|
||||
impl<T> MnemonicKeyboard<T>
|
||||
impl<T, U> MnemonicKeyboard<T, U>
|
||||
where
|
||||
T: MnemonicInput,
|
||||
U: Deref<Target = [u8]>,
|
||||
{
|
||||
pub fn new(input: T, prompt: &'static [u8]) -> Self {
|
||||
pub fn new(input: T, prompt: U) -> Self {
|
||||
Self {
|
||||
prompt: Child::new(Maybe::visible(
|
||||
theme::BG,
|
||||
@ -75,11 +78,16 @@ where
|
||||
self.back
|
||||
.mutate(ctx, |ctx, b| b.show_if(ctx, !prompt_visible));
|
||||
}
|
||||
|
||||
pub fn mnemonic(&self) -> Option<&'static str> {
|
||||
self.input.inner().inner().mnemonic()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Component for MnemonicKeyboard<T>
|
||||
impl<T, U> Component for MnemonicKeyboard<T, U>
|
||||
where
|
||||
T: MnemonicInput,
|
||||
U: Deref<Target = [u8]>,
|
||||
{
|
||||
type Msg = MnemonicKeyboardMsg;
|
||||
|
||||
@ -158,6 +166,7 @@ pub trait MnemonicInput: Component<Msg = MnemonicInputMsg> {
|
||||
fn on_key_click(&mut self, ctx: &mut EventCtx, key: usize);
|
||||
fn on_backspace_click(&mut self, ctx: &mut EventCtx);
|
||||
fn is_empty(&self) -> bool;
|
||||
fn mnemonic(&self) -> Option<&'static str>;
|
||||
}
|
||||
|
||||
pub enum MnemonicInputMsg {
|
||||
@ -167,7 +176,7 @@ pub enum MnemonicInputMsg {
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl<T> crate::trace::Trace for MnemonicKeyboard<T> {
|
||||
impl<T, U> crate::trace::Trace for MnemonicKeyboard<T, U> {
|
||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||
t.open("MnemonicKeyboard");
|
||||
t.close();
|
||||
|
@ -100,6 +100,10 @@ impl PassphraseKeyboard {
|
||||
self.back.mutate(ctx, |ctx, b| b.enable(ctx));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn passphrase(&self) -> &str {
|
||||
self.input.inner().textbox.content()
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for PassphraseKeyboard {
|
||||
|
@ -81,6 +81,10 @@ impl MnemonicInput for Slip39Input {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.textbox.is_empty()
|
||||
}
|
||||
|
||||
fn mnemonic(&self) -> Option<&'static str> {
|
||||
self.final_word
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Slip39Input {
|
||||
|
@ -14,7 +14,7 @@ pub use dialog::{Dialog, DialogLayout, DialogMsg};
|
||||
pub use frame::Frame;
|
||||
pub use keyboard::{
|
||||
bip39::Bip39Input,
|
||||
mnemonic::{MnemonicKeyboard, MnemonicKeyboardMsg},
|
||||
mnemonic::{MnemonicInput, MnemonicKeyboard, MnemonicKeyboardMsg},
|
||||
passphrase::{PassphraseKeyboard, PassphraseKeyboardMsg},
|
||||
pin::{PinKeyboard, PinKeyboardMsg},
|
||||
slip39::Slip39Input,
|
||||
|
@ -1,109 +1,124 @@
|
||||
use core::convert::{TryFrom, TryInto};
|
||||
use core::{convert::TryInto, ops::Deref};
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
micropython::{buffer::Buffer, map::Map, obj::Obj, qstr::Qstr},
|
||||
micropython::{buffer::Buffer, map::Map, module::Module, obj::Obj, qstr::Qstr},
|
||||
ui::{
|
||||
component::{base::ComponentExt, text::paragraphs::Paragraphs, FormattedText},
|
||||
layout::obj::LayoutObj,
|
||||
component::{
|
||||
base::ComponentExt,
|
||||
paginated::{PageMsg, Paginate},
|
||||
text::paragraphs::Paragraphs,
|
||||
Component,
|
||||
},
|
||||
layout::{
|
||||
obj::{ComponentMsgObj, LayoutObj},
|
||||
result::{CANCELLED, CONFIRMED},
|
||||
},
|
||||
},
|
||||
util,
|
||||
};
|
||||
|
||||
use super::{
|
||||
component::{
|
||||
Bip39Input, Button, ButtonMsg, DialogMsg, Frame, HoldToConfirm, HoldToConfirmMsg,
|
||||
MnemonicKeyboard, MnemonicKeyboardMsg, PassphraseKeyboard, PassphraseKeyboardMsg,
|
||||
PinKeyboard, PinKeyboardMsg, Slip39Input, SwipePage,
|
||||
Bip39Input, Button, ButtonMsg, Dialog, DialogMsg, Frame, HoldToConfirm, HoldToConfirmMsg,
|
||||
MnemonicInput, MnemonicKeyboard, MnemonicKeyboardMsg, PassphraseKeyboard,
|
||||
PassphraseKeyboardMsg, PinKeyboard, PinKeyboardMsg, Slip39Input, SwipePage,
|
||||
},
|
||||
theme,
|
||||
};
|
||||
|
||||
impl<T> TryFrom<DialogMsg<T, ButtonMsg, ButtonMsg>> for Obj
|
||||
impl<T, U> ComponentMsgObj for Dialog<T, Button<U>, Button<U>>
|
||||
where
|
||||
Obj: TryFrom<T>,
|
||||
Error: From<<Obj as TryFrom<T>>::Error>,
|
||||
T: ComponentMsgObj,
|
||||
U: AsRef<[u8]>,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(val: DialogMsg<T, ButtonMsg, ButtonMsg>) -> Result<Self, Self::Error> {
|
||||
match val {
|
||||
DialogMsg::Content(c) => Ok(c.try_into()?),
|
||||
DialogMsg::Left(ButtonMsg::Clicked) => 1.try_into(),
|
||||
DialogMsg::Right(ButtonMsg::Clicked) => 2.try_into(),
|
||||
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
|
||||
match msg {
|
||||
DialogMsg::Content(c) => Ok(self.inner().msg_try_into_obj(c)?),
|
||||
DialogMsg::Left(ButtonMsg::Clicked) => Ok(CANCELLED.as_obj()),
|
||||
DialogMsg::Right(ButtonMsg::Clicked) => Ok(CONFIRMED.as_obj()),
|
||||
_ => Ok(Obj::const_none()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TryFrom<HoldToConfirmMsg<T>> for Obj
|
||||
impl<T> ComponentMsgObj for HoldToConfirm<T>
|
||||
where
|
||||
Obj: TryFrom<T>,
|
||||
Error: From<<Obj as TryFrom<T>>::Error>,
|
||||
T: ComponentMsgObj,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(val: HoldToConfirmMsg<T>) -> Result<Self, Self::Error> {
|
||||
match val {
|
||||
HoldToConfirmMsg::Content(c) => Ok(c.try_into()?),
|
||||
HoldToConfirmMsg::Confirmed => 1.try_into(),
|
||||
HoldToConfirmMsg::Cancelled => 2.try_into(),
|
||||
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
|
||||
match msg {
|
||||
HoldToConfirmMsg::Content(c) => Ok(self.inner().msg_try_into_obj(c)?),
|
||||
HoldToConfirmMsg::Confirmed => Ok(CONFIRMED.as_obj()),
|
||||
HoldToConfirmMsg::Cancelled => Ok(CANCELLED.as_obj()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<PinKeyboardMsg> for Obj {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(val: PinKeyboardMsg) -> Result<Self, Self::Error> {
|
||||
match val {
|
||||
PinKeyboardMsg::Confirmed => 1.try_into(),
|
||||
PinKeyboardMsg::Cancelled => 2.try_into(),
|
||||
impl<T> ComponentMsgObj for PinKeyboard<T>
|
||||
where
|
||||
T: Deref<Target = [u8]>,
|
||||
{
|
||||
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
|
||||
match msg {
|
||||
PinKeyboardMsg::Confirmed => self.pin().try_into(),
|
||||
PinKeyboardMsg::Cancelled => Ok(CANCELLED.as_obj()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<MnemonicKeyboardMsg> for Obj {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(val: MnemonicKeyboardMsg) -> Result<Self, Self::Error> {
|
||||
match val {
|
||||
MnemonicKeyboardMsg::Confirmed => Ok(Obj::const_true()),
|
||||
impl ComponentMsgObj for PassphraseKeyboard {
|
||||
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
|
||||
match msg {
|
||||
PassphraseKeyboardMsg::Confirmed => self.passphrase().try_into(),
|
||||
PassphraseKeyboardMsg::Cancelled => Ok(CANCELLED.as_obj()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<PassphraseKeyboardMsg> for Obj {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(val: PassphraseKeyboardMsg) -> Result<Self, Self::Error> {
|
||||
match val {
|
||||
PassphraseKeyboardMsg::Confirmed => Ok(Obj::const_true()),
|
||||
PassphraseKeyboardMsg::Cancelled => Ok(Obj::const_none()),
|
||||
impl<T, U> ComponentMsgObj for MnemonicKeyboard<T, U>
|
||||
where
|
||||
T: MnemonicInput,
|
||||
U: Deref<Target = [u8]>,
|
||||
{
|
||||
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
|
||||
match msg {
|
||||
MnemonicKeyboardMsg::Confirmed => {
|
||||
if let Some(word) = self.mnemonic() {
|
||||
word.try_into()
|
||||
} else {
|
||||
panic!("invalid mnemonic")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn ui_layout_new_example(_param: Obj) -> Obj {
|
||||
let block = move || {
|
||||
let layout = LayoutObj::new(HoldToConfirm::new(
|
||||
FormattedText::new::<theme::TTDefaultText>(
|
||||
"Testing text layout, with some text, and some more text. And {param}",
|
||||
)
|
||||
.with(b"param", b"parameters!"),
|
||||
))?;
|
||||
Ok(layout.into())
|
||||
};
|
||||
unsafe { util::try_or_raise(block) }
|
||||
impl<T, U> ComponentMsgObj for Frame<T, U>
|
||||
where
|
||||
T: ComponentMsgObj,
|
||||
U: AsRef<[u8]>,
|
||||
{
|
||||
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
|
||||
self.inner().msg_try_into_obj(msg)
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn ui_layout_new_confirm_action(
|
||||
n_args: usize,
|
||||
args: *const Obj,
|
||||
kwargs: *const Map,
|
||||
) -> Obj {
|
||||
impl<T, U> ComponentMsgObj for SwipePage<T, U>
|
||||
where
|
||||
T: Component + Paginate,
|
||||
U: Component<Msg = bool>,
|
||||
{
|
||||
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
|
||||
match msg {
|
||||
PageMsg::Content(_) => Err(Error::TypeError),
|
||||
PageMsg::Controls(true) => Ok(CONFIRMED.as_obj()),
|
||||
PageMsg::Controls(false) => Ok(CANCELLED.as_obj()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn new_confirm_action(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||
let title: Buffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
|
||||
let action: Option<Buffer> = kwargs.get(Qstr::MP_QSTR_action)?.try_into_option()?;
|
||||
@ -144,8 +159,7 @@ extern "C" fn ui_layout_new_confirm_action(
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn ui_layout_new_pin(n_args: usize, args: *const Obj, kwargs: *const Map) -> Obj {
|
||||
extern "C" fn new_request_pin(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||
let prompt: Buffer = kwargs.get(Qstr::MP_QSTR_prompt)?.try_into()?;
|
||||
let subprompt: Buffer = kwargs.get(Qstr::MP_QSTR_subprompt)?.try_into()?;
|
||||
@ -160,8 +174,7 @@ extern "C" fn ui_layout_new_pin(n_args: usize, args: *const Obj, kwargs: *const
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn ui_layout_new_passphrase(n_args: usize, args: *const Obj, kwargs: *const Map) -> Obj {
|
||||
extern "C" fn new_request_passphrase(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||
let _prompt: Buffer = kwargs.get(Qstr::MP_QSTR_prompt)?.try_into()?;
|
||||
let _max_len: u32 = kwargs.get(Qstr::MP_QSTR_max_len)?.try_into()?;
|
||||
@ -171,41 +184,88 @@ extern "C" fn ui_layout_new_passphrase(n_args: usize, args: *const Obj, kwargs:
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn ui_layout_new_bip39(n_args: usize, args: *const Obj, kwargs: *const Map) -> Obj {
|
||||
extern "C" fn new_request_bip39(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||
let _prompt: Buffer = kwargs.get(Qstr::MP_QSTR_prompt)?.try_into()?;
|
||||
let obj = LayoutObj::new(
|
||||
MnemonicKeyboard::new(Bip39Input::new(), b"Type word 11 of 12").into_child(),
|
||||
)?;
|
||||
let prompt: Buffer = kwargs.get(Qstr::MP_QSTR_prompt)?.try_into()?;
|
||||
let obj = LayoutObj::new(MnemonicKeyboard::new(Bip39Input::new(), prompt).into_child())?;
|
||||
Ok(obj.into())
|
||||
};
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
|
||||
extern "C" fn new_request_slip39(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||
let prompt: Buffer = kwargs.get(Qstr::MP_QSTR_prompt)?.try_into()?;
|
||||
let obj = LayoutObj::new(MnemonicKeyboard::new(Slip39Input::new(), prompt).into_child())?;
|
||||
Ok(obj.into())
|
||||
};
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn ui_layout_new_slip39(n_args: usize, args: *const Obj, kwargs: *const Map) -> Obj {
|
||||
let block = move |_args: &[Obj], kwargs: &Map| {
|
||||
let _prompt: Buffer = kwargs.get(Qstr::MP_QSTR_prompt)?.try_into()?;
|
||||
let obj = LayoutObj::new(
|
||||
MnemonicKeyboard::new(Slip39Input::new(), b"Type word 13 of 20").into_child(),
|
||||
)?;
|
||||
Ok(obj.into())
|
||||
};
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
}
|
||||
pub static mp_module_trezorui2: Module = obj_module! {
|
||||
Qstr::MP_QSTR___name__ => Qstr::MP_QSTR_trezorui2.to_obj(),
|
||||
|
||||
/// CONFIRMED: object
|
||||
Qstr::MP_QSTR_CONFIRMED => CONFIRMED.as_obj(),
|
||||
|
||||
/// CANCELLED: object
|
||||
Qstr::MP_QSTR_CANCELLED => CANCELLED.as_obj(),
|
||||
|
||||
/// def confirm_action(
|
||||
/// *,
|
||||
/// title: str,
|
||||
/// action: str | None = None,
|
||||
/// description: str | None = None,
|
||||
/// verb: str | None = None,
|
||||
/// verb_cancel: str | None = None,
|
||||
/// hold: bool | None = None,
|
||||
/// reverse: bool = False,
|
||||
/// ) -> object:
|
||||
/// """Confirm action."""
|
||||
Qstr::MP_QSTR_confirm_action => obj_fn_kw!(0, new_confirm_action).as_obj(),
|
||||
|
||||
/// def request_pin(
|
||||
/// *,
|
||||
/// prompt: str,
|
||||
/// subprompt: str | None = None,
|
||||
/// allow_cancel: bool = True,
|
||||
/// warning: str | None = None,
|
||||
/// ) -> str | object:
|
||||
/// """Request pin on device."""
|
||||
Qstr::MP_QSTR_request_pin => obj_fn_kw!(0, new_request_pin).as_obj(),
|
||||
|
||||
/// def request_passphrase(
|
||||
/// *,
|
||||
/// prompt: str,
|
||||
/// max_len: int,
|
||||
/// ) -> str | object:
|
||||
/// """Passphrase input keyboard."""
|
||||
Qstr::MP_QSTR_request_passphrase => obj_fn_kw!(0, new_request_passphrase).as_obj(),
|
||||
|
||||
/// def request_bip39(
|
||||
/// *,
|
||||
/// prompt: str,
|
||||
/// ) -> str:
|
||||
/// """BIP39 word input keyboard."""
|
||||
Qstr::MP_QSTR_request_bip39 => obj_fn_kw!(0, new_request_bip39).as_obj(),
|
||||
|
||||
/// def request_slip39(
|
||||
/// *,
|
||||
/// prompt: str,
|
||||
/// ) -> str:
|
||||
/// """SLIP39 word input keyboard."""
|
||||
Qstr::MP_QSTR_request_slip39 => obj_fn_kw!(0, new_request_slip39).as_obj(),
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
trace::Trace,
|
||||
ui::{
|
||||
component::Component,
|
||||
component::{Component, FormattedText},
|
||||
geometry::Rect,
|
||||
model_tt::{
|
||||
component::{Button, Dialog},
|
||||
constant,
|
||||
},
|
||||
model_tt::constant,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
from typing import *
|
||||
CONFIRMED: object
|
||||
CANCELLED: object
|
||||
|
||||
|
||||
# extmod/rustmods/modtrezorui2.c
|
||||
def layout_new_confirm_action(
|
||||
# rust/src/ui/model_t1/layout.rs
|
||||
def confirm_action(
|
||||
*,
|
||||
title: str,
|
||||
action: str | None = None,
|
||||
@ -12,55 +14,66 @@ def layout_new_confirm_action(
|
||||
hold: bool | None = None,
|
||||
reverse: bool = False,
|
||||
) -> object:
|
||||
"""Example layout."""
|
||||
"""Confirm action."""
|
||||
|
||||
|
||||
# extmod/rustmods/modtrezorui2.c
|
||||
def layout_new_example(text: str) -> object:
|
||||
"""Example layout."""
|
||||
|
||||
|
||||
# extmod/rustmods/modtrezorui2.c
|
||||
def layout_new_pin(
|
||||
*,
|
||||
prompt: str,
|
||||
subprompt: str,
|
||||
allow_cancel: bool,
|
||||
warning: str | None,
|
||||
) -> object:
|
||||
"""PIN keyboard."""
|
||||
|
||||
|
||||
# extmod/rustmods/modtrezorui2.c
|
||||
def layout_new_passphrase(
|
||||
*,
|
||||
prompt: str,
|
||||
max_len: int,
|
||||
) -> object:
|
||||
"""Passphrase keyboard."""
|
||||
|
||||
|
||||
# extmod/rustmods/modtrezorui2.c
|
||||
def layout_new_bip39(
|
||||
*,
|
||||
prompt: str,
|
||||
) -> object:
|
||||
"""BIP39 keyboard."""
|
||||
|
||||
|
||||
# extmod/rustmods/modtrezorui2.c
|
||||
def layout_new_slip39(
|
||||
*,
|
||||
prompt: str,
|
||||
) -> object:
|
||||
"""BIP39 keyboard."""
|
||||
|
||||
|
||||
# extmod/rustmods/modtrezorui2.c
|
||||
def layout_new_confirm_text(
|
||||
# rust/src/ui/model_t1/layout.rs
|
||||
def confirm_text(
|
||||
*,
|
||||
title: str,
|
||||
data: str,
|
||||
description: str | None,
|
||||
) -> object:
|
||||
"""Example layout."""
|
||||
"""Confirm text."""
|
||||
CONFIRMED: object
|
||||
CANCELLED: object
|
||||
|
||||
|
||||
# rust/src/ui/model_tt/layout.rs
|
||||
def confirm_action(
|
||||
*,
|
||||
title: str,
|
||||
action: str | None = None,
|
||||
description: str | None = None,
|
||||
verb: str | None = None,
|
||||
verb_cancel: str | None = None,
|
||||
hold: bool | None = None,
|
||||
reverse: bool = False,
|
||||
) -> object:
|
||||
"""Confirm action."""
|
||||
|
||||
|
||||
# rust/src/ui/model_tt/layout.rs
|
||||
def request_pin(
|
||||
*,
|
||||
prompt: str,
|
||||
subprompt: str | None = None,
|
||||
allow_cancel: bool = True,
|
||||
warning: str | None = None,
|
||||
) -> str | object:
|
||||
"""Request pin on device."""
|
||||
|
||||
|
||||
# rust/src/ui/model_tt/layout.rs
|
||||
def request_passphrase(
|
||||
*,
|
||||
prompt: str,
|
||||
max_len: int,
|
||||
) -> str | object:
|
||||
"""Passphrase input keyboard."""
|
||||
|
||||
|
||||
# rust/src/ui/model_tt/layout.rs
|
||||
def request_bip39(
|
||||
*,
|
||||
prompt: str,
|
||||
) -> str:
|
||||
"""BIP39 word input keyboard."""
|
||||
|
||||
|
||||
# rust/src/ui/model_tt/layout.rs
|
||||
def request_slip39(
|
||||
*,
|
||||
prompt: str,
|
||||
) -> str:
|
||||
"""SLIP39 word input keyboard."""
|
||||
|
@ -3,7 +3,7 @@ from typing import TYPE_CHECKING
|
||||
from trezor import io, log, loop, ui, wire, workflow
|
||||
from trezor.enums import ButtonRequestType
|
||||
|
||||
from trezorui2 import layout_new_confirm_action, layout_new_confirm_text
|
||||
import trezorui2
|
||||
|
||||
from .common import interact
|
||||
|
||||
@ -84,7 +84,7 @@ async def confirm_action(
|
||||
result = await interact(
|
||||
ctx,
|
||||
_RustLayout(
|
||||
layout_new_confirm_action(
|
||||
trezorui2.confirm_action(
|
||||
title=title.upper(),
|
||||
action=action,
|
||||
description=description,
|
||||
@ -97,7 +97,7 @@ async def confirm_action(
|
||||
br_type,
|
||||
br_code,
|
||||
)
|
||||
if result == 1:
|
||||
if result is not trezorui2.CONFIRMED:
|
||||
raise exc
|
||||
|
||||
|
||||
@ -114,7 +114,7 @@ async def confirm_text(
|
||||
result = await interact(
|
||||
ctx,
|
||||
_RustLayout(
|
||||
layout_new_confirm_text(
|
||||
trezorui2.confirm_text(
|
||||
title=title.upper(),
|
||||
data=data,
|
||||
description=description,
|
||||
@ -123,7 +123,7 @@ async def confirm_text(
|
||||
br_type,
|
||||
br_code,
|
||||
)
|
||||
if result == 0:
|
||||
if result is not trezorui2.CONFIRMED:
|
||||
raise wire.ActionCancelled
|
||||
|
||||
|
||||
|
@ -3,15 +3,8 @@ from typing import TYPE_CHECKING
|
||||
from trezor import io, log, loop, ui, wire, workflow
|
||||
from trezor.enums import ButtonRequestType
|
||||
|
||||
from trezorui2 import (
|
||||
layout_new_bip39,
|
||||
layout_new_confirm_action,
|
||||
layout_new_passphrase,
|
||||
layout_new_pin,
|
||||
layout_new_slip39,
|
||||
)
|
||||
import trezorui2
|
||||
|
||||
from ...components.tt import passphrase, pin
|
||||
from ...constants.tt import MONO_ADDR_PER_LINE
|
||||
from ..common import button_request, interact
|
||||
|
||||
@ -99,7 +92,7 @@ async def confirm_action(
|
||||
result = await interact(
|
||||
ctx,
|
||||
_RustLayout(
|
||||
layout_new_confirm_action(
|
||||
trezorui2.confirm_action(
|
||||
title=title.upper(),
|
||||
action=action,
|
||||
description=description,
|
||||
@ -111,7 +104,7 @@ async def confirm_action(
|
||||
br_type,
|
||||
br_code,
|
||||
)
|
||||
if result is not True:
|
||||
if result is not trezorui2.CONFIRMED:
|
||||
raise exc
|
||||
|
||||
|
||||
@ -454,10 +447,10 @@ async def request_passphrase_on_device(ctx: wire.GenericContext, max_len: int) -
|
||||
)
|
||||
|
||||
keyboard = _RustLayout(
|
||||
layout_new_passphrase(prompt="Enter passphrase", max_len=max_len)
|
||||
trezorui2.request_passphrase(prompt="Enter passphrase", max_len=max_len)
|
||||
)
|
||||
result = await ctx.wait(keyboard)
|
||||
if result is passphrase.CANCELLED:
|
||||
if result is trezorui2.CANCELLED:
|
||||
raise wire.ActionCancelled("Passphrase entry cancelled")
|
||||
|
||||
assert isinstance(result, str)
|
||||
@ -480,7 +473,7 @@ async def request_pin_on_device(
|
||||
subprompt = f"{attempts_remaining} tries left"
|
||||
|
||||
dialog = _RustLayout(
|
||||
layout_new_pin(
|
||||
trezorui2.request_pin(
|
||||
prompt=prompt,
|
||||
subprompt=subprompt,
|
||||
allow_cancel=allow_cancel,
|
||||
@ -489,7 +482,7 @@ async def request_pin_on_device(
|
||||
)
|
||||
while True:
|
||||
result = await ctx.wait(dialog)
|
||||
if result is pin.CANCELLED:
|
||||
if result is trezorui2.CANCELLED:
|
||||
raise wire.PinCancelled
|
||||
assert isinstance(result, str)
|
||||
return result
|
||||
@ -500,11 +493,15 @@ async def request_word(
|
||||
) -> str:
|
||||
if is_slip39:
|
||||
keyboard: Any = _RustLayout(
|
||||
layout_new_bip39(prompt=f"Type word {word_index + 1} of {word_count}:")
|
||||
trezorui2.request_bip39(
|
||||
prompt=f"Type word {word_index + 1} of {word_count}:"
|
||||
)
|
||||
)
|
||||
else:
|
||||
keyboard = _RustLayout(
|
||||
layout_new_slip39(prompt=f"Type word {word_index + 1} of {word_count}:")
|
||||
trezorui2.request_slip39(
|
||||
prompt=f"Type word {word_index + 1} of {word_count}:"
|
||||
)
|
||||
)
|
||||
|
||||
word: str = await ctx.wait(keyboard)
|
||||
|
@ -8,6 +8,7 @@ from pathlib import Path
|
||||
|
||||
CORE_DIR = Path(__file__).resolve().parent.parent
|
||||
EXTMOD_PATH = CORE_DIR / "embed" / "extmod"
|
||||
RUSTMOD_PATH = CORE_DIR / "embed" / "rust" / "src"
|
||||
MOCKS_PATH = CORE_DIR / "mocks" / "generated"
|
||||
|
||||
COMMENT_PREFIX = "/// "
|
||||
@ -101,6 +102,37 @@ def build_module(mod_file, dest):
|
||||
store_to_file(dest, split_to_parts(l, mod_desc))
|
||||
|
||||
|
||||
def build_rsmodule(mod_file, dest):
|
||||
global current_indent
|
||||
global current_class
|
||||
global current_package
|
||||
|
||||
assert mod_file.suffix == ".rs"
|
||||
|
||||
start_prefix = "pub static mp_module_"
|
||||
comment_prefix = f" {COMMENT_PREFIX}"
|
||||
in_module = False
|
||||
current_indent = 0
|
||||
current_class = None
|
||||
mod_desc = str(mod_file.relative_to(CORE_DIR / "embed"))
|
||||
|
||||
for l in open(mod_file):
|
||||
if l.startswith(start_prefix):
|
||||
in_module = True
|
||||
current_package = l[len(start_prefix) : ].split(":")[0]
|
||||
elif l.startswith("}"):
|
||||
in_module = False
|
||||
|
||||
if not in_module:
|
||||
continue
|
||||
|
||||
if not l.startswith(comment_prefix):
|
||||
continue
|
||||
|
||||
l = l[len(comment_prefix) :]
|
||||
store_to_file(dest, split_to_parts(l, mod_desc))
|
||||
|
||||
|
||||
def place_symlinks(dest):
|
||||
# make symlinks for the non-generated files
|
||||
for pyi in MOCKS_PATH.glob("../*.pyi"):
|
||||
@ -111,6 +143,8 @@ def place_symlinks(dest):
|
||||
def build_directory(dest):
|
||||
for modfile in sorted(EXTMOD_PATH.glob("**/mod*.[ch]")):
|
||||
build_module(modfile, dest)
|
||||
for modfile in sorted(RUSTMOD_PATH.glob("**/*.rs")):
|
||||
build_rsmodule(modfile, dest)
|
||||
place_symlinks(dest)
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user