1effect module Browser.AnimationManager where { subscription = MySub } exposing 2 ( onAnimationFrame 3 , onAnimationFrameDelta 4 ) 5 6 7import Elm.Kernel.Browser 8import Process 9import Task exposing (Task) 10import Time 11 12 13 14-- PUBLIC STUFF 15 16 17onAnimationFrame : (Time.Posix -> msg) -> Sub msg 18onAnimationFrame tagger = 19 subscription (Time tagger) 20 21 22onAnimationFrameDelta : (Float -> msg) -> Sub msg 23onAnimationFrameDelta tagger = 24 subscription (Delta tagger) 25 26 27 28-- SUBSCRIPTIONS 29 30 31type MySub msg 32 = Time (Time.Posix -> msg) 33 | Delta (Float -> msg) 34 35 36subMap : (a -> b) -> MySub a -> MySub b 37subMap func sub = 38 case sub of 39 Time tagger -> 40 Time (func << tagger) 41 42 Delta tagger -> 43 Delta (func << tagger) 44 45 46 47-- EFFECT MANAGER 48 49 50type alias State msg = 51 { subs : List (MySub msg) 52 , request : Maybe Process.Id 53 , oldTime : Int 54 } 55 56 57-- NOTE: used in onEffects 58-- 59init : Task Never (State msg) 60init = 61 Task.succeed (State [] Nothing 0) 62 63 64onEffects : Platform.Router msg Int -> List (MySub msg) -> State msg -> Task Never (State msg) 65onEffects router subs {request, oldTime} = 66 case (request, subs) of 67 (Nothing, []) -> 68 init 69 70 (Just pid, []) -> 71 Process.kill pid 72 |> Task.andThen (\_ -> init) 73 74 (Nothing, _) -> 75 Process.spawn (Task.andThen (Platform.sendToSelf router) rAF) 76 |> Task.andThen (\pid -> now 77 |> Task.andThen (\time -> Task.succeed (State subs (Just pid) time))) 78 79 (Just _, _) -> 80 Task.succeed (State subs request oldTime) 81 82 83onSelfMsg : Platform.Router msg Int -> Int -> State msg -> Task Never (State msg) 84onSelfMsg router newTime {subs, oldTime} = 85 let 86 send sub = 87 case sub of 88 Time tagger -> 89 Platform.sendToApp router (tagger (Time.millisToPosix newTime)) 90 91 Delta tagger -> 92 Platform.sendToApp router (tagger (toFloat (newTime - oldTime))) 93 in 94 Process.spawn (Task.andThen (Platform.sendToSelf router) rAF) 95 |> Task.andThen (\pid -> Task.sequence (List.map send subs) 96 |> Task.andThen (\_ -> Task.succeed (State subs (Just pid) newTime))) 97 98 99rAF : Task x Int 100rAF = 101 Elm.Kernel.Browser.rAF () 102 103 104now : Task x Int 105now = 106 Elm.Kernel.Browser.now ()