diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 4b1fb12b9f6..abd321b5989 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1751,7 +1751,7 @@ PODS: - React-Core - RNReactNativeHapticFeedback (2.2.0): - React-Core - - RNReanimated (3.16.2): + - RNReanimated (3.16.3): - DoubleConversion - glog - hermes-engine @@ -1771,10 +1771,10 @@ PODS: - React-utils - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNReanimated/reanimated (= 3.16.2) - - RNReanimated/worklets (= 3.16.2) + - RNReanimated/reanimated (= 3.16.3) + - RNReanimated/worklets (= 3.16.3) - Yoga - - RNReanimated/reanimated (3.16.2): + - RNReanimated/reanimated (3.16.3): - DoubleConversion - glog - hermes-engine @@ -1794,9 +1794,9 @@ PODS: - React-utils - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNReanimated/reanimated/apple (= 3.16.2) + - RNReanimated/reanimated/apple (= 3.16.3) - Yoga - - RNReanimated/reanimated/apple (3.16.2): + - RNReanimated/reanimated/apple (3.16.3): - DoubleConversion - glog - hermes-engine @@ -1817,7 +1817,7 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - RNReanimated/worklets (3.16.2): + - RNReanimated/worklets (3.16.3): - DoubleConversion - glog - hermes-engine @@ -2574,7 +2574,7 @@ SPEC CHECKSUMS: RNOS: 31db6fa4a197d179afbba9e6b4d28d450a7f250b RNPermissions: 4e3714e18afe7141d000beae3755e5b5fb2f5e05 RNReactNativeHapticFeedback: ec56a5f81c3941206fd85625fa669ffc7b4545f9 - RNReanimated: 30ed0985f2b8dc16a76c23362cabe8dd5166b64f + RNReanimated: e1c250aeb93d6738eaf51e3d93871873a0c41b81 RNRudderSdk: 805d4b7064714f3295bf5f152d3812cc67f67a93 RNScreens: 6b641f232990a9d505a6d139fd18c3c759c9d290 RNSentry: 6a5d9f48370070c1d4697dfe74044b7f45512420 diff --git a/package.json b/package.json index c32a7d41a37..f7dc00dcd64 100644 --- a/package.json +++ b/package.json @@ -254,7 +254,7 @@ "react-native-quick-md5": "3.0.6", "react-native-radial-gradient": "rainbow-me/react-native-radial-gradient#b99ab59d27dba70364ef516bd5193c37657ba95c", "react-native-randombytes": "3.5.3", - "react-native-reanimated": "3.16.2", + "react-native-reanimated": "3.16.3", "react-native-redash": "16.3.0", "react-native-restart": "0.0.22", "react-native-safe-area-context": "4.14.0", diff --git a/patches/react-native-reanimated+3.16.2.patch b/patches/react-native-reanimated+3.16.3.patch similarity index 50% rename from patches/react-native-reanimated+3.16.2.patch rename to patches/react-native-reanimated+3.16.3.patch index d1dbe630d5d..373265cd347 100644 --- a/patches/react-native-reanimated+3.16.2.patch +++ b/patches/react-native-reanimated+3.16.3.patch @@ -1,3 +1,21 @@ +diff --git a/node_modules/react-native-reanimated/Common/cpp/worklets/SharedItems/Shareables.cpp b/node_modules/react-native-reanimated/Common/cpp/worklets/SharedItems/Shareables.cpp +index 4087065..f22bd06 100644 +--- a/node_modules/react-native-reanimated/Common/cpp/worklets/SharedItems/Shareables.cpp ++++ b/node_modules/react-native-reanimated/Common/cpp/worklets/SharedItems/Shareables.cpp +@@ -47,7 +47,12 @@ jsi::Value makeShareableClone( + if (value.isObject()) { + auto object = value.asObject(rt); + if (!object.getProperty(rt, "__workletHash").isUndefined()) { +- shareable = std::make_shared(rt, object); ++ if (shouldRetainRemote.isBool() && shouldRetainRemote.getBool()) { ++ shareable = ++ std::make_shared>(rt, object); ++ } else { ++ shareable = std::make_shared(rt, object); ++ } + } else if (!object.getProperty(rt, "__init").isUndefined()) { + shareable = std::make_shared(rt, object); + } else if (object.isFunction(rt)) { diff --git a/node_modules/react-native-reanimated/apple/reanimated/apple/REANodesManager.mm b/node_modules/react-native-reanimated/apple/reanimated/apple/REANodesManager.mm index ec86d08..b043442 100644 --- a/node_modules/react-native-reanimated/apple/reanimated/apple/REANodesManager.mm @@ -42,3 +60,32 @@ index 39c77a1..8bcbc7e 100644 textShadowRadius: true, textShadowOffset: true, letterSpacing: true, +diff --git a/node_modules/react-native-reanimated/src/shareables.ts b/node_modules/react-native-reanimated/src/shareables.ts +index 44e961f..1b57980 100644 +--- a/node_modules/react-native-reanimated/src/shareables.ts ++++ b/node_modules/react-native-reanimated/src/shareables.ts +@@ -128,6 +128,7 @@ export function makeShareableCloneRecursive( + const type = typeof value; + const isTypeObject = type === 'object'; + const isTypeFunction = type === 'function'; ++ let isCacheableWorklet = false; + if ((isTypeObject || isTypeFunction) && value !== null) { + const cached = shareableMappingCache.get(value); + if (cached === shareableMappingFlag) { +@@ -166,6 +167,7 @@ export function makeShareableCloneRecursive( + } else if (isPlainJSObject(value) || isTypeFunction) { + toAdapt = {}; + if (isWorkletFunction(value)) { ++ isCacheableWorklet = true; + if (__DEV__) { + const babelVersion = value.__initData.version; + if (babelVersion !== undefined && babelVersion !== jsVersion) { +@@ -275,7 +277,7 @@ Offending code was: \`${getWorkletCode(value)}\``); + } + const adapted = NativeReanimatedModule.makeShareableClone( + toAdapt, +- shouldPersistRemote, ++ shouldPersistRemote || isCacheableWorklet, + value + ); + shareableMappingCache.set(value, adapted); diff --git a/src/components/DappBrowser/BrowserContext.tsx b/src/components/DappBrowser/BrowserContext.tsx index 2f9d42c47b6..a59a3d601b0 100644 --- a/src/components/DappBrowser/BrowserContext.tsx +++ b/src/components/DappBrowser/BrowserContext.tsx @@ -1,5 +1,6 @@ import React, { createContext, useCallback, useContext, useRef } from 'react'; import Animated, { + runOnJS, runOnUI, useAnimatedReaction, useAnimatedRef, @@ -10,7 +11,9 @@ import Animated, { } from 'react-native-reanimated'; import ViewShot from 'react-native-view-shot'; import { SPRING_CONFIGS, TIMING_CONFIGS } from '@/components/animations/animationConfigs'; +import Routes from '@/navigation/routesNames'; import { useBrowserStore } from '@/state/browser/browserStore'; +import { useNavigationStore } from '@/state/navigation/navigationStore'; import { EXTRA_WEBVIEW_HEIGHT } from './Dimensions'; import { RAINBOW_HOME } from './constants'; import { useGestureManager } from './hooks/useGestureManager'; @@ -69,6 +72,7 @@ export const BrowserContextProvider = ({ children }: { children: React.ReactNode const { activeTabRef, extraWebViewHeight, goBack, goForward, shouldCollapseBottomBar, tabViewProgress } = useBrowserTabBarContext(); const activeTabId = useSharedValue(useBrowserStore.getState().getActiveTabId()); + const animatedActiveSwipeRoute = useNavigationStore(state => state.animatedActiveSwipeRoute); const animatedActiveTabIndex = useSharedValue(useBrowserStore.getState().activeTabIndex); const animatedScreenshotData = useSharedValue({}); const animatedTabUrls = useSharedValue(useBrowserStore.getState().persistedTabUrls); @@ -152,7 +156,6 @@ export const BrowserContextProvider = ({ children }: { children: React.ReactNode } runOnUI(() => { - 'worklet'; const tabIdToUse = tabId || activeTabId.value; animatedTabUrls.modify(urls => ({ ...urls, [tabIdToUse]: normalizeUrlWorklet(url) })); })(); @@ -160,6 +163,33 @@ export const BrowserContextProvider = ({ children }: { children: React.ReactNode [activeTabId, activeTabInfo, animatedTabUrls, goToPage, refreshPage] ); + const setWebViewHandlersEnabled = useCallback( + (enabled: boolean) => { + activeTabRef.current?.setActive(enabled); + }, + [activeTabRef] + ); + + // Enables or disables WebView JS handlers when navigating to or away from the browser + // tab, and ensures the tab bar is always revealed when leaving the browser tab + useAnimatedReaction( + () => animatedActiveSwipeRoute.value === Routes.DAPP_BROWSER_SCREEN, + (isOnBrowserTab, prev) => { + if (activeTabInfo.value.isOnHomepage) return; + + const browserBecameActive = isOnBrowserTab && prev === false; + const browserBecameInactive = !isOnBrowserTab && prev; + + if (browserBecameActive) { + runOnJS(setWebViewHandlersEnabled)(true); + } else if (browserBecameInactive) { + runOnJS(setWebViewHandlersEnabled)(false); + if (shouldCollapseBottomBar.value) shouldCollapseBottomBar.value = false; + } + }, + [] + ); + return ( state.animatedActiveSwipeRoute); - const scrollPositionRef = useRef(undefined); const startScrollPositionRef = useRef(undefined); const touchPositionYRef = useRef(undefined); @@ -128,18 +124,6 @@ export function useGestureManager({ [] ); - // Ensures the tab bar never remains collapsed when navigating away from the browser screen - useAnimatedReaction( - () => ({ isOnBrowserTab: activeSwipeRoute.value === Routes.DAPP_BROWSER_SCREEN }), - (current, prev) => { - const resetForInactiveBrowserTab = !current.isOnBrowserTab && prev?.isOnBrowserTab && shouldCollapseBottomBar.value; - if (resetForInactiveBrowserTab) { - shouldCollapseBottomBar.value = false; - } - }, - [] - ); - // Manages setting the last active homepage tab, which is used to determine which homepage should allow reordering favorites useAnimatedReaction( () => ({ diff --git a/src/components/DappBrowser/search-input/TabButton.tsx b/src/components/DappBrowser/search-input/TabButton.tsx index faa7db5abe1..f3e7cb5a5fc 100644 --- a/src/components/DappBrowser/search-input/TabButton.tsx +++ b/src/components/DappBrowser/search-input/TabButton.tsx @@ -1,5 +1,6 @@ import { BlurView } from '@react-native-community/blur'; -import React, { useCallback, useMemo } from 'react'; +import ConditionalWrap from 'conditional-wrap'; +import React, { memo, useCallback, useMemo } from 'react'; import { StyleSheet, TextInput } from 'react-native'; import { AnimatedRef, runOnJS, runOnUI, useAnimatedStyle, useDerivedValue } from 'react-native-reanimated'; import ContextMenuButton from '@/components/native-context-menu/contextMenu'; @@ -8,10 +9,10 @@ import { IS_IOS } from '@/env'; import { useSharedValueState } from '@/hooks/reanimated/useSharedValueState'; import * as i18n from '@/languages'; import { useBrowserStore } from '@/state/browser/browserStore'; +import position from '@/styles/position'; import { GestureHandlerButton } from '@/__swaps__/screens/Swap/components/GestureHandlerButton'; import { THICK_BORDER_WIDTH } from '@/__swaps__/screens/Swap/constants'; import { opacity } from '@/__swaps__/utils/swaps'; -import position from '@/styles/position'; import { haptics, showActionSheetWithOptions } from '@/utils'; import { useBrowserContext } from '../BrowserContext'; import { useBrowserWorkletsContext } from '../BrowserWorkletsContext'; @@ -36,7 +37,6 @@ export const TabButton = React.memo(function TabButton({ const { isDarkMode } = useColorMode(); const fillSecondary = useForegroundColor('fillSecondary'); - const separatorSecondary = useForegroundColor('separatorSecondary'); const isFocusedState = useSharedValueState(isFocused, { initialValue: false }); @@ -53,21 +53,14 @@ export const TabButton = React.memo(function TabButton({ const label = useForegroundColor('label'); const labelSecondary = useForegroundColor('labelSecondary'); - const tabButtonIcon = useDerivedValue(() => { - return isFocused.value ? '􀆈' : '􀐅'; - }); - - const tabButtonIconStyle = useAnimatedStyle(() => { - return { - color: isFocused.value ? labelSecondary : label, - }; - }); + const tabButtonIcon = useDerivedValue(() => (isFocused.value ? '􀆈' : '􀐅')); + const tabButtonIconStyle = useAnimatedStyle(() => ({ color: isFocused.value ? labelSecondary : label })); const blurInput = useCallback(() => { - inputRef?.current?.blur(); + inputRef.current?.blur(); }, [inputRef]); - const onPress = useCallback(() => { + const onPressWorklet = useCallback(() => { 'worklet'; if (!isFocused.value) { toggleTabViewWorklet(); @@ -77,13 +70,6 @@ export const TabButton = React.memo(function TabButton({ }, [blurInput, isFocused, toggleTabViewWorklet]); const longPressMenuConfig = useMemo(() => { - if (isFocusedState) { - return { - menuTitle: '', - menuItems: [], - }; - } - let closeAllTabsTitle: string; switch (numberOfClosableTabs) { case 1: @@ -142,7 +128,7 @@ export const TabButton = React.memo(function TabButton({ menuTitle: '', menuItems, }; - }, [isFocusedState, numberOfClosableTabs]); + }, [numberOfClosableTabs]); const goHome = useCallback(() => { goToUrl(RAINBOW_HOME); @@ -191,10 +177,22 @@ export const TabButton = React.memo(function TabButton({ return ( - + ( + + {children} + + )} + > + {tabButtonIcon} - {IS_IOS && ( - - )} - - + ); }); +const BlurLayer = memo(function BlurLayer({ buttonColor }: { buttonColor: string }) { + const { isDarkMode } = useColorMode(); + const separatorSecondary = useForegroundColor('separatorSecondary'); + + return ( + <> + {IS_IOS && } + + + ); +}); + const styles = StyleSheet.create({ + blurLayer: { + ...position.coverAsObject, + borderRadius: TAB_BUTTON_SIZE / 2, + elevation: -1, + zIndex: -1, + }, + blurTint: { + ...position.coverAsObject, + borderRadius: TAB_BUTTON_SIZE / 2, + zIndex: -1, + }, tabButtonIcon: { width: TAB_BUTTON_SIZE, }, diff --git a/yarn.lock b/yarn.lock index 0b13ad84b36..004c5ca45b8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9316,7 +9316,7 @@ __metadata: react-native-quick-md5: "npm:3.0.6" react-native-radial-gradient: "rainbow-me/react-native-radial-gradient#b99ab59d27dba70364ef516bd5193c37657ba95c" react-native-randombytes: "npm:3.5.3" - react-native-reanimated: "npm:3.16.2" + react-native-reanimated: "npm:3.16.3" react-native-redash: "npm:16.3.0" react-native-restart: "npm:0.0.22" react-native-safe-area-context: "npm:4.14.0" @@ -23440,9 +23440,9 @@ __metadata: languageName: node linkType: hard -"react-native-reanimated@npm:3.16.2": - version: 3.16.2 - resolution: "react-native-reanimated@npm:3.16.2" +"react-native-reanimated@npm:3.16.3": + version: 3.16.3 + resolution: "react-native-reanimated@npm:3.16.3" dependencies: "@babel/plugin-transform-arrow-functions": "npm:^7.0.0-0" "@babel/plugin-transform-class-properties": "npm:^7.0.0-0" @@ -23459,7 +23459,7 @@ __metadata: "@babel/core": ^7.0.0-0 react: "*" react-native: "*" - checksum: 10c0/640790d87683812e964a342016bdfda956d698bfdd289ef6cc0b214b0f62ac34da788f8795a29fe51bcc49b0002bd32fa2074ab79b63640cafb48d99473d36ca + checksum: 10c0/ef0ec527f9d19df3560f1060c79c89f4fa1771e2f16d5537921ebd974eff2e5a2b0badc7f2193843a6e070c36c33010fb7f00720383b225cf90cabdb7e55a406 languageName: node linkType: hard