diff options
-rw-r--r-- | design/design.css | 23 | ||||
-rw-r--r-- | src/Model/Timer.elm | 27 | ||||
-rw-r--r-- | src/Model/TimerState.elm | 8 | ||||
-rw-r--r-- | src/Update/Update.elm | 32 | ||||
-rw-r--r-- | src/Update/UpdateTimer.elm | 18 | ||||
-rw-r--r-- | src/View/Timer.elm | 124 | ||||
-rw-r--r-- | src/View/View.elm | 10 |
7 files changed, 162 insertions, 80 deletions
diff --git a/design/design.css b/design/design.css index ac34f6f..257a017 100644 --- a/design/design.css +++ b/design/design.css @@ -5,15 +5,17 @@ height: 150px; line-height: 150px; font-size: 70px; - padding-left: 50px; } -.title > h1 { +.title > button.title { letter-spacing: 10px; - float: left; + border: none; + padding-left: 50px; + padding-right: 50px; + font-family: "DejaVu Serif"; } -.title > button { +.title > button.addTimer { float: right; color: white; border: 5px solid white; @@ -43,6 +45,19 @@ border-radius: 2px; } +@keyframes ringing { + 30% { + background-color: #FED5AE; + } + 100% { + background-color: #FED5AE; + } +} + +.timer.isRinging > :not(.remove) { + animation: ringing 2s linear infinite alternate; +} + .timer.isRunning > .time { color: #33AA22; } diff --git a/src/Model/Timer.elm b/src/Model/Timer.elm index 754a62a..b73016d 100644 --- a/src/Model/Timer.elm +++ b/src/Model/Timer.elm @@ -8,12 +8,14 @@ module Model.Timer import List import Time (Time) +import Model.TimerState (..) + type alias Timer = { creationTime : Time , name : String , initialTime : Time , currentTime : Time - , isRunning : Bool + , state : TimerState } initialTimer : Time -> String -> Timer @@ -23,23 +25,22 @@ initialTimer creationTime name = , name = name , initialTime = initialTime , currentTime = initTime initialTime - , isRunning = False + , state = Idle } substractTimerTime : Time -> Timer -> Timer substractTimerTime time timer = - if timer.isRunning + if timer.state == Running then - if timer.currentTime - time <= 0.0 - then - { timer - | currentTime <- 0.0 - , isRunning <- False - } - else - { timer - | currentTime <- timer.currentTime - time - } + let newTime = timer.currentTime - time + in if newTime <= 0.0 + then + { timer + | currentTime <- 0.0 + , state <- Ringing + } + else + { timer | currentTime <- newTime } else timer diff --git a/src/Model/TimerState.elm b/src/Model/TimerState.elm new file mode 100644 index 0000000..dbbcb80 --- /dev/null +++ b/src/Model/TimerState.elm @@ -0,0 +1,8 @@ +module Model.TimerState + ( TimerState(..) + ) where + +type TimerState = + Idle + | Running + | Ringing diff --git a/src/Update/Update.elm b/src/Update/Update.elm index 8285760..3bdcc2b 100644 --- a/src/Update/Update.elm +++ b/src/Update/Update.elm @@ -6,6 +6,7 @@ module Update.Update import Signal import Dict +import Dict (Dict) import Time (Time) import Maybe import Keyboard (KeyCode) @@ -20,8 +21,11 @@ import Model.IdGenerator (..) import Update.UpdateTimer (..) import Update.UpdateTimerEdition (..) +import Utils.Maybe (..) + type Action = NoOp + | Initialize | AddNewTimer | DeltaTime Time | UpdateTimer Id TimerAction @@ -38,6 +42,8 @@ update : Action -> Model -> Model update action model = case action of NoOp -> model + Initialize -> + initialModel model.currentTime AddNewTimer -> let (id, newTimerIdGenerator) = getId model.timerIdGenerator timerName = "Timer " ++ (toString id) @@ -51,14 +57,17 @@ update action model = , timers <- substractTimersTime delta model.timers } UpdateTimer id action -> - let inEdition = - model.timerEdition - |> Maybe.map (\timerEdition -> timerEdition.id == id) - |> Maybe.withDefault False - in if inEdition - then - model - else + + let maybeTimerEdition = filterMaybe (\timerEdition -> timerEdition.id == id) model.timerEdition + in case model.timerEdition of + Just timerEdition -> + { model + | timers <- + updateTimerTime timerEdition model.timers + |> Dict.update id (Maybe.map (updateTimer action)) + , timerEdition <- Nothing + } + Nothing -> { model | timers <- Dict.update id (Maybe.map (updateTimer action)) model.timers } RemoveTimer id -> { model | timers <- Dict.remove id model.timers } @@ -71,7 +80,7 @@ update action model = case model.timerEdition of Just timerEdition -> { model - | timers <- Dict.update timerEdition.id (Maybe.map (updateTimer (SetTime (toTime timerEdition.numbers)))) model.timers + | timers <- updateTimerTime timerEdition model.timers , timerEdition <- Nothing } Nothing -> @@ -81,5 +90,6 @@ update action model = KeyPressed keyCode -> { model | timerEdition <- Maybe.map (updateTimerEdition (keyCodeToChar keyCode)) model.timerEdition } -isEnter : KeyCode -> Bool -isEnter = (==) 107 +updateTimerTime : TimerEdition -> Dict Id Timer -> Dict Id Timer +updateTimerTime timerEdition = + Dict.update timerEdition.id (Maybe.map (updateTimer (SetTime (toTime timerEdition.numbers)))) diff --git a/src/Update/UpdateTimer.elm b/src/Update/UpdateTimer.elm index e4671d9..c147d23 100644 --- a/src/Update/UpdateTimer.elm +++ b/src/Update/UpdateTimer.elm @@ -6,6 +6,7 @@ module Update.UpdateTimer import Time (Time) import Model.Timer (..) +import Model.TimerState (..) import Model.Id (..) type TimerAction = @@ -20,19 +21,22 @@ updateTimer action timer = case action of Restart -> { timer - | isRunning <- True - , currentTime <- initTime timer.initialTime + | currentTime <- initTime timer.initialTime + , state <- Running } Pause -> + { timer | state <- Idle } + ToggleRunning -> { timer - | isRunning <- False + | state <- + if timer.currentTime > 0 && timer.state == Idle + then Running + else Idle } - ToggleRunning -> - { timer | isRunning <- timer.currentTime > 0.0 && not timer.isRunning } Stop -> { timer - | isRunning <- False - , currentTime <- initTime timer.initialTime + | currentTime <- initTime timer.initialTime + , state <- Idle } SetTime time -> let augmentedTime = time + 999 diff --git a/src/View/Timer.elm b/src/View/Timer.elm index b508dd6..2325d3a 100644 --- a/src/View/Timer.elm +++ b/src/View/Timer.elm @@ -13,6 +13,7 @@ import Maybe import Model.Model (..) import Model.Timer (..) import Model.TimerEdition (..) +import Model.TimerState (..) import Model.Id (..) import Update.Update (..) @@ -25,49 +26,44 @@ import Utils.Maybe (..) timerView : Model -> (Id, Timer) -> Html timerView model (id, timer) = div - [ class <| "timer" ++ (if timer.isRunning then " isRunning" else "") ] - [ button - [ class "name block" ] - [ text timer.name ] - , let maybeEdition = filterMaybe (\te -> te.id == id) model.timerEdition - in case maybeEdition of - Just edition -> - button - [ class "time block edition" - , onClick (Signal.send updates ValidTimerEdition) - ] - [ text (editionView edition.numbers) ] - Nothing -> - button - [ class "time block" - , onClick (Signal.send updates (EditTimer id)) - ] - [ text (timeView timer.currentTime) ] - , button - [ class <| "restart block" - , onClick (Signal.send updates (UpdateTimer id Restart)) - ] - [ i [ class "fa fa-fw fa-backward" ] [] ] - , button - [ class <| "playPause block" - , onClick (Signal.send updates (UpdateTimer id ToggleRunning)) - ] - [ let icon = if timer.isRunning then "fa-pause" else "fa-play" - in i - [ class <| "fa fa-fw " ++ icon ] - [] - ] - , button - [ class <| "stop block" - , onClick (Signal.send updates (UpdateTimer id Stop)) - ] - [ i [ class "fa fa-fw fa-stop" ] [] ] - , button - [ class <| "remove block" - , onClick (Signal.send updates (RemoveTimer id)) - ] - [ i [ class "fa fa-fw fa-remove" ] [] ] + [ [ (True, "timer") + , (timer.state == Running, "isRunning") + , (timer.state == Ringing, "isRinging") + ] + |> activatedClasses ] + [ nameBlock (id, timer) + , timeBlock model (id, timer) + , restartBlock (id, timer) + , playPauseBlock (id, timer) + , stopBlock (id, timer) + , removeBlock (id, timer) + ] + +nameBlock : (Id, Timer) -> Html +nameBlock (id, timer) = + button + [ class "name block" + , onClick (stopIfRinging (id, timer) (Signal.send updates NoOp)) + ] + [ text timer.name ] + +timeBlock : Model -> (Id, Timer) -> Html +timeBlock model (id, timer) = + let maybeEdition = filterMaybe (\te -> te.id == id) model.timerEdition + in case maybeEdition of + Just edition -> + button + [ class "time block edition" + , onClick (stopIfRinging (id, timer) (Signal.send updates ValidTimerEdition)) + ] + [ text (editionView edition.numbers) ] + Nothing -> + button + [ class "time block" + , onClick (stopIfRinging (id, timer) (Signal.send updates (EditTimer id))) + ] + [ text (timeView timer.currentTime) ] editionView : Numbers -> String editionView numbers = @@ -79,4 +75,46 @@ timeView time = let totalSeconds = truncate (time / 1000) totalMinutes = totalSeconds // 60 restSeconds = totalSeconds `rem` 60 - in (toString totalMinutes) ++ " : " ++ (String.padLeft 2 '0' (toString restSeconds)) + in (String.padLeft 2 '0' (toString totalMinutes)) ++ " : " ++ (String.padLeft 2 '0' (toString restSeconds)) + +restartBlock : (Id, Timer) -> Html +restartBlock (id, timer) = + button + [ class <| "restart block" + , onClick (stopIfRinging (id, timer) (Signal.send updates (UpdateTimer id Restart))) + ] + [ i [ class "fa fa-fw fa-backward" ] [] ] + +playPauseBlock : (Id, Timer) -> Html +playPauseBlock (id, timer) = + button + [ class <| "playPause block" + , onClick (stopIfRinging (id, timer) (Signal.send updates (UpdateTimer id ToggleRunning))) + ] + [ let icon = if timer.state == Running then "fa-pause" else "fa-play" + in i + [ class <| "fa fa-fw " ++ icon ] + [] + ] + +stopBlock : (Id, Timer) -> Html +stopBlock (id, timer) = + button + [ class <| "stop block" + , onClick (stopIfRinging (id, timer) (Signal.send updates (UpdateTimer id Stop))) + ] + [ i [ class "fa fa-fw fa-stop" ] [] ] + +removeBlock : (Id, Timer) -> Html +removeBlock (id, timer) = + button + [ class <| "remove block" + , onClick (Signal.send updates (RemoveTimer id)) + ] + [ i [ class "fa fa-fw fa-remove" ] [] ] + +stopIfRinging : (Id, Timer) -> Signal.Message -> Signal.Message +stopIfRinging (id, timer) message = + if timer.state == Ringing + then Signal.send updates (UpdateTimer id Stop) + else message diff --git a/src/View/View.elm b/src/View/View.elm index d7a9b99..e86ea52 100644 --- a/src/View/View.elm +++ b/src/View/View.elm @@ -34,9 +34,15 @@ title : Html title = div [ class "title" ] - [ h1 [] [ text "Timer" ] + [ button + [ onClick (Signal.send updates Initialize) + , class "title" + ] + [ text "Timer" ] , button - [ onClick (Signal.send updates AddNewTimer) ] + [ onClick (Signal.send updates AddNewTimer) + , class "addTimer" + ] [ i [ class "fa fa-fw fa-plus" ] [] |