dioxus_spring/
use_spring_ref.rs1use crate::spring;
2use dioxus::prelude::*;
3use futures::StreamExt;
4use interpolation::Lerp;
5use std::{collections::VecDeque, pin::Pin, task::Poll, time::Duration};
6
7pub fn use_spring_ref<V>(from: V, f: impl FnMut(V) + 'static) -> UseSpringRef<V>
12where
13 V: Lerp<Scalar = f32> + Clone + 'static,
14{
15 let mut channel = use_hook(|| {
16 let (tx, rx) = async_channel::unbounded();
17 CopyValue::new((tx, Box::pin(rx)))
18 });
19 let mut f_cell = Some(f);
20
21 use_future(move || {
22 let mut f = f_cell.take().unwrap();
23 let mut current = from.clone();
24 let mut spring_cell = None;
25 let mut stack = VecDeque::new();
26
27 futures::future::poll_fn(move |cx| {
28 while let Poll::Ready(Some(msg)) = channel.write().1.poll_next_unpin(cx) {
29 match msg {
30 Message::Set(to, duration_cell) => {
31 if let Some(duration) = duration_cell {
32 let spring = spring(current.clone(), to, duration);
33 spring_cell = Some(Box::pin(spring));
34 stack.clear();
35 } else {
36 current = to.clone();
37 spring_cell.take();
38 stack.clear();
39 f(to);
40 }
41 }
42 Message::Queue(to, duration) => {
43 stack.push_back((to, duration));
44 }
45 }
46 }
47
48 if spring_cell.is_none() {
49 if let Some((to, duration)) = stack.pop_front() {
50 let spring = crate::spring(current.clone(), to, duration);
51 spring_cell = Some(Box::pin(spring));
52 } else {
53 spring_cell = None;
54 }
55 }
56
57 while let Some(spring) = spring_cell.as_mut() {
58 let mut is_done = false;
59 while let Poll::Ready(item) = spring.poll_next_unpin(cx) {
60 if let Some(val) = item {
61 current = val.clone();
62 f(val);
63 } else {
64 is_done = true;
65 break;
66 }
67 }
68
69 if is_done {
70 if let Some((to, duration)) = stack.pop_front() {
71 let spring = crate::spring(current.clone(), to, duration);
72 spring_cell = Some(Box::pin(spring));
73 } else {
74 spring_cell = None;
75 }
76 } else {
77 break;
78 }
79 }
80
81 Poll::<()>::Pending
82 })
83 });
84
85 UseSpringRef { channel }
86}
87
88pub(crate) enum Message<V> {
89 Set(V, Option<Duration>),
90 Queue(V, Duration),
91}
92
93pub struct UseSpringRef<V: 'static> {
95 channel: CopyValue<(
96 async_channel::Sender<Message<V>>,
97 Pin<Box<async_channel::Receiver<Message<V>>>>,
98 )>,
99}
100
101impl<V> UseSpringRef<V> {
102 pub fn set(&self, to: V) {
103 self.channel
104 .read()
105 .0
106 .force_send(Message::Set(to, None))
107 .unwrap();
108 }
109
110 pub fn animate(&self, to: V, duration: Duration) {
111 self.channel
112 .read()
113 .0
114 .force_send(Message::Set(to, Some(duration)))
115 .unwrap();
116 }
117
118 pub fn queue(&self, to: V, duration: Duration) {
119 self.channel
120 .read()
121 .0
122 .force_send(Message::Queue(to, duration))
123 .unwrap();
124 }
125}
126
127impl<V> Clone for UseSpringRef<V> {
128 fn clone(&self) -> Self {
129 *self
130 }
131}
132
133impl<V> Copy for UseSpringRef<V> {}