reflex-dom 0.6.1.1 → 0.6.2.0
raw patch · 7 files changed
+119/−12 lines, 7 filesdep ~aeson
Dependency ranges changed: aeson
Files
- ChangeLog.md +9/−0
- cbits/MainWidget.c +34/−0
- java/org/reflexfrp/reflexdom/MainWidget.java +15/−4
- reflex-dom.cabal +5/−4
- src-android/Reflex/Dom/Android/MainWidget.hsc +20/−2
- src/Reflex/Dom/Internal.hs +16/−2
- src/Reflex/Dom/Location/Platform.hs +20/−0
ChangeLog.md view
@@ -1,5 +1,14 @@ # Revision history for reflex-dom +## 0.6.2.0++* [#452](https://github.com/reflex-frp/reflex-dom/pull/452) Allow file access on newer android, following usage recommended by the [official docs](https://developer.android.com/reference/androidx/webkit/WebViewAssetLoader)+* [#453](https://github.com/reflex-frp/reflex-dom/pull/453) History management for android++## 0.6.1.1-r1++* Loosen reflex-dom-core version bounds to allow reflex-dom-core 0.7.*+ ## 0.6.1.1 * Compile with -fPIC
cbits/MainWidget.c view
@@ -53,6 +53,40 @@ (*env)->PopLocalFrame(env, 0); } +void Reflex_Dom_Android_MainWidget_back(jobject jsExecutor) {+ JNIEnv *env;+ jint attachResult = (*HaskellActivity_jvm)->AttachCurrentThread(HaskellActivity_jvm, &env, NULL);+ assert (attachResult == JNI_OK);++ (*env)->PushLocalFrame(env, 5);++ //TODO: Don't search for this method every time+ jclass cls = (*env)->GetObjectClass(env, jsExecutor);+ assert(cls);+ jmethodID evaluateJavascript = (*env)->GetMethodID(env, cls, "goBack", "()V");+ assert(evaluateJavascript);+ (*env)->CallVoidMethod(env, jsExecutor, evaluateJavascript);++ (*env)->PopLocalFrame(env, 0);+}++void Reflex_Dom_Android_MainWidget_clearHistory(jobject jsExecutor) {+ JNIEnv *env;+ jint attachResult = (*HaskellActivity_jvm)->AttachCurrentThread(HaskellActivity_jvm, &env, NULL);+ assert (attachResult == JNI_OK);++ (*env)->PushLocalFrame(env, 5);++ //TODO: Don't search for this method every time+ jclass cls = (*env)->GetObjectClass(env, jsExecutor);+ assert(cls);+ jmethodID evaluateJavascript = (*env)->GetMethodID(env, cls, "clearHistory", "()V");+ assert(evaluateJavascript);+ (*env)->CallVoidMethod(env, jsExecutor, evaluateJavascript);++ (*env)->PopLocalFrame(env, 0);+}+ JNIEXPORT void JNICALL Java_org_reflexfrp_reflexdom_MainWidget_00024JSaddleCallbacks_startProcessing (JNIEnv *env, jobject thisObj, jlong callbacksLong) { const JSaddleCallbacks *callbacks = (const JSaddleCallbacks *)callbacksLong; (*(callbacks->jsaddleStart))();
java/org/reflexfrp/reflexdom/MainWidget.java view
@@ -41,8 +41,6 @@ a.setContentView(wv); final WebSettings ws = wv.getSettings(); ws.setJavaScriptEnabled(true);- ws.setAllowFileAccessFromFileURLs(true);- ws.setAllowUniversalAccessFromFileURLs(true); ws.setDomStorageEnabled(true); wv.setWebContentsDebuggingEnabled(true); // allow video to play without user interaction@@ -64,7 +62,8 @@ @Override public WebResourceResponse shouldInterceptRequest (WebView view, WebResourceRequest request) { Uri uri = request.getUrl();- if(!uri.getScheme().equals("file"))+ Log.i("reflex", uri.toString());+ if(!uri.getScheme().equals("file") && !uri.getEncodedAuthority().equals("appassets.androidplatform.net")) return null; String path = uri.getPath();@@ -87,7 +86,7 @@ @Override public boolean shouldOverrideUrlLoading(WebView view, String url) {- if( url != null && !url.startsWith("http://") && !url.startsWith("https://") && !url.startsWith("file://")) {+ if( url != null && !url.startsWith("http://appassets.androidplatform.net") && !url.startsWith("https://appassets.androidplatform.net") && !url.startsWith("file://")) { try { view.getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); }@@ -144,6 +143,18 @@ wv.evaluateJavascript(jsStr, null); } });+ }+ public final void goBack() {+ hnd.post(new Runnable() {+ @Override+ public void run() {+ if(wv.canGoBack()) {+ wv.goBack();+ } else {+ a.defaultOnBackPressed();+ }+ }+ }); } }; }
reflex-dom.cabal view
@@ -1,6 +1,6 @@ cabal-version: 1.24 Name: reflex-dom-Version: 0.6.1.1+Version: 0.6.2.0 Synopsis: Functional Reactive Web Apps with Reflex Description: Web applications without callbacks or side-effects.@@ -61,7 +61,7 @@ hs-source-dirs: src-android other-modules: Reflex.Dom.Android.MainWidget build-depends:- aeson >= 1.4 && < 1.6,+ aeson >= 1.4 && < 2.2, android-activity == 0.1.*, data-default == 0.7.*, jsaddle >= 0.9.6 && < 0.10@@ -73,8 +73,8 @@ build-depends: base >= 4.7 && < 4.15, bytestring == 0.10.*,- reflex >= 0.8 && < 0.9,- reflex-dom-core >= 0.6.1.0 && <0.7,+ reflex >= 0.8 && < 1,+ reflex-dom-core >= 0.6.1.0 && <0.9, text == 1.2.* if !impl(ghcjs) if flag(use-warp)@@ -104,6 +104,7 @@ exposed-modules: Reflex.Dom Reflex.Dom.Internal+ Reflex.Dom.Location.Platform reexported-modules: Foreign.JavaScript.Orphans , Foreign.JavaScript.TH
src-android/Reflex/Dom/Android/MainWidget.hsc view
@@ -2,11 +2,15 @@ {-# LANGUAGE OverloadedStrings #-} module Reflex.Dom.Android.MainWidget ( startMainWidget+ , goBack+ , JSExecutor(..)+ , withGlobalJSExecutor ) where import Android.HaskellActivity import Control.Concurrent import Control.Monad+import Control.Monad.IO.Class import Data.Aeson import Data.ByteString (ByteString) import qualified Data.ByteString as BS@@ -23,10 +27,10 @@ import Language.Javascript.JSaddle (JSM) import Language.Javascript.JSaddle.Run (runJavaScript) import Language.Javascript.JSaddle.Run.Files (initState, runBatch, ghcjsHelpers)+import System.IO.Unsafe #include "MainWidget.h" - startMainWidget :: HaskellActivity -> ByteString -> JSM () -> IO () startMainWidget a url jsm = do --TODO: Find a way to eventually release this@@ -57,13 +61,27 @@ \jsaddle.postReady();\n" } BS.useAsCString url $ \curl -> do- writeIORef executorRef =<< startMainWidget_ a curl callbacks+ executor <- startMainWidget_ a curl callbacks+ writeIORef executorRef executor+ writeIORef globalJSExecutor $ Just executor newtype JSExecutor = JSExecutor { unJSExecutor :: Ptr JSExecutor } +-- Ugh. But not doing this is also unfortunate for being able to clear the history so that the "back" list is good.+globalJSExecutor :: IORef (Maybe JSExecutor)+globalJSExecutor = unsafePerformIO $ newIORef Nothing++withGlobalJSExecutor :: MonadIO m => (JSExecutor -> IO ()) -> m ()+withGlobalJSExecutor f = liftIO $ do+ executor <- readIORef globalJSExecutor+ case executor of+ Just e -> f e+ _ -> pure ()+ foreign import ccall safe "Reflex_Dom_Android_MainWidget_start" startMainWidget_ :: HaskellActivity -> CString -> Ptr JSaddleCallbacksPtrs -> IO JSExecutor foreign import ccall safe "Reflex_Dom_Android_MainWidget_runJS" runJS :: JSExecutor -> CString -> CSize -> IO ()+foreign import ccall safe "Reflex_Dom_Android_MainWidget_back" goBack :: JSExecutor -> IO () data JSaddleCallbacks = JSaddleCallbacks { _jsaddleCallbacks_jsaddleStart :: IO ()
src/Reflex/Dom/Internal.hs view
@@ -38,6 +38,7 @@ port <- maybe 3003 read <$> lookupEnv "JSADDLE_WARP_PORT" putStrLn $ "Running jsaddle-warp server on port " <> show port JW.run port jsm+ #elif defined(MIN_VERSION_jsaddle_wkwebview) #if defined(ios_HOST_OS) import Data.Default@@ -56,18 +57,24 @@ return "" Just p -> return $ "file://" <> p <> "/index.html" run' def $ jsaddleMainHTMLWithBaseURL indexHtml baseUrl jsm+ #else import Language.Javascript.JSaddle.WKWebView (run) #endif #elif defined(ANDROID) import Android.HaskellActivity import Control.Monad+import Control.Monad.IO.Class (liftIO, MonadIO) import Control.Concurrent+import Language.Javascript.JSaddle (JSM) import Data.Default+import Data.IORef+import Data.Maybe import Data.String import Reflex.Dom.Android.MainWidget import System.IO-import Language.Javascript.JSaddle (JSM)+import System.IO.Unsafe+import Language.Javascript.JSaddle (JSM, eval) run :: JSM () -> IO () run jsm = do@@ -76,17 +83,24 @@ continueWithCallbacks $ def { _activityCallbacks_onCreate = \_ -> do a <- getHaskellActivity- let startPage = fromString "file:///android_asset/index.html"+ let startPage = fromString "https://appassets.androidplatform.net/index.html" startMainWidget a startPage jsm+ , _activityCallbacks_onBackPressed = triggerBackButton } forever $ threadDelay 1000000000++triggerBackButton :: MonadIO m => m ()+triggerBackButton = withGlobalJSExecutor goBack+ #elif defined(wasm32_HOST_ARCH) import qualified Language.Javascript.JSaddle.Wasm as Wasm (run) import Language.Javascript.JSaddle (JSM) run :: JSM () -> IO () run = Wasm.run 0+ #else import Language.Javascript.JSaddle.WebKitGTK (run)+ #endif mainWidget :: (forall x. Widget x ()) -> IO ()
+ src/Reflex/Dom/Location/Platform.hs view
@@ -0,0 +1,20 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleContexts #-}+#if defined(ANDROID)+module Reflex.Dom.Location.Platform where++import Reflex+import Control.Monad.IO.Class+import Reflex.Dom.Android.MainWidget++popHistoryState+ :: (PerformEvent t m, MonadIO (Performable m))+ => Event t ()+ -> m ()+popHistoryState evt = performEvent_ $ withGlobalJSExecutor goBack <$ evt+#else+module Reflex.Dom.Location.Platform (Reflex.Dom.Location.popHistoryState) where+import qualified Reflex.Dom.Location++#endif+