polyhorn_ios/raw/
animator.rs1use 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
13pub 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 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
75pub struct AnimationHandle {
78 #[allow(dead_code)]
79 handle: QueueBound<PLYAnimationHandle>,
80 rx: Receiver<()>,
81}
82
83impl AnimationHandle {
84 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 {}