From 227160e04455888ab3b644f52f2eded4c21ca232 Mon Sep 17 00:00:00 2001 From: ModZero Date: Thu, 28 Jul 2022 01:47:53 +0200 Subject: [PATCH] Keep a database of timers --- src-tauri/src/main.rs | 158 +++++++++++++++++++++++++++++++++--------- src/App.svelte | 56 +++++++++++---- src/app.css | 45 ++---------- src/main.ts | 4 ++ 4 files changed, 178 insertions(+), 85 deletions(-) diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 0da8618..7b6d5c5 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -3,13 +3,34 @@ windows_subsystem = "windows" )] -use std::time::{Duration, Instant}; +use std::{ + collections::HashMap, + sync::{Arc, Mutex}, + time::{Duration, Instant}, fmt, error::Error, +}; use chrono::{DateTime, FixedOffset, Local}; -use tauri::{async_runtime::spawn, Window}; +use tauri::{State, Window, async_runtime::spawn}; use tokio::time::interval; use uuid::Uuid; +#[derive(serde::Serialize, Debug)] +enum TimerError { + NotFound, + NotStarted, +} + +impl fmt::Display for TimerError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + TimerError::NotFound => write!(f, "timer not found"), + TimerError::NotStarted => write!(f, "timer not started"), + } + } +} + +impl Error for TimerError {} + #[derive(Clone, Default, serde::Serialize)] struct Timer { id: Uuid, @@ -17,6 +38,8 @@ struct Timer { duration: Duration, elapsed: Option, message: String, + #[serde(skip)] + checked: Option, } impl Timer { @@ -33,52 +56,119 @@ impl Timer { self.elapsed.map_or(false, |e| e >= self.duration) } - async fn run(&mut self, window: Window) { - self.started = Some(Local::now().into()); - let mut elapsed = Duration::from_secs(0); - self.elapsed = Some(elapsed); - let mut last_checked = Instant::now(); - - let mut interval = interval(Duration::from_secs(1) / 60); - loop { - interval.tick().await; - let now = Instant::now(); - let duration = now - last_checked; - - elapsed += duration; - self.elapsed = Some(elapsed); - - if self.complete() { - break; - } - - if window.emit("timer-tick", self.clone()).is_err() { - break; - } - last_checked = now; + fn start(self) -> Self { + Timer { + started: Some(Local::now().into()), + elapsed: Some(Duration::from_secs(0)), + checked: Some(Instant::now()), + ..self } + } - window - .emit("timer-done", self.clone()) - .expect("Our window went away?"); + fn tick(self) -> Result { + 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 + }) } } +#[derive(Default)] +struct Timers(Arc>>); + +impl Timers { + fn make_timer(&self, duration: Duration, message: &str) -> Timer { + let timer = Timer::new(message, duration); + + self.0.lock().unwrap().insert(timer.id, timer.clone()); + + timer + } + + fn delete_timer(&self, timer_id: Uuid) -> Option { + self.0.lock().unwrap().get(&timer_id).cloned() + } + + fn start_timer(&self, timer_id: Uuid) -> Result { + let mut timers = self.0.lock().unwrap(); + match timers.get(&timer_id).cloned() { + None => Err(TimerError::NotFound), + Some(t) => { + let started = t.start(); + timers.insert(started.id, started.clone()); + + Ok(started) + } + } + } + + fn tick_timer(&self, timer_id: Uuid) -> Result { + let mut timers = self.0.lock().unwrap(); + match timers.get(&timer_id).cloned() { + None => Err(TimerError::NotFound), + Some(t) => { + let started = t.tick()?; + timers.insert(started.id, started.clone()); + + Ok(started) + } + } + } + +} + #[tauri::command] -fn start_timer(window: Window, duration: Duration, message: &str) -> Uuid { - let mut timer = Timer::new(message, duration); - let timer_id = timer.id; +fn make_timer(timers: State<'_, Timers>, duration: Duration, message: &str) -> Timer { + timers.make_timer(duration, message) +} + +#[tauri::command] +fn delete_timer(timers: State<'_, Timers>, timer_id: Uuid) -> Option { + timers.delete_timer(timer_id) +} + +#[tauri::command] +fn start_timer(window: Window, timers: State<'_, Timers>, timer_id: Uuid) -> Result { + let timers = Timers(timers.0.to_owned()); + let timer = timers.start_timer(timer_id)?; + let res = timer.clone(); spawn(async move { - timer.run(window).await; + let mut interval = interval(Duration::from_secs(1) / 60); + + loop { + interval.tick().await; + match timers.tick_timer(timer_id) { + Err(_) => break, + Ok(timer) => { + if timer.complete() || window.emit("timer-tick", timer).is_err() { + break; + } + } + } + } + + window.emit("timer-done", timer).ok(); }); - timer_id + Ok(res) } fn main() { tauri::Builder::default() - .invoke_handler(tauri::generate_handler![start_timer]) + .manage(Timers(Default::default())) + .invoke_handler(tauri::generate_handler![ + delete_timer, + make_timer, + start_timer + ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); } diff --git a/src/App.svelte b/src/App.svelte index 07cbcf1..bb2c68a 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -1,3 +1,7 @@ +
- - +
+
+ + +
+ + diff --git a/src/app.css b/src/app.css index bcc7233..9236889 100644 --- a/src/app.css +++ b/src/app.css @@ -1,5 +1,5 @@ :root { - font-family: Inter, Avenir, Helvetica, Arial, sans-serif; + font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px; font-weight: 400; @@ -26,7 +26,6 @@ a:hover { body { margin: 0; - display: flex; place-items: center; min-width: 320px; min-height: 100vh; @@ -37,45 +36,15 @@ h1 { line-height: 1.1; } -.card { - padding: 2em; -} #app { + position: absolute; max-width: 1280px; - margin: 0 auto; + margin: 0 0; padding: 2rem; text-align: center; -} - -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; -} -button:hover { - border-color: #646cff; -} -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; -} - -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } - a:hover { - color: #747bff; - } - button { - background-color: #f9f9f9; - } + top: 0; + bottom: 0; + left: 0; + right: 0; } diff --git a/src/main.ts b/src/main.ts index f5a8eeb..fea7b53 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,3 +1,7 @@ +// Copyright 2022 ModZero. +// SPDX-License-Identifier: AGPL-3.0-or-later + + import "./app.css"; import App from "./App.svelte";