Skip to content

Instantly share code, notes, and snippets.

@mfonism
Created October 27, 2022 22:16
Show Gist options
  • Save mfonism/f51be048a1d567543075a1e9363dc6dc to your computer and use it in GitHub Desktop.
Save mfonism/f51be048a1d567543075a1e9363dc6dc to your computer and use it in GitHub Desktop.
Create a Clock with Elm after working through the tutorial at https://guide.elm-lang.org/effects/time.html
module Main exposing (..)
import Browser
import Html exposing (..)
import Html.Events exposing (onClick)
import Task
import Time
main =
Browser.element
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
type alias ZoneAwareTime =
{ posix : Time.Posix
, zone : Time.Zone
}
type alias Model =
{ time : Maybe ZoneAwareTime
, pausedAt : Maybe ZoneAwareTime
}
init : () -> ( Model, Cmd Msg )
init _ =
( { time = Nothing
, pausedAt = Nothing
}
, Task.perform InitZoneAwareTime <|
Task.map2 ZoneAwareTime Time.now Time.here
)
type Msg
= InitZoneAwareTime ZoneAwareTime
| Tick Time.Posix
| Pause
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
InitZoneAwareTime { posix, zone } ->
( { model | time = Just <| ZoneAwareTime posix zone }
, Cmd.none
)
Tick newPosix ->
( { model
| time = Maybe.map (\zoneAwareTime -> { zoneAwareTime | posix = newPosix }) model.time
}
, Cmd.none
)
Pause ->
case model.pausedAt of
Nothing ->
( { model | pausedAt = model.time }, Cmd.none )
Just _ ->
( { model | pausedAt = Nothing }, Cmd.none )
subscriptions : Model -> Sub Msg
subscriptions _ =
-- this causes a little delay in the UX after unpausing, as we have to wait
-- for the next tick before updating the model and effectively, the view
--
-- case model.pausedAt of
-- Nothing ->
-- Time.every 1000 Tick
-- Just _ ->
-- Sub.none
--
-- to make the clock appear to tick immediately after being unpaused
-- we keep subscribing to the tick even when paused
-- so that we have the correct tick to update the view with on unpause
Time.every 1000 Tick
view : Model -> Html Msg
view model =
case model.time of
Nothing ->
text "loading..."
Just zoneAwareTime ->
case model.pausedAt of
Nothing ->
div []
[ viewTime zoneAwareTime
, button [ onClick Pause ] [ text "Pause" ]
]
Just pausedZoneAwareTime ->
div []
[ viewTime pausedZoneAwareTime
, button [ onClick Pause ] [ text "Unpause" ]
]
viewTime : ZoneAwareTime -> Html msg
viewTime { posix, zone } =
let
formatTimePart : Int -> String
formatTimePart =
String.fromInt >> String.padLeft 2 '0'
hour =
Time.toHour zone posix |> formatTimePart
minute =
Time.toMinute zone posix |> formatTimePart
second =
Time.toSecond zone posix |> formatTimePart
in
h1 [] [ text (hour ++ ":" ++ minute ++ ":" ++ second) ]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment