1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-01-03 03:50:58 +00:00

refactor(core/ui): pagination and buttons on TT

This commit is contained in:
Martin Milata 2023-09-27 00:17:38 +02:00
parent 4f2c639ed7
commit d8e7c00087
14 changed files with 1164 additions and 1523 deletions

View File

@ -0,0 +1 @@
[T2T1] Adjust buttons used for scrolling multipage content.

View File

@ -24,7 +24,7 @@ pub use map::MsgMap;
pub use marquee::Marquee;
pub use maybe::Maybe;
pub use pad::Pad;
pub use paginated::{AuxPageMsg, PageMsg, Paginate};
pub use paginated::{PageMsg, Paginate};
pub use painter::Painter;
pub use placed::{FixedHeightBar, Floating, GridPlaced, Split};
pub use qr_code::Qr;

View File

@ -1,7 +1,13 @@
pub enum AuxPageMsg {
/// Page component was instantiated with BACK button on every page and it
/// was pressed.
GoBack,
/// Common message type for pagination components.
pub enum PageMsg<T> {
/// Pass-through from paged component.
Content(T),
/// Confirmed using page controls.
Confirmed,
/// Cancelled using page controls.
Cancelled,
/// Page component was configured to react to swipes and user swiped left.
SwipeLeft,
@ -10,19 +16,6 @@ pub enum AuxPageMsg {
SwipeRight,
}
/// Common message type for pagination components.
pub enum PageMsg<T, U> {
/// Pass-through from paged component.
Content(T),
/// Messages from page controls outside the paged component, like
/// "OK" and "Cancel" buttons.
Controls(U),
/// Auxilliary events used by exotic pages on touchscreens.
Aux(AuxPageMsg),
}
pub trait Paginate {
/// How many pages of content are there in total?
fn page_count(&mut self) -> usize;

View File

@ -162,7 +162,7 @@ where
T: Component + Paginate,
U: StringType + Clone,
{
type Msg = PageMsg<T::Msg, bool>;
type Msg = PageMsg<T::Msg>;
fn place(&mut self, bounds: Rect) -> Rect {
let (content_area, button_area) = bounds.split_bottom(theme::BUTTON_HEIGHT);
@ -191,7 +191,7 @@ where
self.change_page(ctx);
} else {
// Clicked CANCEL. Send result.
return Some(PageMsg::Controls(false));
return Some(PageMsg::Cancelled);
}
}
ButtonPos::Right => {
@ -201,7 +201,7 @@ where
self.change_page(ctx);
} else {
// Clicked CONFIRM. Send result.
return Some(PageMsg::Controls(true));
return Some(PageMsg::Confirmed);
}
}
_ => {}

View File

@ -93,10 +93,9 @@ where
{
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()),
PageMsg::Aux(_) => Err(Error::TypeError),
PageMsg::Confirmed => Ok(CONFIRMED.as_obj()),
PageMsg::Cancelled => Ok(CANCELLED.as_obj()),
_ => Err(Error::TypeError),
}
}
}

View File

@ -1,244 +0,0 @@
use crate::{
time::Instant,
ui::{
component::{Child, Component, ComponentExt, Event, EventCtx, FixedHeightBar, Pad},
geometry::{Grid, Insets, Rect},
util::animation_disabled,
},
};
use super::{theme, Button, ButtonMsg, ButtonStyleSheet, Loader, LoaderMsg};
pub enum HoldToConfirmMsg<T> {
Content(T),
Confirmed,
Cancelled,
}
pub struct HoldToConfirm<T> {
loader: Loader,
content: Child<T>,
buttons: Child<FixedHeightBar<CancelHold>>,
pad: Pad,
}
impl<T> HoldToConfirm<T>
where
T: Component,
{
pub fn new(content: T) -> Self {
Self {
loader: Loader::new(),
content: Child::new(content),
buttons: Child::new(CancelHold::new(theme::button_confirm())),
pad: Pad::with_background(theme::BG),
}
}
pub fn inner(&self) -> &T {
self.content.inner()
}
}
impl<T> Component for HoldToConfirm<T>
where
T: Component,
{
type Msg = HoldToConfirmMsg<T::Msg>;
fn place(&mut self, bounds: Rect) -> Rect {
let controls_area = self.buttons.place(bounds);
let content_area = bounds
.inset(Insets::bottom(controls_area.height()))
.inset(Insets::bottom(theme::BUTTON_SPACING))
.inset(Insets::left(theme::CONTENT_BORDER));
self.pad.place(content_area);
self.loader.place(content_area);
self.content.place(content_area);
bounds
}
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
if let Some(msg) = self.content.event(ctx, event) {
return Some(HoldToConfirmMsg::Content(msg));
}
let button_msg = match self.buttons.event(ctx, event) {
Some(CancelHoldMsg::Cancelled) => return Some(HoldToConfirmMsg::Cancelled),
Some(CancelHoldMsg::HoldButton(b)) => Some(b),
_ => None,
};
if handle_hold_event(
ctx,
event,
button_msg,
&mut self.loader,
&mut self.pad,
&mut self.content,
) {
return Some(HoldToConfirmMsg::Confirmed);
}
None
}
fn paint(&mut self) {
self.pad.paint();
if self.loader.is_animating() {
self.loader.paint();
} else {
self.content.paint();
}
self.buttons.paint();
}
#[cfg(feature = "ui_bounds")]
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
sink(self.pad.area);
if self.loader.is_animating() {
self.loader.bounds(sink)
} else {
self.content.bounds(sink)
}
self.buttons.bounds(sink);
}
}
#[cfg(feature = "ui_debug")]
impl<T> crate::trace::Trace for HoldToConfirm<T>
where
T: crate::trace::Trace,
{
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
t.component("HoldToConfirm");
t.child("content", &self.content);
}
}
pub struct CancelHold {
cancel: Option<Child<Button<&'static str>>>,
hold: Child<Button<&'static str>>,
}
pub enum CancelHoldMsg {
Cancelled,
HoldButton(ButtonMsg),
}
impl CancelHold {
pub fn new(button_style: ButtonStyleSheet) -> FixedHeightBar<Self> {
theme::button_bar(Self {
cancel: Some(Button::with_icon(theme::ICON_CANCEL).into_child()),
hold: Button::with_text("HOLD TO CONFIRM")
.styled(button_style)
.into_child(),
})
}
pub fn with_cancel_arrow() -> FixedHeightBar<Self> {
theme::button_bar(Self {
cancel: Some(Button::with_icon(theme::ICON_UP).into_child()),
hold: Button::with_text("HOLD TO CONFIRM")
.styled(theme::button_confirm())
.into_child(),
})
}
pub fn without_cancel() -> FixedHeightBar<Self> {
theme::button_bar(Self {
cancel: None,
hold: Button::with_text("HOLD TO CONFIRM")
.styled(theme::button_confirm())
.into_child(),
})
}
}
impl Component for CancelHold {
type Msg = CancelHoldMsg;
fn place(&mut self, bounds: Rect) -> Rect {
if self.cancel.is_some() {
let grid = Grid::new(bounds, 1, 4).with_spacing(theme::BUTTON_SPACING);
self.cancel.place(grid.row_col(0, 0));
self.hold
.place(grid.row_col(0, 1).union(grid.row_col(0, 3)));
} else {
self.hold.place(bounds);
};
bounds
}
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
if let Some(ButtonMsg::Clicked) = self.cancel.event(ctx, event) {
return Some(CancelHoldMsg::Cancelled);
}
self.hold.event(ctx, event).map(CancelHoldMsg::HoldButton)
}
fn paint(&mut self) {
self.cancel.paint();
self.hold.paint();
}
#[cfg(feature = "ui_bounds")]
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
self.cancel.bounds(sink);
self.hold.bounds(sink);
}
}
#[cfg(feature = "ui_debug")]
impl crate::trace::Trace for CancelHold {
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
t.component("CancelHold");
}
}
/// Hold-to-confirm logic to be called from event handler of the component that
/// owns `pad`, `loader`, and `content` and a Button. It is expected that the
/// associated button already processed `event` and returned `button_msg`.
/// Returns `true` when the interaction successfully finished.
#[must_use]
pub fn handle_hold_event<T>(
ctx: &mut EventCtx,
event: Event,
button_msg: Option<ButtonMsg>,
loader: &mut Loader,
pad: &mut Pad,
content: &mut T,
) -> bool
where
T: Component,
{
let now = Instant::now();
if let Some(LoaderMsg::ShrunkCompletely) = loader.event(ctx, event) {
// Clear the remnants of the loader.
pad.clear();
// Switch it to the initial state, so we stop painting it.
loader.reset();
// Re-draw the whole content tree.
content.request_complete_repaint(ctx);
// This can be a result of an animation frame event, we should take
// care to not short-circuit here and deliver the event to the
// content as well.
}
match button_msg {
Some(ButtonMsg::Pressed) => {
loader.start_growing(ctx, now);
pad.clear(); // Clear the remnants of the content.
}
Some(ButtonMsg::Released) => {
loader.start_shrinking(ctx, now);
}
Some(ButtonMsg::Clicked) => {
if loader.is_completely_grown(now) || animation_disabled() {
return true;
} else {
loader.start_shrinking(ctx, now);
}
}
_ => {}
}
false
}

View File

@ -7,10 +7,8 @@ mod fido;
mod fido_icons;
mod error;
mod frame;
mod hold_to_confirm;
#[cfg(feature = "micropython")]
mod homescreen;
mod horizontal_page;
mod keyboard;
mod loader;
mod number_input;
@ -18,6 +16,7 @@ mod page;
mod progress;
mod result;
mod scroll;
mod simple_page;
mod swipe;
mod welcome_screen;
@ -31,10 +30,8 @@ pub use dialog::{Dialog, DialogMsg, IconDialog};
pub use error::ErrorScreen;
pub use fido::{FidoConfirm, FidoMsg};
pub use frame::{Frame, FrameMsg};
pub use hold_to_confirm::{HoldToConfirm, HoldToConfirmMsg};
#[cfg(feature = "micropython")]
pub use homescreen::{Homescreen, HomescreenMsg, Lockscreen};
pub use horizontal_page::HorizontalPage;
pub use keyboard::{
bip39::Bip39Input,
mnemonic::{MnemonicInput, MnemonicKeyboard, MnemonicKeyboardMsg},
@ -45,10 +42,11 @@ pub use keyboard::{
};
pub use loader::{Loader, LoaderMsg, LoaderStyle, LoaderStyleSheet};
pub use number_input::{NumberInputDialog, NumberInputDialogMsg};
pub use page::{SwipeHoldPage, SwipePage};
pub use page::ButtonPage;
pub use progress::Progress;
pub use result::{ResultFooter, ResultScreen, ResultStyle};
pub use scroll::ScrollBar;
pub use simple_page::SimplePage;
pub use swipe::{Swipe, SwipeDirection};
pub use welcome_screen::WelcomeScreen;

File diff suppressed because it is too large Load Diff

View File

@ -56,11 +56,17 @@ impl ScrollBar {
}
pub fn go_to_next_page(&mut self) {
self.go_to(self.active_page.saturating_add(1).min(self.page_count - 1));
self.go_to_relative(1)
}
pub fn go_to_previous_page(&mut self) {
self.go_to(self.active_page.saturating_sub(1));
self.go_to_relative(-1)
}
pub fn go_to_relative(&mut self, step: isize) {
self.go_to(
(self.active_page as isize + step).clamp(0, self.page_count as isize - 1) as usize,
);
}
pub fn go_to(&mut self, active_page: usize) {

View File

@ -1,9 +1,7 @@
use crate::ui::{
component::{
base::ComponentExt, AuxPageMsg, Component, Event, EventCtx, Never, Pad, PageMsg, Paginate,
},
component::{base::ComponentExt, Component, Event, EventCtx, Pad, PageMsg, Paginate},
display::{self, Color},
geometry::{Insets, Rect},
geometry::{Axis, Insets, Rect},
};
use super::{theme, ScrollBar, Swipe, SwipeDirection};
@ -11,26 +9,40 @@ use super::{theme, ScrollBar, Swipe, SwipeDirection};
const SCROLLBAR_HEIGHT: i16 = 18;
const SCROLLBAR_BORDER: i16 = 4;
pub struct HorizontalPage<T> {
pub struct SimplePage<T> {
content: T,
pad: Pad,
swipe: Swipe,
scrollbar: ScrollBar,
axis: Axis,
swipe_right_to_go_back: bool,
fade: Option<u16>,
}
impl<T> HorizontalPage<T>
impl<T> SimplePage<T>
where
T: Paginate,
T: Component,
{
pub fn new(content: T, background: Color) -> Self {
pub fn horizontal(content: T, background: Color) -> Self {
Self {
content,
swipe: Swipe::new(),
pad: Pad::with_background(background),
scrollbar: ScrollBar::horizontal(),
axis: Axis::Horizontal,
swipe_right_to_go_back: false,
fade: None,
}
}
pub fn vertical(content: T, background: Color) -> Self {
Self {
content,
swipe: Swipe::new(),
pad: Pad::with_background(background),
scrollbar: ScrollBar::vertical(),
axis: Axis::Vertical,
swipe_right_to_go_back: false,
fade: None,
}
@ -46,11 +58,20 @@ where
}
fn setup_swipe(&mut self) {
self.swipe.allow_left = self.scrollbar.has_next_page();
self.swipe.allow_right = self.scrollbar.has_previous_page() || self.swipe_right_to_go_back;
if self.is_horizontal() {
self.swipe.allow_left = self.scrollbar.has_next_page();
self.swipe.allow_right =
self.scrollbar.has_previous_page() || self.swipe_right_to_go_back;
} else {
self.swipe.allow_up = self.scrollbar.has_next_page();
self.swipe.allow_down = self.scrollbar.has_previous_page();
self.swipe.allow_right = self.swipe_right_to_go_back;
}
}
fn on_page_change(&mut self, ctx: &mut EventCtx) {
fn change_page(&mut self, ctx: &mut EventCtx, step: isize) {
// Advance scrollbar.
self.scrollbar.go_to_relative(step);
// Adjust the swipe parameters according to the scrollbar.
self.setup_swipe();
@ -64,23 +85,43 @@ where
// paint.
self.fade = Some(theme::BACKLIGHT_NORMAL);
}
fn is_horizontal(&self) -> bool {
matches!(self.axis, Axis::Horizontal)
}
}
impl<T> Component for HorizontalPage<T>
impl<T> Component for SimplePage<T>
where
T: Paginate,
T: Component,
{
type Msg = PageMsg<T::Msg, Never>;
type Msg = PageMsg<T::Msg>;
fn place(&mut self, bounds: Rect) -> Rect {
self.swipe.place(bounds);
let (content, scrollbar) = bounds.split_bottom(SCROLLBAR_HEIGHT + SCROLLBAR_BORDER);
self.pad.place(content);
self.content.place(content);
self.scrollbar
.place(scrollbar.inset(Insets::bottom(SCROLLBAR_BORDER)));
let (content, scrollbar) = if self.is_horizontal() {
bounds.split_bottom(SCROLLBAR_HEIGHT + SCROLLBAR_BORDER)
} else {
bounds.split_right(SCROLLBAR_HEIGHT + SCROLLBAR_BORDER)
};
self.content.place(bounds);
if self.content.page_count() > 1 {
self.pad.place(content);
self.content.place(content);
} else {
self.pad.place(bounds);
}
if self.is_horizontal() {
self.scrollbar
.place(scrollbar.inset(Insets::bottom(SCROLLBAR_BORDER)));
} else {
self.scrollbar
.place(scrollbar.inset(Insets::right(SCROLLBAR_BORDER)));
}
self.scrollbar
.set_count_and_active_page(self.content.page_count(), 0);
@ -92,18 +133,19 @@ where
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
ctx.set_page_count(self.scrollbar.page_count);
if let Some(swipe) = self.swipe.event(ctx, event) {
match swipe {
SwipeDirection::Left => {
self.scrollbar.go_to_next_page();
self.on_page_change(ctx);
match (swipe, self.axis) {
(SwipeDirection::Left, Axis::Horizontal) | (SwipeDirection::Up, Axis::Vertical) => {
self.change_page(ctx, 1);
return None;
}
SwipeDirection::Right => {
if self.swipe_right_to_go_back && self.scrollbar.active_page == 0 {
return Some(PageMsg::Aux(AuxPageMsg::GoBack));
}
self.scrollbar.go_to_previous_page();
self.on_page_change(ctx);
(SwipeDirection::Right, _)
if self.swipe_right_to_go_back && self.scrollbar.active_page == 0 =>
{
return Some(PageMsg::Cancelled);
}
(SwipeDirection::Right, Axis::Horizontal)
| (SwipeDirection::Down, Axis::Vertical) => {
self.change_page(ctx, -1);
return None;
}
_ => {
@ -117,7 +159,9 @@ where
fn paint(&mut self) {
self.pad.paint();
self.content.paint();
self.scrollbar.paint();
if self.scrollbar.has_pages() {
self.scrollbar.paint();
}
if let Some(val) = self.fade.take() {
// Note that this is blocking and takes some time.
display::fade_backlight(val);
@ -133,12 +177,12 @@ where
}
#[cfg(feature = "ui_debug")]
impl<T> crate::trace::Trace for HorizontalPage<T>
impl<T> crate::trace::Trace for SimplePage<T>
where
T: crate::trace::Trace,
{
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
t.component("HorizontalPage");
t.component("SimplePage");
t.int("active_page", self.scrollbar.active_page as i64);
t.int("page_count", self.scrollbar.page_count as i64);
t.child("content", &self.content);

View File

@ -20,7 +20,7 @@ use crate::{
component::{
base::ComponentExt,
image::BlendedImage,
paginated::{AuxPageMsg, PageMsg, Paginate},
paginated::{PageMsg, Paginate},
painter,
placed::GridPlaced,
text::{
@ -48,13 +48,12 @@ use crate::{
use super::{
component::{
AddressDetails, Bip39Input, Button, ButtonMsg, ButtonStyleSheet, CancelConfirmMsg,
CancelInfoConfirmMsg, CoinJoinProgress, Dialog, DialogMsg, FidoConfirm, FidoMsg, Frame,
FrameMsg, HoldToConfirm, HoldToConfirmMsg, Homescreen, HomescreenMsg, HorizontalPage,
IconDialog, Lockscreen, MnemonicInput, MnemonicKeyboard, MnemonicKeyboardMsg,
NumberInputDialog, NumberInputDialogMsg, PassphraseKeyboard, PassphraseKeyboardMsg,
PinKeyboard, PinKeyboardMsg, Progress, SelectWordCount, SelectWordCountMsg, SelectWordMsg,
Slip39Input, SwipeHoldPage, SwipePage, WelcomeScreen,
AddressDetails, Bip39Input, Button, ButtonMsg, ButtonPage, ButtonStyleSheet,
CancelConfirmMsg, CancelInfoConfirmMsg, CoinJoinProgress, Dialog, DialogMsg, FidoConfirm,
FidoMsg, Frame, FrameMsg, Homescreen, HomescreenMsg, IconDialog, Lockscreen, MnemonicInput,
MnemonicKeyboard, MnemonicKeyboardMsg, NumberInputDialog, NumberInputDialogMsg,
PassphraseKeyboard, PassphraseKeyboardMsg, PinKeyboard, PinKeyboardMsg, Progress,
SelectWordCount, SelectWordCountMsg, SelectWordMsg, SimplePage, Slip39Input, WelcomeScreen,
},
constant, theme,
};
@ -144,19 +143,6 @@ where
}
}
impl<T> ComponentMsgObj for HoldToConfirm<T>
where
T: ComponentMsgObj,
{
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<T> ComponentMsgObj for PinKeyboard<T>
where
T: AsRef<str>,
@ -209,34 +195,18 @@ where
}
}
impl<T, U> ComponentMsgObj for SwipePage<T, U>
impl<T, U> ComponentMsgObj for ButtonPage<T, U>
where
T: Component + Paginate,
U: Component,
<U as Component>::Msg: TryInto<Obj, Error = Error>,
U: AsRef<str> + From<&'static str>,
{
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
match msg {
PageMsg::Content(_) => Err(Error::TypeError),
PageMsg::Controls(msg) => msg.try_into(),
PageMsg::Aux(AuxPageMsg::GoBack) => Ok(CANCELLED.as_obj()),
PageMsg::Aux(AuxPageMsg::SwipeLeft) => Ok(INFO.as_obj()),
PageMsg::Aux(AuxPageMsg::SwipeRight) => Ok(CANCELLED.as_obj()),
}
}
}
impl<T> ComponentMsgObj for SwipeHoldPage<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(msg) => msg.try_into(),
PageMsg::Aux(AuxPageMsg::GoBack) => Ok(CANCELLED.as_obj()),
PageMsg::Aux(AuxPageMsg::SwipeLeft) => Ok(INFO.as_obj()),
PageMsg::Aux(AuxPageMsg::SwipeRight) => Ok(CANCELLED.as_obj()),
PageMsg::Confirmed => Ok(CONFIRMED.as_obj()),
PageMsg::Cancelled => Ok(CANCELLED.as_obj()),
PageMsg::SwipeLeft => Ok(INFO.as_obj()),
PageMsg::SwipeRight => Ok(CANCELLED.as_obj()),
}
}
}
@ -361,16 +331,15 @@ impl ComponentMsgObj for Qr {
}
}
impl<T> ComponentMsgObj for HorizontalPage<T>
impl<T> ComponentMsgObj for SimplePage<T>
where
T: ComponentMsgObj + Paginate,
{
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
match msg {
PageMsg::Content(inner_msg) => Ok(self.inner().msg_try_into_obj(inner_msg)?),
PageMsg::Controls(_) => Err(Error::TypeError),
PageMsg::Aux(AuxPageMsg::GoBack) => Ok(CANCELLED.as_obj()),
PageMsg::Aux(_) => Err(Error::TypeError),
PageMsg::Cancelled => Ok(CANCELLED.as_obj()),
_ => Err(Error::TypeError),
}
}
}
@ -428,21 +397,15 @@ extern "C" fn new_confirm_action(n_args: usize, args: *const Obj, kwargs: *mut M
paragraphs.into_paragraphs()
};
let obj = if hold {
let page = if hold_danger {
SwipeHoldPage::with_danger(paragraphs, theme::BG)
} else {
SwipeHoldPage::new(paragraphs, theme::BG)
};
LayoutObj::new(Frame::left_aligned(theme::label_title(), title, page))?
let mut page = if hold {
ButtonPage::new(paragraphs, theme::BG).with_hold()
} else {
let buttons = Button::cancel_confirm_text(verb_cancel, verb);
LayoutObj::new(Frame::left_aligned(
theme::label_title(),
title,
SwipePage::new(paragraphs, buttons, theme::BG).with_cancel_on_first_page(),
))?
ButtonPage::new(paragraphs, theme::BG).with_cancel_confirm(verb_cancel, verb)
};
if hold && hold_danger {
page = page.with_confirm_style(theme::button_danger())
}
let obj = LayoutObj::new(Frame::left_aligned(theme::label_title(), title, page))?;
Ok(obj.into())
};
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
@ -472,15 +435,11 @@ extern "C" fn new_confirm_emphasized(n_args: usize, args: *const Obj, kwargs: *m
}
}
let buttons = Button::<StrBuffer>::cancel_confirm_text(None, verb);
let obj = LayoutObj::new(Frame::left_aligned(
theme::label_title(),
title,
SwipePage::new(
FormattedText::new(ops).vertically_centered(),
buttons,
theme::BG,
),
ButtonPage::new(FormattedText::new(ops).vertically_centered(), theme::BG)
.with_cancel_confirm(None, verb),
))?;
Ok(obj.into())
};
@ -558,36 +517,21 @@ impl ConfirmBlobParams {
}
.into_paragraphs();
let obj = if self.hold {
let mut frame = Frame::left_aligned(
theme::label_title(),
self.title,
SwipeHoldPage::new(paragraphs, theme::BG),
);
if let Some(subtitle) = self.subtitle {
frame = frame.with_subtitle(theme::label_subtitle(), subtitle);
}
if self.info_button {
frame = frame.with_info_button();
}
LayoutObj::new(frame)?
let page: ButtonPage<_, StrBuffer> = if self.hold {
ButtonPage::new(paragraphs, theme::BG).with_hold()
} else if let Some(verb) = self.verb {
let buttons = Button::cancel_confirm_text(self.verb_cancel, Some(verb));
let mut frame = Frame::left_aligned(
theme::label_title(),
self.title,
SwipePage::new(paragraphs, buttons, theme::BG).with_cancel_on_first_page(),
);
if let Some(subtitle) = self.subtitle {
frame = frame.with_subtitle(theme::label_subtitle(), subtitle);
}
if self.info_button {
frame = frame.with_info_button();
}
LayoutObj::new(frame)?
ButtonPage::new(paragraphs, theme::BG).with_cancel_confirm(self.verb_cancel, Some(verb))
} else {
panic!("Either `hold=true` or `verb=Some(StrBuffer)` must be specified");
};
let mut frame = Frame::left_aligned(theme::label_title(), self.title, page);
if let Some(subtitle) = self.subtitle {
frame = frame.with_subtitle(theme::label_subtitle(), subtitle);
}
if self.info_button {
frame = frame.with_info_button();
}
let obj = LayoutObj::new(frame)?;
Ok(obj.into())
}
}
@ -649,14 +593,13 @@ extern "C" fn new_confirm_address(n_args: usize, args: *const Obj, kwargs: *mut
}
.into_paragraphs();
let buttons = Button::cancel_confirm_text(None, Some("CONFIRM"));
let obj = LayoutObj::new(
Frame::left_aligned(
theme::label_title(),
title,
SwipePage::new(paragraphs, buttons, theme::BG)
ButtonPage::new(paragraphs, theme::BG)
.with_swipe_left()
.with_cancel_on_first_page(),
.with_cancel_confirm(None, Some("CONFIRM")),
)
.with_info_button(),
)?;
@ -677,21 +620,13 @@ extern "C" fn new_confirm_properties(n_args: usize, args: *const Obj, kwargs: *m
&theme::TEXT_MONO,
&theme::TEXT_MONO,
)?;
let obj = if hold {
LayoutObj::new(Frame::left_aligned(
theme::label_title(),
title,
SwipeHoldPage::new(paragraphs.into_paragraphs(), theme::BG),
))?
let page: ButtonPage<_, StrBuffer> = if hold {
ButtonPage::new(paragraphs.into_paragraphs(), theme::BG).with_hold()
} else {
let buttons = Button::cancel_confirm_text(None, Some("CONFIRM"));
LayoutObj::new(Frame::left_aligned(
theme::label_title(),
title,
SwipePage::new(paragraphs.into_paragraphs(), buttons, theme::BG)
.with_cancel_on_first_page(),
))?
ButtonPage::new(paragraphs.into_paragraphs(), theme::BG)
.with_cancel_confirm(None, Some("CONFIRM".into()))
};
let obj = LayoutObj::new(Frame::left_aligned(theme::label_title(), title, page))?;
Ok(obj.into())
};
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
@ -789,7 +724,8 @@ extern "C" fn new_show_address_details(n_args: usize, args: *const Obj, kwargs:
ad.add_xpub(xtitle, text)?;
}
let obj = LayoutObj::new(HorizontalPage::new(ad, theme::BG).with_swipe_right_to_go_back())?;
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) }
@ -814,7 +750,8 @@ extern "C" fn new_show_info_with_cancel(n_args: usize, args: *const Obj, kwargs:
Frame::left_aligned(
theme::label_title(),
title,
SwipePage::new(paragraphs.into_paragraphs(), Empty, theme::BG).with_swipe_right(),
SimplePage::vertical(paragraphs.into_paragraphs(), theme::BG)
.with_swipe_right_to_go_back(),
)
.with_cancel_button(),
)?;
@ -866,11 +803,11 @@ extern "C" fn new_confirm_total(n_args: usize, args: *const Obj, kwargs: *mut Ma
paragraphs.add(Paragraph::new(&theme::TEXT_NORMAL, label));
paragraphs.add(Paragraph::new(&theme::TEXT_MONO, value));
}
let mut page = if cancel_arrow {
SwipeHoldPage::with_cancel_arrow(paragraphs.into_paragraphs(), theme::BG)
} else {
SwipeHoldPage::new(paragraphs.into_paragraphs(), theme::BG)
};
let mut page: ButtonPage<_, StrBuffer> =
ButtonPage::new(paragraphs.into_paragraphs(), theme::BG).with_hold();
if cancel_arrow {
page = page.with_cancel_arrow()
}
if info_button {
page = page.with_swipe_left();
}
@ -903,11 +840,11 @@ extern "C" fn new_confirm_modify_output(n_args: usize, args: *const Obj, kwargs:
Paragraph::new(&theme::TEXT_MONO, amount_new),
]);
let buttons = Button::cancel_confirm_text(Some("^"), Some("CONTINUE"));
let obj = LayoutObj::new(Frame::left_aligned(
theme::label_title(),
"MODIFY AMOUNT",
SwipePage::new(paragraphs, buttons, theme::BG),
ButtonPage::<_, StrBuffer>::new(paragraphs, theme::BG)
.with_cancel_confirm(Some("^".into()), Some("CONTINUE".into())),
))?;
Ok(obj.into())
};
@ -942,7 +879,9 @@ extern "C" fn new_confirm_modify_fee(n_args: usize, args: *const Obj, kwargs: *m
Frame::left_aligned(
theme::label_title(),
title,
SwipeHoldPage::new(paragraphs, theme::BG).with_swipe_left(),
ButtonPage::<_, StrBuffer>::new(paragraphs, theme::BG)
.with_hold()
.with_swipe_left(),
)
.with_info_button(),
)?;
@ -1241,15 +1180,13 @@ extern "C" fn new_confirm_more(n_args: usize, args: *const Obj, kwargs: *mut Map
paragraphs.add(Paragraph::new(style, text));
}
let button =
theme::button_bar(Button::with_text(button).map(|msg| {
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelConfirmMsg::Confirmed)
}));
let obj = LayoutObj::new(Frame::left_aligned(
theme::label_title(),
title,
SwipePage::new(paragraphs.into_paragraphs(), button, theme::BG).with_back_button(),
ButtonPage::new(paragraphs.into_paragraphs(), theme::BG)
.with_cancel_confirm(None, Some(button))
.with_confirm_style(theme::button_default())
.with_back_button(),
))?;
Ok(obj.into())
};
@ -1271,7 +1208,7 @@ extern "C" fn new_confirm_coinjoin(n_args: usize, args: *const Obj, kwargs: *mut
let obj = LayoutObj::new(Frame::left_aligned(
theme::label_title(),
"AUTHORIZE COINJOIN",
SwipeHoldPage::new(paragraphs, theme::BG),
ButtonPage::<_, StrBuffer>::new(paragraphs, theme::BG).with_hold(),
))?;
Ok(obj.into())
};
@ -1331,12 +1268,10 @@ extern "C" fn new_select_word(n_args: usize, args: *const Obj, kwargs: *mut Map)
let words: [StrBuffer; 3] = iter_into_array(words_iterable)?;
let paragraphs = Paragraphs::new([Paragraph::new(&theme::TEXT_DEMIBOLD, description)]);
let buttons = Button::select_word(words);
let obj = LayoutObj::new(Frame::left_aligned(
theme::label_title(),
title,
SwipePage::new(paragraphs, buttons, theme::BG),
Dialog::new(paragraphs, Button::select_word(words)),
))?;
Ok(obj.into())
};
@ -1357,7 +1292,9 @@ extern "C" fn new_show_share_words(n_args: usize, args: *const Obj, kwargs: *mut
let obj = LayoutObj::new(Frame::left_aligned(
theme::label_title(),
title,
SwipeHoldPage::without_cancel(paragraphs.into_paragraphs(), theme::BG),
ButtonPage::<_, StrBuffer>::new(paragraphs.into_paragraphs(), theme::BG)
.with_hold()
.without_cancel(),
))?;
Ok(obj.into())
};
@ -1535,13 +1472,10 @@ extern "C" fn new_show_remaining_shares(n_args: usize, args: *const Obj, kwargs:
let obj = LayoutObj::new(Frame::left_aligned(
theme::label_title(),
"REMAINING SHARES",
SwipePage::new(
paragraphs.into_paragraphs(),
theme::button_bar(Button::with_text("CONTINUE").map(|msg| {
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelConfirmMsg::Confirmed)
})),
theme::BG,
),
ButtonPage::<_, StrBuffer>::new(paragraphs.into_paragraphs(), theme::BG)
.with_cancel_confirm(None, Some("CONTINUE".into()))
.with_confirm_style(theme::button_default())
.without_cancel(),
))?;
Ok(obj.into())
};

View File

@ -1173,6 +1173,7 @@ async def confirm_signverify(
title,
message,
"Confirm message:",
hold=not verify,
br_code=BR_TYPE_OTHER,
)

View File

@ -262,7 +262,7 @@ class InputFlowShowAddressQRCode(InputFlowBase):
yield
self.debug.click(buttons.CORNER_BUTTON, wait=True)
# synchronize; TODO get rid of this once we have single-global-layout
self.debug.synchronize_at("HorizontalPage")
self.debug.synchronize_at("SimplePage")
self.debug.swipe_left(wait=True)
self.debug.swipe_right(wait=True)
@ -302,7 +302,7 @@ class InputFlowShowAddressQRCodeCancel(InputFlowBase):
yield
self.debug.click(buttons.CORNER_BUTTON, wait=True)
# synchronize; TODO get rid of this once we have single-global-layout
self.debug.synchronize_at("HorizontalPage")
self.debug.synchronize_at("SimplePage")
self.debug.swipe_left(wait=True)
self.debug.click(buttons.CORNER_BUTTON, wait=True)
@ -427,7 +427,7 @@ class InputFlowShowXpubQRCode(InputFlowBase):
self.debug.click(buttons.CORNER_BUTTON, wait=True)
# synchronize; TODO get rid of this once we have single-global-layout
self.debug.synchronize_at("HorizontalPage")
self.debug.synchronize_at("SimplePage")
self.debug.swipe_left(wait=True)
self.debug.swipe_right(wait=True)

File diff suppressed because it is too large Load Diff