diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Main.elm | 26 | ||||
-rw-r--r-- | src/Model/Id.elm | 5 | ||||
-rw-r--r-- | src/Model/IdGenerator.elm | 21 | ||||
-rw-r--r-- | src/Model/Model.elm | 32 | ||||
-rw-r--r-- | src/Model/Timer.elm | 40 | ||||
-rw-r--r-- | src/Update/Update.elm | 48 | ||||
-rw-r--r-- | src/Update/UpdateTimer.elm | 16 | ||||
-rw-r--r-- | src/View/Timer.elm | 37 | ||||
-rw-r--r-- | src/View/View.elm | 71 |
9 files changed, 296 insertions, 0 deletions
diff --git a/src/Main.elm b/src/Main.elm new file mode 100644 index 0000000..c2a7519 --- /dev/null +++ b/src/Main.elm @@ -0,0 +1,26 @@ +module Main + ( main + ) where + +import Signal +import Html (Html) +import Time (..) + +import Model.Model (..) +import Update.Update (..) +import View.View (view) + +main : Signal Html +main = Signal.map view model + +model : Signal Model +model = Signal.foldp update (initialModel initialTime) input + +input : Signal Action +input = + Signal.mergeMany + [ Signal.subscribe updates + , Signal.map DeltaTime (fps 30) + ] + +port initialTime : Time diff --git a/src/Model/Id.elm b/src/Model/Id.elm new file mode 100644 index 0000000..c416804 --- /dev/null +++ b/src/Model/Id.elm @@ -0,0 +1,5 @@ +module Model.Id + ( Id + ) where + +type alias Id = Int diff --git a/src/Model/IdGenerator.elm b/src/Model/IdGenerator.elm new file mode 100644 index 0000000..8bce44f --- /dev/null +++ b/src/Model/IdGenerator.elm @@ -0,0 +1,21 @@ +module Model.IdGenerator + ( IdGenerator + , initialIdGenerator + , getId + ) where + +import Model.Id (..) + +type alias IdGenerator = + { counter : Id + } + +initialIdGenerator = + { counter = 0 + } + +getId : IdGenerator -> (Id, IdGenerator) +getId idGenerator = + ( idGenerator.counter + , { idGenerator | counter <- idGenerator.counter + 1 } + ) diff --git a/src/Model/Model.elm b/src/Model/Model.elm new file mode 100644 index 0000000..fa97d7b --- /dev/null +++ b/src/Model/Model.elm @@ -0,0 +1,32 @@ +module Model.Model + ( Model + , initialModel + , substractTimersTime + ) where + +import Dict (Dict) +import Dict +import Time (Time) + +import Model.Timer (..) +import Model.Id (..) +import Model.IdGenerator (..) + +type alias Model = + { currentTime : Time + , newTimerName : String + , timers : Dict Id Timer + , timerIdGenerator : IdGenerator + } + +initialModel : Time -> Model +initialModel initialTime = + { currentTime = initialTime + , newTimerName = "" + , timers = Dict.empty + , timerIdGenerator = initialIdGenerator + } + +substractTimersTime : Time -> Dict Id Timer -> Dict Id Timer +substractTimersTime t timers = + Dict.map (\id timer -> substractTimerTime t timer) timers diff --git a/src/Model/Timer.elm b/src/Model/Timer.elm new file mode 100644 index 0000000..ddbe97b --- /dev/null +++ b/src/Model/Timer.elm @@ -0,0 +1,40 @@ +module Model.Timer + ( Timer + , initialTimer + , substractTimerTime + ) where + +import List +import Time (Time) + +type alias Timer = + { creationTime : Time + , name : String + , time : Time + , isRunning : Bool + } + +initialTimer : Time -> String -> Timer +initialTimer creationTime name = + { creationTime = creationTime + , name = name + , time = 5 * 60 * 1000 + , isRunning = True + } + +substractTimerTime : Time -> Timer -> Timer +substractTimerTime time timer = + if timer.isRunning + then + if timer.time - time <= 0.0 + then + { timer + | time <- 0.0 + , isRunning <- False + } + else + { timer + | time <- timer.time - time + } + else + timer diff --git a/src/Update/Update.elm b/src/Update/Update.elm new file mode 100644 index 0000000..0252fc8 --- /dev/null +++ b/src/Update/Update.elm @@ -0,0 +1,48 @@ +module Update.Update + ( Action(..) + , updates + , update + ) where + +import Signal +import Dict +import Time (Time) +import Maybe + +import Model.Model (..) +import Model.Timer (..) +import Model.Id (..) +import Model.IdGenerator (..) + +import Update.UpdateTimer (..) + +type Action = + NoOp + | RenameNewTimer String + | AddNewTimer + | DeltaTime Time + | UpdateTimer Id TimerAction + +updates : Signal.Channel Action +updates = Signal.channel NoOp + +update : Action -> Model -> Model +update action model = + case action of + NoOp -> model + RenameNewTimer name -> + { model | newTimerName <- name } + AddNewTimer -> + let (id, newTimerIdGenerator) = getId model.timerIdGenerator + in { model + | timers <- Dict.insert id (initialTimer model.currentTime model.newTimerName) model.timers + , timerIdGenerator <- newTimerIdGenerator + , newTimerName <- "" + } + DeltaTime delta -> + { model + | currentTime <- model.currentTime + delta + , timers <- substractTimersTime delta model.timers + } + UpdateTimer id action -> + { model | timers <- Dict.update id (Maybe.map (updateTimer action)) model.timers } diff --git a/src/Update/UpdateTimer.elm b/src/Update/UpdateTimer.elm new file mode 100644 index 0000000..d8861b7 --- /dev/null +++ b/src/Update/UpdateTimer.elm @@ -0,0 +1,16 @@ +module Update.UpdateTimer + ( TimerAction(..) + , updateTimer + ) where + +import Model.Timer (..) +import Model.Id (..) + +type TimerAction = + ToggleRunning + +updateTimer : TimerAction -> Timer -> Timer +updateTimer action timer = + case action of + ToggleRunning -> + { timer | isRunning <- not timer.isRunning } diff --git a/src/View/Timer.elm b/src/View/Timer.elm new file mode 100644 index 0000000..668bf08 --- /dev/null +++ b/src/View/Timer.elm @@ -0,0 +1,37 @@ +module View.Timer + ( timerView + ) where + +import Html (..) +import Html.Attributes (..) +import Html.Events (..) +import String +import Time (Time) +import Signal + +import Model.Timer (..) +import Model.Id (..) + +import Update.Update (..) +import Update.UpdateTimer (..) + +timerView : (Id, Timer) -> Html +timerView (id, timer) = + div + [ class "timer" ] + [ div + [ class "block" ] + [ text timer.name ] + , div + [ class <| "timerTime block" ++ (if timer.isRunning then " isRunning" else "") + , onClick (Signal.send updates (UpdateTimer id ToggleRunning)) + ] + [ text (timeView timer.time) ] + ] + +timeView : Time -> String +timeView time = + let totalSeconds = truncate (time / 1000) + totalMinutes = totalSeconds // 60 + restSeconds = totalSeconds `rem` 60 + in (toString totalMinutes) ++ ":" ++ (String.padLeft 2 '0' (toString restSeconds)) diff --git a/src/View/View.elm b/src/View/View.elm new file mode 100644 index 0000000..ae60807 --- /dev/null +++ b/src/View/View.elm @@ -0,0 +1,71 @@ +module View.View + ( view + ) where + +import Html (..) +import Html.Attributes (..) +import Html.Events (..) +import Signal +import List +import Dict +import Json.Decode as Json +import Debug + +import Model.Model (..) +import Model.Timer (..) +import Model.Id (..) + +import Update.Update (..) + +import View.Timer (timerView) + +view : Model -> Html +view model = + div + [] + [ h1 [] [ text "Timer" ] + , addTimer model.newTimerName + , model.timers + |> Dict.toList + |> List.sortBy (.creationTime << snd) + |> List.reverse + |> timers + ] + +addTimer : String -> Html +addTimer name = + div + [ class "addTimer" ] + [ input + [ placeholder "Name" + , value name + , on "input" targetValue (Signal.send updates << RenameNewTimer) + , onEnter (Signal.send updates AddNewTimer) + , autofocus True + ] + [] + , button + [ onClick (Signal.send updates AddNewTimer) ] + [ i + [ class "fa fa-fw fa-plus" ] + [] + ] + ] + +onEnter : Signal.Message -> Attribute +onEnter message = + on "keydown" + (Json.customDecoder keyCode is13) + (always message) + +is13 : Int -> Result String () +is13 code = + if code == 13 + then Ok() + else Err "Not the right key code" + +timers : List (Id, Timer) -> Html +timers timers = + div + [ class "timers" ] + (List.map timerView timers) |