From 2abb8ffa46cbe86deedb9ddcbb9b042b51285feb Mon Sep 17 00:00:00 2001 From: Joris Guyonvarch Date: Sun, 22 Mar 2015 12:53:55 +0100 Subject: Editing name first draft --- src/Main.elm | 2 +- src/Model/Edition/Edition.elm | 34 +++++++++++ src/Model/Edition/NameEdition.elm | 15 +++++ src/Model/Edition/TimeEdition.elm | 60 +++++++++++++++++++ src/Model/Model.elm | 9 ++- src/Model/Timer.elm | 8 +-- src/Model/TimerEdition.elm | 77 ------------------------ src/Update/Update.elm | 77 ++++++++++++------------ src/Update/UpdateEdition.elm | 30 ++++++++++ src/Update/UpdateTimer.elm | 5 +- src/Update/UpdateTimerEdition.elm | 34 ----------- src/View/Timer.elm | 120 +++++++++++++++++++++++++------------- 12 files changed, 271 insertions(+), 200 deletions(-) create mode 100644 src/Model/Edition/Edition.elm create mode 100644 src/Model/Edition/NameEdition.elm create mode 100644 src/Model/Edition/TimeEdition.elm delete mode 100644 src/Model/TimerEdition.elm create mode 100644 src/Update/UpdateEdition.elm delete mode 100644 src/Update/UpdateTimerEdition.elm diff --git a/src/Main.elm b/src/Main.elm index 48c7320..4fab1e9 100644 --- a/src/Main.elm +++ b/src/Main.elm @@ -30,7 +30,7 @@ input = Signal.mergeMany [ Signal.subscribe updates , Signal.map DeltaTime (fps 30) - , Signal.map (\_ -> ReadOnly) clickAway + , Signal.map (\_ -> ClickAway) clickAway , Signal.map KeyPressed Keyboard.lastPressed ] diff --git a/src/Model/Edition/Edition.elm b/src/Model/Edition/Edition.elm new file mode 100644 index 0000000..89a0b52 --- /dev/null +++ b/src/Model/Edition/Edition.elm @@ -0,0 +1,34 @@ +module Model.Edition.Edition + ( Edition + , Kind(..) + , newEdition + , keyCodeToChar + ) where + +import Keyboard (KeyCode) + +import Model.Id (..) +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 diff --git a/src/Model/Edition/NameEdition.elm b/src/Model/Edition/NameEdition.elm new file mode 100644 index 0000000..18224ea --- /dev/null +++ b/src/Model/Edition/NameEdition.elm @@ -0,0 +1,15 @@ +module Model.Edition.NameEdition + ( keyCodeToChar + , renderNameEdition + ) where + +import Char +import Keyboard (KeyCode) +import String +import List + +keyCodeToChar : KeyCode -> Maybe Char +keyCodeToChar = Just << Char.fromCode + +renderNameEdition : List Char -> String +renderNameEdition = String.fromList << List.reverse diff --git a/src/Model/Edition/TimeEdition.elm b/src/Model/Edition/TimeEdition.elm new file mode 100644 index 0000000..6999b25 --- /dev/null +++ b/src/Model/Edition/TimeEdition.elm @@ -0,0 +1,60 @@ +module Model.Edition.TimeEdition + ( keyCodeToChar + , toTime + , toMinutesAndSeconds + ) where + +import Time (Time) +import List +import Array +import String +import Keyboard (KeyCode) + +import Utils.List (..) +import Utils.Maybe (..) + +keyCodeToChar : KeyCode -> Maybe Char +keyCodeToChar code = + List.map (flip keyCodeToCharFromZero code) zeroKeyCodes + |> List.foldl orElse Nothing + +zeroKeyCodes = [48, 96] + +keyCodeToCharFromZero : KeyCode -> KeyCode -> Maybe Char +keyCodeToCharFromZero zero code = + let nine = zero + 9 + in if code >= zero && code <= nine + then ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] + |> Array.fromList + |> Array.get (code - zero) + 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/Model.elm b/src/Model/Model.elm index b929261..c45300b 100644 --- a/src/Model/Model.elm +++ b/src/Model/Model.elm @@ -10,7 +10,7 @@ import Time (Time) import List import Model.Timer (..) -import Model.TimerEdition (..) +import Model.Edition.Edition (..) import Model.Id (..) import Model.IdGenerator (..) @@ -18,17 +18,16 @@ type alias Model = { currentTime : Time , timers : Dict Id Timer , timerIdGenerator : IdGenerator - , timerEdition : Maybe TimerEdition + , edition : Maybe Edition } initialModel : Time -> Model initialModel initialTime = let (id, idGenerator) = getId initialIdGenerator - timerName = "Timer " ++ (toString id) in { currentTime = initialTime - , timers = Dict.insert id (initialTimer initialTime timerName) Dict.empty + , timers = Dict.insert id (initialTimer initialTime) Dict.empty , timerIdGenerator = idGenerator - , timerEdition = Nothing + , edition = Nothing } numberOfTimers : Model -> Int diff --git a/src/Model/Timer.elm b/src/Model/Timer.elm index f05c487..35850fc 100644 --- a/src/Model/Timer.elm +++ b/src/Model/Timer.elm @@ -11,17 +11,17 @@ import Model.TimerState (..) type alias Timer = { creationTime : Time - , name : String + , name : Maybe String , initialTime : Time , currentTime : Time , state : TimerState } -initialTimer : Time -> String -> Timer -initialTimer creationTime name = +initialTimer : Time -> Timer +initialTimer creationTime = let initialTime = 5 * 60 * 1000 in { creationTime = creationTime - , name = name + , name = Nothing , initialTime = initialTime , currentTime = initTime initialTime , state = Idle diff --git a/src/Model/TimerEdition.elm b/src/Model/TimerEdition.elm deleted file mode 100644 index 2ec98b7..0000000 --- a/src/Model/TimerEdition.elm +++ /dev/null @@ -1,77 +0,0 @@ -module Model.TimerEdition - ( TimerEdition - , Numbers - , newTimerEdition - , keyCodeToNumberChar - , toTime - , toMinutesAndSeconds - ) where - -import Time (Time) -import List -import Array -import String -import Keyboard (KeyCode) - -import Model.Id (..) - -import Utils.List (..) -import Utils.Maybe (..) - -type alias TimerEdition = - { id : Id - , numbers : Numbers - } - -type alias Numbers = List Char - -newTimerEdition id = - { id = id - , numbers = [] - } - -keyCodeToNumberChar : KeyCode -> Maybe Char -keyCodeToNumberChar code = - List.map (flip keyCodeToCharFromZero code) zeroKeyCodes - |> List.foldl orElse Nothing - -zeroKeyCodes = [48, 96] - -keyCodeToCharFromZero : KeyCode -> KeyCode -> Maybe Char -keyCodeToCharFromZero zero code = - let nine = zero + 9 - in if code >= zero && code <= nine - then ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] - |> Array.fromList - |> Array.get (code - zero) - else Nothing - -toTime : Numbers -> Time -toTime numbers = - numbers - |> toMinutesAndSeconds - |> \(a, b) -> (stringToInt a, stringToInt b) - |> \(minutes, seconds) -> (toFloat minutes) * 60 * 1000 + (toFloat seconds) * 1000 - -toMinutesAndSeconds : Numbers -> (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/Update/Update.elm b/src/Update/Update.elm index fabe0e8..5a4b12a 100644 --- a/src/Update/Update.elm +++ b/src/Update/Update.elm @@ -16,12 +16,14 @@ import List import Model.Model (..) import Model.Timer (..) -import Model.TimerEdition (..) +import Model.Edition.Edition (..) +import Model.Edition.NameEdition (..) +import Model.Edition.TimeEdition (..) import Model.Id (..) import Model.IdGenerator (..) import Update.UpdateTimer (..) -import Update.UpdateTimerEdition (..) +import Update.UpdateEdition (..) import Utils.Maybe (..) @@ -32,9 +34,9 @@ type Action = | DeltaTime Time | UpdateTimer Id TimerAction | RemoveTimer Id - | EditTimer Id - | ValidTimerEdition - | ReadOnly + | Edit Id Kind + | ValidEdition + | ClickAway | KeyPressed KeyCode updates : Signal.Channel Action @@ -54,9 +56,8 @@ update action model = initialModel model.currentTime AddNewTimer -> let (id, newTimerIdGenerator) = getId model.timerIdGenerator - timerName = "Timer " ++ (toString id) in { model - | timers <- Dict.insert id (initialTimer model.currentTime timerName) model.timers + | timers <- Dict.insert id (initialTimer model.currentTime) model.timers , timerIdGenerator <- newTimerIdGenerator } DeltaTime delta -> @@ -65,14 +66,12 @@ update action model = , timers <- Dict.map (\id timer -> updateTimer (SubstractTime delta) timer) model.timers } UpdateTimer id action -> - let maybeTimerEdition = filterMaybe (\timerEdition -> timerEdition.id == id) model.timerEdition - in case maybeTimerEdition of - Just timerEdition -> + let maybeEdition = filterMaybe (\edition -> edition.id == id) model.edition + in case maybeEdition of + Just edition -> { model - | timers <- - updateTimerTime timerEdition model.timers - |> Dict.update id (Maybe.map (updateTimer action)) - , timerEdition <- Nothing + | timers <- Dict.update id (Maybe.map (updateTimer action)) model.timers + , edition <- Nothing } Nothing -> { model | timers <- Dict.update id (Maybe.map (updateTimer action)) model.timers } @@ -82,36 +81,42 @@ update action model = { model | timers <- Dict.remove id model.timers } else model - EditTimer id -> + Edit id kind -> { model - | timerEdition <- Just (newTimerEdition id) + | edition <- Just (newEdition id kind) , timers <- Dict.update id (Maybe.map (updateTimer Pause)) model.timers } - ValidTimerEdition -> - case model.timerEdition of - Just timerEdition -> - { model - | timers <- updateTimerTime timerEdition model.timers - , timerEdition <- Nothing - } - Nothing -> - { model | timerEdition <- Nothing } - ReadOnly -> - { model | timerEdition <- Nothing } + ValidEdition -> + validEdition model + ClickAway -> + { model | edition <- Nothing } KeyPressed keyCode -> if isRemoveKeyCode keyCode then - { model | timerEdition <- Maybe.map (updateTimerEdition DeleteLast) model.timerEdition } + { model | edition <- Maybe.map (updateEdition DeleteLast) model.edition } else - { model | timerEdition <- Maybe.map (updateTimerEdition (AddNumber keyCode)) model.timerEdition } + { model | edition <- Maybe.map (updateEdition (AddChar keyCode)) model.edition } -updateTimerTime : TimerEdition -> Dict Id Timer -> Dict Id Timer -updateTimerTime timerEdition = - if List.isEmpty timerEdition.numbers - then - identity - else - Dict.update timerEdition.id (Maybe.map (updateTimer (SetTime (toTime timerEdition.numbers)))) +validEdition : Model -> Model +validEdition model = + case model.edition of + Just edition -> + if List.isEmpty edition.chars + then + model + else + let action = + case edition.kind of + Name -> + Rename (renderNameEdition edition.chars) + Time -> + SetTime (toTime edition.chars) + in { model + | timers <- Dict.update edition.id (Maybe.map (updateTimer action)) model.timers + , edition <- Nothing + } + Nothing -> + model isRemoveKeyCode : KeyCode -> Bool isRemoveKeyCode = (==) 8 diff --git a/src/Update/UpdateEdition.elm b/src/Update/UpdateEdition.elm new file mode 100644 index 0000000..911a4c1 --- /dev/null +++ b/src/Update/UpdateEdition.elm @@ -0,0 +1,30 @@ +module Update.UpdateEdition + ( updateEdition + , EditionAction(..) + ) where + +import Char (..) + +import Model.Edition.Edition (..) + +import Utils.List (..) + +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 -> + { edition | chars <- char :: edition.chars } + Nothing -> + edition diff --git a/src/Update/UpdateTimer.elm b/src/Update/UpdateTimer.elm index 2e0d9af..30603cd 100644 --- a/src/Update/UpdateTimer.elm +++ b/src/Update/UpdateTimer.elm @@ -10,7 +10,8 @@ import Model.TimerState (..) import Model.Id (..) type TimerAction = - Pause + Rename String + | Pause | ToggleRunning | Stop | SetTime Time @@ -19,6 +20,8 @@ type TimerAction = updateTimer : TimerAction -> Timer -> Timer updateTimer action timer = case action of + Rename name -> + { timer | name <- Just name } Pause -> { timer | state <- Idle } ToggleRunning -> diff --git a/src/Update/UpdateTimerEdition.elm b/src/Update/UpdateTimerEdition.elm deleted file mode 100644 index e9493eb..0000000 --- a/src/Update/UpdateTimerEdition.elm +++ /dev/null @@ -1,34 +0,0 @@ -module Update.UpdateTimerEdition - ( updateTimerEdition - , TimerEditionAction(..) - ) where - -import Char (..) - -import Model.TimerEdition (..) - -import Utils.List (..) - -type TimerEditionAction = - DeleteLast - | AddNumber KeyCode - -updateTimerEdition : TimerEditionAction -> TimerEdition -> TimerEdition -updateTimerEdition action timerEdition = - case action of - DeleteLast -> - case maybeTail timerEdition.numbers of - Just tailNumbers -> - { timerEdition | numbers <- tailNumbers } - Nothing -> - timerEdition - AddNumber keyCode -> - case keyCodeToNumberChar keyCode of - Just char -> - if isDigit char - then - { timerEdition | numbers <- char :: timerEdition.numbers } - else - timerEdition - Nothing -> - timerEdition diff --git a/src/View/Timer.elm b/src/View/Timer.elm index 604b045..100514a 100644 --- a/src/View/Timer.elm +++ b/src/View/Timer.elm @@ -5,15 +5,17 @@ module View.Timer import Html (..) import Html.Attributes (..) import Html.Events (..) -import String import Time (Time) import Signal import Maybe import List +import String import Model.Model (..) import Model.Timer (..) -import Model.TimerEdition (..) +import Model.Edition.Edition (..) +import Model.Edition.NameEdition (..) +import Model.Edition.TimeEdition (..) import Model.TimerState (..) import Model.Id (..) @@ -28,54 +30,75 @@ timerView : Model -> (Id, Timer) -> Html timerView model (id, timer) = div [ class "timer" ] - [ nameBlock (id, timer) - , timeBlock model (id, timer) + [ renderMaybeEdition model id Name (nameBlockReadOnly id timer) (nameBlockEdition id timer) + , renderMaybeEdition model id Time (timeBlockReadOnly id timer) (timeBlockEdition timer) , playPauseBlock (id, timer) , stopBlock (id, timer) , removeBlock (id, timer) ] -nameBlock : (Id, Timer) -> Html -nameBlock (id, timer) = +nameBlockReadOnly : Id -> Timer -> Html +nameBlockReadOnly id timer = button - [ class "name block" ] - [ text timer.name ] + [ class "name block" + , onClick (Signal.send updates (Edit id Name)) + ] + [ text (timerName id timer) ] -timeBlock : Model -> (Id, Timer) -> Html -timeBlock model (id, timer) = - let maybeEdition = filterMaybe (\te -> te.id == id) model.timerEdition - in case maybeEdition of - Just edition -> - let isEmptyEdition = List.isEmpty edition.numbers - in button - [ [ (True, "time block edition") - , (isEmptyEdition, "empty") - ] - |> activatedClasses - , onClick (Signal.send updates ValidTimerEdition) - ] - [ if isEmptyEdition - then - timeWithProgressBar timer - else - text (editionView edition.numbers) - ] +nameBlockEdition : Id -> Timer -> Edition -> Html +nameBlockEdition id timer edition = + button + [ [ (True, "name block edition") + , (List.isEmpty edition.chars, "empty") + ] + |> activatedClasses + , onClick (Signal.send updates ValidEdition) + ] + [ if List.isEmpty edition.chars + then + text (timerName id timer) + else + edition.chars + |> renderNameEdition + |> text + ] - Nothing -> - button - [ [ (True, "time block") - , (timer.state == Ringing, "isRinging") - , (timer.state == Running, "isRunning") - ] - |> activatedClasses - , onClick - <| if timer.state == Ringing - then Signal.send updates (UpdateTimer id Stop) - else Signal.send updates (EditTimer id) - ] - [ timeWithProgressBar timer ] - -editionView : Numbers -> String +timerName : Id -> Timer -> String +timerName id = Maybe.withDefault ("Timer " ++ toString id) << .name + +timeBlockReadOnly : Id -> Timer -> Html +timeBlockReadOnly id timer = + button + [ [ (True, "time block") + , (timer.state == Ringing, "isRinging") + , (timer.state == Running, "isRunning") + ] + |> activatedClasses + , onClick + <| if timer.state == Ringing + then Signal.send updates (UpdateTimer id Stop) + else Signal.send updates (Edit id Time) + ] + [ timeWithProgressBar timer ] + +timeBlockEdition : Timer -> Edition -> Html +timeBlockEdition timer edition = + let isEmptyEdition = List.isEmpty edition.chars + in button + [ [ (True, "time block edition") + , (isEmptyEdition, "empty") + ] + |> activatedClasses + , onClick (Signal.send updates ValidEdition) + ] + [ if isEmptyEdition + then + timeWithProgressBar timer + else + text (editionView edition.chars) + ] + +editionView : List Char -> String editionView numbers = let (minutes, seconds) = toMinutesAndSeconds numbers in minutes ++ " : " ++ seconds @@ -134,3 +157,16 @@ removeBlock (id, timer) = , onClick (Signal.send updates (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 -- cgit v1.2.3