Active display of a timer

This commit is contained in:
2022-07-29 04:22:21 +02:00
parent f67d5f6a2e
commit 263b4edd07
6 changed files with 251 additions and 102 deletions

View File

@@ -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(())