diff options
Diffstat (limited to 'src/lib/stores/timer.svelte.js')
| -rw-r--r-- | src/lib/stores/timer.svelte.js | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/src/lib/stores/timer.svelte.js b/src/lib/stores/timer.svelte.js new file mode 100644 index 0000000..dea1799 --- /dev/null +++ b/src/lib/stores/timer.svelte.js @@ -0,0 +1,106 @@ +import { Notyf } from "notyf"; + +const DEFAULT_MINS = 12; +const MIN_MINS = 0.5; + +const initialMins = Number(sessionStorage.getItem("mins")) || DEFAULT_MINS; +const initialRunning = Boolean(Number(sessionStorage.getItem("running"))); +const initialDeadline = Number(sessionStorage.getItem("deadline")) || Date.now(); +const initialRemainingMs = initialRunning + ? Math.max(initialDeadline - Date.now(), 0) + : initialMins * 60 * 1000; + +let mins = $state(initialMins); +let running = $state(initialRunning); +let deadline = $state(initialDeadline); +let remainingMs = $state(initialRemainingMs); + +let intervalId = null; + +function persist() { + sessionStorage.setItem("mins", mins); + sessionStorage.setItem("running", Number(running)); + sessionStorage.setItem("deadline", deadline); +} + +function showRoundCompletedToast() { + const notyf = new Notyf({ + duration: 0, + position: { x: "center", y: "top" }, + dismissible: true, + }); + notyf.error("Round completed"); +} + +function stopInterval() { + if (intervalId !== null) clearInterval(intervalId); + intervalId = null; +} + +function tick() { + const msToDeadline = deadline - Date.now(); + if (msToDeadline > 0) { + remainingMs = msToDeadline; + return; + } + stopInterval(); + running = false; + remainingMs = mins * 60 * 1000; + persist(); + showRoundCompletedToast(); +} + +export function getMins() { + return mins; +} + +export function getRunning() { + return running; +} + +export function getRemainingMs() { + return remainingMs; +} + +export function formatRemaining(ms) { + const m = Math.floor((ms % (1000 * 60 * 60)) / (1000 * 60)); + const s = Math.floor((ms % (1000 * 60)) / 1000); + const pad = (n) => (n < 10 ? "0" + n : String(n)); + return `${pad(m)}:${pad(s)}`; +} + +export function getDisplay() { + return formatRemaining(remainingMs); +} + +export function stopTimer() { + stopInterval(); + running = false; + remainingMs = mins * 60 * 1000; + persist(); +} + +export function start(fresh = true) { + if (fresh && running) return; + if (fresh) { + deadline = Date.now() + mins * 60 * 1000; + } + running = true; + remainingMs = Math.max(deadline - Date.now(), 0); + persist(); + stopInterval(); + intervalId = setInterval(tick, 1000); +} + +export function changeMinutes(delta) { + mins = Math.max(mins + delta, MIN_MINS); + stopTimer(); +} + +// Resume a timer that was still running across a page reload, otherwise +// settle the display to the resting (not-running) state. +if (initialRunning) { + start(false); +} else { + stopTimer(); +} |
