Skip to content

Commit 74a455d

Browse files
committed
feat: implement WebViewContainer with enhanced navigation and script injection capabilities
1 parent 1346a3c commit 74a455d

2 files changed

Lines changed: 122 additions & 65 deletions

File tree

src/features/browser/screens/BrowserScreen/WebViewComponent.tsx

Lines changed: 0 additions & 65 deletions
This file was deleted.
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import { useScripts } from "@/src/features/scripts/hooks/useScripts";
2+
import { useCallback, useRef } from "react";
3+
import { StyleSheet, View, ViewProps } from "react-native";
4+
import {
5+
WebView,
6+
WebViewMessageEvent,
7+
WebViewNavigation,
8+
} from "react-native-webview";
9+
import { useBrowser } from "../../hooks/useBrowser";
10+
import { normalizeUrl } from "../../utils/urlUtils";
11+
12+
const SCROLL_DIRECTION_THRESHOLD = 8;
13+
14+
function getInjectionScripts(
15+
url: string,
16+
runAt: "document-start" | "document-ready" | "document-end",
17+
getScriptsByRunAt: any
18+
) {
19+
return getScriptsByRunAt(url, runAt)
20+
.map((script: any) => script.code)
21+
.join("\n");
22+
}
23+
24+
type WebViewContainerProps = {
25+
bottomPadding?: number;
26+
onScrollDirectionChange?: (direction: "up" | "down") => void;
27+
} & ViewProps;
28+
29+
export default function WebViewContainer({
30+
bottomPadding = 0,
31+
style,
32+
onScrollDirectionChange,
33+
...props
34+
}: WebViewContainerProps) {
35+
const { activeTab, updateTabById } = useBrowser();
36+
const { getScriptsByRunAt, logExecution } = useScripts();
37+
const webviewRef = useRef<WebView>(null);
38+
39+
// Prepare URL
40+
const url = activeTab?.url ? normalizeUrl(activeTab.url) : "about:blank";
41+
42+
// Inject scripts at different lifecycle points
43+
const injectedJavaScriptBeforeContentLoaded = activeTab?.url
44+
? getInjectionScripts(url, "document-start", getScriptsByRunAt)
45+
: "";
46+
const injectedJavaScript = activeTab?.url
47+
? getInjectionScripts(url, "document-ready", getScriptsByRunAt)
48+
: "";
49+
50+
// Handle navigation events
51+
const onNavigationStateChange = useCallback(
52+
(navState: WebViewNavigation) => {
53+
if (!activeTab) return;
54+
updateTabById(activeTab.id, {
55+
url: navState.url,
56+
title: navState.title ?? "",
57+
canGoBack: navState.canGoBack,
58+
canGoForward: navState.canGoForward,
59+
isLoading: navState.loading,
60+
});
61+
},
62+
[activeTab, updateTabById]
63+
);
64+
65+
// Handle JS execution results
66+
const onMessage = useCallback((event: WebViewMessageEvent) => {
67+
// TODO: Log execution results
68+
}, []);
69+
70+
// Inject CSS to add bottom padding to the body
71+
const injectedCSS = `
72+
const style = document.createElement('style');
73+
style.innerHTML = 'body { padding-bottom: ${bottomPadding}px !important; box-sizing: border-box; }';
74+
document.head.appendChild(style);
75+
`;
76+
77+
const lastScrollY = useRef(0);
78+
const lastDirection = useRef<"up" | "down" | null>(null); // pixels
79+
const handleScroll = (event: any) => {
80+
const currentY = event.nativeEvent.contentOffset?.y ?? 0;
81+
const diff = currentY - lastScrollY.current;
82+
83+
if (Math.abs(diff) > SCROLL_DIRECTION_THRESHOLD) {
84+
const newDirection = diff > 0 ? "down" : "up";
85+
if (newDirection !== lastDirection.current) {
86+
onScrollDirectionChange?.(newDirection);
87+
lastDirection.current = newDirection;
88+
}
89+
}
90+
lastScrollY.current = currentY;
91+
};
92+
93+
return (
94+
<View style={[styles.container, style]} {...props}>
95+
<WebView
96+
ref={webviewRef}
97+
source={{ uri: url }}
98+
injectedJavaScriptBeforeContentLoaded={
99+
injectedJavaScriptBeforeContentLoaded
100+
}
101+
injectedJavaScript={injectedJavaScript}
102+
onNavigationStateChange={onNavigationStateChange}
103+
onMessage={onMessage}
104+
startInLoadingState={true}
105+
allowsInlineMediaPlayback
106+
javaScriptEnabled
107+
domStorageEnabled
108+
setSupportMultipleWindows={false}
109+
allowsBackForwardNavigationGestures
110+
originWhitelist={["*"]}
111+
onScroll={handleScroll}
112+
/>
113+
</View>
114+
);
115+
}
116+
117+
const styles = StyleSheet.create({
118+
container: {
119+
flex: 1,
120+
backgroundColor: "#ecf0f1",
121+
},
122+
});

0 commit comments

Comments
 (0)