Skip to main content

dioxus_nox_timer/
stopwatch.rs

1//! Stopwatch hook — counts elapsed time from a start time.
2
3use dioxus::prelude::*;
4
5use crate::time;
6
7/// Stopwatch hook — counts up from a start time.
8///
9/// Returns a signal with the elapsed seconds. Ticks every second via
10/// wall-clock diff. Automatically stops ticking when `ended_at_ms` is provided.
11///
12/// # Parameters
13///
14/// - `started_at_ms`: Epoch milliseconds when the stopwatch started.
15/// - `ended_at_ms`: Epoch milliseconds when it ended (`None` = still running).
16///
17/// # Example
18///
19/// ```rust,ignore
20/// let started = dioxus_nox_timer::time::now_ms(); // capture start time
21/// let elapsed = use_stopwatch(started, None); // None = still running
22///
23/// rsx! {
24///     p { "Elapsed: {format_duration(*elapsed.read())}" }
25/// }
26/// ```
27pub fn use_stopwatch(started_at_ms: i64, ended_at_ms: Option<i64>) -> Signal<i64> {
28    let mut elapsed_secs = use_signal(|| {
29        let end = ended_at_ms.unwrap_or_else(time::now_ms);
30        ((end - started_at_ms).max(0)) / 1000
31    });
32
33    // If already ended, compute once and don't tick.
34    let is_running = ended_at_ms.is_none();
35
36    use_effect(move || {
37        if !is_running {
38            // Compute final elapsed once.
39            if let Some(end) = ended_at_ms {
40                elapsed_secs.set(((end - started_at_ms).max(0)) / 1000);
41            }
42            return;
43        }
44        spawn(async move {
45            loop {
46                time::sleep_ms(1000).await;
47                let now = time::now_ms();
48                let elapsed = ((now - started_at_ms).max(0)) / 1000;
49                elapsed_secs.set(elapsed);
50            }
51        });
52    });
53
54    elapsed_secs
55}