|
|
@ -3,6 +3,7 @@ use crate::{
|
|
|
|
time::{Duration, Instant},
|
|
|
|
time::{Duration, Instant},
|
|
|
|
ui::{
|
|
|
|
ui::{
|
|
|
|
animation::Animation,
|
|
|
|
animation::Animation,
|
|
|
|
|
|
|
|
button_request::{ButtonRequest, ButtonRequestCode},
|
|
|
|
component::{Component, Event, EventCtx},
|
|
|
|
component::{Component, Event, EventCtx},
|
|
|
|
flow::{base::Decision, swipe::Swipe, FlowMsg, FlowState, FlowStore, SwipeDirection},
|
|
|
|
flow::{base::Decision, swipe::Swipe, FlowMsg, FlowState, FlowStore, SwipeDirection},
|
|
|
|
geometry::{Offset, Rect},
|
|
|
|
geometry::{Offset, Rect},
|
|
|
@ -29,12 +30,19 @@ pub struct SwipeFlow<Q, S> {
|
|
|
|
swipe: Swipe,
|
|
|
|
swipe: Swipe,
|
|
|
|
/// Animation parameter.
|
|
|
|
/// Animation parameter.
|
|
|
|
anim_offset: Offset,
|
|
|
|
anim_offset: Offset,
|
|
|
|
|
|
|
|
/// Button request sent after showing first state.
|
|
|
|
|
|
|
|
initial_button_request: Option<ButtonRequest>,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct Transition<Q> {
|
|
|
|
struct Transition<Q> {
|
|
|
|
|
|
|
|
/// State we are transitioning _from_.
|
|
|
|
prev_state: Q,
|
|
|
|
prev_state: Q,
|
|
|
|
|
|
|
|
/// Animation progress.
|
|
|
|
animation: Animation<Offset>,
|
|
|
|
animation: Animation<Offset>,
|
|
|
|
|
|
|
|
/// Direction of the slide animation.
|
|
|
|
direction: SwipeDirection,
|
|
|
|
direction: SwipeDirection,
|
|
|
|
|
|
|
|
/// Send ButtonRequest when finished.
|
|
|
|
|
|
|
|
button_request: Option<ButtonRequest>,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl<Q: FlowState, S: FlowStore> SwipeFlow<Q, S> {
|
|
|
|
impl<Q: FlowState, S: FlowStore> SwipeFlow<Q, S> {
|
|
|
@ -45,10 +53,26 @@ impl<Q: FlowState, S: FlowStore> SwipeFlow<Q, S> {
|
|
|
|
transition: None,
|
|
|
|
transition: None,
|
|
|
|
swipe: Swipe::new().down().up().left().right(),
|
|
|
|
swipe: Swipe::new().down().up().left().right(),
|
|
|
|
anim_offset: Offset::zero(),
|
|
|
|
anim_offset: Offset::zero(),
|
|
|
|
|
|
|
|
initial_button_request: None,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn goto(&mut self, ctx: &mut EventCtx, direction: SwipeDirection, state: Q) {
|
|
|
|
pub fn with_initial_button_request(
|
|
|
|
|
|
|
|
mut self,
|
|
|
|
|
|
|
|
code: ButtonRequestCode,
|
|
|
|
|
|
|
|
br_type: &'static str,
|
|
|
|
|
|
|
|
) -> Self {
|
|
|
|
|
|
|
|
self.initial_button_request = code.with_type(br_type);
|
|
|
|
|
|
|
|
self
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn goto(
|
|
|
|
|
|
|
|
&mut self,
|
|
|
|
|
|
|
|
ctx: &mut EventCtx,
|
|
|
|
|
|
|
|
direction: SwipeDirection,
|
|
|
|
|
|
|
|
state: Q,
|
|
|
|
|
|
|
|
button_request: Option<ButtonRequest>,
|
|
|
|
|
|
|
|
) {
|
|
|
|
self.transition = Some(Transition {
|
|
|
|
self.transition = Some(Transition {
|
|
|
|
prev_state: self.state,
|
|
|
|
prev_state: self.state,
|
|
|
|
animation: Animation::new(
|
|
|
|
animation: Animation::new(
|
|
|
@ -58,6 +82,7 @@ impl<Q: FlowState, S: FlowStore> SwipeFlow<Q, S> {
|
|
|
|
Instant::now(),
|
|
|
|
Instant::now(),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
direction,
|
|
|
|
direction,
|
|
|
|
|
|
|
|
button_request,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
self.state = state;
|
|
|
|
self.state = state;
|
|
|
|
ctx.request_anim_frame();
|
|
|
|
ctx.request_anim_frame();
|
|
|
@ -91,6 +116,9 @@ impl<Q: FlowState, S: FlowStore> SwipeFlow<Q, S> {
|
|
|
|
fn handle_transition(&mut self, ctx: &mut EventCtx) {
|
|
|
|
fn handle_transition(&mut self, ctx: &mut EventCtx) {
|
|
|
|
if let Some(transition) = &self.transition {
|
|
|
|
if let Some(transition) = &self.transition {
|
|
|
|
if transition.animation.finished(Instant::now()) {
|
|
|
|
if transition.animation.finished(Instant::now()) {
|
|
|
|
|
|
|
|
if let Some(ButtonRequest { code, br_type }) = transition.button_request {
|
|
|
|
|
|
|
|
ctx.send_button_request(code, br_type);
|
|
|
|
|
|
|
|
}
|
|
|
|
self.transition = None;
|
|
|
|
self.transition = None;
|
|
|
|
unwrap!(self.store.clone(None)); // Free the clone.
|
|
|
|
unwrap!(self.store.clone(None)); // Free the clone.
|
|
|
|
|
|
|
|
|
|
|
@ -110,7 +138,7 @@ impl<Q: FlowState, S: FlowStore> SwipeFlow<Q, S> {
|
|
|
|
// can render both states in the transition animation.
|
|
|
|
// can render both states in the transition animation.
|
|
|
|
unwrap!(self.store.clone(Some(i)));
|
|
|
|
unwrap!(self.store.clone(Some(i)));
|
|
|
|
self.store.map_swipable(i, |s| s.swiped(ctx, direction));
|
|
|
|
self.store.map_swipable(i, |s| s.swiped(ctx, direction));
|
|
|
|
Decision::Goto(self.state, direction)
|
|
|
|
Decision::Goto(self.state, direction, None)
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
Decision::Nothing
|
|
|
|
Decision::Nothing
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -139,9 +167,13 @@ impl<Q: FlowState, S: FlowStore> Component for SwipeFlow<Q, S> {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
|
|
|
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
|
|
|
|
|
|
|
if let (Event::Attach, Some(br)) = (event, self.initial_button_request) {
|
|
|
|
|
|
|
|
ctx.send_button_request(br.code, br.br_type)
|
|
|
|
|
|
|
|
}
|
|
|
|
// TODO: are there any events we want to send to all? timers perhaps?
|
|
|
|
// TODO: are there any events we want to send to all? timers perhaps?
|
|
|
|
if let Event::Timer(EventCtx::ANIM_FRAME_TIMER) = event {
|
|
|
|
if let Event::Timer(EventCtx::ANIM_FRAME_TIMER) = event {
|
|
|
|
self.handle_transition(ctx);
|
|
|
|
self.handle_transition(ctx);
|
|
|
|
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Ignore events while transition is running.
|
|
|
|
// Ignore events while transition is running.
|
|
|
|
if self.transition.is_some() {
|
|
|
|
if self.transition.is_some() {
|
|
|
@ -158,8 +190,8 @@ impl<Q: FlowState, S: FlowStore> Component for SwipeFlow<Q, S> {
|
|
|
|
|
|
|
|
|
|
|
|
match decision {
|
|
|
|
match decision {
|
|
|
|
Decision::Nothing => None,
|
|
|
|
Decision::Nothing => None,
|
|
|
|
Decision::Goto(next_state, direction) => {
|
|
|
|
Decision::Goto(next_state, direction, button_request) => {
|
|
|
|
self.goto(ctx, direction, next_state);
|
|
|
|
self.goto(ctx, direction, next_state, button_request);
|
|
|
|
None
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Decision::Return(msg) => Some(msg),
|
|
|
|
Decision::Return(msg) => Some(msg),
|
|
|
|