Skip to content

Instantly share code, notes, and snippets.

@danyx23
Last active January 16, 2016 13:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danyx23/c80ad1791544101c08b0 to your computer and use it in GitHub Desktop.
Save danyx23/c80ad1791544101c08b0 to your computer and use it in GitHub Desktop.
Dealing with ports as part of the Elm Architecture
type PortAction
= StartAudioPlayback AudioPlaybackMessage
| StopAudioPlayback
| DecodeAudioData AudioRawDataMessage
| NoopPortAction
update : Action -> Model -> (Model, Effects Action, PortAction)
app : App Model MainActions.PortAction
app =
start
{ init = (Types.init seed0, Effects.none, MainActions.NoopPortAction)
, update = update
, view = view
, inputs = [Signal.map audioClipLoadedAction audioClipLoaded]
}
-- outgoing port
port startAudioPlayback : Signal AudioPlaybackMessage
port startAudioPlayback =
Signal.filterMap filterStartPlayback (AudioPlaybackMessage (AssetId -1) 0.0) app.portActions
filterStartPlayback : MainActions.PortAction -> Maybe AudioPlaybackMessage
filterStartPlayback portAction =
case portAction of
MainActions.StartAudioPlayback info ->
Just info
_ ->
Nothing
-- incoming port
port audioClipLoaded : Signal AudioDurationMessage
module CustomAppStart
( start
, App
, Config
)
where
import Html exposing (Html)
import Effects exposing (Effects, Never)
import Task
type alias Config model action portAction =
{ init : (model, Effects action, portAction)
, update : action -> model -> (model, Effects action, Maybe portAction)
, view : Signal.Address action -> model -> Html
, inputs : List (Signal.Signal action)
}
type alias App model portAction =
{ html : Signal Html
, model : Signal model
, tasks : Signal (Task.Task Never ())
, portActions : Signal portAction
}
{-| Copy from StartApp but with folp' instead of foldp
Start an application. It requires a bit of wiring once you have created an
`App`. It should pretty much always look like this:
app =
start { init = init, view = view, update = update, inputs = [] }
main =
app.html
port tasks : Signal (Task.Task Never ())
port tasks =
app.tasks
So once we start the `App` we feed the HTML into `main` and feed the resulting
tasks into a `port` that will run them all.
-}
start : Config model action portAction -> App model portAction
start config =
let
fst3 (a, _, _) = a
snd3 (_, b, _) = b
thrd3 (_, _, c) = c
singleton action = [ action ]
-- messages : Signal.Mailbox (List action)
messages = Signal.mailbox []
-- address : Signal.Address action
address = Signal.forwardTo messages.address singleton
-- updateStep : action -> (model, Effects action, Maybe portAction) -> (model, Effects action, Maybe portAction)
updateStep action (oldModel, accumulatedEffects, _) =
let
(newModel, additionalEffects, maybePortAction) = config.update action oldModel
in
(newModel, Effects.batch [accumulatedEffects, additionalEffects], maybePortAction)
-- update : List action -> (model, Effects action, Maybe portAction) -> (model, Effects action, Maybe portAction)
update actions (model, _, _) =
List.foldl updateStep (model, Effects.none, Nothing) actions
-- inputs : Signal (List action)
inputs = Signal.mergeMany (messages.signal :: List.map (Signal.map singleton) config.inputs)
-- effectsAndModel : Signal (model, Effects action, Maybe portAction)
modelEffectsPortActions = Signal.foldp update (config.init |> maybefy) inputs
model = Signal.map fst3 modelEffectsPortActions
tasks = Signal.map (Effects.toTask messages.address << snd3) modelEffectsPortActions
portActions = Signal.filterMap identity (config.init |> thrd3) <| Signal.map thrd3 modelEffectsPortActions
in
{ html = Signal.map (config.view address) model
, model = model
, tasks = tasks
, portActions = portActions
}
maybefy : (model, Effects action, portAction) -> (model, Effects action, Maybe portAction)
maybefy (model, action, portAction) =
(model, action, Just portAction)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment