diff options
author | Joris | 2016-09-04 21:21:11 +0200 |
---|---|---|
committer | Joris | 2016-09-04 21:21:31 +0200 |
commit | 973a039b54327df74396605410ea9abe19c8a4e7 (patch) | |
tree | c702564d17e0a490d56845027238eb4f231be785 | |
parent | 62fee9133f36f655c1ed83e0c2e85394f9948bf5 (diff) |
Upgrade to elm 0.17.1
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | .tmuxinator.yml | 8 | ||||
-rw-r--r-- | Makefile | 26 | ||||
-rw-r--r-- | elm-package.json | 11 | ||||
-rwxr-xr-x | gen | 2 | ||||
-rw-r--r-- | index.html | 47 | ||||
-rw-r--r-- | package.json | 6 | ||||
-rw-r--r-- | public/alarm.wav (renamed from alarm.wav) | bin | 661032 -> 661032 bytes | |||
-rw-r--r-- | public/images/icon.png (renamed from images/icon.png) | bin | 886 -> 886 bytes | |||
-rw-r--r-- | public/index.html | 40 | ||||
-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) | bin | 85908 -> 85908 bytes | |||
-rw-r--r-- | public/style/font-awesome/fonts/fontawesome-webfont.eot (renamed from design/font-awesome/fonts/fontawesome-webfont.eot) | bin | 56006 -> 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) | bin | 112160 -> 112160 bytes | |||
-rw-r--r-- | public/style/font-awesome/fonts/fontawesome-webfont.woff (renamed from design/font-awesome/fonts/fontawesome-webfont.woff) | bin | 65452 -> 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.nix | 15 | ||||
-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.elm | 9 | ||||
-rw-r--r-- | src/Edition/Update.elm | 30 | ||||
-rw-r--r-- | src/Main.elm | 72 | ||||
-rw-r--r-- | src/Model.elm (renamed from src/Model/Model.elm) | 32 | ||||
-rw-r--r-- | src/Model/Id.elm | 4 | ||||
-rw-r--r-- | src/Model/IdGenerator.elm | 6 | ||||
-rw-r--r-- | src/Model/Keyboard.elm | 5 | ||||
-rw-r--r-- | src/Model/Position.elm | 4 | ||||
-rw-r--r-- | src/Model/TimerState.elm | 8 | ||||
-rw-r--r-- | src/Msg.elm | 23 | ||||
-rw-r--r-- | src/Ring.elm | 5 | ||||
-rw-r--r-- | src/Timer/Model.elm (renamed from src/Model/Timer.elm) | 18 | ||||
-rw-r--r-- | src/Timer/Model/State.elm | 8 | ||||
-rw-r--r-- | src/Timer/Msg.elm | 13 | ||||
-rw-r--r-- | src/Timer/Update.elm | 56 | ||||
-rw-r--r-- | src/Timer/View.elm (renamed from src/View/Timer.elm) | 92 | ||||
-rw-r--r-- | src/Update.elm | 141 | ||||
-rw-r--r-- | src/Update/Update.elm | 131 | ||||
-rw-r--r-- | src/Update/UpdateEdition.elm | 33 | ||||
-rw-r--r-- | src/Update/UpdateTimer.elm | 57 | ||||
-rw-r--r-- | src/Utils/List.elm | 18 | ||||
-rw-r--r-- | src/Utils/Maybe.elm | 4 | ||||
-rw-r--r-- | src/View.elm (renamed from src/View/View.elm) | 39 | ||||
-rw-r--r-- | src/View/ActivatedClasses.elm | 15 |
46 files changed, 531 insertions, 474 deletions
@@ -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" } } @@ -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 Binary files differindex 41d6709..41d6709 100644 --- a/alarm.wav +++ b/public/alarm.wav diff --git a/images/icon.png b/public/images/icon.png Binary files differindex a489112..a489112 100644 --- a/images/icon.png +++ b/public/images/icon.png 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 Binary files differindex 81c9ad9..81c9ad9 100644 --- a/design/font-awesome/fonts/FontAwesome.otf +++ b/public/style/font-awesome/fonts/FontAwesome.otf diff --git a/design/font-awesome/fonts/fontawesome-webfont.eot b/public/style/font-awesome/fonts/fontawesome-webfont.eot Binary files differindex 84677bc..84677bc 100644 --- a/design/font-awesome/fonts/fontawesome-webfont.eot +++ b/public/style/font-awesome/fonts/fontawesome-webfont.eot 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 Binary files differindex 96a3639..96a3639 100644 --- a/design/font-awesome/fonts/fontawesome-webfont.ttf +++ b/public/style/font-awesome/fonts/fontawesome-webfont.ttf diff --git a/design/font-awesome/fonts/fontawesome-webfont.woff b/public/style/font-awesome/fonts/fontawesome-webfont.woff Binary files differindex 628b6a5..628b6a5 100644 --- a/design/font-awesome/fonts/fontawesome-webfont.woff +++ b/public/style/font-awesome/fonts/fontawesome-webfont.woff 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) |