aboutsummaryrefslogtreecommitdiff
path: root/src/timer.ml
diff options
context:
space:
mode:
Diffstat (limited to 'src/timer.ml')
-rw-r--r--src/timer.ml116
1 files changed, 116 insertions, 0 deletions
diff --git a/src/timer.ml b/src/timer.ml
new file mode 100644
index 0000000..5ff0b8b
--- /dev/null
+++ b/src/timer.ml
@@ -0,0 +1,116 @@
+(* Audio *)
+
+let c3 = Audio.create "sounds/c3.mp3"
+
+let c4 = Audio.create "sounds/c4.mp3"
+
+let c5 = Audio.create "sounds/c5.mp3"
+
+let playAudio (step : Step.state) =
+ match step.step with
+ | Step.Prepare when step.remaining == !Config.config.prepare ->
+ Audio.playOrReplay c3
+ | Step.Work when step.remaining == !Config.config.work ->
+ Audio.playOrReplay c5
+ | Step.Rest when step.remaining == !Config.config.rest ->
+ Audio.playOrReplay c3
+ | Step.End -> Audio.playOrReplay c3
+ | _ -> if step.remaining <= 3 then Audio.playOrReplay c4 else ()
+
+(* Elements *)
+
+let timerElt = Document.querySelectorUnsafe "#g-Timer"
+
+let dialElt = Document.querySelectorUnsafe "#g-Timer__Dial"
+
+let arcPathElt = Document.querySelectorUnsafe "#g-Timer__ArcProgress"
+
+let stepElt = Document.querySelectorUnsafe "#g-Timer__Step"
+
+let durationElt = Document.querySelectorUnsafe "#g-Timer__Duration"
+
+let tabataCurrentElt = Document.querySelectorUnsafe "#g-Timer__TabataCurrent"
+
+let tabataTotalElt = Document.querySelectorUnsafe "#g-Timer__TabataTotal"
+
+let cycleCurrentElt = Document.querySelectorUnsafe "#g-Timer__CycleCurrent"
+
+let cycleTotalElt = Document.querySelectorUnsafe "#g-Timer__CycleTotal"
+
+let stopElt = Document.querySelectorUnsafe "#g-Timer__Stop"
+
+(* State *)
+
+let interval = ref None
+
+let duration = ref 0
+
+let elapsedTime = ref 0
+
+let onStop : (unit -> unit) ref = ref (fun () -> ())
+
+let isPlaying = ref false
+
+(* Actions *)
+
+let playPause _ = isPlaying := not !isPlaying
+
+let stop _ =
+ let () = Belt.Option.forEach !interval Js.Global.clearInterval in
+ !onStop ()
+
+(* View *)
+
+let updateDom () =
+ let angle =
+ Js.Int.toFloat !elapsedTime /. Js.Int.toFloat !duration *. 360.0
+ in
+ let () =
+ Element.setAttribute arcPathElt "d" (Arc.describe 0.0 0.0 95.0 0.0 angle)
+ in
+ let step = Step.getAt !Config.config !elapsedTime in
+ let () = Element.setInnerText stepElt (Step.prettyPrint step.step) in
+ let () =
+ Element.setInnerText durationElt (Duration.prettyPrint step.remaining)
+ in
+ let () =
+ Element.setInnerText tabataCurrentElt (Js.Int.toString step.tabata)
+ in
+ let () = playAudio step in
+ Element.setInnerText cycleCurrentElt (Js.Int.toString step.cycle)
+
+(* Update *)
+
+let update () =
+ if !isPlaying then
+ let () = elapsedTime := !elapsedTime + 1 in
+ if !elapsedTime > !duration then stop () else updateDom ()
+ else ()
+
+(* Init *)
+
+let init () =
+ let () = duration := Config.getDuration () in
+ let () = elapsedTime := 0 in
+ let () =
+ Element.setInnerText tabataTotalElt (Js.Int.toString !Config.config.tabatas)
+ in
+ Element.setInnerText cycleTotalElt (Js.Int.toString !Config.config.cycles)
+
+(* Setup and start *)
+
+let setup onTimerStop = onStop := onTimerStop
+
+let show () =
+ let () = updateDom () in
+ Element.setStyle timerElt "display: flex"
+
+let hide () = Element.setStyle timerElt "display: none"
+
+let start () =
+ let () = interval := Some (Js.Global.setInterval update 1000) in
+ isPlaying := true
+
+let () =
+ let () = Element.addEventListener stopElt "click" stop in
+ Element.addEventListener dialElt "click" playPause