Skip to content

Commit

Permalink
refactor: make webview dataflow clear
Browse files Browse the repository at this point in the history
  • Loading branch information
linonetwo committed Mar 14, 2024
1 parent 4e23400 commit 4cd42da
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 23 deletions.
20 changes: 10 additions & 10 deletions src/pages/WikiWebView/WikiViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { useConfigStore } from '../../store/config';
import { IWikiWorkspace } from '../../store/workspace';
import { CustomWebView } from './CustomWebview';
import { getWindowMeta } from './getWindowMeta';
import { useStreamChunksToWebView } from './useStreamChunksToWebView';
import { onErrorHandler } from './useStreamChunksToWebView/onErrorHandler';
import { useTiddlyWiki } from './useTiddlyWiki';

Expand Down Expand Up @@ -84,17 +83,17 @@ export const WikiViewer = ({ wikiWorkspace, webviewSideReceiver, quickLoad }: Wi
servicesOfWorkspace.wikiHookService.resetWebviewReceiverReady();
}, [servicesOfWorkspace.wikiHookService]);

/**
* Webview can't load html larger than 20M, we stream the html to webview, and set innerHTML in webview using preloadScript.
* This need to use with `webviewSideReceiver`.
* @url https://github.com/react-native-webview/react-native-webview/issues/3126
*/
const { injectHtmlAndTiddlersStore, streamChunksToWebViewPercentage } = useStreamChunksToWebView(webViewReference, servicesOfWorkspace);
const loading = streamChunksToWebViewPercentage > 0 && streamChunksToWebViewPercentage < 1;
useEffect(() => {
void backgroundSyncService.updateServerOnlineStatus();
}, [webViewKeyToReloadAfterRecycleByOS]);
const { loadHtmlError } = useTiddlyWiki(wikiWorkspace, injectHtmlAndTiddlersStore, loaded && webViewReference.current !== null, webViewKeyToReloadAfterRecycleByOS, quickLoad);
}, [servicesOfWorkspace.wikiHookService, webViewKeyToReloadAfterRecycleByOS]);
const { loadHtmlError, loading, streamChunksToWebViewPercentage } = useTiddlyWiki(
wikiWorkspace,
loaded,
webViewReference,
webViewKeyToReloadAfterRecycleByOS,
quickLoad,
servicesOfWorkspace,
);
const preloadScript = useMemo(() => {
const windowMetaScript = getWindowMeta(wikiWorkspace);
return `
Expand All @@ -112,6 +111,7 @@ export const WikiViewer = ({ wikiWorkspace, webviewSideReceiver, quickLoad }: Wi
${webviewSideReceiver}
window.preloadScriptLoaded = true;
console.log('WikiViewer preloadScriptLoaded');
true; // note: this is required, or you'll sometimes get silent failures
`;
Expand Down
3 changes: 2 additions & 1 deletion src/pages/WikiWebView/useStreamChunksToWebView/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export function useStreamChunksToWebView(webViewReference: MutableRefObject<WebV
try {
// Huawei HONOR device need to wait for a while before sending large data, otherwise first message (send HTML) will lost, cause white screen (no HTML loaded). Maybe its webview has bug.
// Instead of `if (brand === 'HONOR') await new Promise<void>(resolve => setTimeout(resolve, 1000));}`, we use heart beat to check if it is ready.
// This is also required when app bring from background after a while, the webview will be recycled, and need to wait for it to resume before sending large data, otherwise first few data will be lost.
await servicesOfWorkspace.wikiHookService.waitForWebviewReceiverReady(() => {
sendDataToWebView(OnStreamChunksToWebViewEventTypes.CHECK_RECEIVER_READY);
});
Expand Down Expand Up @@ -97,7 +98,7 @@ export function useStreamChunksToWebView(webViewReference: MutableRefObject<WebV
throw error;
}
}
}, [webViewReference, sendDataToWebView]);
}, [webViewReference, servicesOfWorkspace.wikiHookService, sendDataToWebView]);

return { injectHtmlAndTiddlersStore, streamChunksToWebViewPercentage };
}
40 changes: 28 additions & 12 deletions src/pages/WikiWebView/useTiddlyWiki.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@
/* eslint-disable unicorn/no-null */
import { Asset } from 'expo-asset';
import * as fs from 'expo-file-system';
import { Dispatch, SetStateAction, useEffect, useRef, useState } from 'react';
import { Dispatch, MutableRefObject, SetStateAction, useEffect, useRef, useState } from 'react';
import type { WebView } from 'react-native-webview';
import expoFileSystemSyncadaptorUiAssetID from '../../../assets/plugins/syncadaptor-ui.html';
import expoFileSystemSyncadaptorAssetID from '../../../assets/plugins/syncadaptor.html';
import { getWikiFilePath } from '../../constants/paths';
import { WikiHookService } from '../../services/WikiHookService';
import { WikiStorageService } from '../../services/WikiStorageService';
import { IWikiWorkspace } from '../../store/workspace';
import { usePromiseValue } from '../../utils/usePromiseValue';
import { useStreamChunksToWebView } from './useStreamChunksToWebView';
import { createSQLiteTiddlersReadStream, SQLiteTiddlersReadStream } from './useStreamChunksToWebView/SQLiteTiddlersReadStream';

export interface IHtmlContent {
Expand All @@ -18,23 +22,35 @@ export interface IHtmlContent {
}
export function useTiddlyWiki(
workspace: IWikiWorkspace,
injectHtmlAndTiddlersStore: (htmlContent: IHtmlContent) => Promise<void>,
webviewLoaded: boolean,
loaded: boolean,
webViewReference: MutableRefObject<WebView | null>,
keyToTriggerReload: number,
quickLoad: boolean,
servicesOfWorkspace: {
wikiHookService: WikiHookService;
wikiStorageService: WikiStorageService;
},
) {
const [loadHtmlError, setLoadHtmlError] = useState('');
/**
* @url file:///data/user/0/host.exp.exponent/files/wikis/wiki/index.html or 'file:///data/user/0/host.exp.exponent/cache/ExponentAsset-8568a405f924c561e7d18846ddc10c97.html'
*/
const html = usePromiseValue<string>(() => fs.readAsStringAsync(getWikiFilePath(workspace)));
const pluginJSONStrings = usePromiseValue<ITidGiMobilePlugins>(() => getTidGiMobilePlugins());
const tiddlersStreamReference = useRef<SQLiteTiddlersReadStream | undefined>();
/**
* Webview can't load html larger than 20M, we stream the html to webview, and set innerHTML in webview using preloadScript.
* This need to use with `webviewSideReceiver`.
* @url https://github.com/react-native-webview/react-native-webview/issues/3126
*/
const { injectHtmlAndTiddlersStore, streamChunksToWebViewPercentage } = useStreamChunksToWebView(webViewReference, servicesOfWorkspace);
const loading = streamChunksToWebViewPercentage > 0 && streamChunksToWebViewPercentage < 1;

const webviewLoaded = loaded && webViewReference.current !== null;
useEffect(() => {
if (!webviewLoaded || !html || !pluginJSONStrings) return;
if (!webviewLoaded || !pluginJSONStrings) return;
void (async () => {
try {
const htmlWithPrefix = `<!doctype html>${html}`;
/**
* @url file:///data/user/0/host.exp.exponent/files/wikis/wiki/index.html or 'file:///data/user/0/host.exp.exponent/cache/ExponentAsset-8568a405f924c561e7d18846ddc10c97.html'
*/
const html = `<!doctype html>${await fs.readAsStringAsync(getWikiFilePath(workspace))}`;
if (tiddlersStreamReference.current !== undefined) {
tiddlersStreamReference.current.destroy();
}
Expand All @@ -44,7 +60,7 @@ export function useTiddlyWiki(
quickLoad,
});
tiddlersStreamReference.current = tiddlersStream;
await injectHtmlAndTiddlersStore({ html: htmlWithPrefix, tiddlersStream, setLoadHtmlError });
await injectHtmlAndTiddlersStore({ html, tiddlersStream, setLoadHtmlError });
} catch (error) {
console.error(error, (error as Error).stack);
setLoadHtmlError((error as Error).message);
Expand All @@ -53,8 +69,8 @@ export function useTiddlyWiki(
// React Hook useMemo has a missing dependency: 'workspace'. Either include it or remove the dependency array.
// but workspace reference may change multiple times, causing rerender
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [workspace.id, injectHtmlAndTiddlersStore, webviewLoaded, keyToTriggerReload, html, pluginJSONStrings]);
return { loadHtmlError };
}, [workspace.id, injectHtmlAndTiddlersStore, webviewLoaded, keyToTriggerReload, pluginJSONStrings]);
return { loadHtmlError, loading, streamChunksToWebViewPercentage };
}

export interface ITidGiMobilePlugins {
Expand Down

0 comments on commit 4cd42da

Please sign in to comment.