Skip to content

Commit

Permalink
feat: render webpage
Browse files Browse the repository at this point in the history
  • Loading branch information
linonetwo committed Sep 10, 2023
1 parent 2e46686 commit 1fb5b94
Show file tree
Hide file tree
Showing 11 changed files with 194 additions and 44 deletions.
20 changes: 10 additions & 10 deletions src/components/WorkspaceList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@ import React, { useCallback } from 'react';
import DraggableFlatList from 'react-native-draggable-flatlist';
import { Card } from 'react-native-paper';
import { styled } from 'styled-components/native';
import { IWikiWorkspace, useWorkspaceStore } from '../store/workspace';
import { IWorkspace, useWorkspaceStore } from '../store/workspace';

interface WorkspaceListProps {
onLongPress?: (wiki: IWikiWorkspace) => void;
onPress?: (wiki: IWikiWorkspace) => void;
onReorderEnd?: (wikis: IWikiWorkspace[]) => void;
onLongPress?: (workspace: IWorkspace) => void;
onPress?: (workspace: IWorkspace) => void;
onReorderEnd?: (workspaces: IWorkspace[]) => void;
}

export const WorkspaceList: React.FC<WorkspaceListProps> = ({ onPress, onLongPress, onReorderEnd }) => {
const workspacesList = useWorkspaceStore(state => state.workspaces);

const renderItem = useCallback(({ item, drag }: { drag: () => void; item: IWikiWorkspace }) => {
const renderItem = useCallback(({ item, drag }: { drag: () => void; item: IWorkspace }) => {
return (
<WikiCard
<WorkspaceCard
onPress={() => {
onPress?.(item);
}}
Expand All @@ -43,7 +43,7 @@ export const WorkspaceList: React.FC<WorkspaceListProps> = ({ onPress, onLongPre
/>
)}
/>
</WikiCard>
</WorkspaceCard>
);
}, [onLongPress, onPress]);

Expand All @@ -53,15 +53,15 @@ export const WorkspaceList: React.FC<WorkspaceListProps> = ({ onPress, onLongPre
data={workspacesList}
renderItem={renderItem}
keyExtractor={item => item.id}
onDragEnd={({ data: wikis }) => {
onReorderEnd?.(wikis);
onDragEnd={({ data: workspaces }) => {
onReorderEnd?.(workspaces);
}}
/>
</>
);
};

const WikiCard = styled(Card)`
const WorkspaceCard = styled(Card)`
margin: 8px;
padding: 8px;
`;
Expand Down
2 changes: 2 additions & 0 deletions src/constants/webview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// pretending we are sending request from same origin using a Chrome browser. So image site won't block our request.
export const FAKE_USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36';
4 changes: 3 additions & 1 deletion src/i18n/localization/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,9 @@
"ToggleServerList": "Toggle Server List",
"Retry": "Retry",
"ToggleQRCodeScanner": "Toggle QRCode Scanner",
"OpenChangeLogList": "Open Change Log List"
"OpenChangeLogList": "Open Change Log List",
"PageUrl": "Page Url",
"AddWebPageWorkspace": "Add WebPage Workspace"
},
"EditWorkspace": {
"Path": "Wiki Path",
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/localization/locales/zh_CN/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,9 @@
"ToggleServerList": "服务器列表",
"Retry": "重试",
"ToggleQRCodeScanner": "二维码扫描器开关",
"OpenChangeLogList": "打开变更记录列表"
"OpenChangeLogList": "打开变更记录列表",
"PageUrl": "页面地址",
"AddWebPageWorkspace": "新增网页工作区"
},
"EditWorkspace": {
"Path": "Wiki的位置",
Expand Down
22 changes: 21 additions & 1 deletion src/pages/Config/Developer/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import * as Application from 'expo-application';
import * as Clipboard from 'expo-clipboard';
import { useTranslation } from 'react-i18next';
import { Button, Text } from 'react-native-paper';
import { Button, Text, TextInput } from 'react-native-paper';

import { useState } from 'react';
import { useWorkspaceStore } from '../../../store/workspace';
import { useClearAllWikiData } from './useClearAllWikiData';
import { useOpenDirectory } from './useOpenDirectory';

Expand All @@ -11,6 +13,8 @@ export function Developer(): JSX.Element {

const { isOpeningDirectory, openDocumentDirectory, OpenDirectoryResultSnackBar } = useOpenDirectory();
const { ClearAllWikiDataResultSnackBar, clearAllWikiData } = useClearAllWikiData();
const [newPageUrl, newPageUrlSetter] = useState('');
const addPage = useWorkspaceStore(state => state.add);

return (
<>
Expand Down Expand Up @@ -45,6 +49,22 @@ export function Developer(): JSX.Element {
>
<Text>{t('ContextMenu.Copy')} v{Application.nativeApplicationVersion ?? '?-?-?'}</Text>
</Button>
<TextInput
label={t('AddWorkspace.PageUrl')}
value={newPageUrl}
onChangeText={(newText: string) => {
newPageUrlSetter(newText);
}}
/>
<Button
onPress={() => {
addPage({ type: 'webpage', uri: newPageUrl });
}}
disabled={isOpeningDirectory}
mode='outlined'
>
<Text>{t('AddWorkspace.AddWebPageWorkspace')}</Text>
</Button>
</>
);
}
2 changes: 1 addition & 1 deletion src/pages/Importer/useImportHTML.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export function useImportHTML() {
try {
setStatus('creating');

const newWorkspace = addWiki({ name: wikiName, selectiveSyncFilter, syncedServers: [{ serverID, lastSync: Date.now(), syncActive: true }] });
const newWorkspace = addWiki({ type: 'wiki', name: wikiName, selectiveSyncFilter, syncedServers: [{ serverID, lastSync: Date.now(), syncActive: true }] });
if (newWorkspace === undefined) throw new Error('Failed to create workspace');
newWorkspaceID = newWorkspace.id;
// make main folder
Expand Down
79 changes: 79 additions & 0 deletions src/pages/WikiWebView/WebPageViewer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/* eslint-disable @typescript-eslint/strict-boolean-expressions */
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { MD3Colors, Text } from 'react-native-paper';
import { WebView } from 'react-native-webview';
import { styled } from 'styled-components/native';
import { FAKE_USER_AGENT } from '../../constants/webview';
import { IPageWorkspace } from '../../store/workspace';

const WebViewContainer = styled.View`
flex: 2;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
`;
const ErrorText = styled(Text)`
color: ${MD3Colors.error50};
`;

export interface WikiViewerProps {
webPageWorkspace: IPageWorkspace;
}

export const WebPageViewer = ({ webPageWorkspace }: WikiViewerProps) => {
const { t } = useTranslation();
const [loadHtmlError, setLoadHtmlError] = useState('');
const [loaded, setLoaded] = useState(false);
const [webViewKeyToReloadAfterRecycleByOS, setWebViewKeyToReloadAfterRecycleByOS] = useState(0);
const triggerFullReload = () => {
setWebViewKeyToReloadAfterRecycleByOS(webViewKeyToReloadAfterRecycleByOS + 1);
};
if (loadHtmlError) {
return (
<WebViewContainer>
<ErrorText variant='titleLarge'>{loadHtmlError}</ErrorText>
</WebViewContainer>
);
}
return (
<WebView
key={webViewKeyToReloadAfterRecycleByOS}
originWhitelist={['*']}
mediaPlaybackRequiresUserAction={false}
allowsInlineMediaPlayback
javaScriptCanOpenWindowsAutomatically
allowsBackForwardNavigationGestures
allowsProtectedMedia
allowFileAccess
allowFileAccessFromFileURLs
allowUniversalAccessFromFileURLs
focusable
geolocationEnabled
importantForAccessibility='yes'
keyboardDisplayRequiresUserAction={false}
mediaCapturePermissionGrantType='grant'
mixedContentMode='always'
allowsAirPlayForMediaPlayback
allowsFullscreenVideo
userAgent={FAKE_USER_AGENT}
source={{ uri: webPageWorkspace.uri }}
renderError={(errorName) => <Text>{errorName}</Text>}
renderLoading={() => <Text>{t('Loading')}</Text>}
onRenderProcessGone={() => {
// fix webview recycled by system https://github.com/react-native-webview/react-native-webview/issues/3062#issuecomment-1711645611
triggerFullReload();
}}
onError={(syntheticEvent) => {
setLoadHtmlError(syntheticEvent.nativeEvent.description);
}}
onLoadEnd={() => {
// this is called every time a tiddler is opened. And will be call 3 times before wiki loaded, seems including when setting innerHTML.
setLoaded(true);
}}
webviewDebuggingEnabled={true /* Open chrome://inspect/#devices to debug the WebView */}
/>
);
};
3 changes: 1 addition & 2 deletions src/pages/WikiWebView/WikiViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useStreamChunksToWebView } from './useStreamChunksToWebView';
import { onErrorHandler } from './useStreamChunksToWebView/onErrorHandler';
import { useTiddlyWiki } from './useTiddlyWiki';
import { useWindowMeta } from './useWindowMeta';
import { FAKE_USER_AGENT } from '../../constants/webview';

const WebViewContainer = styled.View`
flex: 2;
Expand All @@ -30,8 +31,6 @@ const ErrorText = styled(Text)`
export interface WikiViewerProps {
wikiWorkspace: IWikiWorkspace;
}
// pretending we are sending request from same origin using a Chrome browser. So image site won't block our request.
const FAKE_USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36';

export const WikiViewer = ({ wikiWorkspace }: WikiViewerProps) => {
// TODO: prevent swipe back work, then enable "use notification go back", maybe make this a config option. And let swipe go back become navigate back in the webview
Expand Down
31 changes: 26 additions & 5 deletions src/pages/WikiWebView/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { StackScreenProps } from '@react-navigation/stack';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { Text } from 'react-native-paper';
import { WebView } from 'react-native-webview';
import { styled } from 'styled-components/native';
import { RootStackParameterList } from '../../App';
import { useCloseSQLite } from '../../services/SQLiteService/hooks';
Expand All @@ -16,13 +19,31 @@ export interface WikiWebViewProps {
id?: string;
}
export const WikiWebView: React.FC<StackScreenProps<RootStackParameterList, 'WikiWebView'>> = ({ route }) => {
const { t } = useTranslation();
const { id } = route.params;
const activeWikiWorkspace = useWorkspaceStore(state => state.workspaces.find(wiki => wiki.id === id));
useCloseSQLite(activeWikiWorkspace);

return (
<Container>
{(activeWikiWorkspace !== undefined) && <WikiViewer wikiWorkspace={activeWikiWorkspace} />}
</Container>
);
switch (activeWikiWorkspace?.type) {
case 'wiki': {
return (
<Container>
{(activeWikiWorkspace !== undefined) && <WikiViewer wikiWorkspace={activeWikiWorkspace} />}
</Container>
);
}

case 'webpage': {
return (
<Container>
<WebView source={{ uri: activeWikiWorkspace.uri }} />
</Container>
);
}
default: {
<Container>
<Text>{t('Loading')}</Text>
</Container>;
}
}
};
12 changes: 7 additions & 5 deletions src/services/SQLiteService/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import { useEffect, useRef } from 'react';
import { IWikiWorkspace } from '../../store/workspace';
import { IWorkspace } from '../../store/workspace';
import { sqliteServiceService } from '.';

export function useCloseSQLite(workspace: IWikiWorkspace | undefined) {
export function useCloseSQLite(workspace?: IWorkspace) {
// use ref to prevent update to workspace.lastLocationHash trigger this effect
const databaseToCloseReference = useRef<IWikiWorkspace | undefined>(workspace);
const databaseToCloseReference = useRef<IWorkspace | undefined>(workspace);
useEffect(() => {
return (() => {
void (async () => {
try {
if (databaseToCloseReference.current === undefined) return;
console.log(`Closing sqlite database for ${databaseToCloseReference.current.id} in useSQLiteService`);
// eslint-disable-next-line react-hooks/exhaustive-deps
await sqliteServiceService.closeDatabase(databaseToCloseReference.current);
if (databaseToCloseReference.current?.type === 'wiki') {
// eslint-disable-next-line react-hooks/exhaustive-deps
await sqliteServiceService.closeDatabase(databaseToCloseReference.current);
}
} catch (error) {
console.error(error);
}
Expand Down
Loading

0 comments on commit 1fb5b94

Please sign in to comment.