-
Notifications
You must be signed in to change notification settings - Fork 0
/
Update.elm
145 lines (115 loc) · 3.95 KB
/
Update.elm
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
module Update exposing (update)
import Models exposing (..)
import Messages exposing (..)
import String
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
SetOperation operation ->
( { model | operation = operation }
|> ensureFirstOperand
, Cmd.none
)
SetOperand partial ->
( model
|> setOperand partial
|> resetResult
, Cmd.none
)
CalculateResult ->
( model
|> calculateResult
|> resetCalc
, Cmd.none
)
{-| When the user sets operation before setting the first operand
in a typical calc the operand defaults to 0 or the current result,
if there is any. It's a convenience for the user
-}
ensureFirstOperand : Model -> Model
ensureFirstOperand model =
case ( model.operation, model.operand1 ) of
( Just _, Nothing ) ->
let
operand =
case model.result of
Nothing ->
Just "0"
Just result ->
Just <| toString result
in
{ model | operand1 = operand }
( _, _ ) ->
model
resetResult : Model -> Model
resetResult model =
{ model | result = Nothing }
resetCalc : Model -> Model
resetCalc model =
{ model | operand1 = Nothing, operand2 = Nothing, operation = Nothing }
calculateResult : Model -> Model
calculateResult model =
case model.operation of
Nothing ->
{ model | result = Nothing }
Just operation ->
case ( model.operand1, model.operand2 ) of
( Just operand1, Just operand2 ) ->
{ model | result = performCalculation operation operand1 operand2 }
( _, _ ) ->
model
performCalculation : Operation -> String -> String -> Maybe Float
performCalculation operation operand1 operand2 =
case ( String.toFloat operand1, String.toFloat operand2 ) of
( Ok op1, Ok op2 ) ->
case operation of
Add ->
Just ((+) op1 op2)
Subtract ->
Just ((-) op1 op2)
Multiply ->
Just ((*) op1 op2)
Divide ->
Just ((/) op1 op2)
( _, _ ) ->
Nothing
{-| Mimicking the typical calc behavior we need to keep
concatenating the operand1 with each called value, until the user sets
the operation, and then operand2 until the result is calculated
E.g. Operand goes from Nothing to Just "1", after user clicks "1",
then from Just "1" to Just "12" after user clicks "2", and so on…
Also we need to account for decimals after user clicks "."
-}
setOperand : String -> Model -> Model
setOperand partial model =
if model.operation == Nothing then
{ model | operand1 = getOperand model.operand1 partial }
else
{ model | operand2 = getOperand model.operand2 partial }
{-| If we already have a value for the operand, we need to concatenate it with
the new one, otherwise the new one becomes our operand, with special handling
for decimal "." and "0" as
-}
getOperand : Maybe String -> String -> Maybe String
getOperand current partial =
let
currentString =
case current of
Nothing ->
""
Just operand ->
operand
in
case partial of
"." ->
if String.contains "." currentString then
Just currentString
else
Just (currentString ++ partial)
"0" ->
if currentString == "0" then
Just currentString
else
Just (currentString ++ partial)
_ ->
Just (currentString ++ partial)