use std::cell::RefCell;
use std::rc::Rc;
use web_time::{Duration, Instant};
use crate::{Signal, reactive, signal, timer};
#[deprecated(
note = "Debounced entries live on the shared timer queue, which `ReposeRuntime::tick_overlays` already polls via `timer::poll`. Polling here too would advance frame timers twice per redraw. Use `timer::next_deadline` instead."
)]
pub fn next_deadline() -> Option<Instant> {
timer::next_deadline()
}
#[deprecated(
note = "`ReposeRuntime::tick_overlays` already polls the shared queue via `timer::poll`. Calling this too would advance frame timers twice per redraw. Use `timer::poll` instead."
)]
pub fn poll() {
timer::poll();
}
#[track_caller]
pub fn debounced_signal<T>(source: Signal<T>, delay: Duration) -> Signal<T>
where
T: Clone + PartialEq + 'static,
{
let loc = std::panic::Location::caller();
debounced_signal_with_key(
format!("debounce:{}:{}:{}", loc.file(), loc.line(), loc.column()),
source,
delay,
)
}
pub fn debounced_signal_with_key<T>(
key: impl Into<String>,
source: Signal<T>,
delay: Duration,
) -> Signal<T>
where
T: Clone + PartialEq + 'static,
{
let key = key.into();
crate::remember_with_key(format!("debounce:{key}"), || {
debounced_signal_uncached(source.clone(), delay)
})
.as_ref()
.clone()
}
fn debounced_signal_uncached<T>(source: Signal<T>, delay: Duration) -> Signal<T>
where
T: Clone + PartialEq + 'static,
{
let out = signal(source.get());
let out_clone = out.clone();
let pending: Rc<RefCell<Option<T>>> = Rc::new(RefCell::new(None));
let delay_c = delay;
let slot: Rc<RefCell<Option<timer::TimerHandle>>> = Rc::new(RefCell::new(None));
let obs_id = reactive::new_observer({
let source = source.clone();
let slot = slot.clone();
move || {
let v = source.get();
let old_value = pending.borrow_mut().replace(v.clone());
drop(old_value);
let out_c = out_clone.clone();
let pending_c = pending.clone();
let handle = timer::delay(delay_c, move || {
let value = pending_c.borrow_mut().take();
if let Some(val) = value {
out_c.set_neq(val);
}
});
let old_handle = slot.borrow_mut().replace(handle);
drop(old_handle);
}
});
reactive::run_observer_now(obs_id);
crate::scoped_effect(move || {
crate::on_unmount(move || {
reactive::remove_observer(obs_id);
let old_handle = slot.borrow_mut().take();
drop(old_handle);
})
});
out
}