diff options
Diffstat (limited to 'src/timer.ml')
-rw-r--r-- | src/timer.ml | 116 |
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 |