aboutsummaryrefslogtreecommitdiff
path: root/src/View/timerView.ml
blob: 2384f85e35af69c31ff83b39c888858d21c86297 (plain)
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
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 ()) |]
          ();
      |]
    ()