aboutsummaryrefslogtreecommitdiff
path: root/src/lib/stores/timer.svelte.js
blob: dea179904c116ea3f39a31b18bd5d18093171bfe (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
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();
}