aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkshay <[email protected]>2020-11-22 11:03:45 +0000
committerAkshay <[email protected]>2020-11-22 11:03:45 +0000
commit75afe1122a87c4508d4a134cea697bf334e80850 (patch)
tree53b89a9a8825eb59ab18d713ae4e0d92d9edb76f
parentb90171e1f1862885a1efdfb915869eb5fad13b01 (diff)
refactor main into modules
-rw-r--r--src/Base.elm28
-rw-r--r--src/Main.elm137
-rw-r--r--src/Utils.elm42
-rw-r--r--src/Views.elm71
4 files changed, 148 insertions, 130 deletions
diff --git a/src/Base.elm b/src/Base.elm
new file mode 100644
index 0000000..c3557d3
--- /dev/null
+++ b/src/Base.elm
@@ -0,0 +1,28 @@
1module Base exposing (..)
2
3import Array exposing (Array)
4import Time exposing (Posix)
5
6
7type WordStatus
8 = Correct
9 | Wrong
10 | Todo
11 | CurrentWord
12
13
14type alias Word =
15 { content : String
16 , status : WordStatus
17 }
18
19
20type alias Model =
21 { begin : Maybe Posix
22 , end : Maybe Posix
23 , words : Array Word
24 , accuracy : Maybe Float
25 , length : Int
26 , currentWord : Int
27 , inputBox : String
28 }
diff --git a/src/Main.elm b/src/Main.elm
index 9a35631..a91e12b 100644
--- a/src/Main.elm
+++ b/src/Main.elm
@@ -1,12 +1,15 @@
1module Main exposing (..) 1module Main exposing (..)
2 2
3import Array exposing (..) 3import Array exposing (..)
4import Base exposing (..)
4import Browser 5import Browser
5import Html exposing (..) 6import Html exposing (..)
6import Html.Attributes exposing (..) 7import Html.Attributes exposing (..)
7import Html.Events exposing (onInput) 8import Html.Events exposing (onInput)
8import Task 9import Task
9import Time 10import Time
11import Utils exposing (isJust, isNothing)
12import Views exposing (..)
10 13
11 14
12main = 15main =
@@ -18,30 +21,6 @@ main =
18 } 21 }
19 22
20 23
21type WordStatus
22 = Correct
23 | Wrong
24 | Todo
25 | CurrentWord
26
27
28type alias Word =
29 { content : String
30 , status : WordStatus
31 }
32
33
34type alias Model =
35 { begin : Maybe Time.Posix
36 , end : Maybe Time.Posix
37 , words : Array Word
38 , accuracy : Maybe Float
39 , length : Int
40 , currentWord : Int
41 , inputBox : String
42 }
43
44
45type Msg 24type Msg
46 = Started Time.Posix 25 = Started Time.Posix
47 | Finished Time.Posix 26 | Finished Time.Posix
@@ -137,26 +116,6 @@ handleWordEnded model =
137 ( newModel, cmd ) 116 ( newModel, cmd )
138 117
139 118
140isNothing : Maybe a -> Bool
141isNothing p =
142 case p of
143 Nothing ->
144 True
145
146 Just a ->
147 False
148
149
150isJust : Maybe a -> Bool
151isJust p =
152 not (isNothing p)
153
154
155flip : (a -> b -> c) -> (b -> a -> c)
156flip f =
157 \x y -> f y x
158
159
160update : Msg -> Model -> ( Model, Cmd Msg ) 119update : Msg -> Model -> ( Model, Cmd Msg )
161update msg model = 120update msg model =
162 case msg of 121 case msg of
@@ -199,21 +158,6 @@ update msg model =
199 ) 158 )
200 159
201 160
202displayTime : Time.Posix -> String
203displayTime t =
204 let
205 hh =
206 Time.toHour Time.utc t
207
208 mm =
209 Time.toMinute Time.utc t
210
211 ss =
212 Time.toSecond Time.utc t
213 in
214 String.join ":" (List.map String.fromInt [ hh, mm, ss ])
215
216
217wordStyle : WordStatus -> Attribute msg 161wordStyle : WordStatus -> Attribute msg
218wordStyle w = 162wordStyle w =
219 case w of 163 case w of
@@ -246,83 +190,16 @@ currentContents model =
246 |> Maybe.withDefault "" 190 |> Maybe.withDefault ""
247 191
248 192
249diffDuration : Time.Posix -> Time.Posix -> Float
250diffDuration t1 t2 =
251 let
252 m1 =
253 Time.posixToMillis t1
254
255 m2 =
256 Time.posixToMillis t2
257 in
258 toFloat (m2 - m1) / 1000
259
260
261viewWpm : Model -> String
262viewWpm model =
263 let
264 t1 =
265 model.begin
266
267 t2 =
268 model.end
269
270 duration =
271 Maybe.map2 diffDuration t1 t2
272
273 correctWords =
274 wordCount model.words ((==) Correct)
275
276 wpm =
277 Maybe.map (String.fromInt << truncate << (*) 60 << (/) (toFloat correctWords)) duration
278 in
279 Maybe.withDefault "XX" wpm
280
281
282wordCount : Array Word -> (WordStatus -> Bool) -> Int
283wordCount words predicate =
284 words |> Array.map .status |> Array.filter predicate |> Array.length
285
286
287viewProgress : Model -> String
288viewProgress model =
289 String.fromInt model.currentWord ++ "/" ++ String.fromInt model.length
290
291
292viewAccuracy : Model -> String
293viewAccuracy model =
294 let
295 wordsAttempted =
296 toFloat <| wordCount model.words ((/=) Todo)
297
298 correctCount =
299 toFloat <| wordCount model.words ((==) Correct)
300
301 accuracy =
302 if wordsAttempted == 0.0 then
303 Nothing
304
305 else
306 Just <| correctCount / wordsAttempted * 100
307 in
308 case accuracy of
309 Nothing ->
310 "XX"
311
312 Just a ->
313 String.fromInt <| truncate a
314
315
316view : Model -> Html Msg 193view : Model -> Html Msg
317view model = 194view model =
318 div [] 195 pre []
319 [ p [] [ text (String.fromInt model.currentWord) ] 196 [ toPara model.words model.currentWord (currentContents model)
320 , toPara model.words model.currentWord (currentContents model)
321 197
322 -- , p [] [ text (Maybe.withDefault "XX" (Maybe.map displayTime model.begin)) ] 198 -- , p [] [ text (Maybe.withDefault "XX" (Maybe.map displayTime model.begin)) ]
323 -- , p [] [ text (Maybe.withDefault "XX" (Maybe.map displayTime model.end)) ] 199 -- , p [] [ text (Maybe.withDefault "XX" (Maybe.map displayTime model.end)) ]
200 , p [] [ text ("POS: " ++ viewProgress (model.currentWord + 1) model.length) ]
324 , p [] [ text ("WPM: " ++ viewWpm model) ] 201 , p [] [ text ("WPM: " ++ viewWpm model) ]
325 , p [] [ text ("ACC: " ++ viewAccuracy model) ] 202 , p [] [ text ("ACC: " ++ viewAccuracy model.words) ]
326 , input [ onInput handleInputChanged, value model.inputBox ] [] 203 , input [ onInput handleInputChanged, value model.inputBox ] []
327 ] 204 ]
328 205
diff --git a/src/Utils.elm b/src/Utils.elm
new file mode 100644
index 0000000..0f3164f
--- /dev/null
+++ b/src/Utils.elm
@@ -0,0 +1,42 @@
1module Utils exposing (..)
2
3import Array as A exposing (..)
4import Base exposing (Word, WordStatus(..))
5import Time exposing (Posix, posixToMillis)
6
7
8isNothing : Maybe a -> Bool
9isNothing p =
10 case p of
11 Nothing ->
12 True
13
14 Just a ->
15 False
16
17
18isJust : Maybe a -> Bool
19isJust p =
20 not (isNothing p)
21
22
23flip : (a -> b -> c) -> (b -> a -> c)
24flip f =
25 \x y -> f y x
26
27
28diffDuration : Posix -> Posix -> Float
29diffDuration t1 t2 =
30 let
31 m1 =
32 posixToMillis t1
33
34 m2 =
35 posixToMillis t2
36 in
37 toFloat (m2 - m1) / 1000
38
39
40wordCountWith : Array Word -> (WordStatus -> Bool) -> Int
41wordCountWith words predicate =
42 words |> A.map .status |> A.filter predicate |> A.length
diff --git a/src/Views.elm b/src/Views.elm
new file mode 100644
index 0000000..c5cc159
--- /dev/null
+++ b/src/Views.elm
@@ -0,0 +1,71 @@
1module Views exposing (viewAccuracy, viewProgress, viewWpm)
2
3import Array exposing (..)
4import Base exposing (..)
5import Time exposing (Posix, toHour, toMinute, toSecond, utc)
6import Utils exposing (diffDuration, wordCountWith)
7
8
9viewTime : Posix -> String
10viewTime t =
11 let
12 hh =
13 toHour utc t
14
15 mm =
16 toMinute utc t
17
18 ss =
19 toSecond utc t
20 in
21 String.join ":" (List.map String.fromInt [ hh, mm, ss ])
22
23
24viewWpm : Model -> String
25viewWpm model =
26 let
27 t1 =
28 model.begin
29
30 t2 =
31 model.end
32
33 duration =
34 Maybe.map2 diffDuration t1 t2
35
36 correctWords =
37 wordCountWith model.words ((==) Correct)
38
39 wpm =
40 Maybe.map (String.fromInt << truncate << (*) 60 << (/) (toFloat correctWords)) duration
41 in
42 Maybe.withDefault "XX" wpm
43
44
45viewProgress : Int -> Int -> String
46viewProgress soFar total =
47 String.fromInt soFar ++ "/" ++ String.fromInt total
48
49
50viewAccuracy : Array Word -> String
51viewAccuracy words =
52 let
53 wordsAttempted =
54 toFloat <| wordCountWith words ((/=) Todo)
55
56 correctCount =
57 toFloat <| wordCountWith words ((==) Correct)
58
59 accuracy =
60 if wordsAttempted == 0.0 then
61 Nothing
62
63 else
64 Just <| correctCount / wordsAttempted * 100
65 in
66 case accuracy of
67 Nothing ->
68 "XX"
69
70 Just a ->
71 String.fromInt <| truncate a