Active display of a timer
This commit is contained in:
@@ -13,7 +13,7 @@ use chrono::{DateTime, FixedOffset, Local};
|
||||
use tauri::{
|
||||
async_runtime::spawn,
|
||||
plugin::{Builder, TauriPlugin},
|
||||
AppHandle, Runtime, State, Manager,
|
||||
AppHandle, Manager, Runtime, State,
|
||||
};
|
||||
use tokio::time::interval;
|
||||
use uuid::Uuid;
|
||||
@@ -41,17 +41,16 @@ pub struct Timer {
|
||||
started: Option<DateTime<FixedOffset>>,
|
||||
duration: Duration,
|
||||
elapsed: Option<Duration>,
|
||||
message: String,
|
||||
#[serde(skip)]
|
||||
checked: Option<Instant>,
|
||||
version: u64,
|
||||
}
|
||||
|
||||
impl Timer {
|
||||
fn new(message: &str, duration: Duration) -> Self {
|
||||
fn new(duration: Duration) -> Self {
|
||||
Self {
|
||||
id: Uuid::new_v4(),
|
||||
duration,
|
||||
message: message.to_string(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
@@ -60,28 +59,35 @@ impl Timer {
|
||||
self.elapsed.map_or(false, |e| e >= self.duration)
|
||||
}
|
||||
|
||||
fn start(self) -> Self {
|
||||
Timer {
|
||||
started: Some(Local::now().into()),
|
||||
elapsed: Some(Duration::from_secs(0)),
|
||||
checked: Some(Instant::now()),
|
||||
..self
|
||||
fn start(&mut self) {
|
||||
let now = Local::now().into();
|
||||
self.started = Some(now);
|
||||
self.elapsed = Some(Duration::from_secs(0));
|
||||
self.checked = Some(Instant::now());
|
||||
self.version += 1;
|
||||
}
|
||||
|
||||
/// Increment the timer, returning the time since last tick
|
||||
fn tick(&mut self) -> Result<(), TimerError> {
|
||||
let now = Instant::now();
|
||||
match self.checked {
|
||||
None => Err(TimerError::NotStarted),
|
||||
Some(checked) => {
|
||||
self.elapsed = Some(now - checked);
|
||||
self.checked = Some(checked);
|
||||
self.version += 1;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn tick(self) -> Result<Self, TimerError> {
|
||||
let now = Instant::now();
|
||||
let elapsed = now
|
||||
- match self.checked {
|
||||
None => return Err(TimerError::NotStarted),
|
||||
Some(checked) => checked,
|
||||
};
|
||||
|
||||
Ok(Timer {
|
||||
elapsed: self.elapsed.map(|e| e + elapsed),
|
||||
checked: Some(now),
|
||||
..self
|
||||
})
|
||||
fn reset(&mut self, duration: Duration) {
|
||||
self.duration = duration;
|
||||
self.started = None;
|
||||
self.elapsed = None;
|
||||
self.checked = None;
|
||||
self.version += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,8 +95,8 @@ impl Timer {
|
||||
struct Timers(Arc<Mutex<HashMap<Uuid, Timer>>>);
|
||||
|
||||
impl Timers {
|
||||
fn make(&self, duration: Duration, message: &str) -> Timer {
|
||||
let timer = Timer::new(message, duration);
|
||||
fn make(&self, duration: Duration) -> Timer {
|
||||
let timer = Timer::new(duration);
|
||||
|
||||
self.0.lock().unwrap().insert(timer.id, timer.clone());
|
||||
|
||||
@@ -103,34 +109,40 @@ impl Timers {
|
||||
|
||||
fn start(&self, timer_id: Uuid) -> Result<Timer, TimerError> {
|
||||
let mut timers = self.0.lock().unwrap();
|
||||
match timers.get(&timer_id).cloned() {
|
||||
match timers.get_mut(&timer_id) {
|
||||
None => Err(TimerError::NotFound),
|
||||
Some(t) => {
|
||||
let started = t.start();
|
||||
timers.insert(started.id, started.clone());
|
||||
t.start();
|
||||
|
||||
Ok(started)
|
||||
Ok(t.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn tick(&self, timer_id: Uuid) -> Result<Timer, TimerError> {
|
||||
let mut timers = self.0.lock().unwrap();
|
||||
match timers.get(&timer_id).cloned() {
|
||||
match timers.get_mut(&timer_id) {
|
||||
None => Err(TimerError::NotFound),
|
||||
Some(t) => t.tick().and(Ok(t.clone())),
|
||||
}
|
||||
}
|
||||
|
||||
fn reset(&self, timer_id: Uuid, duration: Duration) -> Result<Timer, TimerError> {
|
||||
let mut timers = self.0.lock().unwrap();
|
||||
match timers.get_mut(&timer_id) {
|
||||
None => Err(TimerError::NotFound),
|
||||
Some(t) => {
|
||||
let started = t.tick()?;
|
||||
timers.insert(started.id, started.clone());
|
||||
t.reset(duration);
|
||||
|
||||
Ok(started)
|
||||
Ok(t.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn make(timers: State<'_, Timers>, duration: Duration, message: &str) -> Timer {
|
||||
timers.make(duration, message)
|
||||
fn make(timers: State<'_, Timers>, duration: Duration) -> Timer {
|
||||
timers.make(duration)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -138,6 +150,22 @@ fn delete(timers: State<'_, Timers>, timer_id: Uuid) -> Option<Timer> {
|
||||
timers.delete(timer_id)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn reset<R: Runtime>(
|
||||
_app: AppHandle<R>,
|
||||
timers: State<'_, Timers>,
|
||||
timer_id: Uuid,
|
||||
duration: Duration,
|
||||
) -> Result<Timer, TimerError> {
|
||||
let res = timers.reset(timer_id, duration);
|
||||
|
||||
if let Ok(timer) = &res {
|
||||
_app.emit_all("timer-update", timer).ok();
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn start<R: Runtime>(
|
||||
_app: AppHandle<R>,
|
||||
@@ -152,14 +180,11 @@ fn start<R: Runtime>(
|
||||
|
||||
loop {
|
||||
interval.tick().await;
|
||||
match timers.tick(timer_id) {
|
||||
Err(_) => break,
|
||||
match &timers.tick(timer_id) {
|
||||
Err(_) => break, // Timer is gone or no longer running, we're done
|
||||
Ok(timer) => {
|
||||
_app.emit_all("timer-update", timer).ok();
|
||||
if timer.is_complete() {
|
||||
_app.emit_all("timer-done", timer).ok();
|
||||
break;
|
||||
}
|
||||
if _app.emit_all("timer-tick", timer).is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -172,11 +197,7 @@ fn start<R: Runtime>(
|
||||
|
||||
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
Builder::new("timers")
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
delete,
|
||||
make,
|
||||
start
|
||||
])
|
||||
.invoke_handler(tauri::generate_handler![delete, make, reset, start,])
|
||||
.setup(|app_handle| {
|
||||
app_handle.manage(Timers::default());
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user