aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoris2016-09-04 21:21:11 +0200
committerJoris2016-09-04 21:21:31 +0200
commit973a039b54327df74396605410ea9abe19c8a4e7 (patch)
treec702564d17e0a490d56845027238eb4f231be785
parent62fee9133f36f655c1ed83e0c2e85394f9948bf5 (diff)
downloadtimer-973a039b54327df74396605410ea9abe19c8a4e7.tar.gz
timer-973a039b54327df74396605410ea9abe19c8a4e7.tar.bz2
timer-973a039b54327df74396605410ea9abe19c8a4e7.zip
Upgrade to elm 0.17.1
-rw-r--r--.gitignore3
-rw-r--r--.tmuxinator.yml8
-rw-r--r--Makefile26
-rw-r--r--elm-package.json11
-rwxr-xr-xgen2
-rw-r--r--index.html47
-rw-r--r--package.json6
-rw-r--r--public/alarm.wav (renamed from alarm.wav)bin661032 -> 661032 bytes
-rw-r--r--public/images/icon.png (renamed from images/icon.png)bin886 -> 886 bytes
-rw-r--r--public/index.html40
-rw-r--r--public/style/font-awesome/css/font-awesome.min.css (renamed from design/font-awesome/css/font-awesome.min.css)0
-rw-r--r--public/style/font-awesome/fonts/FontAwesome.otf (renamed from design/font-awesome/fonts/FontAwesome.otf)bin85908 -> 85908 bytes
-rw-r--r--public/style/font-awesome/fonts/fontawesome-webfont.eot (renamed from design/font-awesome/fonts/fontawesome-webfont.eot)bin56006 -> 56006 bytes
-rw-r--r--public/style/font-awesome/fonts/fontawesome-webfont.svg (renamed from design/font-awesome/fonts/fontawesome-webfont.svg)0
-rw-r--r--public/style/font-awesome/fonts/fontawesome-webfont.ttf (renamed from design/font-awesome/fonts/fontawesome-webfont.ttf)bin112160 -> 112160 bytes
-rw-r--r--public/style/font-awesome/fonts/fontawesome-webfont.woff (renamed from design/font-awesome/fonts/fontawesome-webfont.woff)bin65452 -> 65452 bytes
-rw-r--r--public/style/main.css (renamed from design/design.css)0
-rw-r--r--public/style/reset.css (renamed from design/reset.css)0
-rw-r--r--shell.nix15
-rw-r--r--src/Edition/Model.elm (renamed from src/Model/Edition/Edition.elm)11
-rw-r--r--src/Edition/Model/Name.elm (renamed from src/Model/Edition/NameEdition.elm)7
-rw-r--r--src/Edition/Model/Time.elm (renamed from src/Model/Edition/TimeEdition.elm)6
-rw-r--r--src/Edition/Msg.elm9
-rw-r--r--src/Edition/Update.elm30
-rw-r--r--src/Main.elm72
-rw-r--r--src/Model.elm (renamed from src/Model/Model.elm)32
-rw-r--r--src/Model/Id.elm4
-rw-r--r--src/Model/IdGenerator.elm6
-rw-r--r--src/Model/Keyboard.elm5
-rw-r--r--src/Model/Position.elm4
-rw-r--r--src/Model/TimerState.elm8
-rw-r--r--src/Msg.elm23
-rw-r--r--src/Ring.elm5
-rw-r--r--src/Timer/Model.elm (renamed from src/Model/Timer.elm)18
-rw-r--r--src/Timer/Model/State.elm8
-rw-r--r--src/Timer/Msg.elm13
-rw-r--r--src/Timer/Update.elm56
-rw-r--r--src/Timer/View.elm (renamed from src/View/Timer.elm)92
-rw-r--r--src/Update.elm141
-rw-r--r--src/Update/Update.elm131
-rw-r--r--src/Update/UpdateEdition.elm33
-rw-r--r--src/Update/UpdateTimer.elm57
-rw-r--r--src/Utils/List.elm18
-rw-r--r--src/Utils/Maybe.elm4
-rw-r--r--src/View.elm (renamed from src/View/View.elm)39
-rw-r--r--src/View/ActivatedClasses.elm15
46 files changed, 531 insertions, 474 deletions
diff --git a/.gitignore b/.gitignore
index 3bd52a1..4f4679c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
+node_modules
elm-stuff
-elm.js
+public/client.js
diff --git a/.tmuxinator.yml b/.tmuxinator.yml
new file mode 100644
index 0000000..2be1fda
--- /dev/null
+++ b/.tmuxinator.yml
@@ -0,0 +1,8 @@
+name: sharedCost
+
+windows:
+ - main:
+ layout: fff4,119x58,0,0{94x58,0,0,0,24x58,95,0,1}
+ panes:
+ - # Empty
+ - make install && make && make watch
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..daea513
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,26 @@
+all: build
+
+clean:
+ @rm -r node_modules >/dev/null 2>&1 || true
+ @rm -r elm-stuff >/dev/null 2>&1 || true
+
+install:
+ @npm install
+ @elm package install
+
+watch: kill-server launch-server watch-client
+
+# Build and launch
+# ----------------
+
+kill-server:
+ @fuser -k 8080/tcp || true
+
+launch-server:
+ @./node_modules/http-server/bin/http-server ./public -p 8080 &
+
+build:
+ @elm make src/Main.elm --output public/client.js || true
+
+watch-client:
+ @./node_modules/nodemon/bin/nodemon.js --watch src -e elm --exec 'clear && make build --silent'
diff --git a/elm-package.json b/elm-package.json
index 995d8e9..4d64f3b 100644
--- a/elm-package.json
+++ b/elm-package.json
@@ -1,14 +1,13 @@
{
- "version": "0.0.1",
- "summary": "",
- "description": "",
+ "version": "1.0.0",
+ "summary": "timer",
"repository": "https://github.com/guyonvarch/timer.git",
"license": "BSD3",
"source-directories": ["src"],
"exposed-modules": [],
- "elm-version": "0.15.0 <= v < 0.16.0",
+ "elm-version": "0.17.1 <= v < 0.18.0",
"dependencies": {
- "elm-lang/core": "2.0.1 <= v < 3.0.0",
- "evancz/elm-html": "3.0.0 <= v < 4.0.0"
+ "elm-lang/core": "4.0.5 <= v < 5.0.0",
+ "elm-lang/html": "1.1.0 <= v < 2.0.0"
}
}
diff --git a/gen b/gen
deleted file mode 100755
index e1d94dc..0000000
--- a/gen
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-elm-make src/Main.elm --output elm.js
diff --git a/index.html b/index.html
deleted file mode 100644
index f5f825e..0000000
--- a/index.html
+++ /dev/null
@@ -1,47 +0,0 @@
-<!doctype HTML>
-
-<html>
-
- <head>
- <title>Timer</title>
- <meta charset="utf-8">
- <link rel="stylesheet" href="design/reset.css">
- <link rel="stylesheet" href="design/design.css">
- <link rel="stylesheet" href="design/font-awesome/css/font-awesome.min.css">
- <link rel="icon" type="image/png" href="images/icon.png">
- <script src="elm.js"></script>
- </head>
-
- <body>
- </body>
-
- <script>
- var timer = Elm.fullscreen(Elm.Main, {
- initialTime: new Date().getTime(),
- keyPress: 0
- });
-
- const sound = new Audio('alarm.wav');
- sound.addEventListener('ended', function() {
- this.currentTime = 0;
- this.play();
- }, false);
-
- timer.ports.ringingTimers.subscribe(function(isRinging) {
- if(isRinging) {
- document.title = "~\\ Timer /~";
- sound.play();
- } else {
- document.title = "Timer";
- sound.pause();
- sound.currentTime = 0;
- }
- });
-
- document.onkeypress = function(event) {
- timer.ports.keyPress.send(event.which);
- };
-
- </script>
-
-</html>
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..ba7eb37
--- /dev/null
+++ b/package.json
@@ -0,0 +1,6 @@
+{
+ "devDependencies": {
+ "nodemon": "1.9.1",
+ "http-server": "0.8.5"
+ }
+}
diff --git a/alarm.wav b/public/alarm.wav
index 41d6709..41d6709 100644
--- a/alarm.wav
+++ b/public/alarm.wav
Binary files differ
diff --git a/images/icon.png b/public/images/icon.png
index a489112..a489112 100644
--- a/images/icon.png
+++ b/public/images/icon.png
Binary files differ
diff --git a/public/index.html b/public/index.html
new file mode 100644
index 0000000..44749fc
--- /dev/null
+++ b/public/index.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Timer</title>
+ <meta charset="utf-8">
+ <link rel="stylesheet" href="style/reset.css">
+ <link rel="stylesheet" href="style/main.css">
+ <link rel="stylesheet" href="style/font-awesome/css/font-awesome.min.css">
+ <link rel="icon" type="image/png" href="images/icon.png">
+ <script src="client.js"></script>
+ </head>
+
+ <body>
+ </body>
+
+ <script>
+ const timer = Elm.Main.fullscreen(new Date().getTime())
+
+ document.onkeypress = function(event) {
+ timer.ports.keyPress.send(event.which)
+ };
+
+ const sound = new Audio('alarm.wav');
+ sound.addEventListener('ended', function() {
+ this.currentTime = 0;
+ this.play();
+ }, false);
+
+ timer.ports.ring.subscribe(function(ring) {
+ if(ring) {
+ document.title = "~\\ Timer /~"
+ sound.play()
+ } else {
+ document.title = "Timer"
+ sound.pause()
+ sound.currentTime = 0
+ }
+ });
+ </script>
+</html>
diff --git a/design/font-awesome/css/font-awesome.min.css b/public/style/font-awesome/css/font-awesome.min.css
index ec53d4d..ec53d4d 100644
--- a/design/font-awesome/css/font-awesome.min.css
+++ b/public/style/font-awesome/css/font-awesome.min.css
diff --git a/design/font-awesome/fonts/FontAwesome.otf b/public/style/font-awesome/fonts/FontAwesome.otf
index 81c9ad9..81c9ad9 100644
--- a/design/font-awesome/fonts/FontAwesome.otf
+++ b/public/style/font-awesome/fonts/FontAwesome.otf
Binary files differ
diff --git a/design/font-awesome/fonts/fontawesome-webfont.eot b/public/style/font-awesome/fonts/fontawesome-webfont.eot
index 84677bc..84677bc 100644
--- a/design/font-awesome/fonts/fontawesome-webfont.eot
+++ b/public/style/font-awesome/fonts/fontawesome-webfont.eot
Binary files differ
diff --git a/design/font-awesome/fonts/fontawesome-webfont.svg b/public/style/font-awesome/fonts/fontawesome-webfont.svg
index d907b25..d907b25 100644
--- a/design/font-awesome/fonts/fontawesome-webfont.svg
+++ b/public/style/font-awesome/fonts/fontawesome-webfont.svg
diff --git a/design/font-awesome/fonts/fontawesome-webfont.ttf b/public/style/font-awesome/fonts/fontawesome-webfont.ttf
index 96a3639..96a3639 100644
--- a/design/font-awesome/fonts/fontawesome-webfont.ttf
+++ b/public/style/font-awesome/fonts/fontawesome-webfont.ttf
Binary files differ
diff --git a/design/font-awesome/fonts/fontawesome-webfont.woff b/public/style/font-awesome/fonts/fontawesome-webfont.woff
index 628b6a5..628b6a5 100644
--- a/design/font-awesome/fonts/fontawesome-webfont.woff
+++ b/public/style/font-awesome/fonts/fontawesome-webfont.woff
Binary files differ
diff --git a/design/design.css b/public/style/main.css
index 7602c7d..7602c7d 100644
--- a/design/design.css
+++ b/public/style/main.css
diff --git a/design/reset.css b/public/style/reset.css
index 58fedc2..58fedc2 100644
--- a/design/reset.css
+++ b/public/style/reset.css
diff --git a/shell.nix b/shell.nix
new file mode 100644
index 0000000..d3365c2
--- /dev/null
+++ b/shell.nix
@@ -0,0 +1,15 @@
+with import <nixpkgs> {}; {
+ env = stdenv.mkDerivation {
+ name = "env";
+ buildInputs = [
+ elmPackages.elm
+ nodejs
+ tmux
+ tmuxinator
+ ];
+ shellHook = ''
+ tmux kill-session -t timer >/dev/null 2>&1
+ tmuxinator local
+ '';
+ };
+}
diff --git a/src/Model/Edition/Edition.elm b/src/Edition/Model.elm
index 9a28253..5c1b295 100644
--- a/src/Model/Edition/Edition.elm
+++ b/src/Edition/Model.elm
@@ -1,17 +1,18 @@
-module Model.Edition.Edition
+module Edition.Model exposing
( Edition
, Kind(..)
, newEdition
, keyCodeToChar
, isEmpty
- ) where
+ )
-import Keyboard exposing (KeyCode)
import String
import Model.Id exposing (..)
-import Model.Edition.NameEdition as NameEdition
-import Model.Edition.TimeEdition as TimeEdition
+import Model.Keyboard exposing (KeyCode)
+
+import Edition.Model.Name as NameEdition
+import Edition.Model.Time as TimeEdition
type alias Edition =
{ id : Id
diff --git a/src/Model/Edition/NameEdition.elm b/src/Edition/Model/Name.elm
index be7c6b3..19f4c04 100644
--- a/src/Model/Edition/NameEdition.elm
+++ b/src/Edition/Model/Name.elm
@@ -1,13 +1,14 @@
-module Model.Edition.NameEdition
+module Edition.Model.Name exposing
( keyCodeToChar
, renderNameEdition
- ) where
+ )
import Char
-import Keyboard exposing (KeyCode)
import String
import List
+import Model.Keyboard exposing (KeyCode)
+
keyCodeToChar : KeyCode -> Maybe Char
keyCodeToChar = Just << Char.fromCode
diff --git a/src/Model/Edition/TimeEdition.elm b/src/Edition/Model/Time.elm
index 3b70c3d..35971c3 100644
--- a/src/Model/Edition/TimeEdition.elm
+++ b/src/Edition/Model/Time.elm
@@ -1,16 +1,16 @@
-module Model.Edition.TimeEdition
+module Edition.Model.Time exposing
( keyCodeToChar
, toTime
, toMinutesAndSeconds
- ) where
+ )
import Time exposing (Time)
import List
import Array
import String
-import Keyboard exposing (KeyCode)
import Char
+import Model.Keyboard exposing (KeyCode)
import Utils.List exposing (..)
import Utils.Maybe exposing (..)
diff --git a/src/Edition/Msg.elm b/src/Edition/Msg.elm
new file mode 100644
index 0000000..546e45b
--- /dev/null
+++ b/src/Edition/Msg.elm
@@ -0,0 +1,9 @@
+module Edition.Msg exposing
+ ( Msg(..)
+ )
+
+import Char exposing (KeyCode)
+
+type Msg =
+ DeleteLast
+ | AddChar KeyCode
diff --git a/src/Edition/Update.elm b/src/Edition/Update.elm
new file mode 100644
index 0000000..e219629
--- /dev/null
+++ b/src/Edition/Update.elm
@@ -0,0 +1,30 @@
+module Edition.Update exposing
+ ( updateEdition
+ )
+
+import Char
+import Char exposing (KeyCode)
+import List
+
+import Edition.Model exposing (..)
+import Edition.Msg exposing (..)
+
+updateEdition : Msg -> Edition -> Edition
+updateEdition msg edition =
+ case msg of
+
+ DeleteLast ->
+ case List.tail edition.chars of
+ Just tailChars ->
+ { edition | chars = tailChars }
+ Nothing ->
+ edition
+
+ AddChar keyCode ->
+ case keyCodeToChar edition.kind keyCode of
+ Just char ->
+ if keyCode == 32 && List.head edition.chars == Just (Char.fromCode 32)
+ then edition
+ else { edition | chars = char :: edition.chars }
+ Nothing ->
+ edition
diff --git a/src/Main.elm b/src/Main.elm
index 746df14..743c776 100644
--- a/src/Main.elm
+++ b/src/Main.elm
@@ -1,51 +1,29 @@
-module Main
+port module Main exposing
( main
- ) where
+ )
-import Signal
-import Html exposing (Html)
-import Time exposing (..)
-import Mouse
-import Json.Encode exposing (Value)
-import Keyboard
+import Html.App exposing (programWithFlags)
+import Time
import Char
-import Dict
-import List
-import Keyboard exposing (KeyCode)
-import Model.Model exposing (..)
-import Model.Position exposing (..)
-import Model.TimerState exposing (..)
-import Model.Id exposing (..)
-import Update.Update exposing (..)
-import View.View exposing (view)
-
-main : Signal Html
-main = Signal.map view model
-
-model : Signal Model
-model = Signal.foldp logUpdate (initialModel initialTime) input
-
-input : Signal Action
-input =
- Signal.mergeMany
- [ actions.signal
- , Signal.map DeltaTime (fps 30)
- , Signal.map KeyPressed keyPress
- ]
-
-port ringingTimers : Signal Bool
-port ringingTimers =
- Signal.map
- (\model ->
- model.timers
- |> Dict.toList
- |> List.map snd
- |> List.any (\timer -> timer.state == Ringing)
- )
- model
- |> Signal.dropRepeats
-
-port keyPress : Signal KeyCode
-
-port initialTime : Time
+import Model exposing (init)
+import Model.Keyboard exposing (KeyCode)
+import Msg
+import Update exposing (update)
+import View exposing (view)
+
+main : Program Float
+main =
+ programWithFlags
+ { init = init
+ , update = update
+ , subscriptions = (\model ->
+ Sub.batch
+ [ Time.every 40 Msg.Time
+ , keyPress Msg.KeyPressed
+ ]
+ )
+ , view = view
+ }
+
+port keyPress : (KeyCode -> msg) -> Sub msg
diff --git a/src/Model/Model.elm b/src/Model.elm
index a660b16..6e75c39 100644
--- a/src/Model/Model.elm
+++ b/src/Model.elm
@@ -1,34 +1,40 @@
-module Model.Model
+module Model exposing
( Model
- , initialModel
+ , init
, numberOfTimers
- ) where
+ )
import Dict exposing (Dict)
import Dict
import Time exposing (Time)
import List
-import Model.Timer exposing (..)
-import Model.Edition.Edition exposing (..)
+import Msg exposing (Msg)
+
import Model.Id exposing (..)
import Model.IdGenerator exposing (..)
+import Timer.Model as Timer exposing (Timer)
+
+import Edition.Model exposing (Edition)
+
type alias Model =
- { currentTime : Time
+ { time : Time
, timers : Dict Id Timer
, timerIdGenerator : IdGenerator
, edition : Maybe Edition
}
-initialModel : Time -> Model
-initialModel initialTime =
+init : Time -> (Model, Cmd Msg)
+init initialTime =
let (id, idGenerator) = getId initialIdGenerator
- in { currentTime = initialTime
- , timers = Dict.insert id (initialTimer initialTime) Dict.empty
- , timerIdGenerator = idGenerator
- , edition = Nothing
- }
+ model =
+ { time = initialTime
+ , timers = Dict.insert id (Timer.init initialTime) Dict.empty
+ , timerIdGenerator = idGenerator
+ , edition = Nothing
+ }
+ in (model, Cmd.none)
numberOfTimers : Model -> Int
numberOfTimers = List.length << Dict.toList << .timers
diff --git a/src/Model/Id.elm b/src/Model/Id.elm
index c416804..f71b71e 100644
--- a/src/Model/Id.elm
+++ b/src/Model/Id.elm
@@ -1,5 +1,5 @@
-module Model.Id
+module Model.Id exposing
( Id
- ) where
+ )
type alias Id = Int
diff --git a/src/Model/IdGenerator.elm b/src/Model/IdGenerator.elm
index 9001191..f3eefad 100644
--- a/src/Model/IdGenerator.elm
+++ b/src/Model/IdGenerator.elm
@@ -1,8 +1,8 @@
-module Model.IdGenerator
+module Model.IdGenerator exposing
( IdGenerator
, initialIdGenerator
, getId
- ) where
+ )
import Model.Id exposing (..)
@@ -17,5 +17,5 @@ initialIdGenerator =
getId : IdGenerator -> (Id, IdGenerator)
getId idGenerator =
( idGenerator.counter
- , { idGenerator | counter <- idGenerator.counter + 1 }
+ , { idGenerator | counter = idGenerator.counter + 1 }
)
diff --git a/src/Model/Keyboard.elm b/src/Model/Keyboard.elm
new file mode 100644
index 0000000..7649a56
--- /dev/null
+++ b/src/Model/Keyboard.elm
@@ -0,0 +1,5 @@
+module Model.Keyboard exposing
+ ( KeyCode
+ )
+
+type alias KeyCode = Int
diff --git a/src/Model/Position.elm b/src/Model/Position.elm
index d15e853..12d2f9b 100644
--- a/src/Model/Position.elm
+++ b/src/Model/Position.elm
@@ -1,6 +1,6 @@
-module Model.Position
+module Model.Position exposing
( positionEncoder
- ) where
+ )
import Json.Encode exposing (..)
diff --git a/src/Model/TimerState.elm b/src/Model/TimerState.elm
deleted file mode 100644
index dbbcb80..0000000
--- a/src/Model/TimerState.elm
+++ /dev/null
@@ -1,8 +0,0 @@
-module Model.TimerState
- ( TimerState(..)
- ) where
-
-type TimerState =
- Idle
- | Running
- | Ringing
diff --git a/src/Msg.elm b/src/Msg.elm
new file mode 100644
index 0000000..b5efe2f
--- /dev/null
+++ b/src/Msg.elm
@@ -0,0 +1,23 @@
+module Msg exposing
+ ( Msg(..)
+ )
+
+import Time exposing (Time)
+
+import Model.Id exposing (Id)
+import Model.Keyboard exposing (KeyCode)
+
+import Timer.Msg as Timer
+
+import Edition.Model exposing (Kind)
+
+type Msg =
+ NoOp
+ | Initialize
+ | AddNewTimer
+ | Time Time
+ | UpdateTimer Id Timer.Msg
+ | RemoveTimer Id
+ | Edit Id Kind
+ | ClickAway
+ | KeyPressed KeyCode
diff --git a/src/Ring.elm b/src/Ring.elm
new file mode 100644
index 0000000..fa29928
--- /dev/null
+++ b/src/Ring.elm
@@ -0,0 +1,5 @@
+port module Ring exposing
+ ( ring
+ )
+
+port ring : Bool -> Cmd msg
diff --git a/src/Model/Timer.elm b/src/Timer/Model.elm
index 51d293d..89af67e 100644
--- a/src/Model/Timer.elm
+++ b/src/Timer/Model.elm
@@ -1,27 +1,27 @@
-module Model.Timer
+module Timer.Model exposing
( Timer
- , initialTimer
- ) where
+ , init
+ )
import List
import Time exposing (Time)
-import Model.TimerState exposing (..)
+import Timer.Model.State exposing (..)
type alias Timer =
{ creationTime : Time
, name : Maybe String
, initialTime : Time
- , currentTime : Time
- , state : TimerState
+ , time : Time
+ , state : State
}
-initialTimer : Time -> Timer
-initialTimer creationTime =
+init : Time -> Timer
+init creationTime =
let initialTime = 5 * 60 * 1000
in { creationTime = creationTime
, name = Nothing
, initialTime = initialTime
- , currentTime = initialTime
+ , time = initialTime
, state = Idle
}
diff --git a/src/Timer/Model/State.elm b/src/Timer/Model/State.elm
new file mode 100644
index 0000000..1162e59
--- /dev/null
+++ b/src/Timer/Model/State.elm
@@ -0,0 +1,8 @@
+module Timer.Model.State exposing
+ ( State(..)
+ )
+
+type State =
+ Idle
+ | Running
+ | Ringing
diff --git a/src/Timer/Msg.elm b/src/Timer/Msg.elm
new file mode 100644
index 0000000..150d4fc
--- /dev/null
+++ b/src/Timer/Msg.elm
@@ -0,0 +1,13 @@
+module Timer.Msg exposing
+ ( Msg(..)
+ )
+
+import Time exposing (Time)
+
+type Msg =
+ Rename String
+ | Pause
+ | ToggleRunning
+ | Stop
+ | SetTime Time
+ | SubstractTime Time
diff --git a/src/Timer/Update.elm b/src/Timer/Update.elm
new file mode 100644
index 0000000..31e8a43
--- /dev/null
+++ b/src/Timer/Update.elm
@@ -0,0 +1,56 @@
+module Timer.Update exposing
+ ( updateTimer
+ )
+
+import Time exposing (Time)
+
+import Model.Id exposing (..)
+
+import Timer.Model exposing (..)
+import Timer.Model.State exposing (..)
+import Timer.Msg exposing (..)
+
+updateTimer : Msg -> Timer -> Timer
+updateTimer msg timer =
+ case msg of
+
+ Rename name ->
+ { timer | name = Just name }
+
+ Pause ->
+ { timer | state = Idle }
+
+ ToggleRunning ->
+ { timer
+ | state =
+ if timer.time > 0 && timer.state == Idle
+ then Running
+ else Idle
+ }
+
+ Stop ->
+ { timer
+ | time = timer.initialTime
+ , state = Idle
+ }
+
+ SetTime time ->
+ { timer
+ | initialTime = time
+ , time = time
+ }
+
+ SubstractTime time ->
+ if timer.state == Running
+ then
+ let newTime = timer.time - time
+ in if newTime <= 0.0
+ then
+ { timer
+ | time = 0.0
+ , state = Ringing
+ }
+ else
+ { timer | time = newTime }
+ else
+ timer
diff --git a/src/View/Timer.elm b/src/Timer/View.elm
index 4672594..561ae8f 100644
--- a/src/View/Timer.elm
+++ b/src/Timer/View.elm
@@ -1,39 +1,41 @@
-module View.Timer
- ( timerView
- ) where
+module Timer.View exposing
+ ( view
+ )
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import Time exposing (Time)
-import Signal
import Maybe
import List
import String
-import Model.Model exposing (..)
-import Model.Timer exposing (..)
-import Model.Edition.Edition exposing (..)
-import Model.Edition.NameEdition exposing (..)
-import Model.Edition.TimeEdition exposing (..)
-import Model.TimerState exposing (..)
+import Msg exposing (Msg)
+
+import Model exposing (..)
import Model.Id exposing (..)
-import Update.Update exposing (..)
-import Update.UpdateTimer exposing (..)
+import Timer.Model exposing (..)
+import Timer.Model.State exposing (..)
+import Timer.Update exposing (..)
+import Timer.Msg as Timer
+
+import Edition.Model exposing (..)
+import Edition.Model.Name exposing (..)
+import Edition.Model.Time exposing (..)
-import View.ActivatedClasses exposing (..)
+import Update exposing (..)
import Utils.Maybe exposing (..)
-timerView : Model -> (Id, Timer) -> Html
-timerView model (id, timer) =
+view : Model -> (Id, Timer) -> Html Msg
+view model (id, timer) =
div
- [ [ (True, "timer")
- , (timer.state == Ringing, "isRinging")
- , (timer.state == Running, "isRunning")
+ [ [ ("timer", True)
+ , ("isRinging", timer.state == Ringing)
+ , ("isRunning", timer.state == Running)
]
- |> activatedClasses
+ |> classList
]
[ renderMaybeEdition model id Name (nameBlockReadOnly id timer) (nameBlockEdition id timer)
, renderMaybeEdition model id Time (timeBlockReadOnly (id, timer)) (timeBlockEdition (id, timer))
@@ -42,22 +44,23 @@ timerView model (id, timer) =
, removeTimer (id, timer)
]
-nameBlockReadOnly : Id -> Timer -> Html
+nameBlockReadOnly : Id -> Timer -> Html Msg
nameBlockReadOnly id timer =
div
[ class "name"
- , onClick actions.address (Edit id Name)
+ , onClick (Msg.Edit id Name)
]
[ text (timerName id timer) ]
-nameBlockEdition : Id -> Timer -> Edition -> Html
+nameBlockEdition : Id -> Timer -> Edition -> Html Msg
nameBlockEdition id timer edition =
div
- [ [ (True, "name edition")
- , (isEmpty edition, "empty")
+ [ [ ("name", True)
+ , ("edition", True)
+ , ("empty", isEmpty edition)
]
- |> activatedClasses
- , onClick actions.address NoOp
+ |> classList
+ , onClick Msg.NoOp
]
[ if isEmpty edition
then
@@ -72,22 +75,23 @@ nameBlockEdition id timer edition =
timerName : Id -> Timer -> String
timerName id = Maybe.withDefault ("Timer " ++ toString id) << .name
-timeBlockReadOnly : (Id, Timer) -> Html
+timeBlockReadOnly : (Id, Timer) -> Html Msg
timeBlockReadOnly (id, timer) =
div
[ class "time"
- , onClick actions.address (Edit id Time)
+ , onClick (Msg.Edit id Time)
]
[ timeWithProgressBar (id, timer) ]
-timeBlockEdition : (Id, Timer) -> Edition -> Html
+timeBlockEdition : (Id, Timer) -> Edition -> Html Msg
timeBlockEdition (id, timer) edition =
div
- [ [ (True, "time edition")
- , (isEmpty edition, "empty")
+ [ [ ("time", True)
+ , ("edition", True)
+ , ("empty", isEmpty edition)
]
- |> activatedClasses
- , onClick actions.address NoOp
+ |> classList
+ , onClick Msg.NoOp
]
[ if isEmpty edition
then
@@ -108,32 +112,32 @@ timeView time =
restSeconds = totalSeconds `rem` 60
in (String.padLeft 2 '0' (toString totalMinutes)) ++ " : " ++ (String.padLeft 2 '0' (toString restSeconds))
-timeWithProgressBar : (Id, Timer) -> Html
+timeWithProgressBar : (Id, Timer) -> Html Msg
timeWithProgressBar (id, timer) =
div
[]
[ span
[ class "progressBar"
, let width =
- 1 - timer.currentTime / timer.initialTime
+ 1 - timer.time / timer.initialTime
|> (*) 1020
|> round
|> toString
|> flip String.append "px"
in style [ ("width", width) ]
- , onClick actions.address (UpdateTimer id Stop)
+ , onClick (Msg.UpdateTimer id Timer.Stop)
]
[]
, span
[ class "text" ]
- [ text (timeView timer.currentTime) ]
+ [ text (timeView timer.time) ]
]
-playPauseTimer : (Id, Timer) -> Html
+playPauseTimer : (Id, Timer) -> Html Msg
playPauseTimer (id, timer) =
button
[ class <| "playPause"
- , onClick actions.address (UpdateTimer id ToggleRunning)
+ , onClick (Msg.UpdateTimer id Timer.ToggleRunning)
]
[ let icon = if timer.state == Running then "fa-pause" else "fa-play"
in i
@@ -141,23 +145,23 @@ playPauseTimer (id, timer) =
[]
]
-stopTimer : (Id, Timer) -> Html
+stopTimer : (Id, Timer) -> Html Msg
stopTimer (id, timer) =
button
[ class <| "stop"
- , onClick actions.address (UpdateTimer id Stop)
+ , onClick (Msg.UpdateTimer id Timer.Stop)
]
[ i [ class "fa fa-fw fa-stop" ] [] ]
-removeTimer : (Id, Timer) -> Html
+removeTimer : (Id, Timer) -> Html Msg
removeTimer (id, timer) =
button
[ class <| "remove"
- , onClick actions.address (RemoveTimer id)
+ , onClick (Msg.RemoveTimer id)
]
[ i [ class "fa fa-fw fa-remove" ] [] ]
-renderMaybeEdition : Model -> Id -> Kind -> Html -> (Edition -> Html) -> Html
+renderMaybeEdition : Model -> Id -> Kind -> Html Msg -> (Edition -> Html Msg) -> Html Msg
renderMaybeEdition model id kind readOnlyView editionView =
let maybeEdition = filterMaybe (\edition -> edition.id == id) model.edition
in case maybeEdition of
diff --git a/src/Update.elm b/src/Update.elm
new file mode 100644
index 0000000..42eb682
--- /dev/null
+++ b/src/Update.elm
@@ -0,0 +1,141 @@
+module Update exposing
+ ( update
+ )
+
+import Dict
+
+import Msg exposing (Msg)
+
+import Ring
+
+import Model exposing (Model)
+import Model.Id exposing (..)
+import Model.IdGenerator exposing (..)
+import Model.Keyboard exposing (KeyCode)
+
+import Timer.Model as Timer exposing (..)
+import Timer.Model.State as TimerState
+import Timer.Update exposing (..)
+import Timer.Msg as Timer
+
+import Edition.Model exposing (..)
+import Edition.Model.Name exposing (..)
+import Edition.Model.Time exposing (..)
+import Edition.Update exposing (..)
+import Edition.Msg as Edition
+
+import Utils.Maybe exposing (..)
+
+update : Msg -> Model -> (Model, Cmd Msg)
+update msg model =
+ case msg of
+
+ Msg.NoOp ->
+ (model, Cmd.none)
+
+ Msg.Initialize ->
+ Model.init model.time
+
+ Msg.AddNewTimer ->
+ let (id, newTimerIdGenerator) = getId model.timerIdGenerator
+ in ( { model
+ | timers = Dict.insert id (Timer.init model.time) model.timers
+ , timerIdGenerator = newTimerIdGenerator
+ }
+ , Cmd.none
+ )
+
+ Msg.Time time ->
+ let delta = time - model.time
+ newModel =
+ { model
+ | time = time
+ , timers = Dict.map (\id timer -> updateTimer (Timer.SubstractTime delta) timer) model.timers
+ }
+ ringing =
+ newModel.timers
+ |> Dict.values
+ |> List.map .state
+ |> List.member TimerState.Ringing
+ in ( newModel
+ , Ring.ring ringing
+ )
+
+ Msg.UpdateTimer id timerMsg ->
+ let maybeEdition = filterMaybe (\edition -> edition.id == id) model.edition
+ newModel =
+ case maybeEdition of
+ Just edition ->
+ if edition.kind == Time then validEdition model else model
+ Nothing ->
+ model
+ in ( { newModel | timers = Dict.update id (Maybe.map (updateTimer timerMsg)) newModel.timers }
+ , Cmd.none
+ )
+
+ Msg.RemoveTimer id ->
+ if Model.numberOfTimers model > 1
+ then
+ ( { model | timers = Dict.remove id model.timers }
+ , Cmd.none
+ )
+ else
+ (model, Cmd.none)
+
+ Msg.Edit id kind ->
+ ( { model
+ | edition = Just (newEdition id kind)
+ , timers =
+ if kind == Time
+ then Dict.update id (Maybe.map (updateTimer Timer.Pause)) model.timers
+ else model.timers
+ }
+ , Cmd.none
+ )
+
+ Msg.ClickAway ->
+ ( { model | edition = Nothing }
+ , Cmd.none
+ )
+
+ Msg.KeyPressed keyCode ->
+ if isEnterKeyCode keyCode
+ then
+ (validEdition model, Cmd.none)
+ else
+ let editionAction =
+ if isRemoveKeyCode keyCode
+ then Edition.DeleteLast
+ else Edition.AddChar keyCode
+ in ( { model | edition = Maybe.map (updateEdition editionAction) model.edition }
+ , Cmd.none
+ )
+
+validEdition : Model -> Model
+validEdition model =
+ case model.edition of
+ Just edition ->
+ if isEmpty edition
+ then
+ { model
+ | edition = Nothing
+ }
+ else
+ let timerMsg =
+ case edition.kind of
+ Name ->
+ Timer.Rename (renderNameEdition edition.chars)
+ Time ->
+ Timer.SetTime (toTime edition.chars)
+ in { model
+ | timers = Dict.update edition.id (Maybe.map (updateTimer timerMsg)) model.timers
+ , edition = Nothing
+ }
+ Nothing ->
+ model
+
+isEnterKeyCode : KeyCode -> Bool
+isEnterKeyCode = (==) 13
+
+isRemoveKeyCode : KeyCode -> Bool
+isRemoveKeyCode = (==) 8
diff --git a/src/Update/Update.elm b/src/Update/Update.elm
deleted file mode 100644
index b4cf741..0000000
--- a/src/Update/Update.elm
+++ /dev/null
@@ -1,131 +0,0 @@
-module Update.Update
- ( Action(..)
- , actions
- , logUpdate
- , update
- ) where
-
-import Signal
-import Dict
-import Dict exposing (Dict)
-import Time exposing (Time)
-import Maybe
-import Keyboard exposing (KeyCode)
-import Char
-import List
-import Debug
-
-import Model.Model exposing (..)
-import Model.Timer exposing (..)
-import Model.Edition.Edition exposing (..)
-import Model.Edition.NameEdition exposing (..)
-import Model.Edition.TimeEdition exposing (..)
-import Model.Id exposing (..)
-import Model.IdGenerator exposing (..)
-
-import Update.UpdateTimer exposing (..)
-import Update.UpdateEdition exposing (..)
-
-import Utils.Maybe exposing (..)
-
-type Action =
- NoOp
- | Initialize
- | AddNewTimer
- | DeltaTime Time
- | UpdateTimer Id TimerAction
- | RemoveTimer Id
- | Edit Id Kind
- | ClickAway
- | KeyPressed KeyCode
-
-actions : Signal.Mailbox Action
-actions = Signal.mailbox NoOp
-
-logUpdate : Action -> Model -> Model
-logUpdate action model =
- case action of
- DeltaTime _ -> update action model
- _ -> update (Debug.log "action" action) model
-
-update : Action -> Model -> Model
-update action model =
- case action of
- NoOp -> model
- Initialize ->
- initialModel model.currentTime
- AddNewTimer ->
- let (id, newTimerIdGenerator) = getId model.timerIdGenerator
- in { model
- | timers <- Dict.insert id (initialTimer model.currentTime) model.timers
- , timerIdGenerator <- newTimerIdGenerator
- }
- DeltaTime delta ->
- { model
- | currentTime <- model.currentTime + delta
- , timers <- Dict.map (\id timer -> updateTimer (SubstractTime delta) timer) model.timers
- }
- UpdateTimer id timerAction ->
- let maybeEdition = filterMaybe (\edition -> edition.id == id) model.edition
- newModel =
- case maybeEdition of
- Just edition ->
- if edition.kind == Time then validEdition model else model
- Nothing ->
- model
- in { newModel | timers <- Dict.update id (Maybe.map (updateTimer timerAction)) newModel.timers }
- RemoveTimer id ->
- if numberOfTimers model > 1
- then
- { model | timers <- Dict.remove id model.timers }
- else
- model
- Edit id kind ->
- { model
- | edition <- Just (newEdition id kind)
- , timers <-
- if kind == Time
- then Dict.update id (Maybe.map (updateTimer Pause)) model.timers
- else model.timers
- }
- ClickAway ->
- { model | edition <- Nothing }
- KeyPressed keyCode ->
- if isEnterKeyCode keyCode
- then
- validEdition model
- else
- let editionAction =
- if isRemoveKeyCode keyCode
- then DeleteLast
- else AddChar keyCode
- in { model | edition <- Maybe.map (updateEdition editionAction) model.edition }
-
-validEdition : Model -> Model
-validEdition model =
- case model.edition of
- Just edition ->
- if isEmpty edition
- then
- { model
- | edition <- Nothing
- }
- else
- let timerAction =
- case edition.kind of
- Name ->
- Rename (renderNameEdition edition.chars)
- Time ->
- SetTime (toTime edition.chars)
- in { model
- | timers <- Dict.update edition.id (Maybe.map (updateTimer timerAction)) model.timers
- , edition <- Nothing
- }
- Nothing ->
- model
-
-isEnterKeyCode : KeyCode -> Bool
-isEnterKeyCode = (==) 13
-
-isRemoveKeyCode : KeyCode -> Bool
-isRemoveKeyCode = (==) 8
diff --git a/src/Update/UpdateEdition.elm b/src/Update/UpdateEdition.elm
deleted file mode 100644
index 47b0e22..0000000
--- a/src/Update/UpdateEdition.elm
+++ /dev/null
@@ -1,33 +0,0 @@
-module Update.UpdateEdition
- ( updateEdition
- , EditionAction(..)
- ) where
-
-import Char
-import Char exposing (KeyCode)
-
-import Model.Edition.Edition exposing (..)
-
-import Utils.List exposing (..)
-
-type EditionAction =
- DeleteLast
- | AddChar KeyCode
-
-updateEdition : EditionAction -> Edition -> Edition
-updateEdition action edition =
- case action of
- DeleteLast ->
- case maybeTail edition.chars of
- Just tailChars ->
- { edition | chars <- tailChars }
- Nothing ->
- edition
- AddChar keyCode ->
- case keyCodeToChar edition.kind keyCode of
- Just char ->
- if keyCode == 32 && maybeHead edition.chars == Just (Char.fromCode 32)
- then edition
- else { edition | chars <- char :: edition.chars }
- Nothing ->
- edition
diff --git a/src/Update/UpdateTimer.elm b/src/Update/UpdateTimer.elm
deleted file mode 100644
index 08b9969..0000000
--- a/src/Update/UpdateTimer.elm
+++ /dev/null
@@ -1,57 +0,0 @@
-module Update.UpdateTimer
- ( TimerAction(..)
- , updateTimer
- ) where
-
-import Time exposing (Time)
-
-import Model.Timer exposing (..)
-import Model.TimerState exposing (..)
-import Model.Id exposing (..)
-
-type TimerAction =
- Rename String
- | Pause
- | ToggleRunning
- | Stop
- | SetTime Time
- | SubstractTime Time
-
-updateTimer : TimerAction -> Timer -> Timer
-updateTimer action timer =
- case action of
- Rename name ->
- { timer | name <- Just name }
- Pause ->
- { timer | state <- Idle }
- ToggleRunning ->
- { timer
- | state <-
- if timer.currentTime > 0 && timer.state == Idle
- then Running
- else Idle
- }
- Stop ->
- { timer
- | currentTime <- timer.initialTime
- , state <- Idle
- }
- SetTime time ->
- { timer
- | initialTime <- time
- , currentTime <- time
- }
- SubstractTime time ->
- if timer.state == Running
- then
- 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/Utils/List.elm b/src/Utils/List.elm
index 83b11eb..7f2e928 100644
--- a/src/Utils/List.elm
+++ b/src/Utils/List.elm
@@ -1,9 +1,7 @@
-module Utils.List
+module Utils.List exposing
( repeat
, splitAt
- , maybeHead
- , maybeTail
- ) where
+ )
import List
@@ -17,15 +15,3 @@ repeat count elem =
splitAt : Int -> List a -> (List a, List a)
splitAt n xs = (List.take n xs, List.drop n xs)
-
-maybeHead : List a -> Maybe a
-maybeHead xs =
- case xs of
- x :: _ -> Just x
- _ -> Nothing
-
-maybeTail : List a -> Maybe (List a)
-maybeTail xs =
- case xs of
- _ :: tl -> Just tl
- _ -> Nothing
diff --git a/src/Utils/Maybe.elm b/src/Utils/Maybe.elm
index 355ded9..db25bff 100644
--- a/src/Utils/Maybe.elm
+++ b/src/Utils/Maybe.elm
@@ -1,7 +1,7 @@
-module Utils.Maybe
+module Utils.Maybe exposing
( filterMaybe
, orElse
- ) where
+ )
filterMaybe : (a -> Bool) -> Maybe a -> Maybe a
filterMaybe cond maybe =
diff --git a/src/View/View.elm b/src/View.elm
index a69d662..5b3ad8d 100644
--- a/src/View/View.elm
+++ b/src/View.elm
@@ -1,24 +1,25 @@
-module View.View
+module View exposing
( view
- ) where
+ )
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
-import Signal
import List
import Dict
import Json.Decode as Json
-import Model.Model exposing (..)
-import Model.Timer exposing (..)
+import Msg exposing (Msg)
+
+import Model exposing (..)
import Model.Id exposing (..)
-import Update.Update exposing (..)
+import Timer.Model exposing (..)
+import Timer.View as Timer
-import View.Timer exposing (timerView)
+import Update exposing (..)
-view : Model -> Html
+view : Model -> Html Msg
view model =
div
[]
@@ -29,17 +30,17 @@ view model =
|> timers model
]
-title : Html
+title : Html Msg
title =
div
[ class "headerBar" ]
[ button
- [ onClick actions.address Initialize
+ [ onClick Msg.Initialize
, class "title"
]
[ text "Timer" ]
, button
- [ onClick actions.address AddNewTimer
+ [ onClick Msg.AddNewTimer
, class "addTimer"
]
[ i
@@ -48,20 +49,8 @@ title =
]
]
-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 : Model -> List (Id, Timer) -> Html
+timers : Model -> List (Id, Timer) -> Html Msg
timers model timers =
div
[ class "timers" ]
- (List.map (timerView model) timers)
+ (List.map (Timer.view model) timers)
diff --git a/src/View/ActivatedClasses.elm b/src/View/ActivatedClasses.elm
deleted file mode 100644
index 85b0841..0000000
--- a/src/View/ActivatedClasses.elm
+++ /dev/null
@@ -1,15 +0,0 @@
-module View.ActivatedClasses
- ( activatedClasses
- ) where
-
-import Html
-import Html.Attributes exposing (..)
-import List
-import String
-
-activatedClasses : List (Bool, String) -> Html.Attribute
-activatedClasses =
- class
- << String.concat
- << List.intersperse " "
- << List.filterMap (\(activated, str) -> if activated then Just str else Nothing)