Shpadoinkle-html-0.0.0.1: Shpadoinkle/Html/LocalStorage.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
-- | Local storage IO operations
-- Get and set localstorage values from some 'LocalStorageKey'
module Shpadoinkle.Html.LocalStorage where
import Control.Monad
import Data.Maybe
import Data.String
import Data.Text
import GHC.Generics
import GHCJS.DOM
import GHCJS.DOM.Storage
import GHCJS.DOM.Window
import Text.Read
import UnliftIO
import UnliftIO.Concurrent (forkIO)
import Shpadoinkle (MonadJSM, Territory (..), liftJSM)
-- | The key for a specific state kept in local storage
newtype LocalStorageKey a = LocalStorageKey { unLocalStorageKey :: Text }
deriving (Semigroup, Monoid, IsString, Eq, Ord, Show, Read, Generic)
setStorage :: MonadJSM m => Show a => LocalStorageKey a -> a -> m ()
setStorage (LocalStorageKey k) m = do
s <- getLocalStorage =<< currentWindowUnchecked
setItem s k $ show m
getStorage :: MonadJSM m => Read a => LocalStorageKey a -> m (Maybe a)
getStorage (LocalStorageKey k) = do
s <- getLocalStorage =<< currentWindowUnchecked
(>>= readMaybe) <$> getItem s k
-- Whe we should update we save
saveOnChange :: MonadJSM m => Territory t => Show a => Eq a
=> LocalStorageKey a -> t a -> m ()
saveOnChange k = liftJSM . shouldUpdate (const $ setStorage k) ()
manageLocalStorage
:: MonadUnliftIO m
#ifndef ghcjs_HOST_OS
=> MonadJSM m
#endif
=> Show a
=> Read a
=> Eq a
=> LocalStorageKey a -> a -> m (TVar a)
manageLocalStorage k initial = do
model <- liftIO . newTVarIO . fromMaybe initial =<< getStorage k
void . forkIO $ saveOnChange k model
return model