DEV Community

Lance Wicks
Lance Wicks

Posted on • Originally published at lancewicks.com on

Building a “1-2-4-All” Timer in Elm.

I have been wanting to learn Elm for a while and as I mentioned in an earlier post (https://lancewicks.com/2020/06/21/exploring-the-elm-programming-language/) I have managed on the third attempt to do so.

In the previous post I built a simple toy that displayed SVG. This time I decided to build something more practical; a timer app for the 1-2-4-All way of meeting facilitation (http://www.liberatingstructures.com/1-1-2-4-all/)

This app required “time”, specifically a countdown timer. So, it was a good opportunity to explore subscriptions in Elm. In this app I decided also to experiment with the Elm-UI package; which brings all your layout into Elm and prevents having to do CSS magic!

Elm-UI worked pretty well; I really like the ideas in elm-ui and not having to worry about CSS and to have a design system to hand. I won’t lie, it’s still ugly… but that is me not the language or package.

Being a more complicated application turned out to be helpful for my learning. I initially had a time subscription that was naive and just counted upwards. So then I simply hard coded the second thresholds to display the right text at the right time.

Later I re-wrote it. The nice thing about a typed language with an awesome compiler is that this was all pretty easy and safe. When I changed things the compiler would tell me when I needed to update something else.

The main logic looks like this:


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        Start ->
            ( { model | status = True }, Cmd.none ) |> Update.andThen update PhaseOne

        Stop ->
            ( { model | status = False }, Cmd.none )

        Restart ->
            ( { model | status = True }, Cmd.none )

        PhaseOne ->
            ( { model | phase = "One", next = "Two", timer = 60 }, Cmd.none )

        PhaseTwo ->
            ( { model | phase = "Two", next = "Four", timer = 120 }, Cmd.none )

        PhaseFour ->
            ( { model | phase = "Four", next = "All", timer = 240 }, Cmd.none )

        PhaseAll ->
            ( { model | phase = "All", next = "All", timer = 300 }, Cmd.none )

        Tick _ ->
            if model.status then
                if model.timer > 0 then
                    ( { model | timer = model.timer - 1 }, Cmd.none )

                else
                    case model.next of
                        "Two" ->
                            ( { model | timer = 1 }, Cmd.none ) |> Update.andThen update PhaseTwo

                        "Four" ->
                            ( { model | timer = 1 }, Cmd.none ) |> Update.andThen update PhaseFour

                        "All" ->
                            ( { model | timer = 1 }, Cmd.none ) |> Update.andThen update PhaseAll

                        _ ->
                            ( model, Cmd.none )

            else
                ( { model | timer = model.timer - 0 }
                , Cmd.none
                )
Enter fullscreen mode Exit fullscreen mode

It’s I am sure, not very idiomatic; but it works and is I hope pretty understandable.

The full code is here: https://github.com/lancew/124all

You can play with it here: https://lancew.github.io/124all/

I was going to try and add a SVG clock or something like that to this app; but my interest is waning. Time to find a new puzzle to solve… I think rewriting https://www.judowrl.com in Elm. It is a small application I wrote in Javascript some time ago.

This will mean obtaining data from an API and so forth; so it will I hope round out the areas I have not looked at yet.

Stay tuned, if you follow me on Scuttlebutt I post more regular “dev diary” type posts on there (Look in my https://lancewicks.com/contact page for more on how to reach me on SSB).

Top comments (0)