1use std::sync::Arc;
2
3use dioxus_core::{
4 prelude::spawn,
5 use_hook,
6 AttributeValue,
7};
8use dioxus_signals::{
9 ReadOnlySignal,
10 Readable,
11 Signal,
12 Writable,
13};
14use freya_core::custom_attributes::{
15 CustomAttributeValues,
16 NodeReference,
17 NodeReferenceLayout,
18};
19use tokio::sync::watch::channel;
20
21pub fn use_node() -> (AttributeValue, NodeReferenceLayout) {
23 use_node_from_signal(Signal::default)
24}
25
26pub fn use_node_from_signal(
27 init: impl FnOnce() -> Signal<NodeReferenceLayout>,
28) -> (AttributeValue, NodeReferenceLayout) {
29 let (tx, signal) = use_hook(|| {
30 let (tx, mut rx) = channel::<NodeReferenceLayout>(NodeReferenceLayout::default());
31 let mut signal = init();
32 spawn(async move {
33 while rx.changed().await.is_ok() {
34 if *signal.peek() != *rx.borrow() {
35 signal.set(rx.borrow().clone());
36 }
37 }
38 });
39
40 (Arc::new(tx), signal)
41 });
42
43 (
44 AttributeValue::any_value(CustomAttributeValues::Reference(NodeReference(tx))),
45 signal.read_unchecked().clone(),
46 )
47}
48
49pub fn use_node_signal() -> (AttributeValue, ReadOnlySignal<NodeReferenceLayout>) {
51 let (tx, signal) = use_hook(|| {
52 let (tx, mut rx) = channel::<NodeReferenceLayout>(NodeReferenceLayout::default());
53 let mut signal = Signal::new(NodeReferenceLayout::default());
54
55 spawn(async move {
56 while rx.changed().await.is_ok() {
57 if *signal.peek() != *rx.borrow() {
58 signal.set(rx.borrow().clone());
59 }
60 }
61 });
62
63 (Arc::new(tx), signal)
64 });
65
66 (
67 AttributeValue::any_value(CustomAttributeValues::Reference(NodeReference(tx))),
68 signal.into(),
69 )
70}
71
72pub fn use_node_signal_with_prev() -> (
73 AttributeValue,
74 ReadOnlySignal<Option<NodeReferenceLayout>>,
75 ReadOnlySignal<Option<NodeReferenceLayout>>,
76) {
77 let (tx, curr_signal, prev_signal) = use_hook(|| {
78 let (tx, mut rx) = channel::<NodeReferenceLayout>(NodeReferenceLayout::default());
79 let mut curr_signal = Signal::new(None);
80 let mut prev_signal = Signal::new(None);
81
82 spawn(async move {
83 while rx.changed().await.is_ok() {
84 if *curr_signal.peek() != Some(rx.borrow().clone()) {
85 prev_signal.set(curr_signal());
86 curr_signal.set(Some(rx.borrow().clone()));
87 }
88 }
89 });
90
91 (Arc::new(tx), curr_signal, prev_signal)
92 });
93
94 (
95 AttributeValue::any_value(CustomAttributeValues::Reference(NodeReference(tx))),
96 curr_signal.into(),
97 prev_signal.into(),
98 )
99}
100
101pub fn use_node_with_reference() -> (NodeReference, ReadOnlySignal<NodeReferenceLayout>) {
102 let (tx, signal) = use_hook(|| {
103 let (tx, mut rx) = channel::<NodeReferenceLayout>(NodeReferenceLayout::default());
104 let mut signal = Signal::new(NodeReferenceLayout::default());
105
106 spawn(async move {
107 while rx.changed().await.is_ok() {
108 if *signal.peek() != *rx.borrow() {
109 signal.set(rx.borrow().clone());
110 }
111 }
112 });
113
114 (Arc::new(tx), signal)
115 });
116
117 (NodeReference(tx), signal.into())
118}
119
120#[cfg(test)]
121mod test {
122 use freya::prelude::*;
123 use freya_testing::prelude::*;
124
125 use crate::use_node;
126
127 #[tokio::test]
128 pub async fn track_size() {
129 fn use_node_app() -> Element {
130 let (reference, size) = use_node();
131
132 rsx!(
133 rect {
134 reference: reference,
135 width: "50%",
136 height: "25%",
137 label {
138 "{size.area.width()}"
139 }
140 }
141 )
142 }
143
144 let mut utils = launch_test_with_config(
145 use_node_app,
146 TestingConfig::<()> {
147 size: (500.0, 800.0).into(),
148 ..TestingConfig::default()
149 },
150 );
151
152 utils.wait_for_update().await;
153 let root = utils.root().get(0);
154 assert_eq!(
155 root.get(0).get(0).text().unwrap().parse::<f32>(),
156 Ok(500.0 * 0.5)
157 );
158
159 utils.resize((300.0, 800.0).into());
160 utils.wait_for_update().await;
161
162 let root = utils.root().get(0);
163 assert_eq!(
164 root.get(0).get(0).text().unwrap().parse::<f32>(),
165 Ok(300.0 * 0.5)
166 );
167 }
168}