module Reflex.Dom.Time where
import Reflex
import Reflex.Dom.Class
import Control.Concurrent
import Control.Monad
import Control.Monad.IO.Class
import Data.Fixed
import Data.Time.Clock
import Data.Typeable
data TickInfo
= TickInfo { _tickInfo_lastUTC :: UTCTime
, _tickInfo_n :: Integer
, _tickInfo_alreadyElapsed :: NominalDiffTime
}
deriving (Eq, Ord, Typeable)
tickLossy :: MonadWidget t m => NominalDiffTime -> UTCTime -> m (Event t TickInfo)
tickLossy dt t0 = tickLossyFrom dt t0 =<< getPostBuild
tickLossyFrom
:: MonadWidget t m
=> NominalDiffTime
-> UTCTime
-> Event t a
-> m (Event t TickInfo)
tickLossyFrom dt t0 e = performEventAsync $ fmap callAtNextInterval e
where callAtNextInterval _ cb = void $ liftIO $ forkIO $ forever $ do
tick <- getCurrentTick dt t0
threadDelay $ ceiling $ (dt _tickInfo_alreadyElapsed tick) * 1000000
cb tick
clockLossy :: MonadWidget t m => NominalDiffTime -> UTCTime -> m (Dynamic t TickInfo)
clockLossy dt t0 = do
initial <- liftIO $ getCurrentTick dt t0
e <- tickLossy dt t0
holdDyn initial e
getCurrentTick :: NominalDiffTime -> UTCTime -> IO TickInfo
getCurrentTick dt t0 = do
t <- getCurrentTime
let offset = t `diffUTCTime` t0
(n, alreadyElapsed) = offset `divMod'` dt
return $ TickInfo t n alreadyElapsed
delay :: MonadWidget t m => NominalDiffTime -> Event t a -> m (Event t a)
delay dt e = performEventAsync $ ffor e $ \a cb -> liftIO $ void $ forkIO $ do
threadDelay $ ceiling $ dt * 1000000
cb a
debounce :: MonadWidget t m => NominalDiffTime -> Event t a -> m (Event t a)
debounce dt e = do
n :: Dynamic t Integer <- count e
let tagged = attachDynWith (,) n e
delayed <- delay dt tagged
return $ attachWithMaybe (\n' (t, v) -> if n' == t then Just v else Nothing) (current n) delayed