use ferroui_reactive::disposables::Disposable;
use ferroui_reactive::Observer;
use ferroui_system::events::Event;
use ferroui_system::{IDisposable, IObservable};
use std::any::Any;
use std::cell::Cell;
use std::rc::{Rc, Weak};
#[derive(Default)]
pub(crate) struct ReactiveCommandBase {
can_execute_changed: Event<()>,
can_execute_value: Cell<bool>,
}
impl ReactiveCommandBase {
pub(crate) fn new() -> Rc<Self> {
Rc::new(Self::default())
}
pub(crate) fn on_can_execute_changed(&self, new_value: bool) {
self.can_execute_value.set(new_value);
self.can_execute_changed.raise(&());
}
pub(crate) fn icommand_can_execute(&self, _parameter: Option<&dyn Any>) -> bool {
self.can_execute_value.get()
}
pub(crate) fn add_can_execute_changed(self: &Rc<Self>, handler: Rc<dyn Fn()>) -> Rc<dyn IDisposable> {
let token = self.can_execute_changed.add(Rc::new(move |_: &()| handler()));
let base: Weak<Self> = Rc::downgrade(self);
Disposable::create(move || {
if let Some(base) = base.upgrade() {
base.can_execute_changed.remove(token);
}
})
}
}
pub(crate) fn icommand_execute<P: Clone + Default + 'static, R: 'static>(
parameter: Option<&dyn Any>,
execute: impl FnOnce(P) -> Rc<dyn IObservable<R>>,
) {
let parameter = match parameter {
None => P::default(),
Some(value) => match value.downcast_ref::<P>() {
Some(value) => value.clone(),
None => panic!(
"InvalidOperationException: Command requires parameters of type {}, but received parameter of another type.",
std::any::type_name::<P>()
),
},
};
let result = execute(parameter);
let _ = result.subscribe(Observer::create_all(|_| {}, |_| {}, || {}));
}