From 74a455d0173997cfd8ca0e8b0b7febf3a51c068f Mon Sep 17 00:00:00 2001 From: afnx Date: Sun, 26 Oct 2025 23:01:51 -0700 Subject: [PATCH 1/3] feat: implement WebViewContainer with enhanced navigation and script injection capabilities --- .../BrowserScreen/WebViewComponent.tsx | 65 ---------- .../BrowserScreen/WebViewContainer.tsx | 122 ++++++++++++++++++ 2 files changed, 122 insertions(+), 65 deletions(-) delete mode 100644 src/features/browser/screens/BrowserScreen/WebViewComponent.tsx create mode 100644 src/features/browser/screens/BrowserScreen/WebViewContainer.tsx diff --git a/src/features/browser/screens/BrowserScreen/WebViewComponent.tsx b/src/features/browser/screens/BrowserScreen/WebViewComponent.tsx deleted file mode 100644 index 406eeb3..0000000 --- a/src/features/browser/screens/BrowserScreen/WebViewComponent.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import { useRef } from "react"; -import { StyleSheet, View, ViewProps } from "react-native"; -import { WebView } from "react-native-webview"; -import { useBrowser } from "../../hooks/useBrowser"; - -type WebViewComponentProps = { - bottomPadding?: number; - onScrollDirectionChange?: (direction: "up" | "down") => void; -} & ViewProps; - -const SCROLL_DIRECTION_THRESHOLD = 8; - -export default function WebViewComponent({ - bottomPadding = 0, - style, - onScrollDirectionChange, - ...props -}: WebViewComponentProps) { - const { activeTab, updateTabById } = useBrowser(); - const { url } = activeTab || {}; - // Inject CSS to add bottom padding to the body - const injectedCSS = ` - const style = document.createElement('style'); - style.innerHTML = 'body { padding-bottom: ${bottomPadding}px !important; box-sizing: border-box; }'; - document.head.appendChild(style); - `; - - const lastScrollY = useRef(0); - const lastDirection = useRef<"up" | "down" | null>(null); // pixels - const handleScroll = (event: any) => { - const currentY = event.nativeEvent.contentOffset?.y ?? 0; - const diff = currentY - lastScrollY.current; - - if (Math.abs(diff) > SCROLL_DIRECTION_THRESHOLD) { - const newDirection = diff > 0 ? "down" : "up"; - if (newDirection !== lastDirection.current) { - onScrollDirectionChange?.(newDirection); - lastDirection.current = newDirection; - } - } - lastScrollY.current = currentY; - }; - - return ( - - { - if (activeTab?.id) { - updateTabById(activeTab!.id, { url: navState.url }); - } - }} - onScroll={handleScroll} - /> - - ); -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - backgroundColor: "#ecf0f1", - }, -}); diff --git a/src/features/browser/screens/BrowserScreen/WebViewContainer.tsx b/src/features/browser/screens/BrowserScreen/WebViewContainer.tsx new file mode 100644 index 0000000..307447d --- /dev/null +++ b/src/features/browser/screens/BrowserScreen/WebViewContainer.tsx @@ -0,0 +1,122 @@ +import { useScripts } from "@/src/features/scripts/hooks/useScripts"; +import { useCallback, useRef } from "react"; +import { StyleSheet, View, ViewProps } from "react-native"; +import { + WebView, + WebViewMessageEvent, + WebViewNavigation, +} from "react-native-webview"; +import { useBrowser } from "../../hooks/useBrowser"; +import { normalizeUrl } from "../../utils/urlUtils"; + +const SCROLL_DIRECTION_THRESHOLD = 8; + +function getInjectionScripts( + url: string, + runAt: "document-start" | "document-ready" | "document-end", + getScriptsByRunAt: any +) { + return getScriptsByRunAt(url, runAt) + .map((script: any) => script.code) + .join("\n"); +} + +type WebViewContainerProps = { + bottomPadding?: number; + onScrollDirectionChange?: (direction: "up" | "down") => void; +} & ViewProps; + +export default function WebViewContainer({ + bottomPadding = 0, + style, + onScrollDirectionChange, + ...props +}: WebViewContainerProps) { + const { activeTab, updateTabById } = useBrowser(); + const { getScriptsByRunAt, logExecution } = useScripts(); + const webviewRef = useRef(null); + + // Prepare URL + const url = activeTab?.url ? normalizeUrl(activeTab.url) : "about:blank"; + + // Inject scripts at different lifecycle points + const injectedJavaScriptBeforeContentLoaded = activeTab?.url + ? getInjectionScripts(url, "document-start", getScriptsByRunAt) + : ""; + const injectedJavaScript = activeTab?.url + ? getInjectionScripts(url, "document-ready", getScriptsByRunAt) + : ""; + + // Handle navigation events + const onNavigationStateChange = useCallback( + (navState: WebViewNavigation) => { + if (!activeTab) return; + updateTabById(activeTab.id, { + url: navState.url, + title: navState.title ?? "", + canGoBack: navState.canGoBack, + canGoForward: navState.canGoForward, + isLoading: navState.loading, + }); + }, + [activeTab, updateTabById] + ); + + // Handle JS execution results + const onMessage = useCallback((event: WebViewMessageEvent) => { + // TODO: Log execution results + }, []); + + // Inject CSS to add bottom padding to the body + const injectedCSS = ` + const style = document.createElement('style'); + style.innerHTML = 'body { padding-bottom: ${bottomPadding}px !important; box-sizing: border-box; }'; + document.head.appendChild(style); + `; + + const lastScrollY = useRef(0); + const lastDirection = useRef<"up" | "down" | null>(null); // pixels + const handleScroll = (event: any) => { + const currentY = event.nativeEvent.contentOffset?.y ?? 0; + const diff = currentY - lastScrollY.current; + + if (Math.abs(diff) > SCROLL_DIRECTION_THRESHOLD) { + const newDirection = diff > 0 ? "down" : "up"; + if (newDirection !== lastDirection.current) { + onScrollDirectionChange?.(newDirection); + lastDirection.current = newDirection; + } + } + lastScrollY.current = currentY; + }; + + return ( + + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: "#ecf0f1", + }, +}); From 475dbaf52e67a40c088c94151f779271db3631bb Mon Sep 17 00:00:00 2001 From: afnx Date: Sun, 26 Oct 2025 23:02:02 -0700 Subject: [PATCH 2/3] feat: replace WebViewComponent with WebViewContainer in BrowserScreen --- src/features/browser/screens/BrowserScreen/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/features/browser/screens/BrowserScreen/index.tsx b/src/features/browser/screens/BrowserScreen/index.tsx index d3fc774..f3ac257 100644 --- a/src/features/browser/screens/BrowserScreen/index.tsx +++ b/src/features/browser/screens/BrowserScreen/index.tsx @@ -10,7 +10,7 @@ import { useBrowser } from "../../hooks/useBrowser"; import AddressBar from "./AddressBar"; import AddressBarDisplay from "./AddressBarDisplay"; import Toolbar from "./Toolbar"; -import WebViewComponent from "./WebViewComponent"; +import WebViewContainer from "./WebViewContainer"; const KEYBOARD_OPENED_HEIGHT = 102; const KEYBOARD_CLOSED_HEIGHT = 0; @@ -89,7 +89,7 @@ export default function BrowserScreen() { edges={["top"]} > - From 7efdc80dc783400a502cfc1382099b2e4c36f132 Mon Sep 17 00:00:00 2001 From: afnx Date: Mon, 27 Oct 2025 00:33:50 -0700 Subject: [PATCH 3/3] feat: refactor bottom container animation and style handling in BrowserScreen --- .../browser/screens/BrowserScreen/index.tsx | 56 +++++++++---------- 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/src/features/browser/screens/BrowserScreen/index.tsx b/src/features/browser/screens/BrowserScreen/index.tsx index f3ac257..db74dd5 100644 --- a/src/features/browser/screens/BrowserScreen/index.tsx +++ b/src/features/browser/screens/BrowserScreen/index.tsx @@ -55,30 +55,33 @@ export default function BrowserScreen() { outputRange: [KEYBOARD_CLOSED_HEIGHT, KEYBOARD_OPENED_HEIGHT], }); - const addressBarStyle = useMemo( + const bottomContainerY = useMemo(() => new Animated.Value(0), []); + + useEffect(() => { + Animated.timing(bottomContainerY, { + toValue: showBottomContainer ? 0 : 200, + duration: 400, + useNativeDriver: true, + }).start(); + }, [showBottomContainer, bottomContainerY]); + + const bottomContainerStyle = useMemo( () => [ { transform: [ { translateY: Animated.add(height, offset), }, + { + translateY: bottomContainerY, + }, ], }, { backgroundColor: "white" }, ], - [height, offset] + [height, offset, bottomContainerY] ); - const bottomContainerY = useMemo(() => new Animated.Value(0), []); - - useEffect(() => { - Animated.timing(bottomContainerY, { - toValue: showBottomContainer ? 0 : 200, - duration: 400, - useNativeDriver: true, - }).start(); - }, [showBottomContainer, bottomContainerY]); - return ( - - - {showAddressBar && ( - - )} - {!showAddressBar && } - + + {showAddressBar && ( + + )} + {!showAddressBar && } {/* Toolbar contains the SafeAreaView */} @@ -132,5 +121,10 @@ const styles = StyleSheet.create({ }, bottomContainer: { width: "100%", + backgroundColor: "white", + position: "absolute", + left: 0, + right: 0, + bottom: 0, }, });