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:
parent
4f2c639ed7
commit
d8e7c00087
1
core/.changelog.d/2888.changed
Normal file
1
core/.changelog.d/2888.changed
Normal file
@ -0,0 +1 @@
|
|||||||
|
[T2T1] Adjust buttons used for scrolling multipage content.
|
@ -24,7 +24,7 @@ pub use map::MsgMap;
|
|||||||
pub use marquee::Marquee;
|
pub use marquee::Marquee;
|
||||||
pub use maybe::Maybe;
|
pub use maybe::Maybe;
|
||||||
pub use pad::Pad;
|
pub use pad::Pad;
|
||||||
pub use paginated::{AuxPageMsg, PageMsg, Paginate};
|
pub use paginated::{PageMsg, Paginate};
|
||||||
pub use painter::Painter;
|
pub use painter::Painter;
|
||||||
pub use placed::{FixedHeightBar, Floating, GridPlaced, Split};
|
pub use placed::{FixedHeightBar, Floating, GridPlaced, Split};
|
||||||
pub use qr_code::Qr;
|
pub use qr_code::Qr;
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
pub enum AuxPageMsg {
|
/// Common message type for pagination components.
|
||||||
/// Page component was instantiated with BACK button on every page and it
|
pub enum PageMsg<T> {
|
||||||
/// was pressed.
|
/// Pass-through from paged component.
|
||||||
GoBack,
|
Content(T),
|
||||||
|
|
||||||
|
/// Confirmed using page controls.
|
||||||
|
Confirmed,
|
||||||
|
|
||||||
|
/// Cancelled using page controls.
|
||||||
|
Cancelled,
|
||||||
|
|
||||||
/// Page component was configured to react to swipes and user swiped left.
|
/// Page component was configured to react to swipes and user swiped left.
|
||||||
SwipeLeft,
|
SwipeLeft,
|
||||||
@ -10,19 +16,6 @@ pub enum AuxPageMsg {
|
|||||||
SwipeRight,
|
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 {
|
pub trait Paginate {
|
||||||
/// How many pages of content are there in total?
|
/// How many pages of content are there in total?
|
||||||
fn page_count(&mut self) -> usize;
|
fn page_count(&mut self) -> usize;
|
||||||
|
@ -162,7 +162,7 @@ where
|
|||||||
T: Component + Paginate,
|
T: Component + Paginate,
|
||||||
U: StringType + Clone,
|
U: StringType + Clone,
|
||||||
{
|
{
|
||||||
type Msg = PageMsg<T::Msg, bool>;
|
type Msg = PageMsg<T::Msg>;
|
||||||
|
|
||||||
fn place(&mut self, bounds: Rect) -> Rect {
|
fn place(&mut self, bounds: Rect) -> Rect {
|
||||||
let (content_area, button_area) = bounds.split_bottom(theme::BUTTON_HEIGHT);
|
let (content_area, button_area) = bounds.split_bottom(theme::BUTTON_HEIGHT);
|
||||||
@ -191,7 +191,7 @@ where
|
|||||||
self.change_page(ctx);
|
self.change_page(ctx);
|
||||||
} else {
|
} else {
|
||||||
// Clicked CANCEL. Send result.
|
// Clicked CANCEL. Send result.
|
||||||
return Some(PageMsg::Controls(false));
|
return Some(PageMsg::Cancelled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ButtonPos::Right => {
|
ButtonPos::Right => {
|
||||||
@ -201,7 +201,7 @@ where
|
|||||||
self.change_page(ctx);
|
self.change_page(ctx);
|
||||||
} else {
|
} else {
|
||||||
// Clicked CONFIRM. Send result.
|
// Clicked CONFIRM. Send result.
|
||||||
return Some(PageMsg::Controls(true));
|
return Some(PageMsg::Confirmed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -93,10 +93,9 @@ where
|
|||||||
{
|
{
|
||||||
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
|
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
|
||||||
match msg {
|
match msg {
|
||||||
PageMsg::Content(_) => Err(Error::TypeError),
|
PageMsg::Confirmed => Ok(CONFIRMED.as_obj()),
|
||||||
PageMsg::Controls(true) => Ok(CONFIRMED.as_obj()),
|
PageMsg::Cancelled => Ok(CANCELLED.as_obj()),
|
||||||
PageMsg::Controls(false) => Ok(CANCELLED.as_obj()),
|
_ => Err(Error::TypeError),
|
||||||
PageMsg::Aux(_) => Err(Error::TypeError),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
|
||||||
}
|
|
@ -7,10 +7,8 @@ mod fido;
|
|||||||
mod fido_icons;
|
mod fido_icons;
|
||||||
mod error;
|
mod error;
|
||||||
mod frame;
|
mod frame;
|
||||||
mod hold_to_confirm;
|
|
||||||
#[cfg(feature = "micropython")]
|
#[cfg(feature = "micropython")]
|
||||||
mod homescreen;
|
mod homescreen;
|
||||||
mod horizontal_page;
|
|
||||||
mod keyboard;
|
mod keyboard;
|
||||||
mod loader;
|
mod loader;
|
||||||
mod number_input;
|
mod number_input;
|
||||||
@ -18,6 +16,7 @@ mod page;
|
|||||||
mod progress;
|
mod progress;
|
||||||
mod result;
|
mod result;
|
||||||
mod scroll;
|
mod scroll;
|
||||||
|
mod simple_page;
|
||||||
mod swipe;
|
mod swipe;
|
||||||
mod welcome_screen;
|
mod welcome_screen;
|
||||||
|
|
||||||
@ -31,10 +30,8 @@ pub use dialog::{Dialog, DialogMsg, IconDialog};
|
|||||||
pub use error::ErrorScreen;
|
pub use error::ErrorScreen;
|
||||||
pub use fido::{FidoConfirm, FidoMsg};
|
pub use fido::{FidoConfirm, FidoMsg};
|
||||||
pub use frame::{Frame, FrameMsg};
|
pub use frame::{Frame, FrameMsg};
|
||||||
pub use hold_to_confirm::{HoldToConfirm, HoldToConfirmMsg};
|
|
||||||
#[cfg(feature = "micropython")]
|
#[cfg(feature = "micropython")]
|
||||||
pub use homescreen::{Homescreen, HomescreenMsg, Lockscreen};
|
pub use homescreen::{Homescreen, HomescreenMsg, Lockscreen};
|
||||||
pub use horizontal_page::HorizontalPage;
|
|
||||||
pub use keyboard::{
|
pub use keyboard::{
|
||||||
bip39::Bip39Input,
|
bip39::Bip39Input,
|
||||||
mnemonic::{MnemonicInput, MnemonicKeyboard, MnemonicKeyboardMsg},
|
mnemonic::{MnemonicInput, MnemonicKeyboard, MnemonicKeyboardMsg},
|
||||||
@ -45,10 +42,11 @@ pub use keyboard::{
|
|||||||
};
|
};
|
||||||
pub use loader::{Loader, LoaderMsg, LoaderStyle, LoaderStyleSheet};
|
pub use loader::{Loader, LoaderMsg, LoaderStyle, LoaderStyleSheet};
|
||||||
pub use number_input::{NumberInputDialog, NumberInputDialogMsg};
|
pub use number_input::{NumberInputDialog, NumberInputDialogMsg};
|
||||||
pub use page::{SwipeHoldPage, SwipePage};
|
pub use page::ButtonPage;
|
||||||
pub use progress::Progress;
|
pub use progress::Progress;
|
||||||
pub use result::{ResultFooter, ResultScreen, ResultStyle};
|
pub use result::{ResultFooter, ResultScreen, ResultStyle};
|
||||||
pub use scroll::ScrollBar;
|
pub use scroll::ScrollBar;
|
||||||
|
pub use simple_page::SimplePage;
|
||||||
pub use swipe::{Swipe, SwipeDirection};
|
pub use swipe::{Swipe, SwipeDirection};
|
||||||
pub use welcome_screen::WelcomeScreen;
|
pub use welcome_screen::WelcomeScreen;
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -56,11 +56,17 @@ impl ScrollBar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn go_to_next_page(&mut self) {
|
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) {
|
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) {
|
pub fn go_to(&mut self, active_page: usize) {
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
use crate::ui::{
|
use crate::ui::{
|
||||||
component::{
|
component::{base::ComponentExt, Component, Event, EventCtx, Pad, PageMsg, Paginate},
|
||||||
base::ComponentExt, AuxPageMsg, Component, Event, EventCtx, Never, Pad, PageMsg, Paginate,
|
|
||||||
},
|
|
||||||
display::{self, Color},
|
display::{self, Color},
|
||||||
geometry::{Insets, Rect},
|
geometry::{Axis, Insets, Rect},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{theme, ScrollBar, Swipe, SwipeDirection};
|
use super::{theme, ScrollBar, Swipe, SwipeDirection};
|
||||||
@ -11,26 +9,40 @@ use super::{theme, ScrollBar, Swipe, SwipeDirection};
|
|||||||
const SCROLLBAR_HEIGHT: i16 = 18;
|
const SCROLLBAR_HEIGHT: i16 = 18;
|
||||||
const SCROLLBAR_BORDER: i16 = 4;
|
const SCROLLBAR_BORDER: i16 = 4;
|
||||||
|
|
||||||
pub struct HorizontalPage<T> {
|
pub struct SimplePage<T> {
|
||||||
content: T,
|
content: T,
|
||||||
pad: Pad,
|
pad: Pad,
|
||||||
swipe: Swipe,
|
swipe: Swipe,
|
||||||
scrollbar: ScrollBar,
|
scrollbar: ScrollBar,
|
||||||
|
axis: Axis,
|
||||||
swipe_right_to_go_back: bool,
|
swipe_right_to_go_back: bool,
|
||||||
fade: Option<u16>,
|
fade: Option<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> HorizontalPage<T>
|
impl<T> SimplePage<T>
|
||||||
where
|
where
|
||||||
T: Paginate,
|
T: Paginate,
|
||||||
T: Component,
|
T: Component,
|
||||||
{
|
{
|
||||||
pub fn new(content: T, background: Color) -> Self {
|
pub fn horizontal(content: T, background: Color) -> Self {
|
||||||
Self {
|
Self {
|
||||||
content,
|
content,
|
||||||
swipe: Swipe::new(),
|
swipe: Swipe::new(),
|
||||||
pad: Pad::with_background(background),
|
pad: Pad::with_background(background),
|
||||||
scrollbar: ScrollBar::horizontal(),
|
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,
|
swipe_right_to_go_back: false,
|
||||||
fade: None,
|
fade: None,
|
||||||
}
|
}
|
||||||
@ -46,11 +58,20 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn setup_swipe(&mut self) {
|
fn setup_swipe(&mut self) {
|
||||||
self.swipe.allow_left = self.scrollbar.has_next_page();
|
if self.is_horizontal() {
|
||||||
self.swipe.allow_right = self.scrollbar.has_previous_page() || self.swipe_right_to_go_back;
|
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.
|
// Adjust the swipe parameters according to the scrollbar.
|
||||||
self.setup_swipe();
|
self.setup_swipe();
|
||||||
|
|
||||||
@ -64,23 +85,43 @@ where
|
|||||||
// paint.
|
// paint.
|
||||||
self.fade = Some(theme::BACKLIGHT_NORMAL);
|
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
|
where
|
||||||
T: Paginate,
|
T: Paginate,
|
||||||
T: Component,
|
T: Component,
|
||||||
{
|
{
|
||||||
type Msg = PageMsg<T::Msg, Never>;
|
type Msg = PageMsg<T::Msg>;
|
||||||
|
|
||||||
fn place(&mut self, bounds: Rect) -> Rect {
|
fn place(&mut self, bounds: Rect) -> Rect {
|
||||||
self.swipe.place(bounds);
|
self.swipe.place(bounds);
|
||||||
|
|
||||||
let (content, scrollbar) = bounds.split_bottom(SCROLLBAR_HEIGHT + SCROLLBAR_BORDER);
|
let (content, scrollbar) = if self.is_horizontal() {
|
||||||
self.pad.place(content);
|
bounds.split_bottom(SCROLLBAR_HEIGHT + SCROLLBAR_BORDER)
|
||||||
self.content.place(content);
|
} else {
|
||||||
self.scrollbar
|
bounds.split_right(SCROLLBAR_HEIGHT + SCROLLBAR_BORDER)
|
||||||
.place(scrollbar.inset(Insets::bottom(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
|
self.scrollbar
|
||||||
.set_count_and_active_page(self.content.page_count(), 0);
|
.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> {
|
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
||||||
ctx.set_page_count(self.scrollbar.page_count);
|
ctx.set_page_count(self.scrollbar.page_count);
|
||||||
if let Some(swipe) = self.swipe.event(ctx, event) {
|
if let Some(swipe) = self.swipe.event(ctx, event) {
|
||||||
match swipe {
|
match (swipe, self.axis) {
|
||||||
SwipeDirection::Left => {
|
(SwipeDirection::Left, Axis::Horizontal) | (SwipeDirection::Up, Axis::Vertical) => {
|
||||||
self.scrollbar.go_to_next_page();
|
self.change_page(ctx, 1);
|
||||||
self.on_page_change(ctx);
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
SwipeDirection::Right => {
|
(SwipeDirection::Right, _)
|
||||||
if self.swipe_right_to_go_back && self.scrollbar.active_page == 0 {
|
if self.swipe_right_to_go_back && self.scrollbar.active_page == 0 =>
|
||||||
return Some(PageMsg::Aux(AuxPageMsg::GoBack));
|
{
|
||||||
}
|
return Some(PageMsg::Cancelled);
|
||||||
self.scrollbar.go_to_previous_page();
|
}
|
||||||
self.on_page_change(ctx);
|
(SwipeDirection::Right, Axis::Horizontal)
|
||||||
|
| (SwipeDirection::Down, Axis::Vertical) => {
|
||||||
|
self.change_page(ctx, -1);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@ -117,7 +159,9 @@ where
|
|||||||
fn paint(&mut self) {
|
fn paint(&mut self) {
|
||||||
self.pad.paint();
|
self.pad.paint();
|
||||||
self.content.paint();
|
self.content.paint();
|
||||||
self.scrollbar.paint();
|
if self.scrollbar.has_pages() {
|
||||||
|
self.scrollbar.paint();
|
||||||
|
}
|
||||||
if let Some(val) = self.fade.take() {
|
if let Some(val) = self.fade.take() {
|
||||||
// Note that this is blocking and takes some time.
|
// Note that this is blocking and takes some time.
|
||||||
display::fade_backlight(val);
|
display::fade_backlight(val);
|
||||||
@ -133,12 +177,12 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
#[cfg(feature = "ui_debug")]
|
||||||
impl<T> crate::trace::Trace for HorizontalPage<T>
|
impl<T> crate::trace::Trace for SimplePage<T>
|
||||||
where
|
where
|
||||||
T: crate::trace::Trace,
|
T: crate::trace::Trace,
|
||||||
{
|
{
|
||||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
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("active_page", self.scrollbar.active_page as i64);
|
||||||
t.int("page_count", self.scrollbar.page_count as i64);
|
t.int("page_count", self.scrollbar.page_count as i64);
|
||||||
t.child("content", &self.content);
|
t.child("content", &self.content);
|
@ -20,7 +20,7 @@ use crate::{
|
|||||||
component::{
|
component::{
|
||||||
base::ComponentExt,
|
base::ComponentExt,
|
||||||
image::BlendedImage,
|
image::BlendedImage,
|
||||||
paginated::{AuxPageMsg, PageMsg, Paginate},
|
paginated::{PageMsg, Paginate},
|
||||||
painter,
|
painter,
|
||||||
placed::GridPlaced,
|
placed::GridPlaced,
|
||||||
text::{
|
text::{
|
||||||
@ -48,13 +48,12 @@ use crate::{
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
component::{
|
component::{
|
||||||
AddressDetails, Bip39Input, Button, ButtonMsg, ButtonStyleSheet, CancelConfirmMsg,
|
AddressDetails, Bip39Input, Button, ButtonMsg, ButtonPage, ButtonStyleSheet,
|
||||||
CancelInfoConfirmMsg, CoinJoinProgress, Dialog, DialogMsg, FidoConfirm, FidoMsg, Frame,
|
CancelConfirmMsg, CancelInfoConfirmMsg, CoinJoinProgress, Dialog, DialogMsg, FidoConfirm,
|
||||||
FrameMsg, HoldToConfirm, HoldToConfirmMsg, Homescreen, HomescreenMsg, HorizontalPage,
|
FidoMsg, Frame, FrameMsg, Homescreen, HomescreenMsg, IconDialog, Lockscreen, MnemonicInput,
|
||||||
IconDialog, Lockscreen, MnemonicInput, MnemonicKeyboard, MnemonicKeyboardMsg,
|
MnemonicKeyboard, MnemonicKeyboardMsg, NumberInputDialog, NumberInputDialogMsg,
|
||||||
NumberInputDialog, NumberInputDialogMsg, PassphraseKeyboard, PassphraseKeyboardMsg,
|
PassphraseKeyboard, PassphraseKeyboardMsg, PinKeyboard, PinKeyboardMsg, Progress,
|
||||||
PinKeyboard, PinKeyboardMsg, Progress, SelectWordCount, SelectWordCountMsg, SelectWordMsg,
|
SelectWordCount, SelectWordCountMsg, SelectWordMsg, SimplePage, Slip39Input, WelcomeScreen,
|
||||||
Slip39Input, SwipeHoldPage, SwipePage, WelcomeScreen,
|
|
||||||
},
|
},
|
||||||
constant, theme,
|
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>
|
impl<T> ComponentMsgObj for PinKeyboard<T>
|
||||||
where
|
where
|
||||||
T: AsRef<str>,
|
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
|
where
|
||||||
T: Component + Paginate,
|
T: Component + Paginate,
|
||||||
U: Component,
|
U: AsRef<str> + From<&'static str>,
|
||||||
<U as Component>::Msg: TryInto<Obj, Error = Error>,
|
|
||||||
{
|
{
|
||||||
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
|
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
|
||||||
match msg {
|
match msg {
|
||||||
PageMsg::Content(_) => Err(Error::TypeError),
|
PageMsg::Content(_) => Err(Error::TypeError),
|
||||||
PageMsg::Controls(msg) => msg.try_into(),
|
PageMsg::Confirmed => Ok(CONFIRMED.as_obj()),
|
||||||
PageMsg::Aux(AuxPageMsg::GoBack) => Ok(CANCELLED.as_obj()),
|
PageMsg::Cancelled => Ok(CANCELLED.as_obj()),
|
||||||
PageMsg::Aux(AuxPageMsg::SwipeLeft) => Ok(INFO.as_obj()),
|
PageMsg::SwipeLeft => Ok(INFO.as_obj()),
|
||||||
PageMsg::Aux(AuxPageMsg::SwipeRight) => Ok(CANCELLED.as_obj()),
|
PageMsg::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()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -361,16 +331,15 @@ impl ComponentMsgObj for Qr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ComponentMsgObj for HorizontalPage<T>
|
impl<T> ComponentMsgObj for SimplePage<T>
|
||||||
where
|
where
|
||||||
T: ComponentMsgObj + Paginate,
|
T: ComponentMsgObj + Paginate,
|
||||||
{
|
{
|
||||||
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
|
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
|
||||||
match msg {
|
match msg {
|
||||||
PageMsg::Content(inner_msg) => Ok(self.inner().msg_try_into_obj(inner_msg)?),
|
PageMsg::Content(inner_msg) => Ok(self.inner().msg_try_into_obj(inner_msg)?),
|
||||||
PageMsg::Controls(_) => Err(Error::TypeError),
|
PageMsg::Cancelled => Ok(CANCELLED.as_obj()),
|
||||||
PageMsg::Aux(AuxPageMsg::GoBack) => Ok(CANCELLED.as_obj()),
|
_ => Err(Error::TypeError),
|
||||||
PageMsg::Aux(_) => 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()
|
paragraphs.into_paragraphs()
|
||||||
};
|
};
|
||||||
|
|
||||||
let obj = if hold {
|
let mut page = if hold {
|
||||||
let page = if hold_danger {
|
ButtonPage::new(paragraphs, theme::BG).with_hold()
|
||||||
SwipeHoldPage::with_danger(paragraphs, theme::BG)
|
|
||||||
} else {
|
|
||||||
SwipeHoldPage::new(paragraphs, theme::BG)
|
|
||||||
};
|
|
||||||
LayoutObj::new(Frame::left_aligned(theme::label_title(), title, page))?
|
|
||||||
} else {
|
} else {
|
||||||
let buttons = Button::cancel_confirm_text(verb_cancel, verb);
|
ButtonPage::new(paragraphs, theme::BG).with_cancel_confirm(verb_cancel, verb)
|
||||||
LayoutObj::new(Frame::left_aligned(
|
|
||||||
theme::label_title(),
|
|
||||||
title,
|
|
||||||
SwipePage::new(paragraphs, buttons, theme::BG).with_cancel_on_first_page(),
|
|
||||||
))?
|
|
||||||
};
|
};
|
||||||
|
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())
|
Ok(obj.into())
|
||||||
};
|
};
|
||||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
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(
|
let obj = LayoutObj::new(Frame::left_aligned(
|
||||||
theme::label_title(),
|
theme::label_title(),
|
||||||
title,
|
title,
|
||||||
SwipePage::new(
|
ButtonPage::new(FormattedText::new(ops).vertically_centered(), theme::BG)
|
||||||
FormattedText::new(ops).vertically_centered(),
|
.with_cancel_confirm(None, verb),
|
||||||
buttons,
|
|
||||||
theme::BG,
|
|
||||||
),
|
|
||||||
))?;
|
))?;
|
||||||
Ok(obj.into())
|
Ok(obj.into())
|
||||||
};
|
};
|
||||||
@ -558,36 +517,21 @@ impl ConfirmBlobParams {
|
|||||||
}
|
}
|
||||||
.into_paragraphs();
|
.into_paragraphs();
|
||||||
|
|
||||||
let obj = if self.hold {
|
let page: ButtonPage<_, StrBuffer> = if self.hold {
|
||||||
let mut frame = Frame::left_aligned(
|
ButtonPage::new(paragraphs, theme::BG).with_hold()
|
||||||
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)?
|
|
||||||
} else if let Some(verb) = self.verb {
|
} else if let Some(verb) = self.verb {
|
||||||
let buttons = Button::cancel_confirm_text(self.verb_cancel, Some(verb));
|
ButtonPage::new(paragraphs, theme::BG).with_cancel_confirm(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)?
|
|
||||||
} else {
|
} else {
|
||||||
panic!("Either `hold=true` or `verb=Some(StrBuffer)` must be specified");
|
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())
|
Ok(obj.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -649,14 +593,13 @@ extern "C" fn new_confirm_address(n_args: usize, args: *const Obj, kwargs: *mut
|
|||||||
}
|
}
|
||||||
.into_paragraphs();
|
.into_paragraphs();
|
||||||
|
|
||||||
let buttons = Button::cancel_confirm_text(None, Some("CONFIRM"));
|
|
||||||
let obj = LayoutObj::new(
|
let obj = LayoutObj::new(
|
||||||
Frame::left_aligned(
|
Frame::left_aligned(
|
||||||
theme::label_title(),
|
theme::label_title(),
|
||||||
title,
|
title,
|
||||||
SwipePage::new(paragraphs, buttons, theme::BG)
|
ButtonPage::new(paragraphs, theme::BG)
|
||||||
.with_swipe_left()
|
.with_swipe_left()
|
||||||
.with_cancel_on_first_page(),
|
.with_cancel_confirm(None, Some("CONFIRM")),
|
||||||
)
|
)
|
||||||
.with_info_button(),
|
.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,
|
||||||
&theme::TEXT_MONO,
|
&theme::TEXT_MONO,
|
||||||
)?;
|
)?;
|
||||||
let obj = if hold {
|
let page: ButtonPage<_, StrBuffer> = if hold {
|
||||||
LayoutObj::new(Frame::left_aligned(
|
ButtonPage::new(paragraphs.into_paragraphs(), theme::BG).with_hold()
|
||||||
theme::label_title(),
|
|
||||||
title,
|
|
||||||
SwipeHoldPage::new(paragraphs.into_paragraphs(), theme::BG),
|
|
||||||
))?
|
|
||||||
} else {
|
} else {
|
||||||
let buttons = Button::cancel_confirm_text(None, Some("CONFIRM"));
|
ButtonPage::new(paragraphs.into_paragraphs(), theme::BG)
|
||||||
LayoutObj::new(Frame::left_aligned(
|
.with_cancel_confirm(None, Some("CONFIRM".into()))
|
||||||
theme::label_title(),
|
|
||||||
title,
|
|
||||||
SwipePage::new(paragraphs.into_paragraphs(), buttons, theme::BG)
|
|
||||||
.with_cancel_on_first_page(),
|
|
||||||
))?
|
|
||||||
};
|
};
|
||||||
|
let obj = LayoutObj::new(Frame::left_aligned(theme::label_title(), title, page))?;
|
||||||
Ok(obj.into())
|
Ok(obj.into())
|
||||||
};
|
};
|
||||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
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)?;
|
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())
|
Ok(obj.into())
|
||||||
};
|
};
|
||||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
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(
|
Frame::left_aligned(
|
||||||
theme::label_title(),
|
theme::label_title(),
|
||||||
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(),
|
.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_NORMAL, label));
|
||||||
paragraphs.add(Paragraph::new(&theme::TEXT_MONO, value));
|
paragraphs.add(Paragraph::new(&theme::TEXT_MONO, value));
|
||||||
}
|
}
|
||||||
let mut page = if cancel_arrow {
|
let mut page: ButtonPage<_, StrBuffer> =
|
||||||
SwipeHoldPage::with_cancel_arrow(paragraphs.into_paragraphs(), theme::BG)
|
ButtonPage::new(paragraphs.into_paragraphs(), theme::BG).with_hold();
|
||||||
} else {
|
if cancel_arrow {
|
||||||
SwipeHoldPage::new(paragraphs.into_paragraphs(), theme::BG)
|
page = page.with_cancel_arrow()
|
||||||
};
|
}
|
||||||
if info_button {
|
if info_button {
|
||||||
page = page.with_swipe_left();
|
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),
|
Paragraph::new(&theme::TEXT_MONO, amount_new),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let buttons = Button::cancel_confirm_text(Some("^"), Some("CONTINUE"));
|
|
||||||
let obj = LayoutObj::new(Frame::left_aligned(
|
let obj = LayoutObj::new(Frame::left_aligned(
|
||||||
theme::label_title(),
|
theme::label_title(),
|
||||||
"MODIFY AMOUNT",
|
"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())
|
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(
|
Frame::left_aligned(
|
||||||
theme::label_title(),
|
theme::label_title(),
|
||||||
title,
|
title,
|
||||||
SwipeHoldPage::new(paragraphs, theme::BG).with_swipe_left(),
|
ButtonPage::<_, StrBuffer>::new(paragraphs, theme::BG)
|
||||||
|
.with_hold()
|
||||||
|
.with_swipe_left(),
|
||||||
)
|
)
|
||||||
.with_info_button(),
|
.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));
|
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(
|
let obj = LayoutObj::new(Frame::left_aligned(
|
||||||
theme::label_title(),
|
theme::label_title(),
|
||||||
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())
|
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(
|
let obj = LayoutObj::new(Frame::left_aligned(
|
||||||
theme::label_title(),
|
theme::label_title(),
|
||||||
"AUTHORIZE COINJOIN",
|
"AUTHORIZE COINJOIN",
|
||||||
SwipeHoldPage::new(paragraphs, theme::BG),
|
ButtonPage::<_, StrBuffer>::new(paragraphs, theme::BG).with_hold(),
|
||||||
))?;
|
))?;
|
||||||
Ok(obj.into())
|
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 words: [StrBuffer; 3] = iter_into_array(words_iterable)?;
|
||||||
|
|
||||||
let paragraphs = Paragraphs::new([Paragraph::new(&theme::TEXT_DEMIBOLD, description)]);
|
let paragraphs = Paragraphs::new([Paragraph::new(&theme::TEXT_DEMIBOLD, description)]);
|
||||||
let buttons = Button::select_word(words);
|
|
||||||
|
|
||||||
let obj = LayoutObj::new(Frame::left_aligned(
|
let obj = LayoutObj::new(Frame::left_aligned(
|
||||||
theme::label_title(),
|
theme::label_title(),
|
||||||
title,
|
title,
|
||||||
SwipePage::new(paragraphs, buttons, theme::BG),
|
Dialog::new(paragraphs, Button::select_word(words)),
|
||||||
))?;
|
))?;
|
||||||
Ok(obj.into())
|
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(
|
let obj = LayoutObj::new(Frame::left_aligned(
|
||||||
theme::label_title(),
|
theme::label_title(),
|
||||||
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())
|
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(
|
let obj = LayoutObj::new(Frame::left_aligned(
|
||||||
theme::label_title(),
|
theme::label_title(),
|
||||||
"REMAINING SHARES",
|
"REMAINING SHARES",
|
||||||
SwipePage::new(
|
ButtonPage::<_, StrBuffer>::new(paragraphs.into_paragraphs(), theme::BG)
|
||||||
paragraphs.into_paragraphs(),
|
.with_cancel_confirm(None, Some("CONTINUE".into()))
|
||||||
theme::button_bar(Button::with_text("CONTINUE").map(|msg| {
|
.with_confirm_style(theme::button_default())
|
||||||
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelConfirmMsg::Confirmed)
|
.without_cancel(),
|
||||||
})),
|
|
||||||
theme::BG,
|
|
||||||
),
|
|
||||||
))?;
|
))?;
|
||||||
Ok(obj.into())
|
Ok(obj.into())
|
||||||
};
|
};
|
||||||
|
@ -1173,6 +1173,7 @@ async def confirm_signverify(
|
|||||||
title,
|
title,
|
||||||
message,
|
message,
|
||||||
"Confirm message:",
|
"Confirm message:",
|
||||||
|
hold=not verify,
|
||||||
br_code=BR_TYPE_OTHER,
|
br_code=BR_TYPE_OTHER,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -262,7 +262,7 @@ class InputFlowShowAddressQRCode(InputFlowBase):
|
|||||||
yield
|
yield
|
||||||
self.debug.click(buttons.CORNER_BUTTON, wait=True)
|
self.debug.click(buttons.CORNER_BUTTON, wait=True)
|
||||||
# synchronize; TODO get rid of this once we have single-global-layout
|
# 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_left(wait=True)
|
||||||
self.debug.swipe_right(wait=True)
|
self.debug.swipe_right(wait=True)
|
||||||
@ -302,7 +302,7 @@ class InputFlowShowAddressQRCodeCancel(InputFlowBase):
|
|||||||
yield
|
yield
|
||||||
self.debug.click(buttons.CORNER_BUTTON, wait=True)
|
self.debug.click(buttons.CORNER_BUTTON, wait=True)
|
||||||
# synchronize; TODO get rid of this once we have single-global-layout
|
# 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_left(wait=True)
|
||||||
self.debug.click(buttons.CORNER_BUTTON, 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)
|
self.debug.click(buttons.CORNER_BUTTON, wait=True)
|
||||||
# synchronize; TODO get rid of this once we have single-global-layout
|
# 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_left(wait=True)
|
||||||
self.debug.swipe_right(wait=True)
|
self.debug.swipe_right(wait=True)
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user