From 973a039b54327df74396605410ea9abe19c8a4e7 Mon Sep 17 00:00:00 2001 From: Joris Date: Sun, 4 Sep 2016 21:21:11 +0200 Subject: Upgrade to elm 0.17.1 --- src/Edition/Model.elm | 45 ++++++++++ src/Edition/Model/Name.elm | 19 +++++ src/Edition/Model/Time.elm | 52 +++++++++++ src/Edition/Msg.elm | 9 ++ src/Edition/Update.elm | 30 +++++++ src/Main.elm | 72 ++++++---------- src/Model.elm | 40 +++++++++ src/Model/Edition/Edition.elm | 44 ---------- src/Model/Edition/NameEdition.elm | 18 ---- src/Model/Edition/TimeEdition.elm | 52 ----------- src/Model/Id.elm | 4 +- src/Model/IdGenerator.elm | 6 +- src/Model/Keyboard.elm | 5 ++ src/Model/Model.elm | 34 -------- src/Model/Position.elm | 4 +- src/Model/Timer.elm | 27 ------ src/Model/TimerState.elm | 8 -- src/Msg.elm | 23 +++++ src/Ring.elm | 5 ++ src/Timer/Model.elm | 27 ++++++ src/Timer/Model/State.elm | 8 ++ src/Timer/Msg.elm | 13 +++ src/Timer/Update.elm | 56 ++++++++++++ src/Timer/View.elm | 175 ++++++++++++++++++++++++++++++++++++++ src/Update.elm | 141 ++++++++++++++++++++++++++++++ src/Update/Update.elm | 131 ---------------------------- src/Update/UpdateEdition.elm | 33 ------- src/Update/UpdateTimer.elm | 57 ------------- src/Utils/List.elm | 18 +--- src/Utils/Maybe.elm | 4 +- src/View.elm | 56 ++++++++++++ src/View/ActivatedClasses.elm | 15 ---- src/View/Timer.elm | 171 ------------------------------------- src/View/View.elm | 67 --------------- 34 files changed, 740 insertions(+), 729 deletions(-) create mode 100644 src/Edition/Model.elm create mode 100644 src/Edition/Model/Name.elm create mode 100644 src/Edition/Model/Time.elm create mode 100644 src/Edition/Msg.elm create mode 100644 src/Edition/Update.elm create mode 100644 src/Model.elm delete mode 100644 src/Model/Edition/Edition.elm delete mode 100644 src/Model/Edition/NameEdition.elm delete mode 100644 src/Model/Edition/TimeEdition.elm create mode 100644 src/Model/Keyboard.elm delete mode 100644 src/Model/Model.elm delete mode 100644 src/Model/Timer.elm delete mode 100644 src/Model/TimerState.elm create mode 100644 src/Msg.elm create mode 100644 src/Ring.elm create mode 100644 src/Timer/Model.elm create mode 100644 src/Timer/Model/State.elm create mode 100644 src/Timer/Msg.elm create mode 100644 src/Timer/Update.elm create mode 100644 src/Timer/View.elm create mode 100644 src/Update.elm delete mode 100644 src/Update/Update.elm delete mode 100644 src/Update/UpdateEdition.elm delete mode 100644 src/Update/UpdateTimer.elm create mode 100644 src/View.elm delete mode 100644 src/View/ActivatedClasses.elm delete mode 100644 src/View/Timer.elm delete mode 100644 src/View/View.elm (limited to 'src') diff --git a/src/Edition/Model.elm b/src/Edition/Model.elm new file mode 100644 index 0000000..5c1b295 --- /dev/null +++ b/src/Edition/Model.elm @@ -0,0 +1,45 @@ +module Edition.Model exposing + ( Edition + , Kind(..) + , newEdition + , keyCodeToChar + , isEmpty + ) + +import String + +import Model.Id exposing (..) +import Model.Keyboard exposing (KeyCode) + +import Edition.Model.Name as NameEdition +import Edition.Model.Time as TimeEdition + +type alias Edition = + { id : Id + , kind : Kind + , chars : List Char + } + +type Kind = + Name + | Time + +newEdition id kind = + { id = id + , kind = kind + , chars = [] + } + +keyCodeToChar : Kind -> KeyCode -> Maybe Char +keyCodeToChar kind = + case kind of + Name -> NameEdition.keyCodeToChar + Time -> TimeEdition.keyCodeToChar + +isEmpty : Edition -> Bool +isEmpty edition = + edition.chars + |> String.fromList + |> String.trim + |> String.length + |> (==) 0 diff --git a/src/Edition/Model/Name.elm b/src/Edition/Model/Name.elm new file mode 100644 index 0000000..19f4c04 --- /dev/null +++ b/src/Edition/Model/Name.elm @@ -0,0 +1,19 @@ +module Edition.Model.Name exposing + ( keyCodeToChar + , renderNameEdition + ) + +import Char +import String +import List + +import Model.Keyboard exposing (KeyCode) + +keyCodeToChar : KeyCode -> Maybe Char +keyCodeToChar = Just << Char.fromCode + +renderNameEdition : List Char -> String +renderNameEdition chars = + chars + |> List.reverse + |> String.fromList diff --git a/src/Edition/Model/Time.elm b/src/Edition/Model/Time.elm new file mode 100644 index 0000000..35971c3 --- /dev/null +++ b/src/Edition/Model/Time.elm @@ -0,0 +1,52 @@ +module Edition.Model.Time exposing + ( keyCodeToChar + , toTime + , toMinutesAndSeconds + ) + +import Time exposing (Time) +import List +import Array +import String +import Char + +import Model.Keyboard exposing (KeyCode) +import Utils.List exposing (..) +import Utils.Maybe exposing (..) + +keyCodeToChar : KeyCode -> Maybe Char +keyCodeToChar code = + let char = Char.fromCode code + in if Char.isDigit char + then Just char + else Nothing + +toTime : List Char -> Time +toTime numbers = + numbers + |> toMinutesAndSeconds + |> \(a, b) -> (stringToInt a, stringToInt b) + |> \(minutes, seconds) -> (toFloat minutes) * 60 * 1000 + (toFloat seconds) * 1000 + +toMinutesAndSeconds : List Char -> (String, String) +toMinutesAndSeconds numbers = + numbers + |> List.take 4 + |> List.reverse + |> completeBegin '0' 4 + |> splitAt 2 + |> \(a, b) -> (String.fromList a, String.fromList b) + +completeBegin : a -> Int -> List a -> List a +completeBegin x count xs = + let length = List.length xs + in List.append (repeat (count - length) x) xs + +stringToInt : String -> Int +stringToInt str = + str + |> String.toInt + |> \res -> + case res of + Ok n -> n + Err _ -> 0 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.elm b/src/Model.elm new file mode 100644 index 0000000..6e75c39 --- /dev/null +++ b/src/Model.elm @@ -0,0 +1,40 @@ +module Model exposing + ( Model + , init + , numberOfTimers + ) + +import Dict exposing (Dict) +import Dict +import Time exposing (Time) +import List + +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 = + { time : Time + , timers : Dict Id Timer + , timerIdGenerator : IdGenerator + , edition : Maybe Edition + } + +init : Time -> (Model, Cmd Msg) +init initialTime = + let (id, idGenerator) = getId initialIdGenerator + 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/Edition/Edition.elm b/src/Model/Edition/Edition.elm deleted file mode 100644 index 9a28253..0000000 --- a/src/Model/Edition/Edition.elm +++ /dev/null @@ -1,44 +0,0 @@ -module Model.Edition.Edition - ( 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 - -type alias Edition = - { id : Id - , kind : Kind - , chars : List Char - } - -type Kind = - Name - | Time - -newEdition id kind = - { id = id - , kind = kind - , chars = [] - } - -keyCodeToChar : Kind -> KeyCode -> Maybe Char -keyCodeToChar kind = - case kind of - Name -> NameEdition.keyCodeToChar - Time -> TimeEdition.keyCodeToChar - -isEmpty : Edition -> Bool -isEmpty edition = - edition.chars - |> String.fromList - |> String.trim - |> String.length - |> (==) 0 diff --git a/src/Model/Edition/NameEdition.elm b/src/Model/Edition/NameEdition.elm deleted file mode 100644 index be7c6b3..0000000 --- a/src/Model/Edition/NameEdition.elm +++ /dev/null @@ -1,18 +0,0 @@ -module Model.Edition.NameEdition - ( keyCodeToChar - , renderNameEdition - ) where - -import Char -import Keyboard exposing (KeyCode) -import String -import List - -keyCodeToChar : KeyCode -> Maybe Char -keyCodeToChar = Just << Char.fromCode - -renderNameEdition : List Char -> String -renderNameEdition chars = - chars - |> List.reverse - |> String.fromList diff --git a/src/Model/Edition/TimeEdition.elm b/src/Model/Edition/TimeEdition.elm deleted file mode 100644 index 3b70c3d..0000000 --- a/src/Model/Edition/TimeEdition.elm +++ /dev/null @@ -1,52 +0,0 @@ -module Model.Edition.TimeEdition - ( keyCodeToChar - , toTime - , toMinutesAndSeconds - ) where - -import Time exposing (Time) -import List -import Array -import String -import Keyboard exposing (KeyCode) -import Char - -import Utils.List exposing (..) -import Utils.Maybe exposing (..) - -keyCodeToChar : KeyCode -> Maybe Char -keyCodeToChar code = - let char = Char.fromCode code - in if Char.isDigit char - then Just char - else Nothing - -toTime : List Char -> Time -toTime numbers = - numbers - |> toMinutesAndSeconds - |> \(a, b) -> (stringToInt a, stringToInt b) - |> \(minutes, seconds) -> (toFloat minutes) * 60 * 1000 + (toFloat seconds) * 1000 - -toMinutesAndSeconds : List Char -> (String, String) -toMinutesAndSeconds numbers = - numbers - |> List.take 4 - |> List.reverse - |> completeBegin '0' 4 - |> splitAt 2 - |> \(a, b) -> (String.fromList a, String.fromList b) - -completeBegin : a -> Int -> List a -> List a -completeBegin x count xs = - let length = List.length xs - in List.append (repeat (count - length) x) xs - -stringToInt : String -> Int -stringToInt str = - str - |> String.toInt - |> \res -> - case res of - Ok n -> n - Err _ -> 0 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/Model.elm b/src/Model/Model.elm deleted file mode 100644 index a660b16..0000000 --- a/src/Model/Model.elm +++ /dev/null @@ -1,34 +0,0 @@ -module Model.Model - ( Model - , initialModel - , numberOfTimers - ) where - -import Dict exposing (Dict) -import Dict -import Time exposing (Time) -import List - -import Model.Timer exposing (..) -import Model.Edition.Edition exposing (..) -import Model.Id exposing (..) -import Model.IdGenerator exposing (..) - -type alias Model = - { currentTime : Time - , timers : Dict Id Timer - , timerIdGenerator : IdGenerator - , edition : Maybe Edition - } - -initialModel : Time -> Model -initialModel initialTime = - let (id, idGenerator) = getId initialIdGenerator - in { currentTime = initialTime - , timers = Dict.insert id (initialTimer initialTime) Dict.empty - , timerIdGenerator = idGenerator - , edition = Nothing - } - -numberOfTimers : Model -> Int -numberOfTimers = List.length << Dict.toList << .timers 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/Timer.elm b/src/Model/Timer.elm deleted file mode 100644 index 51d293d..0000000 --- a/src/Model/Timer.elm +++ /dev/null @@ -1,27 +0,0 @@ -module Model.Timer - ( Timer - , initialTimer - ) where - -import List -import Time exposing (Time) - -import Model.TimerState exposing (..) - -type alias Timer = - { creationTime : Time - , name : Maybe String - , initialTime : Time - , currentTime : Time - , state : TimerState - } - -initialTimer : Time -> Timer -initialTimer creationTime = - let initialTime = 5 * 60 * 1000 - in { creationTime = creationTime - , name = Nothing - , initialTime = initialTime - , currentTime = initialTime - , state = Idle - } 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/Timer/Model.elm b/src/Timer/Model.elm new file mode 100644 index 0000000..89af67e --- /dev/null +++ b/src/Timer/Model.elm @@ -0,0 +1,27 @@ +module Timer.Model exposing + ( Timer + , init + ) + +import List +import Time exposing (Time) + +import Timer.Model.State exposing (..) + +type alias Timer = + { creationTime : Time + , name : Maybe String + , initialTime : Time + , time : Time + , state : State + } + +init : Time -> Timer +init creationTime = + let initialTime = 5 * 60 * 1000 + in { creationTime = creationTime + , name = Nothing + , initialTime = 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/Timer/View.elm b/src/Timer/View.elm new file mode 100644 index 0000000..561ae8f --- /dev/null +++ b/src/Timer/View.elm @@ -0,0 +1,175 @@ +module Timer.View exposing + ( view + ) + +import Html exposing (..) +import Html.Attributes exposing (..) +import Html.Events exposing (..) +import Time exposing (Time) +import Maybe +import List +import String + +import Msg exposing (Msg) + +import Model exposing (..) +import Model.Id 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 Update exposing (..) + +import Utils.Maybe exposing (..) + +view : Model -> (Id, Timer) -> Html Msg +view model (id, timer) = + div + [ [ ("timer", True) + , ("isRinging", timer.state == Ringing) + , ("isRunning", timer.state == Running) + ] + |> classList + ] + [ renderMaybeEdition model id Name (nameBlockReadOnly id timer) (nameBlockEdition id timer) + , renderMaybeEdition model id Time (timeBlockReadOnly (id, timer)) (timeBlockEdition (id, timer)) + , playPauseTimer (id, timer) + , stopTimer (id, timer) + , removeTimer (id, timer) + ] + +nameBlockReadOnly : Id -> Timer -> Html Msg +nameBlockReadOnly id timer = + div + [ class "name" + , onClick (Msg.Edit id Name) + ] + [ text (timerName id timer) ] + +nameBlockEdition : Id -> Timer -> Edition -> Html Msg +nameBlockEdition id timer edition = + div + [ [ ("name", True) + , ("edition", True) + , ("empty", isEmpty edition) + ] + |> classList + , onClick Msg.NoOp + ] + [ if isEmpty edition + then + text (timerName id timer) + else + edition.chars + |> renderNameEdition + |> flip String.append "_" + |> text + ] + +timerName : Id -> Timer -> String +timerName id = Maybe.withDefault ("Timer " ++ toString id) << .name + +timeBlockReadOnly : (Id, Timer) -> Html Msg +timeBlockReadOnly (id, timer) = + div + [ class "time" + , onClick (Msg.Edit id Time) + ] + [ timeWithProgressBar (id, timer) ] + +timeBlockEdition : (Id, Timer) -> Edition -> Html Msg +timeBlockEdition (id, timer) edition = + div + [ [ ("time", True) + , ("edition", True) + , ("empty", isEmpty edition) + ] + |> classList + , onClick Msg.NoOp + ] + [ if isEmpty edition + then + timeWithProgressBar (id, timer) + else + text (editionView edition.chars) + ] + +editionView : List Char -> String +editionView numbers = + let (minutes, seconds) = toMinutesAndSeconds numbers + in minutes ++ " : " ++ seconds + +timeView : Time -> String +timeView time = + let totalSeconds = ceiling (time / 1000) + totalMinutes = totalSeconds // 60 + restSeconds = totalSeconds `rem` 60 + in (String.padLeft 2 '0' (toString totalMinutes)) ++ " : " ++ (String.padLeft 2 '0' (toString restSeconds)) + +timeWithProgressBar : (Id, Timer) -> Html Msg +timeWithProgressBar (id, timer) = + div + [] + [ span + [ class "progressBar" + , let width = + 1 - timer.time / timer.initialTime + |> (*) 1020 + |> round + |> toString + |> flip String.append "px" + in style [ ("width", width) ] + , onClick (Msg.UpdateTimer id Timer.Stop) + ] + [] + , span + [ class "text" ] + [ text (timeView timer.time) ] + ] + +playPauseTimer : (Id, Timer) -> Html Msg +playPauseTimer (id, timer) = + button + [ class <| "playPause" + , onClick (Msg.UpdateTimer id Timer.ToggleRunning) + ] + [ let icon = if timer.state == Running then "fa-pause" else "fa-play" + in i + [ class <| "fa fa-fw " ++ icon ] + [] + ] + +stopTimer : (Id, Timer) -> Html Msg +stopTimer (id, timer) = + button + [ class <| "stop" + , onClick (Msg.UpdateTimer id Timer.Stop) + ] + [ i [ class "fa fa-fw fa-stop" ] [] ] + +removeTimer : (Id, Timer) -> Html Msg +removeTimer (id, timer) = + button + [ class <| "remove" + , onClick (Msg.RemoveTimer id) + ] + [ i [ class "fa fa-fw fa-remove" ] [] ] + +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 + Just edition -> + if edition.kind == kind + then + editionView edition + else + readOnlyView + Nothing -> + readOnlyView 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.elm b/src/View.elm new file mode 100644 index 0000000..5b3ad8d --- /dev/null +++ b/src/View.elm @@ -0,0 +1,56 @@ +module View exposing + ( view + ) + +import Html exposing (..) +import Html.Attributes exposing (..) +import Html.Events exposing (..) +import List +import Dict +import Json.Decode as Json + +import Msg exposing (Msg) + +import Model exposing (..) +import Model.Id exposing (..) + +import Timer.Model exposing (..) +import Timer.View as Timer + +import Update exposing (..) + +view : Model -> Html Msg +view model = + div + [] + [ title + , model.timers + |> Dict.toList + |> List.sortBy (.creationTime << snd) + |> timers model + ] + +title : Html Msg +title = + div + [ class "headerBar" ] + [ button + [ onClick Msg.Initialize + , class "title" + ] + [ text "Timer" ] + , button + [ onClick Msg.AddNewTimer + , class "addTimer" + ] + [ i + [ class "fa fa-fw fa-plus" ] + [] + ] + ] + +timers : Model -> List (Id, Timer) -> Html Msg +timers model timers = + div + [ class "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) diff --git a/src/View/Timer.elm b/src/View/Timer.elm deleted file mode 100644 index 4672594..0000000 --- a/src/View/Timer.elm +++ /dev/null @@ -1,171 +0,0 @@ -module View.Timer - ( timerView - ) where - -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 Model.Id exposing (..) - -import Update.Update exposing (..) -import Update.UpdateTimer exposing (..) - -import View.ActivatedClasses exposing (..) - -import Utils.Maybe exposing (..) - -timerView : Model -> (Id, Timer) -> Html -timerView model (id, timer) = - div - [ [ (True, "timer") - , (timer.state == Ringing, "isRinging") - , (timer.state == Running, "isRunning") - ] - |> activatedClasses - ] - [ renderMaybeEdition model id Name (nameBlockReadOnly id timer) (nameBlockEdition id timer) - , renderMaybeEdition model id Time (timeBlockReadOnly (id, timer)) (timeBlockEdition (id, timer)) - , playPauseTimer (id, timer) - , stopTimer (id, timer) - , removeTimer (id, timer) - ] - -nameBlockReadOnly : Id -> Timer -> Html -nameBlockReadOnly id timer = - div - [ class "name" - , onClick actions.address (Edit id Name) - ] - [ text (timerName id timer) ] - -nameBlockEdition : Id -> Timer -> Edition -> Html -nameBlockEdition id timer edition = - div - [ [ (True, "name edition") - , (isEmpty edition, "empty") - ] - |> activatedClasses - , onClick actions.address NoOp - ] - [ if isEmpty edition - then - text (timerName id timer) - else - edition.chars - |> renderNameEdition - |> flip String.append "_" - |> text - ] - -timerName : Id -> Timer -> String -timerName id = Maybe.withDefault ("Timer " ++ toString id) << .name - -timeBlockReadOnly : (Id, Timer) -> Html -timeBlockReadOnly (id, timer) = - div - [ class "time" - , onClick actions.address (Edit id Time) - ] - [ timeWithProgressBar (id, timer) ] - -timeBlockEdition : (Id, Timer) -> Edition -> Html -timeBlockEdition (id, timer) edition = - div - [ [ (True, "time edition") - , (isEmpty edition, "empty") - ] - |> activatedClasses - , onClick actions.address NoOp - ] - [ if isEmpty edition - then - timeWithProgressBar (id, timer) - else - text (editionView edition.chars) - ] - -editionView : List Char -> String -editionView numbers = - let (minutes, seconds) = toMinutesAndSeconds numbers - in minutes ++ " : " ++ seconds - -timeView : Time -> String -timeView time = - let totalSeconds = ceiling (time / 1000) - totalMinutes = totalSeconds // 60 - restSeconds = totalSeconds `rem` 60 - in (String.padLeft 2 '0' (toString totalMinutes)) ++ " : " ++ (String.padLeft 2 '0' (toString restSeconds)) - -timeWithProgressBar : (Id, Timer) -> Html -timeWithProgressBar (id, timer) = - div - [] - [ span - [ class "progressBar" - , let width = - 1 - timer.currentTime / timer.initialTime - |> (*) 1020 - |> round - |> toString - |> flip String.append "px" - in style [ ("width", width) ] - , onClick actions.address (UpdateTimer id Stop) - ] - [] - , span - [ class "text" ] - [ text (timeView timer.currentTime) ] - ] - -playPauseTimer : (Id, Timer) -> Html -playPauseTimer (id, timer) = - button - [ class <| "playPause" - , onClick actions.address (UpdateTimer id ToggleRunning) - ] - [ let icon = if timer.state == Running then "fa-pause" else "fa-play" - in i - [ class <| "fa fa-fw " ++ icon ] - [] - ] - -stopTimer : (Id, Timer) -> Html -stopTimer (id, timer) = - button - [ class <| "stop" - , onClick actions.address (UpdateTimer id Stop) - ] - [ i [ class "fa fa-fw fa-stop" ] [] ] - -removeTimer : (Id, Timer) -> Html -removeTimer (id, timer) = - button - [ class <| "remove" - , onClick actions.address (RemoveTimer id) - ] - [ i [ class "fa fa-fw fa-remove" ] [] ] - -renderMaybeEdition : Model -> Id -> Kind -> Html -> (Edition -> Html) -> Html -renderMaybeEdition model id kind readOnlyView editionView = - let maybeEdition = filterMaybe (\edition -> edition.id == id) model.edition - in case maybeEdition of - Just edition -> - if edition.kind == kind - then - editionView edition - else - readOnlyView - Nothing -> - readOnlyView diff --git a/src/View/View.elm b/src/View/View.elm deleted file mode 100644 index a69d662..0000000 --- a/src/View/View.elm +++ /dev/null @@ -1,67 +0,0 @@ -module View.View - ( 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 Model.Id exposing (..) - -import Update.Update exposing (..) - -import View.Timer exposing (timerView) - -view : Model -> Html -view model = - div - [] - [ title - , model.timers - |> Dict.toList - |> List.sortBy (.creationTime << snd) - |> timers model - ] - -title : Html -title = - div - [ class "headerBar" ] - [ button - [ onClick actions.address Initialize - , class "title" - ] - [ text "Timer" ] - , button - [ onClick actions.address AddNewTimer - , class "addTimer" - ] - [ 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 : Model -> List (Id, Timer) -> Html -timers model timers = - div - [ class "timers" ] - (List.map (timerView model) timers) -- cgit v1.2.3