use std::any::Any;
use floem_reactive::{
create_effect, create_rw_signal, create_updater, RwSignal, SignalGet, SignalUpdate,
};
use crate::{
context::UpdateCx,
id::ViewId,
view::{IntoView, View},
};
pub struct ValueContainer<T> {
id: ViewId,
on_update: Option<Box<dyn Fn(T)>>,
}
pub fn create_value_container_signals<T>(
producer: impl Fn() -> T + 'static,
) -> (RwSignal<T>, RwSignal<T>)
where
T: Clone + 'static,
{
let initial_value = producer();
let inbound_signal = create_rw_signal(initial_value.clone());
create_effect(move |_| {
let checked = producer();
inbound_signal.set(checked);
});
let outbound_signal = create_rw_signal(initial_value.clone());
create_effect(move |_| {
let checked = outbound_signal.get();
inbound_signal.set(checked);
});
(inbound_signal, outbound_signal)
}
pub fn value_container<T: 'static, V: IntoView + 'static>(
child: V,
value_update: impl Fn() -> T + 'static,
) -> ValueContainer<T> {
let id = ViewId::new();
let child = child.into_view();
id.set_children(vec![child]);
create_updater(value_update, move |new_value| id.update_state(new_value));
ValueContainer {
id,
on_update: None,
}
}
impl<T> ValueContainer<T> {
pub fn on_update(mut self, action: impl Fn(T) + 'static) -> Self {
self.on_update = Some(Box::new(action));
self
}
}
impl<T: 'static> View for ValueContainer<T> {
fn id(&self) -> ViewId {
self.id
}
fn update(&mut self, _cx: &mut UpdateCx, state: Box<dyn Any>) {
if let Ok(state) = state.downcast::<T>() {
if let Some(on_update) = self.on_update.as_ref() {
on_update(*state);
}
}
}
}