mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-30 10:08:18 +00:00
refactor(core/rust): refactor SwipeFlow
* remove SwipeStore in favor of Vec<dyn FlowComponent> * unify state and controllers * implement tighter coupling between controller/states and pages of the flow
This commit is contained in:
parent
4c10a4f643
commit
3fcb0acaff
@ -1,5 +1,4 @@
|
||||
use crate::ui::component::{swipe_detect::SwipeConfig, SwipeDirection};
|
||||
use num_traits::ToPrimitive;
|
||||
|
||||
pub trait Swipable {
|
||||
fn get_swipe_config(&self) -> SwipeConfig;
|
||||
@ -22,20 +21,20 @@ pub enum FlowMsg {
|
||||
|
||||
/// Composable event handler result.
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Decision<Q> {
|
||||
pub enum Decision {
|
||||
/// Do nothing, continue with processing next handler.
|
||||
Nothing,
|
||||
|
||||
/// Initiate transition to another state, end event processing.
|
||||
/// NOTE: it might make sense to include Option<ButtonRequest> here
|
||||
Goto(Q, SwipeDirection),
|
||||
Transition(SwipeDirection),
|
||||
|
||||
/// Yield a message to the caller of the flow (i.e. micropython), end event
|
||||
/// processing.
|
||||
Return(FlowMsg),
|
||||
}
|
||||
|
||||
impl<Q> Decision<Q> {
|
||||
impl Decision {
|
||||
pub fn or_else(self, func: impl FnOnce() -> Self) -> Self {
|
||||
match self {
|
||||
Decision::Nothing => func(),
|
||||
@ -44,24 +43,71 @@ impl<Q> Decision<Q> {
|
||||
}
|
||||
}
|
||||
|
||||
/// State transition type.
|
||||
///
|
||||
/// Contains a new state (by convention it must be of the same concrete type as
|
||||
/// the current one) and a Decision object that tells the flow what to do next.
|
||||
pub type StateChange = (&'static dyn FlowState, Decision);
|
||||
|
||||
/// Encodes the flow logic as a set of states, and transitions between them
|
||||
/// triggered by events and swipes.
|
||||
pub trait FlowState
|
||||
where
|
||||
Self: Sized + Copy + Eq + ToPrimitive,
|
||||
{
|
||||
/// There needs to be a mapping from states to indices of the FlowStore
|
||||
/// array. Default implementation works for states that are enums, the
|
||||
/// FlowStore has to have number of elements equal to number of states.
|
||||
fn index(&self) -> usize {
|
||||
unwrap!(self.to_usize())
|
||||
}
|
||||
|
||||
pub trait FlowState {
|
||||
/// What to do when user swipes on screen and current component doesn't
|
||||
/// respond to swipe of that direction.
|
||||
fn handle_swipe(&self, direction: SwipeDirection) -> Decision<Self>;
|
||||
///
|
||||
/// By convention, the type of the new state inside the state change must be
|
||||
/// Self. This can't be enforced by the type system unfortunately, because
|
||||
/// this trait must remain object-safe and so can't refer to Self.
|
||||
fn handle_swipe(&'static self, direction: SwipeDirection) -> StateChange;
|
||||
|
||||
/// What to do when the current component emits a message in response to an
|
||||
/// event.
|
||||
fn handle_event(&self, msg: FlowMsg) -> Decision<Self>;
|
||||
///
|
||||
/// By convention, the type of the new state inside the state change must be
|
||||
/// Self. This can't be enforced by the type system unfortunately, because
|
||||
/// this trait must remain object-safe and so can't refer to Self.
|
||||
fn handle_event(&'static self, msg: FlowMsg) -> StateChange;
|
||||
|
||||
/// Page index of the current state.
|
||||
fn index(&'static self) -> usize;
|
||||
}
|
||||
|
||||
/// Helper trait for writing nicer flow logic.
|
||||
pub trait DecisionBuilder: FlowState + Sized {
|
||||
#[inline]
|
||||
fn swipe(&'static self, direction: SwipeDirection) -> StateChange {
|
||||
(self, Decision::Transition(direction))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn swipe_left(&'static self) -> StateChange {
|
||||
self.swipe(SwipeDirection::Left)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn swipe_right(&'static self) -> StateChange {
|
||||
self.swipe(SwipeDirection::Right)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn swipe_up(&'static self) -> StateChange {
|
||||
self.swipe(SwipeDirection::Up)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn swipe_down(&'static self) -> StateChange {
|
||||
self.swipe(SwipeDirection::Down)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn do_nothing(&'static self) -> StateChange {
|
||||
(self, Decision::Nothing)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn return_msg(&'static self, msg: FlowMsg) -> StateChange {
|
||||
(self, Decision::Return(msg))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FlowState> DecisionBuilder for T {}
|
||||
|
@ -1,9 +1,7 @@
|
||||
pub mod base;
|
||||
pub mod page;
|
||||
mod store;
|
||||
mod swipe;
|
||||
|
||||
pub use base::{FlowMsg, FlowState, Swipable};
|
||||
pub use page::SwipePage;
|
||||
pub use store::{flow_store, FlowStore};
|
||||
pub use swipe::SwipeFlow;
|
||||
|
@ -1,190 +0,0 @@
|
||||
use crate::{
|
||||
error,
|
||||
maybe_trace::MaybeTrace,
|
||||
ui::{
|
||||
component::{Component, Event, EventCtx},
|
||||
flow::base::FlowMsg,
|
||||
geometry::Rect,
|
||||
shape::Renderer,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
micropython::gc::Gc,
|
||||
ui::{component::swipe_detect::SwipeConfig, flow::Swipable},
|
||||
};
|
||||
|
||||
/// `FlowStore` is essentially `Vec<Gc<dyn Component + SimpleSwipable>>` except
|
||||
/// that `trait Component` is not object-safe so it ends up being a kind of
|
||||
/// recursively-defined tuple.
|
||||
/// Implementors are something like the V in MVC.
|
||||
pub trait FlowStore {
|
||||
/// Call `Component::place` on all elements.
|
||||
fn place(&mut self, bounds: Rect) -> Rect;
|
||||
|
||||
/// Call `Component::event` on i-th element.
|
||||
fn event(&mut self, i: usize, ctx: &mut EventCtx, event: Event) -> Option<FlowMsg>;
|
||||
|
||||
/// Call `Component::render` on i-th element.
|
||||
fn render<'s>(&'s self, i: usize, target: &mut impl Renderer<'s>);
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
/// Call `Trace::trace` on i-th element.
|
||||
fn trace(&self, i: usize, t: &mut dyn crate::trace::Tracer);
|
||||
|
||||
/// Forward `SimpleSwipable` methods to i-th element.
|
||||
fn map_swipable<T>(&mut self, i: usize, func: impl FnOnce(&mut dyn Swipable) -> T) -> T;
|
||||
|
||||
fn get_swipe_config(&self, i: usize) -> SwipeConfig;
|
||||
|
||||
fn get_internal_page_count(&mut self, i: usize) -> usize;
|
||||
|
||||
/// Add a Component to the end of a `FlowStore`.
|
||||
fn add<E: Component<Msg = FlowMsg> + MaybeTrace + Swipable>(
|
||||
self,
|
||||
elem: E,
|
||||
) -> Result<impl FlowStore, error::Error>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
/// Create new empty flow store.
|
||||
pub fn flow_store() -> impl FlowStore {
|
||||
FlowEmpty {}
|
||||
}
|
||||
|
||||
/// Terminating element of a recursive structure.
|
||||
struct FlowEmpty;
|
||||
|
||||
// Methods that take an index panic because it's always out of bounds.
|
||||
impl FlowStore for FlowEmpty {
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
bounds
|
||||
}
|
||||
|
||||
fn event(&mut self, _i: usize, _ctx: &mut EventCtx, _event: Event) -> Option<FlowMsg> {
|
||||
panic!()
|
||||
}
|
||||
|
||||
fn render<'s>(&self, _i: usize, _target: &mut impl Renderer<'s>) {
|
||||
panic!()
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
fn trace(&self, _i: usize, _t: &mut dyn crate::trace::Tracer) {
|
||||
panic!()
|
||||
}
|
||||
|
||||
fn map_swipable<T>(&mut self, _i: usize, _func: impl FnOnce(&mut dyn Swipable) -> T) -> T {
|
||||
panic!()
|
||||
}
|
||||
|
||||
fn add<E: Component<Msg = FlowMsg> + MaybeTrace + Swipable>(
|
||||
self,
|
||||
elem: E,
|
||||
) -> Result<impl FlowStore, error::Error>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Ok(FlowComponent2 {
|
||||
elem: Gc::new(elem)?,
|
||||
next: Self,
|
||||
})
|
||||
}
|
||||
fn get_swipe_config(&self, _i: usize) -> SwipeConfig {
|
||||
SwipeConfig::new()
|
||||
}
|
||||
fn get_internal_page_count(&mut self, _i: usize) -> usize {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
struct FlowComponent2<E: Component<Msg = FlowMsg>, P> {
|
||||
/// Component allocated on micropython heap.
|
||||
pub elem: Gc<E>,
|
||||
|
||||
/// Nested FlowStore.
|
||||
pub next: P,
|
||||
}
|
||||
|
||||
impl<E: Component<Msg = FlowMsg>, P> FlowComponent2<E, P> {
|
||||
fn as_ref(&self) -> &E {
|
||||
&self.elem
|
||||
}
|
||||
|
||||
fn as_mut(&mut self) -> &mut E {
|
||||
// SAFETY: micropython can only access this object through LayoutObj which wraps
|
||||
// us in a RefCell which guarantees uniqueness
|
||||
unsafe { Gc::as_mut(&mut self.elem) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<E, P> FlowStore for FlowComponent2<E, P>
|
||||
where
|
||||
E: Component<Msg = FlowMsg> + MaybeTrace + Swipable,
|
||||
P: FlowStore,
|
||||
{
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.as_mut().place(bounds);
|
||||
self.next.place(bounds);
|
||||
bounds
|
||||
}
|
||||
|
||||
fn event(&mut self, i: usize, ctx: &mut EventCtx, event: Event) -> Option<FlowMsg> {
|
||||
if i == 0 {
|
||||
self.as_mut().event(ctx, event)
|
||||
} else {
|
||||
self.next.event(i - 1, ctx, event)
|
||||
}
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, i: usize, target: &mut impl Renderer<'s>) {
|
||||
if i == 0 {
|
||||
self.as_ref().render(target)
|
||||
} else {
|
||||
self.next.render(i - 1, target)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
fn trace(&self, i: usize, t: &mut dyn crate::trace::Tracer) {
|
||||
if i == 0 {
|
||||
self.as_ref().trace(t)
|
||||
} else {
|
||||
self.next.trace(i - 1, t)
|
||||
}
|
||||
}
|
||||
|
||||
fn map_swipable<T>(&mut self, i: usize, func: impl FnOnce(&mut dyn Swipable) -> T) -> T {
|
||||
if i == 0 {
|
||||
func(self.as_mut())
|
||||
} else {
|
||||
self.next.map_swipable(i - 1, func)
|
||||
}
|
||||
}
|
||||
|
||||
fn add<F: Component<Msg = FlowMsg> + MaybeTrace + Swipable>(
|
||||
self,
|
||||
elem: F,
|
||||
) -> Result<impl FlowStore, error::Error>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Ok(FlowComponent2 {
|
||||
elem: self.elem,
|
||||
next: self.next.add(elem)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn get_swipe_config(&self, i: usize) -> SwipeConfig {
|
||||
if i == 0 {
|
||||
self.as_ref().get_swipe_config()
|
||||
} else {
|
||||
self.next.get_swipe_config(i - 1)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_internal_page_count(&mut self, i: usize) -> usize {
|
||||
self.map_swipable(i, |swipable| swipable.get_internal_page_count())
|
||||
}
|
||||
}
|
@ -1,29 +1,103 @@
|
||||
use crate::{
|
||||
error,
|
||||
error::{self, Error},
|
||||
maybe_trace::MaybeTrace,
|
||||
micropython::{
|
||||
gc::{self, GcBox},
|
||||
obj::Obj,
|
||||
},
|
||||
ui::{
|
||||
component::{
|
||||
base::AttachType, swipe_detect::SwipeSettings, Component, Event, EventCtx, SwipeDetect,
|
||||
SwipeDetectMsg, SwipeDirection,
|
||||
},
|
||||
display::Color,
|
||||
event::{SwipeEvent, TouchEvent},
|
||||
flow::{base::Decision, FlowMsg, FlowState, FlowStore},
|
||||
flow::{base::Decision, FlowMsg, FlowState},
|
||||
geometry::Rect,
|
||||
shape::Renderer,
|
||||
layout::obj::ObjComponent,
|
||||
shape::{render_on_display, ConcreteRenderer, Renderer, ScopedRenderer},
|
||||
util::animation_disabled,
|
||||
},
|
||||
};
|
||||
|
||||
/// Given a state enum and a corresponding FlowStore, create a Component that
|
||||
/// implements a swipe navigation between the states with animated transitions.
|
||||
use super::{base::StateChange, Swipable};
|
||||
|
||||
use heapless::Vec;
|
||||
|
||||
/// Component-like proto-object-safe trait.
|
||||
///
|
||||
/// This copies the Component interface, but it is parametrized by a concrete
|
||||
/// Renderer type, making it object-safe.
|
||||
pub trait FlowComponentTrait<'s, R: Renderer<'s>>: Swipable {
|
||||
fn place(&mut self, bounds: Rect) -> Rect;
|
||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<FlowMsg>;
|
||||
fn render(&'s self, target: &mut R);
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
fn trace(&self, t: &mut dyn crate::trace::Tracer);
|
||||
}
|
||||
|
||||
/// FlowComponentTrait implementation for Components.
|
||||
///
|
||||
/// Components implementing FlowComponentTrait must:
|
||||
/// * also implement Swipable, required by FlowComponentTrait,
|
||||
/// * use FlowMsg as their Msg type,
|
||||
/// * implement MaybeTrace to be able to conform to ObjComponent.
|
||||
impl<'s, R, C> FlowComponentTrait<'s, R> for C
|
||||
where
|
||||
C: Component<Msg = FlowMsg> + MaybeTrace + Swipable,
|
||||
R: Renderer<'s>,
|
||||
{
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
<Self as Component>::place(self, bounds)
|
||||
}
|
||||
|
||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<FlowMsg> {
|
||||
<Self as Component>::event(self, ctx, event)
|
||||
}
|
||||
|
||||
fn render(&'s self, target: &mut R) {
|
||||
<Self as Component>::render(self, target)
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||
<Self as crate::trace::Trace>::trace(self, t)
|
||||
}
|
||||
}
|
||||
|
||||
/// Shortcut type for the concrete renderer passed into `render()` method.
|
||||
type RendererImpl<'a, 'alloc, 'env> = ScopedRenderer<'alloc, 'env, ConcreteRenderer<'a, 'alloc>>;
|
||||
|
||||
/// Fully object-safe component-like trait for flow components.
|
||||
///
|
||||
/// This trait has no generic parameters:
|
||||
/// * it is instantiated with a concrete Renderer type, and
|
||||
/// * it requires the `FlowComponentTrait` trait to be implemented for _any_
|
||||
/// lifetimes.
|
||||
pub trait FlowComponentDynTrait:
|
||||
for<'a, 'alloc, 'env> FlowComponentTrait<'alloc, RendererImpl<'a, 'alloc, 'env>>
|
||||
{
|
||||
}
|
||||
|
||||
impl<T> FlowComponentDynTrait for T where
|
||||
T: for<'a, 'alloc, 'env> FlowComponentTrait<'alloc, RendererImpl<'a, 'alloc, 'env>>
|
||||
{
|
||||
}
|
||||
|
||||
/// Swipe flow consisting of multiple screens.
|
||||
///
|
||||
/// Implements swipe navigation between the states with animated transitions,
|
||||
/// based on state transitions provided by the FlowState type.
|
||||
///
|
||||
/// If a swipe is detected:
|
||||
/// - currently active component is asked to handle the event,
|
||||
/// - if it can't then FlowState::handle_swipe is consulted.
|
||||
pub struct SwipeFlow<Q, S> {
|
||||
/// Current state.
|
||||
state: Q,
|
||||
/// FlowStore with all screens/components.
|
||||
store: S,
|
||||
pub struct SwipeFlow {
|
||||
/// Current state of the flow.
|
||||
state: &'static dyn FlowState,
|
||||
/// Store of all screens which are part of the flow.
|
||||
store: Vec<GcBox<dyn FlowComponentDynTrait>, 10>,
|
||||
/// Swipe detector.
|
||||
swipe: SwipeDetect,
|
||||
/// Swipe allowed
|
||||
@ -34,33 +108,53 @@ pub struct SwipeFlow<Q, S> {
|
||||
internal_pages: u16,
|
||||
/// If triggering swipe by event, make this decision instead of default
|
||||
/// after the swipe.
|
||||
decision_override: Option<Decision<Q>>,
|
||||
decision_override: Option<StateChange>,
|
||||
}
|
||||
|
||||
impl<Q: FlowState, S: FlowStore> SwipeFlow<Q, S> {
|
||||
pub fn new(init: Q, store: S) -> Result<Self, error::Error> {
|
||||
impl SwipeFlow {
|
||||
pub fn new(initial_state: &'static dyn FlowState) -> Result<Self, error::Error> {
|
||||
Ok(Self {
|
||||
state: init,
|
||||
state: initial_state,
|
||||
swipe: SwipeDetect::new(),
|
||||
store,
|
||||
store: Vec::new(),
|
||||
allow_swipe: true,
|
||||
internal_state: 0,
|
||||
internal_pages: 1,
|
||||
decision_override: None,
|
||||
})
|
||||
}
|
||||
fn goto(&mut self, ctx: &mut EventCtx, direction: SwipeDirection, state: Q) {
|
||||
self.state = state;
|
||||
|
||||
/// Add a page to the flow.
|
||||
///
|
||||
/// Pages must be inserted in the order of the flow state index.
|
||||
pub fn with_page(
|
||||
mut self,
|
||||
state: &'static dyn FlowState,
|
||||
page: impl FlowComponentDynTrait + 'static,
|
||||
) -> Result<Self, error::Error> {
|
||||
debug_assert!(self.store.len() == state.index());
|
||||
let alloc = GcBox::new(page)?;
|
||||
let page = gc::coerce!(FlowComponentDynTrait, alloc);
|
||||
unwrap!(self.store.push(page));
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn current_page(&self) -> &GcBox<dyn FlowComponentDynTrait> {
|
||||
&self.store[self.state.index()]
|
||||
}
|
||||
|
||||
fn current_page_mut(&mut self) -> &mut GcBox<dyn FlowComponentDynTrait> {
|
||||
&mut self.store[self.state.index()]
|
||||
}
|
||||
|
||||
fn goto(&mut self, ctx: &mut EventCtx, direction: SwipeDirection) {
|
||||
self.swipe = SwipeDetect::new();
|
||||
self.allow_swipe = true;
|
||||
|
||||
self.store.event(
|
||||
state.index(),
|
||||
ctx,
|
||||
Event::Attach(AttachType::Swipe(direction)),
|
||||
);
|
||||
self.current_page_mut()
|
||||
.event(ctx, Event::Attach(AttachType::Swipe(direction)));
|
||||
|
||||
self.internal_pages = self.store.get_internal_page_count(state.index()) as u16;
|
||||
self.internal_pages = self.current_page_mut().get_internal_page_count() as u16;
|
||||
|
||||
match direction {
|
||||
SwipeDirection::Up => {
|
||||
@ -75,46 +169,43 @@ impl<Q: FlowState, S: FlowStore> SwipeFlow<Q, S> {
|
||||
ctx.request_paint();
|
||||
}
|
||||
|
||||
fn render_state<'s>(&'s self, state: Q, target: &mut impl Renderer<'s>) {
|
||||
self.store.render(state.index(), target)
|
||||
fn render_state<'s>(&'s self, state: usize, target: &mut RendererImpl<'_, 's, '_>) {
|
||||
self.store[state].render(target);
|
||||
}
|
||||
|
||||
fn handle_swipe_child(
|
||||
&mut self,
|
||||
_ctx: &mut EventCtx,
|
||||
direction: SwipeDirection,
|
||||
) -> Decision<Q> {
|
||||
) -> StateChange {
|
||||
self.state.handle_swipe(direction)
|
||||
}
|
||||
|
||||
fn handle_event_child(&mut self, ctx: &mut EventCtx, event: Event) -> Decision<Q> {
|
||||
let msg = self.store.event(self.state.index(), ctx, event);
|
||||
fn handle_event_child(&mut self, ctx: &mut EventCtx, event: Event) -> StateChange {
|
||||
let msg = self.current_page_mut().event(ctx, event);
|
||||
|
||||
if let Some(msg) = msg {
|
||||
self.state.handle_event(msg)
|
||||
} else {
|
||||
Decision::Nothing
|
||||
(self.state, Decision::Nothing)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Q: FlowState, S: FlowStore> Component for SwipeFlow<Q, S> {
|
||||
type Msg = FlowMsg;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.store.place(bounds)
|
||||
fn state_unchanged(&self) -> StateChange {
|
||||
(self.state, Decision::Nothing)
|
||||
}
|
||||
|
||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
||||
let mut decision: Decision<Q> = Decision::Nothing;
|
||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<FlowMsg> {
|
||||
let mut state_change = self.state_unchanged();
|
||||
let mut return_transition: AttachType = AttachType::Initial;
|
||||
|
||||
let mut attach = false;
|
||||
|
||||
let e = if self.allow_swipe {
|
||||
let mut config = self.store.get_swipe_config(self.state.index());
|
||||
let page = self.current_page();
|
||||
let mut config = page.get_swipe_config();
|
||||
|
||||
self.internal_pages = self.store.get_internal_page_count(self.state.index()) as u16;
|
||||
self.internal_pages = page.get_internal_page_count() as u16;
|
||||
|
||||
// add additional swipe directions if there are more internal pages
|
||||
// todo can we get internal settings from config somehow?
|
||||
@ -135,9 +226,9 @@ impl<Q: FlowState, S: FlowStore> Component for SwipeFlow<Q, S> {
|
||||
match self.swipe.event(ctx, event, config) {
|
||||
Some(SwipeDetectMsg::Trigger(dir)) => {
|
||||
if let Some(override_decision) = self.decision_override.take() {
|
||||
decision = override_decision;
|
||||
state_change = override_decision;
|
||||
} else {
|
||||
decision = self.handle_swipe_child(ctx, dir);
|
||||
state_change = self.handle_swipe_child(ctx, dir);
|
||||
}
|
||||
|
||||
return_transition = AttachType::Swipe(dir);
|
||||
@ -148,11 +239,11 @@ impl<Q: FlowState, S: FlowStore> Component for SwipeFlow<Q, S> {
|
||||
let current_state = self.internal_state;
|
||||
if dir == SwipeDirection::Left && current_state < states_num - 1 {
|
||||
self.internal_state += 1;
|
||||
decision = Decision::Nothing;
|
||||
state_change = self.state_unchanged();
|
||||
attach = true;
|
||||
} else if dir == SwipeDirection::Right && current_state > 0 {
|
||||
self.internal_state -= 1;
|
||||
decision = Decision::Nothing;
|
||||
state_change = self.state_unchanged();
|
||||
attach = true;
|
||||
}
|
||||
}
|
||||
@ -160,77 +251,75 @@ impl<Q: FlowState, S: FlowStore> Component for SwipeFlow<Q, S> {
|
||||
let current_state = self.internal_state;
|
||||
if dir == SwipeDirection::Up && current_state < states_num - 1 {
|
||||
self.internal_state += 1;
|
||||
decision = Decision::Nothing;
|
||||
state_change = self.state_unchanged();
|
||||
attach = true;
|
||||
} else if dir == SwipeDirection::Down && current_state > 0 {
|
||||
self.internal_state -= 1;
|
||||
decision = Decision::Nothing;
|
||||
state_change = self.state_unchanged();
|
||||
attach = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(Event::Swipe(SwipeEvent::End(dir)))
|
||||
Event::Swipe(SwipeEvent::End(dir))
|
||||
}
|
||||
Some(SwipeDetectMsg::Move(dir, progress)) => {
|
||||
Some(Event::Swipe(SwipeEvent::Move(dir, progress as i16)))
|
||||
Event::Swipe(SwipeEvent::Move(dir, progress as i16))
|
||||
}
|
||||
Some(SwipeDetectMsg::Start(_)) => Some(Event::Touch(TouchEvent::TouchAbort)),
|
||||
_ => Some(event),
|
||||
Some(SwipeDetectMsg::Start(_)) => Event::Touch(TouchEvent::TouchAbort),
|
||||
_ => event,
|
||||
}
|
||||
} else {
|
||||
Some(event)
|
||||
event
|
||||
};
|
||||
|
||||
if let Some(e) = e {
|
||||
match decision {
|
||||
Decision::Nothing => {
|
||||
decision = self.handle_event_child(ctx, e);
|
||||
match state_change {
|
||||
(_, Decision::Nothing) => {
|
||||
state_change = self.handle_event_child(ctx, e);
|
||||
|
||||
// when doing internal transition, pass attach event to the child after sending
|
||||
// swipe end.
|
||||
if attach {
|
||||
if let Event::Swipe(SwipeEvent::End(dir)) = e {
|
||||
self.store.event(
|
||||
self.state.index(),
|
||||
ctx,
|
||||
Event::Attach(AttachType::Swipe(dir)),
|
||||
);
|
||||
// when doing internal transition, pass attach event to the child after sending
|
||||
// swipe end.
|
||||
if attach {
|
||||
if let Event::Swipe(SwipeEvent::End(dir)) = e {
|
||||
self.current_page_mut()
|
||||
.event(ctx, Event::Attach(AttachType::Swipe(dir)));
|
||||
}
|
||||
}
|
||||
|
||||
if ctx.disable_swipe_requested() {
|
||||
self.swipe.reset();
|
||||
self.allow_swipe = false;
|
||||
}
|
||||
if ctx.enable_swipe_requested() {
|
||||
self.swipe.reset();
|
||||
self.allow_swipe = true;
|
||||
};
|
||||
|
||||
let config = self.current_page().get_swipe_config();
|
||||
|
||||
if let (_, Decision::Transition(direction)) = state_change {
|
||||
if config.is_allowed(direction) {
|
||||
if !animation_disabled() {
|
||||
self.swipe.trigger(ctx, direction, config);
|
||||
self.decision_override = Some(state_change);
|
||||
state_change = self.state_unchanged();
|
||||
}
|
||||
}
|
||||
|
||||
if ctx.disable_swipe_requested() {
|
||||
self.swipe.reset();
|
||||
self.allow_swipe = false;
|
||||
}
|
||||
if ctx.enable_swipe_requested() {
|
||||
self.swipe.reset();
|
||||
self.allow_swipe = true;
|
||||
};
|
||||
|
||||
let config = self.store.get_swipe_config(self.state.index());
|
||||
|
||||
if let Decision::Goto(_, direction) = decision {
|
||||
if config.is_allowed(direction) {
|
||||
if !animation_disabled() {
|
||||
self.swipe.trigger(ctx, direction, config);
|
||||
self.decision_override = Some(decision);
|
||||
decision = Decision::Nothing;
|
||||
}
|
||||
self.allow_swipe = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
//ignore message, we are already transitioning
|
||||
self.store.event(self.state.index(), ctx, event);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
//ignore message, we are already transitioning
|
||||
self.current_page_mut().event(ctx, event);
|
||||
}
|
||||
}
|
||||
|
||||
let (new_state, decision) = state_change;
|
||||
self.state = new_state;
|
||||
match decision {
|
||||
Decision::Goto(next_state, direction) => {
|
||||
self.goto(ctx, direction, next_state);
|
||||
Decision::Transition(direction) => {
|
||||
self.state = new_state;
|
||||
self.goto(ctx, direction);
|
||||
None
|
||||
}
|
||||
Decision::Return(msg) => {
|
||||
@ -242,34 +331,49 @@ impl<Q: FlowState, S: FlowStore> Component for SwipeFlow<Q, S> {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn paint(&mut self) {}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
self.render_state(self.state, target);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl<Q: FlowState, S: FlowStore> crate::trace::Trace for SwipeFlow<Q, S> {
|
||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||
self.store.trace(self.state.index(), t)
|
||||
}
|
||||
}
|
||||
|
||||
/// ObjComponent implementation for SwipeFlow.
|
||||
///
|
||||
/// Instead of using the generic `impl ObjComponent for ComponentMsgObj`, we
|
||||
/// provide our own short-circuit implementation for `SwipeFlow`. This way we
|
||||
/// can completely avoid implementing `Component`. That also allows us to pass
|
||||
/// around concrete Renderers instead of having to conform to `Component`'s
|
||||
/// not-object-safe interface.
|
||||
///
|
||||
/// This implementation relies on the fact that swipe components always return
|
||||
/// `FlowMsg` as their `Component::Msg` (provided by `impl FlowComponentTrait`
|
||||
/// earlier in this file).
|
||||
#[cfg(feature = "micropython")]
|
||||
impl<Q: FlowState, S: FlowStore> crate::ui::layout::obj::ComponentMsgObj for SwipeFlow<Q, S> {
|
||||
fn msg_try_into_obj(
|
||||
&self,
|
||||
msg: Self::Msg,
|
||||
) -> Result<crate::micropython::obj::Obj, error::Error> {
|
||||
match msg {
|
||||
FlowMsg::Confirmed => Ok(crate::ui::layout::result::CONFIRMED.as_obj()),
|
||||
FlowMsg::Cancelled => Ok(crate::ui::layout::result::CANCELLED.as_obj()),
|
||||
FlowMsg::Info => Ok(crate::ui::layout::result::INFO.as_obj()),
|
||||
FlowMsg::Choice(i) => {
|
||||
impl ObjComponent for SwipeFlow {
|
||||
fn obj_place(&mut self, bounds: Rect) -> Rect {
|
||||
for elem in self.store.iter_mut() {
|
||||
elem.place(bounds);
|
||||
}
|
||||
bounds
|
||||
}
|
||||
|
||||
fn obj_event(&mut self, ctx: &mut EventCtx, event: Event) -> Result<Obj, Error> {
|
||||
match self.event(ctx, event) {
|
||||
None => Ok(Obj::const_none()),
|
||||
Some(FlowMsg::Confirmed) => Ok(crate::ui::layout::result::CONFIRMED.as_obj()),
|
||||
Some(FlowMsg::Cancelled) => Ok(crate::ui::layout::result::CANCELLED.as_obj()),
|
||||
Some(FlowMsg::Info) => Ok(crate::ui::layout::result::INFO.as_obj()),
|
||||
Some(FlowMsg::Choice(i)) => {
|
||||
Ok((crate::ui::layout::result::CONFIRMED.as_obj(), i.try_into()?).try_into()?)
|
||||
}
|
||||
}
|
||||
}
|
||||
fn obj_paint(&mut self) {
|
||||
render_on_display(None, Some(Color::black()), |target| {
|
||||
self.render_state(self.state.index(), target);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl crate::trace::Trace for SwipeFlow {
|
||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||
self.current_page().trace(t)
|
||||
}
|
||||
}
|
||||
|
@ -319,8 +319,7 @@ impl LayoutObjInner {
|
||||
|
||||
impl LayoutObj {
|
||||
/// Create a new `LayoutObj`, wrapping a root component.
|
||||
#[inline(never)]
|
||||
pub fn new(root: impl ComponentMsgObj + MaybeTrace + 'static) -> Result<Gc<Self>, Error> {
|
||||
pub fn new(root: impl ObjComponent + 'static) -> Result<Gc<Self>, Error> {
|
||||
// SAFETY: This is a Python object and hase a base as first element
|
||||
unsafe {
|
||||
Gc::new_with_custom_finaliser(Self {
|
||||
|
@ -1,123 +1,101 @@
|
||||
use crate::{
|
||||
error,
|
||||
maybe_trace::MaybeTrace,
|
||||
micropython::{map::Map, obj::Obj, qstr::Qstr, util},
|
||||
strutil::TString,
|
||||
translations::TR,
|
||||
ui::{
|
||||
component::{text::paragraphs::Paragraph, ComponentExt, SwipeDirection},
|
||||
flow::{base::Decision, FlowMsg, FlowState, FlowStore},
|
||||
component::{
|
||||
swipe_detect::SwipeSettings,
|
||||
text::paragraphs::{Paragraph, ParagraphSource, ParagraphVecShort, VecExt},
|
||||
Component, ComponentExt, Paginate, SwipeDirection,
|
||||
},
|
||||
flow::{
|
||||
base::{DecisionBuilder as _, StateChange},
|
||||
FlowMsg, FlowState, SwipeFlow, SwipePage,
|
||||
},
|
||||
layout::obj::LayoutObj,
|
||||
},
|
||||
};
|
||||
|
||||
use super::super::{
|
||||
component::{Frame, FrameMsg, PromptScreen, VerticalMenu, VerticalMenuChoiceMsg},
|
||||
component::{Frame, FrameMsg, PromptScreen, SwipeContent, VerticalMenu, VerticalMenuChoiceMsg},
|
||||
theme,
|
||||
};
|
||||
|
||||
// TODO: merge with code from https://github.com/trezor/trezor-firmware/pull/3805
|
||||
// when ready
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, ToPrimitive)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum ConfirmAction {
|
||||
Intro,
|
||||
Menu,
|
||||
Confirm,
|
||||
}
|
||||
|
||||
impl FlowState for ConfirmAction {
|
||||
fn index(&'static self) -> usize {
|
||||
*self as usize
|
||||
}
|
||||
|
||||
fn handle_swipe(&'static self, direction: SwipeDirection) -> StateChange {
|
||||
match (self, direction) {
|
||||
(Self::Intro, SwipeDirection::Left) => Self::Menu.swipe(direction),
|
||||
(Self::Menu, SwipeDirection::Right) => Self::Intro.swipe(direction),
|
||||
(Self::Intro, SwipeDirection::Up) => Self::Confirm.swipe(direction),
|
||||
(Self::Confirm, SwipeDirection::Down) => Self::Intro.swipe(direction),
|
||||
(Self::Confirm, SwipeDirection::Left) => Self::Menu.swipe(direction),
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_event(&'static self, msg: FlowMsg) -> StateChange {
|
||||
match (self, msg) {
|
||||
(Self::Intro, FlowMsg::Info) => Self::Menu.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Cancelled) => Self::Intro.swipe_right(),
|
||||
(Self::Menu, FlowMsg::Choice(0)) => self.return_msg(FlowMsg::Cancelled),
|
||||
(Self::Menu, FlowMsg::Choice(1)) => self.return_msg(FlowMsg::Info),
|
||||
(Self::Confirm, FlowMsg::Confirmed) => self.return_msg(FlowMsg::Confirmed),
|
||||
(Self::Confirm, FlowMsg::Info) => Self::Menu.swipe_left(),
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// ConfirmAction flow without a separate "Tap to confirm" or "Hold to confirm"
|
||||
/// screen. Swiping up directly from the intro screen confirms action.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, ToPrimitive)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum ConfirmActionSimple {
|
||||
Intro,
|
||||
Menu,
|
||||
}
|
||||
|
||||
impl FlowState for ConfirmAction {
|
||||
fn handle_swipe(&self, direction: SwipeDirection) -> Decision<Self> {
|
||||
match (self, direction) {
|
||||
(ConfirmAction::Intro, SwipeDirection::Left) => {
|
||||
Decision::Goto(ConfirmAction::Menu, direction)
|
||||
}
|
||||
(ConfirmAction::Menu, SwipeDirection::Right) => {
|
||||
Decision::Goto(ConfirmAction::Intro, direction)
|
||||
}
|
||||
(ConfirmAction::Intro, SwipeDirection::Up) => {
|
||||
Decision::Goto(ConfirmAction::Confirm, direction)
|
||||
}
|
||||
(ConfirmAction::Confirm, SwipeDirection::Down) => {
|
||||
Decision::Goto(ConfirmAction::Intro, direction)
|
||||
}
|
||||
(ConfirmAction::Confirm, SwipeDirection::Left) => {
|
||||
Decision::Goto(ConfirmAction::Menu, direction)
|
||||
}
|
||||
_ => Decision::Nothing,
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_event(&self, msg: FlowMsg) -> Decision<Self> {
|
||||
match (self, msg) {
|
||||
(ConfirmAction::Intro, FlowMsg::Info) => {
|
||||
Decision::Goto(ConfirmAction::Menu, SwipeDirection::Left)
|
||||
}
|
||||
(ConfirmAction::Menu, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(ConfirmAction::Intro, SwipeDirection::Right)
|
||||
}
|
||||
(ConfirmAction::Menu, FlowMsg::Choice(0)) => Decision::Return(FlowMsg::Cancelled),
|
||||
(ConfirmAction::Menu, FlowMsg::Choice(1)) => Decision::Return(FlowMsg::Info),
|
||||
(ConfirmAction::Confirm, FlowMsg::Confirmed) => Decision::Return(FlowMsg::Confirmed),
|
||||
(ConfirmAction::Confirm, FlowMsg::Info) => {
|
||||
Decision::Goto(ConfirmAction::Menu, SwipeDirection::Left)
|
||||
}
|
||||
_ => Decision::Nothing,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FlowState for ConfirmActionSimple {
|
||||
fn handle_swipe(&self, direction: SwipeDirection) -> Decision<Self> {
|
||||
#[inline]
|
||||
fn index(&'static self) -> usize {
|
||||
*self as usize
|
||||
}
|
||||
|
||||
fn handle_swipe(&'static self, direction: SwipeDirection) -> StateChange {
|
||||
match (self, direction) {
|
||||
(ConfirmActionSimple::Intro, SwipeDirection::Left) => {
|
||||
Decision::Goto(ConfirmActionSimple::Menu, direction)
|
||||
}
|
||||
(ConfirmActionSimple::Menu, SwipeDirection::Right) => {
|
||||
Decision::Goto(ConfirmActionSimple::Intro, direction)
|
||||
}
|
||||
(ConfirmActionSimple::Intro, SwipeDirection::Up) => {
|
||||
Decision::Return(FlowMsg::Confirmed)
|
||||
}
|
||||
_ => Decision::Nothing,
|
||||
(Self::Intro, SwipeDirection::Left) => Self::Menu.swipe(direction),
|
||||
(Self::Menu, SwipeDirection::Right) => Self::Intro.swipe(direction),
|
||||
(Self::Intro, SwipeDirection::Up) => self.return_msg(FlowMsg::Confirmed),
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_event(&self, msg: FlowMsg) -> Decision<Self> {
|
||||
fn handle_event(&'static self, msg: FlowMsg) -> StateChange {
|
||||
match (self, msg) {
|
||||
(ConfirmActionSimple::Intro, FlowMsg::Info) => {
|
||||
Decision::Goto(ConfirmActionSimple::Menu, SwipeDirection::Left)
|
||||
}
|
||||
(ConfirmActionSimple::Menu, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(ConfirmActionSimple::Intro, SwipeDirection::Right)
|
||||
}
|
||||
(ConfirmActionSimple::Menu, FlowMsg::Choice(0)) => Decision::Return(FlowMsg::Cancelled),
|
||||
(ConfirmActionSimple::Menu, FlowMsg::Choice(1)) => Decision::Return(FlowMsg::Info),
|
||||
_ => Decision::Nothing,
|
||||
(Self::Intro, FlowMsg::Info) => Self::Menu.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Cancelled) => Self::Intro.swipe_right(),
|
||||
(Self::Menu, FlowMsg::Choice(0)) => self.return_msg(FlowMsg::Cancelled),
|
||||
(Self::Menu, FlowMsg::Choice(1)) => self.return_msg(FlowMsg::Info),
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use crate::{
|
||||
micropython::{map::Map, obj::Obj, qstr::Qstr, util},
|
||||
ui::{
|
||||
component::{
|
||||
swipe_detect::SwipeSettings,
|
||||
text::paragraphs::{ParagraphSource, ParagraphVecShort, VecExt},
|
||||
Component, Paginate,
|
||||
},
|
||||
flow::{flow_store, SwipeFlow, SwipePage},
|
||||
layout::obj::LayoutObj,
|
||||
model_mercury::component::SwipeContent,
|
||||
},
|
||||
};
|
||||
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
pub extern "C" fn new_confirm_action(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, new_confirm_action_obj) }
|
||||
@ -248,15 +226,15 @@ pub fn new_confirm_action_uni<T: Component + MaybeTrace + 'static>(
|
||||
FrameMsg::Button(_) => Some(FlowMsg::Info),
|
||||
});
|
||||
|
||||
let store = flow_store()
|
||||
.add(content_intro)?
|
||||
.add(content_menu)?
|
||||
.add(content_confirm)?;
|
||||
let res = SwipeFlow::new(ConfirmAction::Intro, store)?;
|
||||
let res = SwipeFlow::new(&ConfirmAction::Intro)?
|
||||
.with_page(&ConfirmAction::Intro, content_intro)?
|
||||
.with_page(&ConfirmAction::Menu, content_menu)?
|
||||
.with_page(&ConfirmAction::Confirm, content_confirm)?;
|
||||
Ok(LayoutObj::new(res)?.into())
|
||||
} else {
|
||||
let store = flow_store().add(content_intro)?.add(content_menu)?;
|
||||
let res = SwipeFlow::new(ConfirmActionSimple::Intro, store)?;
|
||||
let res = SwipeFlow::new(&ConfirmActionSimple::Intro)?
|
||||
.with_page(&ConfirmActionSimple::Intro, content_intro)?
|
||||
.with_page(&ConfirmActionSimple::Menu, content_menu)?;
|
||||
Ok(LayoutObj::new(res)?.into())
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,31 @@
|
||||
use crate::{
|
||||
error,
|
||||
micropython::qstr::Qstr,
|
||||
micropython::{map::Map, obj::Obj, qstr::Qstr, util},
|
||||
strutil::TString,
|
||||
translations::TR,
|
||||
ui::{
|
||||
button_request::ButtonRequest,
|
||||
component::{ButtonRequestExt, ComponentExt, SwipeDirection},
|
||||
flow::{base::Decision, flow_store, FlowMsg, FlowState, FlowStore, SwipeFlow},
|
||||
component::{swipe_detect::SwipeSettings, ButtonRequestExt, ComponentExt, SwipeDirection},
|
||||
flow::{
|
||||
base::{DecisionBuilder as _, StateChange},
|
||||
FlowMsg, FlowState, SwipeFlow,
|
||||
},
|
||||
layout::obj::LayoutObj,
|
||||
model_mercury::component::SwipeContent,
|
||||
},
|
||||
};
|
||||
|
||||
use super::super::{
|
||||
component::{
|
||||
AddressDetails, Frame, FrameMsg, PromptScreen, VerticalMenu, VerticalMenuChoiceMsg,
|
||||
use super::{
|
||||
super::{
|
||||
component::{
|
||||
AddressDetails, Frame, FrameMsg, PromptScreen, VerticalMenu, VerticalMenuChoiceMsg,
|
||||
},
|
||||
theme,
|
||||
},
|
||||
theme,
|
||||
util::ConfirmBlobParams,
|
||||
};
|
||||
|
||||
use super::util::ConfirmBlobParams;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, ToPrimitive)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum ConfirmOutput {
|
||||
Address,
|
||||
Amount,
|
||||
@ -30,58 +36,39 @@ pub enum ConfirmOutput {
|
||||
}
|
||||
|
||||
impl FlowState for ConfirmOutput {
|
||||
fn handle_swipe(&self, direction: SwipeDirection) -> Decision<Self> {
|
||||
#[inline]
|
||||
fn index(&'static self) -> usize {
|
||||
*self as usize
|
||||
}
|
||||
|
||||
fn handle_swipe(&'static self, direction: SwipeDirection) -> StateChange {
|
||||
match (self, direction) {
|
||||
(ConfirmOutput::Address | ConfirmOutput::Amount, SwipeDirection::Left) => {
|
||||
Decision::Goto(ConfirmOutput::Menu, direction)
|
||||
(Self::Address | Self::Amount, SwipeDirection::Left) => Self::Menu.swipe(direction),
|
||||
(Self::Address, SwipeDirection::Up) => Self::Amount.swipe(direction),
|
||||
(Self::Amount, SwipeDirection::Up) => self.return_msg(FlowMsg::Confirmed),
|
||||
(Self::Amount, SwipeDirection::Down) => Self::Address.swipe(direction),
|
||||
(Self::Menu, SwipeDirection::Right) => Self::Address.swipe(direction),
|
||||
(Self::Menu, SwipeDirection::Left) => Self::AccountInfo.swipe(direction),
|
||||
(Self::AccountInfo | Self::CancelTap, SwipeDirection::Right) => {
|
||||
Self::Menu.swipe(direction)
|
||||
}
|
||||
(ConfirmOutput::Address, SwipeDirection::Up) => {
|
||||
Decision::Goto(ConfirmOutput::Amount, direction)
|
||||
}
|
||||
(ConfirmOutput::Amount, SwipeDirection::Up) => Decision::Return(FlowMsg::Confirmed),
|
||||
(ConfirmOutput::Amount, SwipeDirection::Down) => {
|
||||
Decision::Goto(ConfirmOutput::Address, direction)
|
||||
}
|
||||
(ConfirmOutput::Menu, SwipeDirection::Right) => {
|
||||
Decision::Goto(ConfirmOutput::Address, direction)
|
||||
}
|
||||
(ConfirmOutput::Menu, SwipeDirection::Left) => {
|
||||
Decision::Goto(ConfirmOutput::AccountInfo, direction)
|
||||
}
|
||||
(ConfirmOutput::AccountInfo | ConfirmOutput::CancelTap, SwipeDirection::Right) => {
|
||||
Decision::Goto(ConfirmOutput::Menu, direction)
|
||||
}
|
||||
_ => Decision::Nothing,
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_event(&self, msg: FlowMsg) -> Decision<Self> {
|
||||
fn handle_event(&'static self, msg: FlowMsg) -> StateChange {
|
||||
match (self, msg) {
|
||||
(_, FlowMsg::Info) => Decision::Goto(ConfirmOutput::Menu, SwipeDirection::Left),
|
||||
(ConfirmOutput::Menu, FlowMsg::Choice(0)) => {
|
||||
Decision::Goto(ConfirmOutput::AccountInfo, SwipeDirection::Left)
|
||||
}
|
||||
(ConfirmOutput::Menu, FlowMsg::Choice(1)) => {
|
||||
Decision::Goto(ConfirmOutput::CancelTap, SwipeDirection::Left)
|
||||
}
|
||||
(ConfirmOutput::Menu, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(ConfirmOutput::Address, SwipeDirection::Right)
|
||||
}
|
||||
(ConfirmOutput::CancelTap, FlowMsg::Confirmed) => Decision::Return(FlowMsg::Cancelled),
|
||||
(_, FlowMsg::Cancelled) => Decision::Goto(ConfirmOutput::Menu, SwipeDirection::Right),
|
||||
_ => Decision::Nothing,
|
||||
(_, FlowMsg::Info) => Self::Menu.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Choice(0)) => Self::AccountInfo.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Choice(1)) => Self::CancelTap.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Cancelled) => Self::Address.swipe_right(),
|
||||
(Self::CancelTap, FlowMsg::Confirmed) => self.return_msg(FlowMsg::Cancelled),
|
||||
(_, FlowMsg::Cancelled) => Self::Menu.swipe_right(),
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use crate::{
|
||||
micropython::{map::Map, obj::Obj, util},
|
||||
ui::{
|
||||
component::swipe_detect::SwipeSettings, layout::obj::LayoutObj,
|
||||
model_mercury::component::SwipeContent,
|
||||
},
|
||||
};
|
||||
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
pub extern "C" fn new_confirm_output(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, ConfirmOutput::new_obj) }
|
||||
@ -156,13 +143,12 @@ impl ConfirmOutput {
|
||||
FrameMsg::Button(_) => Some(FlowMsg::Cancelled),
|
||||
});
|
||||
|
||||
let store = flow_store()
|
||||
.add(content_address)?
|
||||
.add(content_amount)?
|
||||
.add(content_menu)?
|
||||
.add(content_account)?
|
||||
.add(content_cancel_tap)?;
|
||||
let res = SwipeFlow::new(ConfirmOutput::Address, store)?;
|
||||
let res = SwipeFlow::new(&ConfirmOutput::Address)?
|
||||
.with_page(&ConfirmOutput::Address, content_address)?
|
||||
.with_page(&ConfirmOutput::Amount, content_amount)?
|
||||
.with_page(&ConfirmOutput::Menu, content_menu)?
|
||||
.with_page(&ConfirmOutput::AccountInfo, content_account)?
|
||||
.with_page(&ConfirmOutput::CancelTap, content_cancel_tap)?;
|
||||
Ok(LayoutObj::new(res)?.into())
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,10 @@ use crate::{
|
||||
text::paragraphs::{Paragraph, Paragraphs},
|
||||
ButtonRequestExt, ComponentExt, SwipeDirection,
|
||||
},
|
||||
flow::{base::Decision, flow_store, FlowMsg, FlowState, FlowStore, SwipeFlow},
|
||||
flow::{
|
||||
base::{DecisionBuilder as _, StateChange},
|
||||
FlowMsg, FlowState, SwipeFlow,
|
||||
},
|
||||
layout::obj::LayoutObj,
|
||||
model_mercury::component::{PromptScreen, SwipeContent},
|
||||
},
|
||||
@ -21,7 +24,7 @@ use super::super::{
|
||||
theme,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, ToPrimitive)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum ConfirmResetCreate {
|
||||
Intro,
|
||||
Menu,
|
||||
@ -29,43 +32,30 @@ pub enum ConfirmResetCreate {
|
||||
}
|
||||
|
||||
impl FlowState for ConfirmResetCreate {
|
||||
fn handle_swipe(&self, direction: SwipeDirection) -> Decision<Self> {
|
||||
#[inline]
|
||||
fn index(&'static self) -> usize {
|
||||
*self as usize
|
||||
}
|
||||
|
||||
fn handle_swipe(&'static self, direction: SwipeDirection) -> StateChange {
|
||||
match (self, direction) {
|
||||
(ConfirmResetCreate::Intro, SwipeDirection::Left) => {
|
||||
Decision::Goto(ConfirmResetCreate::Menu, direction)
|
||||
}
|
||||
(ConfirmResetCreate::Intro, SwipeDirection::Up) => {
|
||||
Decision::Goto(ConfirmResetCreate::Confirm, direction)
|
||||
}
|
||||
(ConfirmResetCreate::Menu, SwipeDirection::Right) => {
|
||||
Decision::Goto(ConfirmResetCreate::Intro, direction)
|
||||
}
|
||||
(ConfirmResetCreate::Confirm, SwipeDirection::Down) => {
|
||||
Decision::Goto(ConfirmResetCreate::Intro, direction)
|
||||
}
|
||||
(ConfirmResetCreate::Confirm, SwipeDirection::Left) => {
|
||||
Decision::Goto(ConfirmResetCreate::Menu, direction)
|
||||
}
|
||||
_ => Decision::Nothing,
|
||||
(Self::Intro, SwipeDirection::Left) => Self::Menu.swipe(direction),
|
||||
(Self::Intro, SwipeDirection::Up) => Self::Confirm.swipe(direction),
|
||||
(Self::Menu, SwipeDirection::Right) => Self::Intro.swipe(direction),
|
||||
(Self::Confirm, SwipeDirection::Down) => Self::Intro.swipe(direction),
|
||||
(Self::Confirm, SwipeDirection::Left) => Self::Menu.swipe(direction),
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_event(&self, msg: FlowMsg) -> Decision<Self> {
|
||||
fn handle_event(&'static self, msg: FlowMsg) -> StateChange {
|
||||
match (self, msg) {
|
||||
(ConfirmResetCreate::Intro, FlowMsg::Info) => {
|
||||
Decision::Goto(ConfirmResetCreate::Menu, SwipeDirection::Left)
|
||||
}
|
||||
(ConfirmResetCreate::Menu, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(ConfirmResetCreate::Intro, SwipeDirection::Right)
|
||||
}
|
||||
(ConfirmResetCreate::Menu, FlowMsg::Choice(0)) => Decision::Return(FlowMsg::Cancelled),
|
||||
(ConfirmResetCreate::Confirm, FlowMsg::Confirmed) => {
|
||||
Decision::Return(FlowMsg::Confirmed)
|
||||
}
|
||||
(ConfirmResetCreate::Confirm, FlowMsg::Info) => {
|
||||
Decision::Goto(ConfirmResetCreate::Menu, SwipeDirection::Left)
|
||||
}
|
||||
_ => Decision::Nothing,
|
||||
(Self::Intro, FlowMsg::Info) => Self::Menu.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Cancelled) => Self::Intro.swipe_right(),
|
||||
(Self::Menu, FlowMsg::Choice(0)) => self.return_msg(FlowMsg::Cancelled),
|
||||
(Self::Confirm, FlowMsg::Confirmed) => self.return_msg(FlowMsg::Confirmed),
|
||||
(Self::Confirm, FlowMsg::Info) => Self::Menu.swipe_left(),
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -124,12 +114,10 @@ impl ConfirmResetCreate {
|
||||
})
|
||||
.one_button_request(ButtonRequestCode::ResetDevice.with_type("confirm_setup_device"));
|
||||
|
||||
let store = flow_store()
|
||||
.add(content_intro)?
|
||||
.add(content_menu)?
|
||||
.add(content_confirm)?;
|
||||
|
||||
let res = SwipeFlow::new(ConfirmResetCreate::Intro, store)?;
|
||||
let res = SwipeFlow::new(&ConfirmResetCreate::Intro)?
|
||||
.with_page(&ConfirmResetCreate::Intro, content_intro)?
|
||||
.with_page(&ConfirmResetCreate::Menu, content_menu)?
|
||||
.with_page(&ConfirmResetCreate::Confirm, content_confirm)?;
|
||||
Ok(LayoutObj::new(res)?.into())
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,20 @@
|
||||
use crate::{
|
||||
error,
|
||||
micropython::{map::Map, obj::Obj, util},
|
||||
translations::TR,
|
||||
ui::{
|
||||
button_request::ButtonRequestCode,
|
||||
component::{
|
||||
swipe_detect::SwipeSettings,
|
||||
text::paragraphs::{Paragraph, Paragraphs},
|
||||
ButtonRequestExt, ComponentExt, SwipeDirection,
|
||||
},
|
||||
flow::{base::Decision, flow_store, FlowMsg, FlowState, FlowStore, SwipeFlow},
|
||||
flow::{
|
||||
base::{DecisionBuilder as _, StateChange},
|
||||
FlowMsg, FlowState, SwipeFlow,
|
||||
},
|
||||
layout::obj::LayoutObj,
|
||||
model_mercury::component::SwipeContent,
|
||||
},
|
||||
};
|
||||
|
||||
@ -16,51 +23,37 @@ use super::super::{
|
||||
theme,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, ToPrimitive)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum ConfirmResetRecover {
|
||||
Intro,
|
||||
Menu,
|
||||
}
|
||||
|
||||
impl FlowState for ConfirmResetRecover {
|
||||
fn handle_swipe(&self, direction: SwipeDirection) -> Decision<Self> {
|
||||
#[inline]
|
||||
fn index(&'static self) -> usize {
|
||||
*self as usize
|
||||
}
|
||||
|
||||
fn handle_swipe(&'static self, direction: SwipeDirection) -> StateChange {
|
||||
match (self, direction) {
|
||||
(ConfirmResetRecover::Intro, SwipeDirection::Left) => {
|
||||
Decision::Goto(ConfirmResetRecover::Menu, direction)
|
||||
}
|
||||
(ConfirmResetRecover::Menu, SwipeDirection::Right) => {
|
||||
Decision::Goto(ConfirmResetRecover::Intro, direction)
|
||||
}
|
||||
(ConfirmResetRecover::Intro, SwipeDirection::Up) => {
|
||||
Decision::Return(FlowMsg::Confirmed)
|
||||
}
|
||||
_ => Decision::Nothing,
|
||||
(Self::Intro, SwipeDirection::Left) => Self::Menu.swipe(direction),
|
||||
(Self::Menu, SwipeDirection::Right) => Self::Intro.swipe(direction),
|
||||
(Self::Intro, SwipeDirection::Up) => self.return_msg(FlowMsg::Confirmed),
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_event(&self, msg: FlowMsg) -> Decision<Self> {
|
||||
fn handle_event(&'static self, msg: FlowMsg) -> StateChange {
|
||||
match (self, msg) {
|
||||
(ConfirmResetRecover::Intro, FlowMsg::Info) => {
|
||||
Decision::Goto(ConfirmResetRecover::Menu, SwipeDirection::Left)
|
||||
}
|
||||
(ConfirmResetRecover::Menu, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(ConfirmResetRecover::Intro, SwipeDirection::Right)
|
||||
}
|
||||
(ConfirmResetRecover::Menu, FlowMsg::Choice(0)) => Decision::Return(FlowMsg::Cancelled),
|
||||
_ => Decision::Nothing,
|
||||
(Self::Intro, FlowMsg::Info) => Self::Menu.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Cancelled) => Self::Intro.swipe_right(),
|
||||
(Self::Menu, FlowMsg::Choice(0)) => self.return_msg(FlowMsg::Cancelled),
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use crate::{
|
||||
micropython::{map::Map, obj::Obj, util},
|
||||
ui::{
|
||||
component::swipe_detect::SwipeSettings,
|
||||
layout::obj::LayoutObj,
|
||||
model_mercury::component::{PromptScreen, SwipeContent},
|
||||
},
|
||||
};
|
||||
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
pub extern "C" fn new_confirm_reset_recover(
|
||||
n_args: usize,
|
||||
@ -104,23 +97,9 @@ impl ConfirmResetRecover {
|
||||
FrameMsg::Button(_) => Some(FlowMsg::Cancelled),
|
||||
});
|
||||
|
||||
let content_confirm = Frame::left_aligned(
|
||||
TR::reset__title_create_wallet.into(),
|
||||
SwipeContent::new(PromptScreen::new_hold_to_confirm()),
|
||||
)
|
||||
.with_footer(TR::instructions__hold_to_confirm.into(), None)
|
||||
.with_swipe(SwipeDirection::Down, SwipeSettings::default())
|
||||
.map(|msg| match msg {
|
||||
FrameMsg::Content(()) => Some(FlowMsg::Confirmed),
|
||||
_ => Some(FlowMsg::Cancelled),
|
||||
});
|
||||
|
||||
let store = flow_store()
|
||||
.add(content_intro)?
|
||||
.add(content_menu)?
|
||||
.add(content_confirm)?;
|
||||
|
||||
let res = SwipeFlow::new(ConfirmResetRecover::Intro, store)?;
|
||||
let res = SwipeFlow::new(&ConfirmResetRecover::Intro)?
|
||||
.with_page(&ConfirmResetRecover::Intro, content_intro)?
|
||||
.with_page(&ConfirmResetRecover::Menu, content_menu)?;
|
||||
Ok(LayoutObj::new(res)?.into())
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,20 @@
|
||||
use crate::{
|
||||
error,
|
||||
micropython::qstr::Qstr,
|
||||
micropython::{map::Map, obj::Obj, qstr::Qstr, util},
|
||||
strutil::TString,
|
||||
translations::TR,
|
||||
ui::{
|
||||
component::{
|
||||
swipe_detect::SwipeSettings,
|
||||
text::paragraphs::{Paragraph, Paragraphs},
|
||||
ComponentExt, SwipeDirection,
|
||||
},
|
||||
flow::{base::Decision, FlowMsg, FlowState, FlowStore},
|
||||
flow::{
|
||||
base::{DecisionBuilder as _, StateChange},
|
||||
FlowMsg, FlowState, SwipeFlow,
|
||||
},
|
||||
layout::obj::LayoutObj,
|
||||
model_mercury::component::SwipeContent,
|
||||
},
|
||||
};
|
||||
|
||||
@ -19,7 +25,7 @@ use super::super::{
|
||||
theme,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, ToPrimitive)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum SetNewPin {
|
||||
Intro,
|
||||
Menu,
|
||||
@ -28,63 +34,37 @@ pub enum SetNewPin {
|
||||
}
|
||||
|
||||
impl FlowState for SetNewPin {
|
||||
fn handle_swipe(&self, direction: SwipeDirection) -> Decision<Self> {
|
||||
match (self, direction) {
|
||||
(SetNewPin::Intro, SwipeDirection::Left) => Decision::Goto(SetNewPin::Menu, direction),
|
||||
(SetNewPin::Intro, SwipeDirection::Up) => Decision::Return(FlowMsg::Confirmed),
|
||||
#[inline]
|
||||
fn index(&'static self) -> usize {
|
||||
*self as usize
|
||||
}
|
||||
|
||||
(SetNewPin::Menu, SwipeDirection::Right) => Decision::Goto(SetNewPin::Intro, direction),
|
||||
(SetNewPin::CancelPinIntro, SwipeDirection::Up) => {
|
||||
Decision::Goto(SetNewPin::CancelPinConfirm, direction)
|
||||
}
|
||||
(SetNewPin::CancelPinIntro, SwipeDirection::Right) => {
|
||||
Decision::Goto(SetNewPin::Intro, direction)
|
||||
}
|
||||
(SetNewPin::CancelPinConfirm, SwipeDirection::Down) => {
|
||||
Decision::Goto(SetNewPin::CancelPinIntro, direction)
|
||||
}
|
||||
(SetNewPin::CancelPinConfirm, SwipeDirection::Right) => {
|
||||
Decision::Goto(SetNewPin::Intro, direction)
|
||||
}
|
||||
_ => Decision::Nothing,
|
||||
fn handle_swipe(&'static self, direction: SwipeDirection) -> StateChange {
|
||||
match (self, direction) {
|
||||
(Self::Intro, SwipeDirection::Left) => Self::Menu.swipe(direction),
|
||||
(Self::Intro, SwipeDirection::Up) => self.return_msg(FlowMsg::Confirmed),
|
||||
(Self::Menu, SwipeDirection::Right) => Self::Intro.swipe(direction),
|
||||
(Self::CancelPinIntro, SwipeDirection::Up) => Self::CancelPinConfirm.swipe(direction),
|
||||
(Self::CancelPinIntro, SwipeDirection::Right) => Self::Intro.swipe(direction),
|
||||
(Self::CancelPinConfirm, SwipeDirection::Down) => Self::CancelPinIntro.swipe(direction),
|
||||
(Self::CancelPinConfirm, SwipeDirection::Right) => Self::Intro.swipe(direction),
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_event(&self, msg: FlowMsg) -> Decision<Self> {
|
||||
fn handle_event(&'static self, msg: FlowMsg) -> StateChange {
|
||||
match (self, msg) {
|
||||
(SetNewPin::Intro, FlowMsg::Info) => {
|
||||
Decision::Goto(SetNewPin::Menu, SwipeDirection::Left)
|
||||
}
|
||||
(SetNewPin::Menu, FlowMsg::Choice(0)) => {
|
||||
Decision::Goto(SetNewPin::CancelPinIntro, SwipeDirection::Left)
|
||||
}
|
||||
(SetNewPin::Menu, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(SetNewPin::Intro, SwipeDirection::Right)
|
||||
}
|
||||
(SetNewPin::CancelPinIntro, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(SetNewPin::Intro, SwipeDirection::Right)
|
||||
}
|
||||
(SetNewPin::CancelPinConfirm, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(SetNewPin::CancelPinIntro, SwipeDirection::Right)
|
||||
}
|
||||
(SetNewPin::CancelPinConfirm, FlowMsg::Confirmed) => {
|
||||
Decision::Return(FlowMsg::Cancelled)
|
||||
}
|
||||
_ => Decision::Nothing,
|
||||
(Self::Intro, FlowMsg::Info) => Self::Menu.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Choice(0)) => Self::CancelPinIntro.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Cancelled) => Self::Intro.swipe_right(),
|
||||
(Self::CancelPinIntro, FlowMsg::Cancelled) => Self::Intro.swipe_right(),
|
||||
(Self::CancelPinConfirm, FlowMsg::Cancelled) => Self::CancelPinIntro.swipe_right(),
|
||||
(Self::CancelPinConfirm, FlowMsg::Confirmed) => self.return_msg(FlowMsg::Cancelled),
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use crate::{
|
||||
micropython::{map::Map, obj::Obj, util},
|
||||
ui::{
|
||||
component::swipe_detect::SwipeSettings,
|
||||
flow::{flow_store, SwipeFlow},
|
||||
layout::obj::LayoutObj,
|
||||
model_mercury::component::SwipeContent,
|
||||
},
|
||||
};
|
||||
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
pub extern "C" fn new_set_new_pin(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, SetNewPin::new_obj) }
|
||||
@ -155,12 +135,11 @@ impl SetNewPin {
|
||||
_ => None,
|
||||
});
|
||||
|
||||
let store = flow_store()
|
||||
.add(content_intro)?
|
||||
.add(content_menu)?
|
||||
.add(content_cancel_intro)?
|
||||
.add(content_cancel_confirm)?;
|
||||
let res = SwipeFlow::new(SetNewPin::Intro, store)?;
|
||||
let res = SwipeFlow::new(&SetNewPin::Intro)?
|
||||
.with_page(&SetNewPin::Intro, content_intro)?
|
||||
.with_page(&SetNewPin::Menu, content_menu)?
|
||||
.with_page(&SetNewPin::CancelPinIntro, content_cancel_intro)?
|
||||
.with_page(&SetNewPin::CancelPinConfirm, content_cancel_confirm)?;
|
||||
Ok(LayoutObj::new(res)?.into())
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,29 @@
|
||||
use crate::{
|
||||
error,
|
||||
micropython::{iter::IterBuf, qstr::Qstr},
|
||||
micropython::{iter::IterBuf, map::Map, obj::Obj, qstr::Qstr, util},
|
||||
strutil::TString,
|
||||
translations::TR,
|
||||
ui::{
|
||||
button_request::ButtonRequest,
|
||||
component::{ButtonRequestExt, ComponentExt, SwipeDirection},
|
||||
flow::{base::Decision, flow_store, FlowMsg, FlowState, FlowStore, SwipeFlow},
|
||||
component::{swipe_detect::SwipeSettings, ButtonRequestExt, ComponentExt, SwipeDirection},
|
||||
flow::{
|
||||
base::{DecisionBuilder as _, StateChange},
|
||||
FlowMsg, FlowState, SwipeFlow,
|
||||
},
|
||||
layout::obj::LayoutObj,
|
||||
model_mercury::component::SwipeContent,
|
||||
},
|
||||
};
|
||||
|
||||
use super::super::{
|
||||
component::{Frame, FrameMsg, PromptScreen, VerticalMenu, VerticalMenuChoiceMsg},
|
||||
theme,
|
||||
use super::{
|
||||
super::{
|
||||
component::{Frame, FrameMsg, PromptScreen, VerticalMenu, VerticalMenuChoiceMsg},
|
||||
theme,
|
||||
},
|
||||
util::ShowInfoParams,
|
||||
};
|
||||
|
||||
use super::util::ShowInfoParams;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, ToPrimitive)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum ConfirmSummary {
|
||||
Summary,
|
||||
Hold,
|
||||
@ -28,62 +34,40 @@ pub enum ConfirmSummary {
|
||||
}
|
||||
|
||||
impl FlowState for ConfirmSummary {
|
||||
fn handle_swipe(&self, direction: SwipeDirection) -> Decision<Self> {
|
||||
#[inline]
|
||||
fn index(&'static self) -> usize {
|
||||
*self as usize
|
||||
}
|
||||
|
||||
fn handle_swipe(&'static self, direction: SwipeDirection) -> StateChange {
|
||||
match (self, direction) {
|
||||
(ConfirmSummary::Summary | ConfirmSummary::Hold, SwipeDirection::Left) => {
|
||||
Decision::Goto(ConfirmSummary::Menu, direction)
|
||||
(Self::Summary | Self::Hold, SwipeDirection::Left) => Self::Menu.swipe(direction),
|
||||
(Self::Summary, SwipeDirection::Up) => Self::Hold.swipe(direction),
|
||||
(Self::Hold, SwipeDirection::Down) => Self::Summary.swipe(direction),
|
||||
(Self::Menu, SwipeDirection::Right) => Self::Summary.swipe(direction),
|
||||
(Self::Menu, SwipeDirection::Left) => Self::FeeInfo.swipe(direction),
|
||||
(Self::AccountInfo | Self::FeeInfo | Self::CancelTap, SwipeDirection::Right) => {
|
||||
Self::Menu.swipe(direction)
|
||||
}
|
||||
(ConfirmSummary::Summary, SwipeDirection::Up) => {
|
||||
Decision::Goto(ConfirmSummary::Hold, direction)
|
||||
}
|
||||
(ConfirmSummary::Hold, SwipeDirection::Down) => {
|
||||
Decision::Goto(ConfirmSummary::Summary, direction)
|
||||
}
|
||||
(ConfirmSummary::Menu, SwipeDirection::Right) => {
|
||||
Decision::Goto(ConfirmSummary::Summary, direction)
|
||||
}
|
||||
(ConfirmSummary::Menu, SwipeDirection::Left) => {
|
||||
Decision::Goto(ConfirmSummary::FeeInfo, direction)
|
||||
}
|
||||
(
|
||||
ConfirmSummary::AccountInfo | ConfirmSummary::FeeInfo | ConfirmSummary::CancelTap,
|
||||
SwipeDirection::Right,
|
||||
) => Decision::Goto(ConfirmSummary::Menu, direction),
|
||||
_ => Decision::Nothing,
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_event(&self, msg: FlowMsg) -> Decision<Self> {
|
||||
fn handle_event(&'static self, msg: FlowMsg) -> StateChange {
|
||||
match (self, msg) {
|
||||
(_, FlowMsg::Info) => Decision::Goto(ConfirmSummary::Menu, SwipeDirection::Left),
|
||||
(ConfirmSummary::Hold, FlowMsg::Confirmed) => Decision::Return(FlowMsg::Confirmed),
|
||||
(ConfirmSummary::Menu, FlowMsg::Choice(0)) => {
|
||||
Decision::Goto(ConfirmSummary::FeeInfo, SwipeDirection::Left)
|
||||
}
|
||||
(ConfirmSummary::Menu, FlowMsg::Choice(1)) => {
|
||||
Decision::Goto(ConfirmSummary::AccountInfo, SwipeDirection::Left)
|
||||
}
|
||||
(ConfirmSummary::Menu, FlowMsg::Choice(2)) => {
|
||||
Decision::Goto(ConfirmSummary::CancelTap, SwipeDirection::Left)
|
||||
}
|
||||
(ConfirmSummary::Menu, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(ConfirmSummary::Summary, SwipeDirection::Right)
|
||||
}
|
||||
(ConfirmSummary::CancelTap, FlowMsg::Confirmed) => Decision::Return(FlowMsg::Cancelled),
|
||||
(_, FlowMsg::Cancelled) => Decision::Goto(ConfirmSummary::Menu, SwipeDirection::Right),
|
||||
_ => Decision::Nothing,
|
||||
(_, FlowMsg::Info) => Self::Menu.swipe_left(),
|
||||
(Self::Hold, FlowMsg::Confirmed) => self.return_msg(FlowMsg::Confirmed),
|
||||
(Self::Menu, FlowMsg::Choice(0)) => Self::FeeInfo.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Choice(1)) => Self::AccountInfo.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Choice(2)) => Self::CancelTap.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Cancelled) => Self::Summary.swipe_right(),
|
||||
(Self::CancelTap, FlowMsg::Confirmed) => self.return_msg(FlowMsg::Cancelled),
|
||||
(_, FlowMsg::Cancelled) => Self::Menu.swipe_right(),
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use crate::{
|
||||
micropython::{map::Map, obj::Obj, util},
|
||||
ui::{
|
||||
component::swipe_detect::SwipeSettings, layout::obj::LayoutObj,
|
||||
model_mercury::component::SwipeContent,
|
||||
},
|
||||
};
|
||||
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
pub extern "C" fn new_confirm_summary(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, ConfirmSummary::new_obj) }
|
||||
@ -171,14 +155,14 @@ impl ConfirmSummary {
|
||||
FrameMsg::Button(_) => Some(FlowMsg::Cancelled),
|
||||
});
|
||||
|
||||
let store = flow_store()
|
||||
.add(content_summary)?
|
||||
.add(content_hold)?
|
||||
.add(content_menu)?
|
||||
.add(content_fee)?
|
||||
.add(content_account)?
|
||||
.add(content_cancel_tap)?;
|
||||
let res = SwipeFlow::new(ConfirmSummary::Summary, store)?;
|
||||
let res = SwipeFlow::new(&ConfirmSummary::Summary)?
|
||||
.with_page(&ConfirmSummary::Summary, content_summary)?
|
||||
.with_page(&ConfirmSummary::Hold, content_hold)?
|
||||
.with_page(&ConfirmSummary::Menu, content_menu)?
|
||||
.with_page(&ConfirmSummary::FeeInfo, content_fee)?
|
||||
.with_page(&ConfirmSummary::AccountInfo, content_account)?
|
||||
.with_page(&ConfirmSummary::CancelTap, content_cancel_tap)?;
|
||||
|
||||
Ok(LayoutObj::new(res)?.into())
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,21 @@
|
||||
use crate::{
|
||||
error,
|
||||
micropython::{iter::IterBuf, qstr::Qstr},
|
||||
micropython::{iter::IterBuf, map::Map, obj::Obj, qstr::Qstr, util},
|
||||
strutil::TString,
|
||||
translations::TR,
|
||||
ui::{
|
||||
button_request::ButtonRequest,
|
||||
component::{
|
||||
swipe_detect::SwipeSettings,
|
||||
text::paragraphs::{Paragraph, ParagraphSource, Paragraphs},
|
||||
ButtonRequestExt, ComponentExt, Qr, SwipeDirection,
|
||||
},
|
||||
flow::{base::Decision, flow_store, FlowMsg, FlowState, FlowStore, SwipeFlow},
|
||||
layout::util::ConfirmBlob,
|
||||
flow::{
|
||||
base::{DecisionBuilder as _, StateChange},
|
||||
FlowMsg, FlowState, SwipeFlow, SwipePage,
|
||||
},
|
||||
layout::{obj::LayoutObj, util::ConfirmBlob},
|
||||
model_mercury::component::SwipeContent,
|
||||
},
|
||||
};
|
||||
|
||||
@ -24,7 +29,7 @@ use super::super::{
|
||||
|
||||
const QR_BORDER: i16 = 4;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, ToPrimitive)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum GetAddress {
|
||||
Address,
|
||||
Tap,
|
||||
@ -37,104 +42,48 @@ pub enum GetAddress {
|
||||
}
|
||||
|
||||
impl FlowState for GetAddress {
|
||||
fn handle_swipe(&self, direction: SwipeDirection) -> Decision<Self> {
|
||||
#[inline]
|
||||
fn index(&'static self) -> usize {
|
||||
*self as usize
|
||||
}
|
||||
|
||||
fn handle_swipe(&'static self, direction: SwipeDirection) -> StateChange {
|
||||
match (self, direction) {
|
||||
(GetAddress::Address, SwipeDirection::Left) => {
|
||||
Decision::Goto(GetAddress::Menu, direction)
|
||||
}
|
||||
(GetAddress::Address, SwipeDirection::Up) => Decision::Goto(GetAddress::Tap, direction),
|
||||
(GetAddress::Tap, SwipeDirection::Down) => {
|
||||
Decision::Goto(GetAddress::Address, direction)
|
||||
}
|
||||
(GetAddress::Tap, SwipeDirection::Left) => Decision::Goto(GetAddress::Menu, direction),
|
||||
(GetAddress::Menu, SwipeDirection::Right) => {
|
||||
Decision::Goto(GetAddress::Address, direction)
|
||||
}
|
||||
(GetAddress::QrCode, SwipeDirection::Right) => {
|
||||
Decision::Goto(GetAddress::Menu, direction)
|
||||
}
|
||||
(GetAddress::AccountInfo, SwipeDirection::Right) => {
|
||||
Decision::Goto(GetAddress::Menu, SwipeDirection::Right)
|
||||
}
|
||||
(GetAddress::Cancel, SwipeDirection::Up) => {
|
||||
Decision::Goto(GetAddress::CancelTap, direction)
|
||||
}
|
||||
(GetAddress::Cancel, SwipeDirection::Right) => {
|
||||
Decision::Goto(GetAddress::Menu, direction)
|
||||
}
|
||||
(GetAddress::CancelTap, SwipeDirection::Down) => {
|
||||
Decision::Goto(GetAddress::Cancel, direction)
|
||||
}
|
||||
(GetAddress::CancelTap, SwipeDirection::Right) => {
|
||||
Decision::Goto(GetAddress::Menu, direction)
|
||||
}
|
||||
_ => Decision::Nothing,
|
||||
(Self::Address, SwipeDirection::Left) => Self::Menu.swipe(direction),
|
||||
(Self::Address, SwipeDirection::Up) => Self::Tap.swipe(direction),
|
||||
(Self::Tap, SwipeDirection::Down) => Self::Address.swipe(direction),
|
||||
(Self::Tap, SwipeDirection::Left) => Self::Menu.swipe(direction),
|
||||
(Self::Menu, SwipeDirection::Right) => Self::Address.swipe(direction),
|
||||
(Self::QrCode, SwipeDirection::Right) => Self::Menu.swipe(direction),
|
||||
(Self::AccountInfo, SwipeDirection::Right) => Self::Menu.swipe_right(),
|
||||
(Self::Cancel, SwipeDirection::Up) => Self::CancelTap.swipe(direction),
|
||||
(Self::Cancel, SwipeDirection::Right) => Self::Menu.swipe(direction),
|
||||
(Self::CancelTap, SwipeDirection::Down) => Self::Cancel.swipe(direction),
|
||||
(Self::CancelTap, SwipeDirection::Right) => Self::Menu.swipe(direction),
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_event(&self, msg: FlowMsg) -> Decision<Self> {
|
||||
fn handle_event(&'static self, msg: FlowMsg) -> StateChange {
|
||||
match (self, msg) {
|
||||
(GetAddress::Address, FlowMsg::Info) => {
|
||||
Decision::Goto(GetAddress::Menu, SwipeDirection::Left)
|
||||
}
|
||||
|
||||
(GetAddress::Tap, FlowMsg::Confirmed) => {
|
||||
Decision::Goto(GetAddress::Confirmed, SwipeDirection::Up)
|
||||
}
|
||||
|
||||
(GetAddress::Tap, FlowMsg::Info) => {
|
||||
Decision::Goto(GetAddress::Menu, SwipeDirection::Left)
|
||||
}
|
||||
|
||||
(GetAddress::Confirmed, _) => Decision::Return(FlowMsg::Confirmed),
|
||||
|
||||
(GetAddress::Menu, FlowMsg::Choice(0)) => {
|
||||
Decision::Goto(GetAddress::QrCode, SwipeDirection::Left)
|
||||
}
|
||||
|
||||
(GetAddress::Menu, FlowMsg::Choice(1)) => {
|
||||
Decision::Goto(GetAddress::AccountInfo, SwipeDirection::Left)
|
||||
}
|
||||
|
||||
(GetAddress::Menu, FlowMsg::Choice(2)) => {
|
||||
Decision::Goto(GetAddress::Cancel, SwipeDirection::Left)
|
||||
}
|
||||
|
||||
(GetAddress::Menu, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(GetAddress::Address, SwipeDirection::Right)
|
||||
}
|
||||
|
||||
(GetAddress::QrCode, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(GetAddress::Menu, SwipeDirection::Right)
|
||||
}
|
||||
|
||||
(GetAddress::AccountInfo, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(GetAddress::Menu, SwipeDirection::Right)
|
||||
}
|
||||
|
||||
(GetAddress::Cancel, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(GetAddress::Menu, SwipeDirection::Right)
|
||||
}
|
||||
|
||||
(GetAddress::CancelTap, FlowMsg::Confirmed) => Decision::Return(FlowMsg::Cancelled),
|
||||
|
||||
(GetAddress::CancelTap, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(GetAddress::Menu, SwipeDirection::Right)
|
||||
}
|
||||
|
||||
_ => Decision::Nothing,
|
||||
(Self::Address, FlowMsg::Info) => Self::Menu.swipe_left(),
|
||||
(Self::Tap, FlowMsg::Confirmed) => Self::Confirmed.swipe_up(),
|
||||
(Self::Tap, FlowMsg::Info) => Self::Menu.swipe_left(),
|
||||
(Self::Confirmed, _) => self.return_msg(FlowMsg::Confirmed),
|
||||
(Self::Menu, FlowMsg::Choice(0)) => Self::QrCode.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Choice(1)) => Self::AccountInfo.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Choice(2)) => Self::Cancel.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Cancelled) => Self::Address.swipe_right(),
|
||||
(Self::QrCode, FlowMsg::Cancelled) => Self::Menu.swipe_right(),
|
||||
(Self::AccountInfo, FlowMsg::Cancelled) => Self::Menu.swipe_right(),
|
||||
(Self::Cancel, FlowMsg::Cancelled) => Self::Menu.swipe_right(),
|
||||
(Self::CancelTap, FlowMsg::Confirmed) => self.return_msg(FlowMsg::Cancelled),
|
||||
(Self::CancelTap, FlowMsg::Cancelled) => Self::Menu.swipe_right(),
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use crate::{
|
||||
micropython::{map::Map, obj::Obj, util},
|
||||
ui::{
|
||||
component::swipe_detect::SwipeSettings, flow::SwipePage, layout::obj::LayoutObj,
|
||||
model_mercury::component::SwipeContent,
|
||||
},
|
||||
};
|
||||
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
pub extern "C" fn new_get_address(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, GetAddress::new_obj) }
|
||||
@ -271,16 +220,15 @@ impl GetAddress {
|
||||
_ => None,
|
||||
});
|
||||
|
||||
let store = flow_store()
|
||||
.add(content_address)?
|
||||
.add(content_tap)?
|
||||
.add(content_confirmed)?
|
||||
.add(content_menu)?
|
||||
.add(content_qr)?
|
||||
.add(content_account)?
|
||||
.add(content_cancel_info)?
|
||||
.add(content_cancel_tap)?;
|
||||
let res = SwipeFlow::new(GetAddress::Address, store)?;
|
||||
let res = SwipeFlow::new(&GetAddress::Address)?
|
||||
.with_page(&GetAddress::Address, content_address)?
|
||||
.with_page(&GetAddress::Tap, content_tap)?
|
||||
.with_page(&GetAddress::Confirmed, content_confirmed)?
|
||||
.with_page(&GetAddress::Menu, content_menu)?
|
||||
.with_page(&GetAddress::QrCode, content_qr)?
|
||||
.with_page(&GetAddress::AccountInfo, content_account)?
|
||||
.with_page(&GetAddress::Cancel, content_cancel_info)?
|
||||
.with_page(&GetAddress::CancelTap, content_cancel_tap)?;
|
||||
Ok(LayoutObj::new(res)?.into())
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,20 @@
|
||||
use crate::{
|
||||
error,
|
||||
micropython::{map::Map, obj::Obj, util},
|
||||
strutil::TString,
|
||||
translations::TR,
|
||||
ui::{
|
||||
component::{
|
||||
swipe_detect::SwipeSettings,
|
||||
text::paragraphs::{Paragraph, Paragraphs},
|
||||
ComponentExt, SwipeDirection,
|
||||
},
|
||||
flow::{base::Decision, FlowMsg, FlowState, FlowStore},
|
||||
flow::{
|
||||
base::{DecisionBuilder as _, StateChange},
|
||||
FlowMsg, FlowState, SwipeFlow,
|
||||
},
|
||||
layout::obj::LayoutObj,
|
||||
model_mercury::component::SwipeContent,
|
||||
},
|
||||
};
|
||||
|
||||
@ -18,7 +25,7 @@ use super::super::{
|
||||
theme,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, ToPrimitive)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum PromptBackup {
|
||||
Intro,
|
||||
Menu,
|
||||
@ -27,68 +34,39 @@ pub enum PromptBackup {
|
||||
}
|
||||
|
||||
impl FlowState for PromptBackup {
|
||||
fn handle_swipe(&self, direction: SwipeDirection) -> Decision<Self> {
|
||||
#[inline]
|
||||
fn index(&'static self) -> usize {
|
||||
*self as usize
|
||||
}
|
||||
|
||||
fn handle_swipe(&'static self, direction: SwipeDirection) -> StateChange {
|
||||
match (self, direction) {
|
||||
(PromptBackup::Intro, SwipeDirection::Left) => {
|
||||
Decision::Goto(PromptBackup::Menu, direction)
|
||||
(Self::Intro, SwipeDirection::Left) => Self::Menu.swipe(direction),
|
||||
(Self::Intro, SwipeDirection::Up) => self.return_msg(FlowMsg::Confirmed),
|
||||
(Self::Menu, SwipeDirection::Right) => Self::Intro.swipe(direction),
|
||||
(Self::SkipBackupIntro, SwipeDirection::Up) => Self::SkipBackupConfirm.swipe(direction),
|
||||
(Self::SkipBackupIntro, SwipeDirection::Right) => Self::Intro.swipe(direction),
|
||||
(Self::SkipBackupConfirm, SwipeDirection::Down) => {
|
||||
Self::SkipBackupIntro.swipe(direction)
|
||||
}
|
||||
(PromptBackup::Intro, SwipeDirection::Up) => Decision::Return(FlowMsg::Confirmed),
|
||||
|
||||
(PromptBackup::Menu, SwipeDirection::Right) => {
|
||||
Decision::Goto(PromptBackup::Intro, direction)
|
||||
}
|
||||
|
||||
(PromptBackup::SkipBackupIntro, SwipeDirection::Up) => {
|
||||
Decision::Goto(PromptBackup::SkipBackupConfirm, direction)
|
||||
}
|
||||
(PromptBackup::SkipBackupIntro, SwipeDirection::Right) => {
|
||||
Decision::Goto(PromptBackup::Intro, direction)
|
||||
}
|
||||
(PromptBackup::SkipBackupConfirm, SwipeDirection::Down) => {
|
||||
Decision::Goto(PromptBackup::SkipBackupIntro, direction)
|
||||
}
|
||||
(PromptBackup::SkipBackupConfirm, SwipeDirection::Right) => {
|
||||
Decision::Goto(PromptBackup::Intro, direction)
|
||||
}
|
||||
_ => Decision::Nothing,
|
||||
(Self::SkipBackupConfirm, SwipeDirection::Right) => Self::Intro.swipe(direction),
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_event(&self, msg: FlowMsg) -> Decision<Self> {
|
||||
fn handle_event(&'static self, msg: FlowMsg) -> StateChange {
|
||||
match (self, msg) {
|
||||
(PromptBackup::Intro, FlowMsg::Info) => {
|
||||
Decision::Goto(PromptBackup::Menu, SwipeDirection::Left)
|
||||
}
|
||||
(PromptBackup::Menu, FlowMsg::Choice(0)) => {
|
||||
Decision::Goto(PromptBackup::SkipBackupIntro, SwipeDirection::Left)
|
||||
}
|
||||
(PromptBackup::Menu, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(PromptBackup::Intro, SwipeDirection::Right)
|
||||
}
|
||||
(PromptBackup::SkipBackupIntro, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(PromptBackup::Menu, SwipeDirection::Right)
|
||||
}
|
||||
(PromptBackup::SkipBackupConfirm, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(PromptBackup::SkipBackupIntro, SwipeDirection::Right)
|
||||
}
|
||||
(PromptBackup::SkipBackupConfirm, FlowMsg::Confirmed) => {
|
||||
Decision::Return(FlowMsg::Cancelled)
|
||||
}
|
||||
_ => Decision::Nothing,
|
||||
(Self::Intro, FlowMsg::Info) => Self::Menu.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Choice(0)) => Self::SkipBackupIntro.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Cancelled) => Self::Intro.swipe_right(),
|
||||
(Self::SkipBackupIntro, FlowMsg::Cancelled) => Self::Menu.swipe_right(),
|
||||
(Self::SkipBackupConfirm, FlowMsg::Cancelled) => Self::SkipBackupIntro.swipe_right(),
|
||||
(Self::SkipBackupConfirm, FlowMsg::Confirmed) => self.return_msg(FlowMsg::Cancelled),
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use crate::{
|
||||
micropython::{map::Map, obj::Obj, util},
|
||||
ui::{
|
||||
component::swipe_detect::SwipeSettings,
|
||||
flow::{flow_store, SwipeFlow},
|
||||
layout::obj::LayoutObj,
|
||||
model_mercury::component::SwipeContent,
|
||||
},
|
||||
};
|
||||
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
pub extern "C" fn new_prompt_backup(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, PromptBackup::new_obj) }
|
||||
@ -159,12 +137,11 @@ impl PromptBackup {
|
||||
_ => None,
|
||||
});
|
||||
|
||||
let store = flow_store()
|
||||
.add(content_intro)?
|
||||
.add(content_menu)?
|
||||
.add(content_skip_intro)?
|
||||
.add(content_skip_confirm)?;
|
||||
let res = SwipeFlow::new(PromptBackup::Intro, store)?;
|
||||
let res = SwipeFlow::new(&PromptBackup::Intro)?
|
||||
.with_page(&PromptBackup::Intro, content_intro)?
|
||||
.with_page(&PromptBackup::Menu, content_menu)?
|
||||
.with_page(&PromptBackup::SkipBackupIntro, content_skip_intro)?
|
||||
.with_page(&PromptBackup::SkipBackupConfirm, content_skip_confirm)?;
|
||||
Ok(LayoutObj::new(res)?.into())
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,21 @@
|
||||
use crate::{
|
||||
error,
|
||||
micropython::qstr::Qstr,
|
||||
micropython::{map::Map, obj::Obj, qstr::Qstr, util},
|
||||
strutil::TString,
|
||||
translations::TR,
|
||||
ui::{
|
||||
button_request::ButtonRequest,
|
||||
component::{
|
||||
swipe_detect::SwipeSettings,
|
||||
text::paragraphs::{Paragraph, Paragraphs},
|
||||
ButtonRequestExt, ComponentExt, SwipeDirection,
|
||||
},
|
||||
flow::{base::Decision, flow_store, FlowMsg, FlowState, FlowStore, SwipeFlow},
|
||||
flow::{
|
||||
base::{DecisionBuilder as _, StateChange},
|
||||
FlowMsg, FlowState, SwipeFlow,
|
||||
},
|
||||
layout::obj::LayoutObj,
|
||||
model_mercury::component::SwipeContent,
|
||||
},
|
||||
};
|
||||
|
||||
@ -21,7 +27,7 @@ use super::super::{
|
||||
theme,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, ToPrimitive)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum RequestNumber {
|
||||
Number,
|
||||
Menu,
|
||||
@ -29,49 +35,32 @@ pub enum RequestNumber {
|
||||
}
|
||||
|
||||
impl FlowState for RequestNumber {
|
||||
fn handle_swipe(&self, direction: SwipeDirection) -> Decision<Self> {
|
||||
#[inline]
|
||||
fn index(&'static self) -> usize {
|
||||
*self as usize
|
||||
}
|
||||
|
||||
fn handle_swipe(&'static self, direction: SwipeDirection) -> StateChange {
|
||||
match (self, direction) {
|
||||
(RequestNumber::Number, SwipeDirection::Left) => {
|
||||
Decision::Goto(RequestNumber::Menu, direction)
|
||||
}
|
||||
(RequestNumber::Menu, SwipeDirection::Right) => {
|
||||
Decision::Goto(RequestNumber::Number, direction)
|
||||
}
|
||||
(RequestNumber::Info, SwipeDirection::Right) => {
|
||||
Decision::Goto(RequestNumber::Menu, direction)
|
||||
}
|
||||
_ => Decision::Nothing,
|
||||
(Self::Number, SwipeDirection::Left) => Self::Menu.swipe(direction),
|
||||
(Self::Menu, SwipeDirection::Right) => Self::Number.swipe(direction),
|
||||
(Self::Info, SwipeDirection::Right) => Self::Menu.swipe(direction),
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_event(&self, msg: FlowMsg) -> Decision<Self> {
|
||||
fn handle_event(&'static self, msg: FlowMsg) -> StateChange {
|
||||
match (self, msg) {
|
||||
(RequestNumber::Number, FlowMsg::Info) => {
|
||||
Decision::Goto(RequestNumber::Menu, SwipeDirection::Left)
|
||||
}
|
||||
(RequestNumber::Menu, FlowMsg::Choice(0)) => {
|
||||
Decision::Goto(RequestNumber::Info, SwipeDirection::Left)
|
||||
}
|
||||
(RequestNumber::Menu, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(RequestNumber::Number, SwipeDirection::Right)
|
||||
}
|
||||
(RequestNumber::Info, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(RequestNumber::Menu, SwipeDirection::Right)
|
||||
}
|
||||
(RequestNumber::Number, FlowMsg::Choice(n)) => Decision::Return(FlowMsg::Choice(n)),
|
||||
_ => Decision::Nothing,
|
||||
(Self::Number, FlowMsg::Info) => Self::Menu.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Choice(0)) => Self::Info.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Cancelled) => Self::Number.swipe_right(),
|
||||
(Self::Info, FlowMsg::Cancelled) => Self::Menu.swipe_right(),
|
||||
(Self::Number, FlowMsg::Choice(n)) => self.return_msg(FlowMsg::Choice(n)),
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use crate::{
|
||||
micropython::{map::Map, obj::Obj, util},
|
||||
ui::{
|
||||
component::swipe_detect::SwipeSettings, layout::obj::LayoutObj,
|
||||
model_mercury::component::SwipeContent,
|
||||
},
|
||||
};
|
||||
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
pub extern "C" fn new_request_number(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, RequestNumber::new_obj) }
|
||||
@ -143,11 +132,10 @@ impl RequestNumber {
|
||||
_ => None,
|
||||
});
|
||||
|
||||
let store = flow_store()
|
||||
.add(content_number_input)?
|
||||
.add(content_menu)?
|
||||
.add(content_info)?;
|
||||
let res = SwipeFlow::new(RequestNumber::Number, store)?;
|
||||
let res = SwipeFlow::new(&RequestNumber::Number)?
|
||||
.with_page(&RequestNumber::Number, content_number_input)?
|
||||
.with_page(&RequestNumber::Menu, content_menu)?
|
||||
.with_page(&RequestNumber::Info, content_info)?;
|
||||
Ok(LayoutObj::new(res)?.into())
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,10 @@ use crate::{
|
||||
text::paragraphs::{Paragraph, ParagraphSource, ParagraphVecShort, Paragraphs, VecExt},
|
||||
ButtonRequestExt, ComponentExt, SwipeDirection,
|
||||
},
|
||||
flow::{base::Decision, flow_store, FlowMsg, FlowState, FlowStore, SwipeFlow},
|
||||
flow::{
|
||||
base::{DecisionBuilder as _, StateChange},
|
||||
FlowMsg, FlowState, SwipeFlow,
|
||||
},
|
||||
layout::obj::LayoutObj,
|
||||
model_mercury::component::SwipeContent,
|
||||
},
|
||||
@ -22,7 +25,7 @@ use super::super::{
|
||||
theme,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, ToPrimitive)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum ShowShareWords {
|
||||
Instruction,
|
||||
Words,
|
||||
@ -31,39 +34,28 @@ pub enum ShowShareWords {
|
||||
}
|
||||
|
||||
impl FlowState for ShowShareWords {
|
||||
fn handle_swipe(&self, direction: SwipeDirection) -> Decision<Self> {
|
||||
#[inline]
|
||||
fn index(&'static self) -> usize {
|
||||
*self as usize
|
||||
}
|
||||
|
||||
fn handle_swipe(&'static self, direction: SwipeDirection) -> StateChange {
|
||||
match (self, direction) {
|
||||
(ShowShareWords::Instruction, SwipeDirection::Up) => {
|
||||
Decision::Goto(ShowShareWords::Words, direction)
|
||||
}
|
||||
(ShowShareWords::Confirm, SwipeDirection::Down) => {
|
||||
Decision::Goto(ShowShareWords::Words, direction)
|
||||
}
|
||||
(ShowShareWords::Words, SwipeDirection::Up) => {
|
||||
Decision::Goto(ShowShareWords::Confirm, direction)
|
||||
}
|
||||
(ShowShareWords::Words, SwipeDirection::Down) => {
|
||||
Decision::Goto(ShowShareWords::Instruction, direction)
|
||||
}
|
||||
(ShowShareWords::CheckBackupIntro, SwipeDirection::Up) => {
|
||||
Decision::Return(FlowMsg::Confirmed)
|
||||
}
|
||||
_ => Decision::Nothing,
|
||||
(Self::Instruction, SwipeDirection::Up) => Self::Words.swipe(direction),
|
||||
(Self::Confirm, SwipeDirection::Down) => Self::Words.swipe(direction),
|
||||
(Self::Words, SwipeDirection::Up) => Self::Confirm.swipe(direction),
|
||||
(Self::Words, SwipeDirection::Down) => Self::Instruction.swipe(direction),
|
||||
(Self::CheckBackupIntro, SwipeDirection::Up) => self.return_msg(FlowMsg::Confirmed),
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_event(&self, msg: FlowMsg) -> Decision<Self> {
|
||||
fn handle_event(&'static self, msg: FlowMsg) -> StateChange {
|
||||
match (self, msg) {
|
||||
(ShowShareWords::Words, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(ShowShareWords::Instruction, SwipeDirection::Down)
|
||||
}
|
||||
(ShowShareWords::Words, FlowMsg::Confirmed) => {
|
||||
Decision::Goto(ShowShareWords::Confirm, SwipeDirection::Up)
|
||||
}
|
||||
(ShowShareWords::Confirm, FlowMsg::Confirmed) => {
|
||||
Decision::Goto(ShowShareWords::CheckBackupIntro, SwipeDirection::Up)
|
||||
}
|
||||
_ => Decision::Nothing,
|
||||
(Self::Words, FlowMsg::Cancelled) => Self::Instruction.swipe_down(),
|
||||
(Self::Words, FlowMsg::Confirmed) => Self::Confirm.swipe_up(),
|
||||
(Self::Confirm, FlowMsg::Confirmed) => Self::CheckBackupIntro.swipe_up(),
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -131,12 +123,14 @@ impl ShowShareWords {
|
||||
.with_swipe(SwipeDirection::Up, SwipeSettings::default())
|
||||
.map(|_| Some(FlowMsg::Confirmed));
|
||||
|
||||
let store = flow_store()
|
||||
.add(content_instruction)?
|
||||
.add(content_words)?
|
||||
.add(content_confirm)?
|
||||
.add(content_check_backup_intro)?;
|
||||
let res = SwipeFlow::new(ShowShareWords::Instruction, store)?;
|
||||
let res = SwipeFlow::new(&ShowShareWords::Instruction)?
|
||||
.with_page(&ShowShareWords::Instruction, content_instruction)?
|
||||
.with_page(&ShowShareWords::Words, content_words)?
|
||||
.with_page(&ShowShareWords::Confirm, content_confirm)?
|
||||
.with_page(
|
||||
&ShowShareWords::CheckBackupIntro,
|
||||
content_check_backup_intro,
|
||||
)?;
|
||||
Ok(LayoutObj::new(res)?.into())
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::{
|
||||
error,
|
||||
micropython::{map::Map, obj::Obj, util},
|
||||
translations::TR,
|
||||
ui::{
|
||||
component::{
|
||||
@ -7,7 +8,10 @@ use crate::{
|
||||
text::paragraphs::{Paragraph, Paragraphs},
|
||||
ComponentExt, SwipeDirection,
|
||||
},
|
||||
flow::{base::Decision, flow_store, FlowMsg, FlowState, FlowStore, SwipeFlow},
|
||||
flow::{
|
||||
base::{DecisionBuilder as _, StateChange},
|
||||
FlowMsg, FlowState, SwipeFlow,
|
||||
},
|
||||
layout::obj::LayoutObj,
|
||||
model_mercury::component::SwipeContent,
|
||||
},
|
||||
@ -18,7 +22,7 @@ use super::super::{
|
||||
theme,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, ToPrimitive)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum ShowTutorial {
|
||||
StepWelcome,
|
||||
StepBegin,
|
||||
@ -32,76 +36,43 @@ pub enum ShowTutorial {
|
||||
}
|
||||
|
||||
impl FlowState for ShowTutorial {
|
||||
fn handle_swipe(&self, direction: SwipeDirection) -> Decision<Self> {
|
||||
#[inline]
|
||||
fn index(&'static self) -> usize {
|
||||
*self as usize
|
||||
}
|
||||
|
||||
fn handle_swipe(&'static self, direction: SwipeDirection) -> StateChange {
|
||||
match (self, direction) {
|
||||
(ShowTutorial::StepBegin, SwipeDirection::Up) => {
|
||||
Decision::Goto(ShowTutorial::StepNavigation, direction)
|
||||
}
|
||||
(ShowTutorial::StepNavigation, SwipeDirection::Up) => {
|
||||
Decision::Goto(ShowTutorial::StepMenu, direction)
|
||||
}
|
||||
(ShowTutorial::StepNavigation, SwipeDirection::Down) => {
|
||||
Decision::Goto(ShowTutorial::StepBegin, direction)
|
||||
}
|
||||
(ShowTutorial::StepMenu, SwipeDirection::Up) => {
|
||||
Decision::Goto(ShowTutorial::StepHold, direction)
|
||||
}
|
||||
(ShowTutorial::StepMenu, SwipeDirection::Down) => {
|
||||
Decision::Goto(ShowTutorial::StepNavigation, direction)
|
||||
}
|
||||
(ShowTutorial::StepMenu, SwipeDirection::Left) => {
|
||||
Decision::Goto(ShowTutorial::Menu, direction)
|
||||
}
|
||||
(ShowTutorial::Menu, SwipeDirection::Left) => {
|
||||
Decision::Goto(ShowTutorial::DidYouKnow, direction)
|
||||
}
|
||||
(ShowTutorial::Menu, SwipeDirection::Right) => {
|
||||
Decision::Goto(ShowTutorial::StepBegin, direction)
|
||||
}
|
||||
(ShowTutorial::DidYouKnow, SwipeDirection::Right) => {
|
||||
Decision::Goto(ShowTutorial::Menu, direction)
|
||||
}
|
||||
(ShowTutorial::StepDone, SwipeDirection::Up) => Decision::Return(FlowMsg::Confirmed),
|
||||
_ => Decision::Nothing,
|
||||
(Self::StepBegin, SwipeDirection::Up) => Self::StepNavigation.swipe(direction),
|
||||
(Self::StepNavigation, SwipeDirection::Up) => Self::StepMenu.swipe(direction),
|
||||
(Self::StepNavigation, SwipeDirection::Down) => Self::StepBegin.swipe(direction),
|
||||
(Self::StepMenu, SwipeDirection::Up) => Self::StepHold.swipe(direction),
|
||||
(Self::StepMenu, SwipeDirection::Down) => Self::StepNavigation.swipe(direction),
|
||||
(Self::StepMenu, SwipeDirection::Left) => Self::Menu.swipe(direction),
|
||||
(Self::Menu, SwipeDirection::Left) => Self::DidYouKnow.swipe(direction),
|
||||
(Self::Menu, SwipeDirection::Right) => Self::StepBegin.swipe(direction),
|
||||
(Self::DidYouKnow, SwipeDirection::Right) => Self::Menu.swipe(direction),
|
||||
(Self::StepDone, SwipeDirection::Up) => self.return_msg(FlowMsg::Confirmed),
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_event(&self, msg: FlowMsg) -> Decision<Self> {
|
||||
fn handle_event(&'static self, msg: FlowMsg) -> StateChange {
|
||||
match (self, msg) {
|
||||
(ShowTutorial::StepWelcome, FlowMsg::Confirmed) => {
|
||||
Decision::Goto(ShowTutorial::StepBegin, SwipeDirection::Up)
|
||||
}
|
||||
(ShowTutorial::StepMenu, FlowMsg::Info) => {
|
||||
Decision::Goto(ShowTutorial::Menu, SwipeDirection::Left)
|
||||
}
|
||||
(ShowTutorial::Menu, FlowMsg::Choice(0)) => {
|
||||
Decision::Goto(ShowTutorial::DidYouKnow, SwipeDirection::Left)
|
||||
}
|
||||
(ShowTutorial::Menu, FlowMsg::Choice(1)) => {
|
||||
Decision::Goto(ShowTutorial::StepBegin, SwipeDirection::Right)
|
||||
}
|
||||
(ShowTutorial::Menu, FlowMsg::Choice(2)) => {
|
||||
Decision::Goto(ShowTutorial::HoldToExit, SwipeDirection::Up)
|
||||
}
|
||||
(ShowTutorial::Menu, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(ShowTutorial::StepMenu, SwipeDirection::Right)
|
||||
}
|
||||
(ShowTutorial::DidYouKnow, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(ShowTutorial::Menu, SwipeDirection::Right)
|
||||
}
|
||||
(ShowTutorial::StepHold, FlowMsg::Confirmed) => {
|
||||
Decision::Goto(ShowTutorial::StepDone, SwipeDirection::Up)
|
||||
}
|
||||
(ShowTutorial::HoldToExit, FlowMsg::Confirmed) => {
|
||||
Decision::Goto(ShowTutorial::StepDone, SwipeDirection::Up)
|
||||
}
|
||||
_ => Decision::Nothing,
|
||||
(Self::StepWelcome, FlowMsg::Confirmed) => Self::StepBegin.swipe_up(),
|
||||
(Self::StepMenu, FlowMsg::Info) => Self::Menu.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Choice(0)) => Self::DidYouKnow.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Choice(1)) => Self::StepBegin.swipe_right(),
|
||||
(Self::Menu, FlowMsg::Choice(2)) => Self::HoldToExit.swipe_up(),
|
||||
(Self::Menu, FlowMsg::Cancelled) => Self::StepMenu.swipe_right(),
|
||||
(Self::DidYouKnow, FlowMsg::Cancelled) => Self::Menu.swipe_right(),
|
||||
(Self::StepHold, FlowMsg::Confirmed) => Self::StepDone.swipe_up(),
|
||||
(Self::HoldToExit, FlowMsg::Confirmed) => Self::StepDone.swipe_up(),
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use crate::micropython::{map::Map, obj::Obj, util};
|
||||
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
pub extern "C" fn new_show_tutorial(_n_args: usize, _args: *const Obj, _kwargs: *mut Map) -> Obj {
|
||||
unsafe { util::try_or_raise(ShowTutorial::new_obj) }
|
||||
@ -213,17 +184,16 @@ impl ShowTutorial {
|
||||
.with_footer(TR::instructions__exit_tutorial.into(), None)
|
||||
.map(|msg| matches!(msg, FrameMsg::Content(())).then_some(FlowMsg::Confirmed));
|
||||
|
||||
let store = flow_store()
|
||||
.add(content_step_welcome)?
|
||||
.add(content_step_begin)?
|
||||
.add(content_step_navigation)?
|
||||
.add(content_step_menu)?
|
||||
.add(content_step_hold)?
|
||||
.add(content_step_done)?
|
||||
.add(content_menu)?
|
||||
.add(content_did_you_know)?
|
||||
.add(content_hold_to_exit)?;
|
||||
let res = SwipeFlow::new(ShowTutorial::StepWelcome, store)?;
|
||||
let res = SwipeFlow::new(&ShowTutorial::StepWelcome)?
|
||||
.with_page(&ShowTutorial::StepWelcome, content_step_welcome)?
|
||||
.with_page(&ShowTutorial::StepBegin, content_step_begin)?
|
||||
.with_page(&ShowTutorial::StepNavigation, content_step_navigation)?
|
||||
.with_page(&ShowTutorial::StepMenu, content_step_menu)?
|
||||
.with_page(&ShowTutorial::StepHold, content_step_hold)?
|
||||
.with_page(&ShowTutorial::StepDone, content_step_done)?
|
||||
.with_page(&ShowTutorial::Menu, content_menu)?
|
||||
.with_page(&ShowTutorial::DidYouKnow, content_did_you_know)?
|
||||
.with_page(&ShowTutorial::HoldToExit, content_hold_to_exit)?;
|
||||
Ok(LayoutObj::new(res)?.into())
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,20 @@
|
||||
use crate::{
|
||||
error,
|
||||
micropython::qstr::Qstr,
|
||||
micropython::{map::Map, obj::Obj, qstr::Qstr, util},
|
||||
strutil::TString,
|
||||
translations::TR,
|
||||
ui::{
|
||||
component::{
|
||||
swipe_detect::SwipeSettings,
|
||||
text::paragraphs::{Paragraph, ParagraphSource},
|
||||
ComponentExt, SwipeDirection,
|
||||
},
|
||||
flow::{base::Decision, flow_store, FlowMsg, FlowState, FlowStore, SwipeFlow},
|
||||
flow::{
|
||||
base::{DecisionBuilder as _, StateChange},
|
||||
FlowMsg, FlowState, SwipeFlow,
|
||||
},
|
||||
layout::obj::LayoutObj,
|
||||
model_mercury::component::SwipeContent,
|
||||
},
|
||||
};
|
||||
|
||||
@ -17,7 +23,7 @@ use super::super::{
|
||||
theme,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, ToPrimitive)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum WarningHiPrio {
|
||||
Message,
|
||||
Menu,
|
||||
@ -25,47 +31,32 @@ pub enum WarningHiPrio {
|
||||
}
|
||||
|
||||
impl FlowState for WarningHiPrio {
|
||||
fn handle_swipe(&self, direction: SwipeDirection) -> Decision<Self> {
|
||||
#[inline]
|
||||
fn index(&'static self) -> usize {
|
||||
*self as usize
|
||||
}
|
||||
|
||||
fn handle_swipe(&'static self, direction: SwipeDirection) -> StateChange {
|
||||
match (self, direction) {
|
||||
(WarningHiPrio::Message, SwipeDirection::Left) => {
|
||||
Decision::Goto(WarningHiPrio::Menu, direction)
|
||||
}
|
||||
(WarningHiPrio::Message, SwipeDirection::Up) => {
|
||||
Decision::Goto(WarningHiPrio::Cancelled, direction)
|
||||
}
|
||||
(WarningHiPrio::Menu, SwipeDirection::Right) => {
|
||||
Decision::Goto(WarningHiPrio::Message, direction)
|
||||
}
|
||||
_ => Decision::Nothing,
|
||||
(Self::Message, SwipeDirection::Left) => Self::Menu.swipe(direction),
|
||||
(Self::Message, SwipeDirection::Up) => Self::Cancelled.swipe(direction),
|
||||
(Self::Menu, SwipeDirection::Right) => Self::Message.swipe(direction),
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_event(&self, msg: FlowMsg) -> Decision<Self> {
|
||||
fn handle_event(&'static self, msg: FlowMsg) -> StateChange {
|
||||
match (self, msg) {
|
||||
(WarningHiPrio::Message, FlowMsg::Info) => {
|
||||
Decision::Goto(WarningHiPrio::Menu, SwipeDirection::Left)
|
||||
}
|
||||
(WarningHiPrio::Menu, FlowMsg::Choice(1)) => Decision::Return(FlowMsg::Confirmed),
|
||||
(WarningHiPrio::Menu, FlowMsg::Choice(_)) => {
|
||||
Decision::Goto(WarningHiPrio::Cancelled, SwipeDirection::Up)
|
||||
}
|
||||
(WarningHiPrio::Menu, FlowMsg::Cancelled) => {
|
||||
Decision::Goto(WarningHiPrio::Message, SwipeDirection::Right)
|
||||
}
|
||||
(WarningHiPrio::Cancelled, _) => Decision::Return(FlowMsg::Cancelled),
|
||||
_ => Decision::Nothing,
|
||||
(Self::Message, FlowMsg::Info) => Self::Menu.swipe_left(),
|
||||
(Self::Menu, FlowMsg::Choice(1)) => self.return_msg(FlowMsg::Confirmed),
|
||||
(Self::Menu, FlowMsg::Choice(_)) => Self::Cancelled.swipe_up(),
|
||||
(Self::Menu, FlowMsg::Cancelled) => Self::Message.swipe_right(),
|
||||
(Self::Cancelled, _) => self.return_msg(FlowMsg::Cancelled),
|
||||
_ => self.do_nothing(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use crate::{
|
||||
micropython::{map::Map, obj::Obj, util},
|
||||
ui::{
|
||||
component::swipe_detect::SwipeSettings, layout::obj::LayoutObj,
|
||||
model_mercury::component::SwipeContent,
|
||||
},
|
||||
};
|
||||
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
pub extern "C" fn new_warning_hi_prio(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, WarningHiPrio::new_obj) }
|
||||
@ -118,11 +109,10 @@ impl WarningHiPrio {
|
||||
.with_footer(TR::instructions__continue_in_app.into(), None)
|
||||
.map(|_| Some(FlowMsg::Cancelled));
|
||||
|
||||
let store = flow_store()
|
||||
.add(content_message)?
|
||||
.add(content_menu)?
|
||||
.add(content_cancelled)?;
|
||||
let res = SwipeFlow::new(WarningHiPrio::Message, store)?;
|
||||
let res = SwipeFlow::new(&WarningHiPrio::Message)?
|
||||
.with_page(&WarningHiPrio::Message, content_message)?
|
||||
.with_page(&WarningHiPrio::Menu, content_menu)?
|
||||
.with_page(&WarningHiPrio::Cancelled, content_cancelled)?;
|
||||
Ok(LayoutObj::new(res)?.into())
|
||||
}
|
||||
}
|
||||
|
@ -28,12 +28,12 @@ pub use canvas::{
|
||||
};
|
||||
pub use circle::Circle;
|
||||
pub use corner_highlight::CornerHighlight;
|
||||
pub use display::{render_on_canvas, render_on_display, unlock_bumps_on_failure};
|
||||
pub use display::{render_on_canvas, render_on_display, unlock_bumps_on_failure, ConcreteRenderer};
|
||||
#[cfg(feature = "ui_jpeg_decoder")]
|
||||
pub use jpeg::JpegImage;
|
||||
pub use qrcode::QrImage;
|
||||
pub use rawimage::RawImage;
|
||||
pub use render::{DirectRenderer, ProgressiveRenderer, Renderer};
|
||||
pub use render::{DirectRenderer, ProgressiveRenderer, Renderer, ScopedRenderer};
|
||||
pub use text::Text;
|
||||
pub use toif::ToifImage;
|
||||
#[cfg(feature = "ui_image_buffer")]
|
||||
|
Loading…
Reference in New Issue
Block a user