Skip to main content

polyhorn_ios/raw/
animator.rs

1use dispatch::Queue;
2use futures::channel::oneshot::{channel, Receiver};
3use futures::Future;
4use polyhorn_ios_sys::polykit::{PLYAnimationHandle, PLYCallback, PLYKeyframeAnimation, PLYView};
5use polyhorn_ios_sys::quartzcore::CATransform3D;
6use polyhorn_ios_sys::IntoRaw;
7use polyhorn_ui::animation::{Animation, Keyframe, KeyframeAnimation};
8use std::pin::Pin;
9use std::task::{Context, Poll};
10
11use super::{Convert, QueueBound};
12
13/// Concrete implementation of an animator that animates `UIView`s and related
14/// classes.
15pub struct Animator {
16    view: PLYView,
17}
18
19fn convert_keyframes<T>(keyframes: KeyframeAnimation<T>) -> PLYKeyframeAnimation
20where
21    T: Copy + IntoRaw,
22{
23    PLYKeyframeAnimation::new(
24        keyframes.duration.as_secs_f64(),
25        keyframes
26            .keyframes
27            .iter()
28            .map(|frame| frame.time.as_secs_f64() / keyframes.duration.as_secs_f64())
29            .collect::<Vec<_>>()
30            .as_slice(),
31        keyframes
32            .keyframes
33            .iter()
34            .map(|frame| frame.value)
35            .collect::<Vec<_>>()
36            .as_slice(),
37    )
38}
39
40impl Animator {
41    /// Returns a new animator for the given view.
42    pub fn new(view: PLYView) -> Animator {
43        Animator { view }
44    }
45}
46
47impl polyhorn_ui::animation::Animator for Animator {
48    type AnimationHandle = AnimationHandle;
49
50    fn start(&mut self, animation: Animation) -> AnimationHandle {
51        let handle = match animation {
52            Animation::Opacity(keyframes) => self
53                .view
54                .add_animation(convert_keyframes(keyframes), "opacity"),
55            Animation::Transform(keyframes) => self.view.add_animation(
56                convert_keyframes(KeyframeAnimation {
57                    keyframes: keyframes
58                        .keyframes
59                        .into_iter()
60                        .map(|keyframe| Keyframe {
61                            time: keyframe.time,
62                            value: Convert::<CATransform3D>::convert(keyframe.value),
63                        })
64                        .collect(),
65                    duration: keyframes.duration,
66                }),
67                "transform",
68            ),
69        };
70
71        AnimationHandle::new(handle)
72    }
73}
74
75/// Concrete implementation of a handle that controls the animation of a
76/// `UIView` or a related class.
77pub struct AnimationHandle {
78    #[allow(dead_code)]
79    handle: QueueBound<PLYAnimationHandle>,
80    rx: Receiver<()>,
81}
82
83impl AnimationHandle {
84    /// Returns a new wrapper around the given Objective-C animation handle.
85    pub fn new(handle: PLYAnimationHandle) -> AnimationHandle {
86        let mut handle = handle;
87        let (tx, rx) = channel();
88        let mut tx = Some(tx);
89
90        handle.set_on_stop(PLYCallback::new(move |_| {
91            if let Some(tx) = tx.take() {
92                let _ = tx.send(());
93            }
94        }));
95
96        let handle = unsafe { QueueBound::adopt(Queue::main(), handle) };
97
98        AnimationHandle { handle, rx }
99    }
100}
101
102impl Future for AnimationHandle {
103    type Output = ();
104
105    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
106        match Pin::new(&mut self.rx).poll(cx) {
107            Poll::Pending => Poll::Pending,
108            Poll::Ready(_) => Poll::Ready(()),
109        }
110    }
111}
112
113impl polyhorn_ui::animation::AnimationHandle for AnimationHandle {}