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}