From b64c69c3fffe9df74242ba94afa3c7b76c2b16ed Mon Sep 17 00:00:00 2001 From: Martin Milata Date: Tue, 18 Jan 2022 23:56:34 +0100 Subject: [PATCH] feat(core/rust/ui): implement confirm_action [no changelog] --- core/embed/extmod/rustmods/modtrezorui2.c | 23 +++---- .../rust/src/ui/component/text/paragraphs.rs | 10 ++- core/embed/rust/src/ui/layout/obj.rs | 13 +++- core/embed/rust/src/ui/model_t1/layout.rs | 19 ++---- core/embed/rust/src/ui/model_tt/layout.rs | 65 +++++++++++++++++-- core/embed/rust/src/ui/model_tt/theme.rs | 59 +++++++++++++++-- 6 files changed, 148 insertions(+), 41 deletions(-) diff --git a/core/embed/extmod/rustmods/modtrezorui2.c b/core/embed/extmod/rustmods/modtrezorui2.c index b211473a46..a347f474cc 100644 --- a/core/embed/extmod/rustmods/modtrezorui2.c +++ b/core/embed/extmod/rustmods/modtrezorui2.c @@ -23,12 +23,6 @@ #include "librust.h" -#if TREZOR_MODEL == T -/// def layout_new_example(text: str) -> None: -/// """Example layout.""" -STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorui2_layout_new_example_obj, - ui_layout_new_example); -#elif TREZOR_MODEL == 1 /// def layout_new_confirm_action( /// *, /// title: str, @@ -38,30 +32,37 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorui2_layout_new_example_obj, /// verb_cancel: str | None, /// hold: bool | None, /// reverse: bool, -/// ) -> int: +/// ) -> 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); +#elif TREZOR_MODEL == 1 /// def layout_new_confirm_text( /// *, /// title: str, /// data: str, /// description: str | None, -/// ) -> int: +/// ) -> 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[] = { -#if TREZOR_MODEL == T {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)}, #elif TREZOR_MODEL == 1 - {MP_ROM_QSTR(MP_QSTR_layout_new_confirm_action), - MP_ROM_PTR(&mod_trezorui2_layout_new_confirm_action_obj)}, {MP_ROM_QSTR(MP_QSTR_layout_new_confirm_text), MP_ROM_PTR(&mod_trezorui2_layout_new_confirm_text_obj)}, #endif diff --git a/core/embed/rust/src/ui/component/text/paragraphs.rs b/core/embed/rust/src/ui/component/text/paragraphs.rs index cc38fb21e2..95d76910fc 100644 --- a/core/embed/rust/src/ui/component/text/paragraphs.rs +++ b/core/embed/rust/src/ui/component/text/paragraphs.rs @@ -9,6 +9,7 @@ use crate::ui::{ use super::layout::{DefaultTextTheme, LayoutFit, TextLayout, TextNoOp, TextRenderer}; pub const MAX_PARAGRAPHS: usize = 6; +pub const DEFAULT_SPACING: i32 = 3; pub struct Paragraphs { area: Rect, @@ -26,7 +27,9 @@ where Self { area, list: Vec::new(), - layout: LinearLayout::vertical().align_at_center().with_spacing(10), + layout: LinearLayout::vertical() + .align_at_center() + .with_spacing(DEFAULT_SPACING), para_offset: 0, char_offset: 0, } @@ -37,6 +40,11 @@ where self } + pub fn with_spacing(mut self, spacing: i32) -> Self { + self.layout = self.layout.with_spacing(spacing); + self + } + pub fn add(mut self, text_font: Font, content: T) -> Self { if content.as_ref().is_empty() { return self; diff --git a/core/embed/rust/src/ui/layout/obj.rs b/core/embed/rust/src/ui/layout/obj.rs index 39a070be47..e9101f1f2f 100644 --- a/core/embed/rust/src/ui/layout/obj.rs +++ b/core/embed/rust/src/ui/layout/obj.rs @@ -13,7 +13,7 @@ use crate::{ typ::Type, }, time::Duration, - ui::component::{Child, Component, Event, EventCtx, Never, TimerToken}, + ui::component::{Child, Component, Event, EventCtx, Never, PageMsg, TimerToken}, util, }; @@ -277,6 +277,17 @@ impl TryFrom for Obj { } } +impl TryFrom> for Obj { + type Error = Error; + + fn try_from(val: PageMsg) -> Result { + match val { + PageMsg::Content(_) => Err(Error::TypeError), + PageMsg::Controls(c) => Ok(c.into()), + } + } +} + impl From for Obj { fn from(_: Never) -> Self { unreachable!() diff --git a/core/embed/rust/src/ui/model_t1/layout.rs b/core/embed/rust/src/ui/model_t1/layout.rs index 9133c54237..60e17178ce 100644 --- a/core/embed/rust/src/ui/model_t1/layout.rs +++ b/core/embed/rust/src/ui/model_t1/layout.rs @@ -1,10 +1,9 @@ -use core::convert::{TryFrom, TryInto}; +use core::convert::TryInto; use crate::{ - error::Error, micropython::{buffer::Buffer, map::Map, obj::Obj, qstr::Qstr}, ui::{ - component::{text::paragraphs::Paragraphs, Child, FormattedText, PageMsg}, + component::{text::paragraphs::Paragraphs, Child, FormattedText}, display, layout::obj::LayoutObj, }, @@ -16,17 +15,6 @@ use super::{ theme, }; -impl TryFrom> for Obj { - type Error = Error; - - fn try_from(val: PageMsg) -> Result { - match val { - PageMsg::Content(_) => 2.try_into(), - PageMsg::Controls(c) => Ok(c.into()), - } - } -} - #[no_mangle] extern "C" fn ui_layout_new_confirm_action( n_args: usize, @@ -106,7 +94,8 @@ extern "C" fn ui_layout_new_confirm_text( #[cfg(test)] mod tests { use crate::{ - trace::{Trace, Tracer}, + error::Error, + trace::Trace, ui::model_t1::component::{Dialog, DialogMsg}, }; diff --git a/core/embed/rust/src/ui/model_tt/layout.rs b/core/embed/rust/src/ui/model_tt/layout.rs index 9b8419d90b..3a6bdf840a 100644 --- a/core/embed/rust/src/ui/model_tt/layout.rs +++ b/core/embed/rust/src/ui/model_tt/layout.rs @@ -2,9 +2,9 @@ use core::convert::{TryFrom, TryInto}; use crate::{ error::Error, - micropython::obj::Obj, + micropython::{buffer::Buffer, map::Map, obj::Obj, qstr::Qstr}, ui::{ - component::{Child, FormattedText}, + component::{base::ComponentExt, text::paragraphs::Paragraphs, Child, FormattedText}, display, layout::obj::LayoutObj, }, @@ -12,7 +12,7 @@ use crate::{ }; use super::{ - component::{ButtonMsg, DialogMsg, HoldToConfirm, HoldToConfirmMsg}, + component::{Button, ButtonMsg, DialogMsg, Frame, HoldToConfirm, HoldToConfirmMsg, SwipePage}, theme, }; @@ -64,6 +64,61 @@ extern "C" fn ui_layout_new_example(_param: Obj) -> Obj { unsafe { util::try_or_raise(block) } } +#[no_mangle] +extern "C" fn ui_layout_new_confirm_action( + n_args: usize, + args: *const Obj, + kwargs: *const Map, +) -> Obj { + let block = move |_args: &[Obj], kwargs: &Map| { + let title: Buffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; + let action: Option = kwargs.get(Qstr::MP_QSTR_action)?.try_into_option()?; + let description: Option = + kwargs.get(Qstr::MP_QSTR_description)?.try_into_option()?; + let verb: Option = kwargs.get(Qstr::MP_QSTR_verb)?.try_into_option()?; + let reverse: bool = kwargs.get(Qstr::MP_QSTR_reverse)?.try_into()?; + + let obj = LayoutObj::new( + Frame::new(theme::borders(), title, |area| { + SwipePage::new( + area, + theme::BG, + |area| { + let action = action.unwrap_or("".into()); + let description = description.unwrap_or("".into()); + let mut para = Paragraphs::new(area); + if !reverse { + para = para + .add::(theme::FONT_BOLD, action) + .add::(theme::FONT_NORMAL, description); + } else { + para = para + .add::(theme::FONT_NORMAL, description) + .add::(theme::FONT_BOLD, action); + } + para + }, + |area| { + Button::array2( + area, + |area| Button::with_icon(area, theme::ICON_CANCEL), + |msg| (matches!(msg, ButtonMsg::Clicked)).then(|| false), + |area| { + Button::with_text(area, verb.unwrap_or("CONFIRM".into())) + .styled(theme::button_confirm()) + }, + |msg| (matches!(msg, ButtonMsg::Clicked)).then(|| true), + ) + }, + ) + }) + .into_child(), + )?; + Ok(obj.into()) + }; + unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } +} + #[cfg(test)] mod tests { use crate::{ @@ -130,9 +185,7 @@ mod tests { )); assert_eq!( trace(&layout), - r#" left: