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 ()) |]
();
|]
()
|