use crate::utils::easing::Easing;
use std::time::{Duration, Instant};
#[derive(Clone, Debug)]
pub struct Timer {
start: Option<Instant>,
pub duration: Duration,
elapsed_on_pause: Duration,
paused: bool,
}
impl Timer {
pub fn new(duration: Duration) -> Self {
Self {
start: None,
duration,
elapsed_on_pause: Duration::ZERO,
paused: false,
}
}
pub fn from_millis(ms: u64) -> Self {
Self::new(Duration::from_millis(ms))
}
pub fn from_secs_f32(secs: f32) -> Self {
Self::new(Duration::from_secs_f32(secs))
}
pub fn start(&mut self) {
self.start = Some(Instant::now());
self.elapsed_on_pause = Duration::ZERO;
self.paused = false;
}
pub fn pause(&mut self) {
if !self.paused && self.start.is_some() {
self.elapsed_on_pause = self.elapsed();
self.paused = true;
}
}
pub fn resume(&mut self) {
if self.paused {
self.start = Some(Instant::now() - self.elapsed_on_pause);
self.paused = false;
}
}
pub fn reset(&mut self) {
self.start = None;
self.elapsed_on_pause = Duration::ZERO;
self.paused = false;
}
pub fn restart(&mut self) {
self.reset();
self.start();
}
pub fn is_running(&self) -> bool {
self.start.is_some() && !self.paused && !self.is_finished()
}
pub fn is_finished(&self) -> bool {
self.elapsed() >= self.duration
}
pub fn elapsed(&self) -> Duration {
match self.start {
Some(start) if !self.paused => Instant::now() - start,
_ => self.elapsed_on_pause,
}
}
pub fn remaining(&self) -> Duration {
self.duration.saturating_sub(self.elapsed())
}
pub fn progress(&self) -> f64 {
let elapsed = self.elapsed().as_secs_f64();
let duration = self.duration.as_secs_f64();
if duration == 0.0 {
1.0
} else {
(elapsed / duration).clamp(0.0, 1.0)
}
}
pub fn progress_eased(&self, easing: Easing) -> f64 {
easing.ease(self.progress())
}
}