aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJoris Guyonvarch2015-03-16 00:15:05 +0100
committerJoris Guyonvarch2015-03-16 00:15:05 +0100
commitcd3b37adebca99138fad1acca37908183036ace9 (patch)
treed566ae0564d82ab94901e4deda98f36abd22ad2d /src
Initial commit, can create and name 5 minute timers, can toggle running state
Diffstat (limited to 'src')
-rw-r--r--src/Main.elm26
-rw-r--r--src/Model/Id.elm5
-rw-r--r--src/Model/IdGenerator.elm21
-rw-r--r--src/Model/Model.elm32
-rw-r--r--src/Model/Timer.elm40
-rw-r--r--src/Update/Update.elm48
-rw-r--r--src/Update/UpdateTimer.elm16
-rw-r--r--src/View/Timer.elm37
-rw-r--r--src/View/View.elm71
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)