reflex-dom-contrib-0.4.1: src/Reflex/Dom/Contrib/Geoposition.hs
module Reflex.Dom.Contrib.Geoposition where
import Control.Concurrent (forkIO)
import Control.Exception (catch, throwIO)
import Control.Monad.IO.Class (liftIO)
import Reflex (Event)
import Reflex.Dom (MonadWidget)
import Reflex.Dom.Class (performEventAsync)
import GHCJS.DOM (currentWindow)
import GHCJS.DOM.PositionError (PositionException(..), PositionErrorCode(..))
import qualified GHCJS.DOM.Coordinates as Coord
import GHCJS.DOM.Geolocation (getCurrentPosition)
import GHCJS.DOM.Geoposition (getCoords)
import GHCJS.DOM.Navigator (getGeolocation)
import GHCJS.DOM.Window (getNavigator)
defaultPosException :: PositionException
defaultPosException = PositionException PositionUnavailable "Failed to get geolocation"
data GeopositionInfo = GeopositionInfo
{ geoLatitude :: Double
, geoLongitude :: Double
, geoAltitudeMeters :: Maybe Double
, geoAccuracyMeters :: Double
, geoAltitudeAccuracyMeters :: Maybe Double
, geoHeadingDegrees :: Maybe Double
, geoSpeedMetersPerSec :: Maybe Double
} deriving (Show, Eq)
getGeopositionInfo :: IO (Either PositionException GeopositionInfo)
getGeopositionInfo = (Right <$> getInfo) `catch` (pure . Left)
where
getInfo = do
window <- currentWindow >>= orBombOut
nav <- getNavigator window >>= orBombOut
geoloc <- getGeolocation nav >>= orBombOut
geopos <- getCurrentPosition geoloc Nothing
coord <- getCoords geopos >>= orBombOut
GeopositionInfo
<$> Coord.getLatitude coord
<*> Coord.getLongitude coord
<*> Coord.getAltitude coord
<*> Coord.getAccuracy coord
<*> Coord.getAltitudeAccuracy coord
<*> Coord.getHeading coord
<*> Coord.getSpeed coord
orBombOut = maybe (throwIO defaultPosException) pure
attachGeoposition :: MonadWidget t m => Event t a -> m (Event t (Either PositionException GeopositionInfo, a))
attachGeoposition event = performEventAsync (fetchInfoAsync <$> event)
where
fetchInfoAsync a callback = liftIO $ do
_ <- forkIO $ do
info <- getGeopositionInfo
callback (info, a)
pure ()