aboutsummaryrefslogtreecommitdiff
path: root/src/View/timerView.ml
diff options
context:
space:
mode:
Diffstat (limited to 'src/View/timerView.ml')
-rw-r--r--src/View/timerView.ml123
1 files changed, 123 insertions, 0 deletions
diff --git a/src/View/timerView.ml b/src/View/timerView.ml
new file mode 100644
index 0000000..2384f85
--- /dev/null
+++ b/src/View/timerView.ml
@@ -0,0 +1,123 @@
+open CreateElement
+
+let render (config : Config.config) onStop =
+ let duration = Config.getDuration config in
+ (* State *)
+ let interval = ref None in
+ let elapsed = ref 0 in
+ let step = ref (Step.getAt config !elapsed) in
+ let isPlaying = ref true in
+ (* Elements *)
+ let stepElt = text (Step.prettyPrint !step.step) in
+ let durationElt = text (Duration.prettyPrint !step.remaining) in
+ let arcPathElt = path ~attributes:[| className "g-Timer__ArcProgress" |] () in
+ let tabataCurrentElt = text (Js.Int.toString !step.tabata) in
+ let cycleCurrentElt = text (Js.Int.toString !step.cycle) in
+ (* Update *)
+ let stop () =
+ let () = Belt.Option.forEach !interval Js.Global.clearInterval in
+ onStop config
+ in
+ let updateDom () =
+ let angle = Js.Int.toFloat !elapsed /. 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 !elapsed in
+ let () = Element.setTextContent stepElt (Step.prettyPrint step.step) in
+ let () =
+ Element.setTextContent durationElt (Duration.prettyPrint step.remaining)
+ in
+ let () =
+ Element.setTextContent tabataCurrentElt (Js.Int.toString step.tabata)
+ in
+ let () =
+ Element.setTextContent cycleCurrentElt (Js.Int.toString step.cycle)
+ in
+ Audio.playFromStep config step
+ in
+ let update () =
+ if !isPlaying then
+ let () = elapsed := !elapsed + 1 in
+ let () = step := Step.getAt config !elapsed in
+ if !elapsed > duration then stop () else updateDom ()
+ else ()
+ in
+ (* Start timer *)
+ let () = interval := Some (Js.Global.setInterval update 1000) in
+ (* View *)
+ section
+ ~attributes:[| className "g-Timer" |]
+ ~children:
+ [|
+ button
+ ~attributes:[| className "g-Timer__Dial" |]
+ ~eventListeners:[| onClick (fun _ -> isPlaying := not !isPlaying) |]
+ ~children:
+ [|
+ svg
+ ~attributes:
+ [| className "g-Timer__Arc"; viewBox "-100 -100 200 200" |]
+ ~children:
+ [|
+ path
+ ~attributes:
+ [|
+ className "g-Timer__ArcTotal";
+ d (Arc.describe 0.0 0.0 95.0 0.0 359.999);
+ |]
+ ();
+ arcPathElt;
+ |]
+ ();
+ div
+ ~attributes:[| className "g-Timer__Step" |]
+ ~children:[| stepElt |] ();
+ div
+ ~attributes:[| className "g-Timer__Duration" |]
+ ~children:[| durationElt |] ();
+ |]
+ ();
+ div
+ ~attributes:[| className "g-Timer__TabataAndCycle" |]
+ ~children:
+ [|
+ div
+ ~attributes:[| className "g-Timer__Tabata" |]
+ ~children:
+ [|
+ div ~children:[| text "Tabata" |] ();
+ span
+ ~attributes:[| className "g-Timer__TabataCurrent" |]
+ ~children:[| tabataCurrentElt |] ();
+ text "/";
+ span
+ ~attributes:[| className "g-Timer__TabataTotal" |]
+ ~children:[| text (Js.Int.toString config.tabatas) |]
+ ();
+ |]
+ ();
+ div
+ ~attributes:[| className "g-Timer__Cycle" |]
+ ~children:
+ [|
+ div ~children:[| text "Cycle" |] ();
+ span
+ ~attributes:[| className "g-Timer__CycleCurrent" |]
+ ~children:[| cycleCurrentElt |] ();
+ text "/";
+ span
+ ~attributes:[| className "g-Timer__CycleTotal" |]
+ ~children:[| text (Js.Int.toString config.cycles) |]
+ ();
+ |]
+ ();
+ |]
+ ();
+ div
+ ~attributes:[| className "g-Timer__Stop" |]
+ ~children:[| text "stop" |]
+ ~eventListeners:[| onClick (fun _ -> stop ()) |]
+ ();
+ |]
+ ()