Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
a27f515
Styled Components: Enhancement - remove dependency and migrate applic…
gabrielbazan7 Jul 24, 2026
4df0c8a
App Performance: Enhancement - optimize Redux, persistence, logging, …
gabrielbazan7 Jul 24, 2026
d0fbf75
Shared UI: Enhancement - optimize buttons, modals, notifications, and…
gabrielbazan7 Jul 24, 2026
8d51aef
Screen Performance: Enhancement - optimize onboarding, home, wallet l…
gabrielbazan7 Jul 24, 2026
9fdc2ae
Runtime/Development: Fix - handle missing Braze configuration and add…
gabrielbazan7 Jul 24, 2026
0682a5c
Runtime/Development: Fix - remove Claude-specific ignore configuration
gabrielbazan7 Jul 24, 2026
e8261d7
Styled Components: Fix - migrate newly integrated TSS views to React …
gabrielbazan7 Jul 25, 2026
012dff7
Performance: Enhancement - gate performance diagnostics behind PERF_D…
gabrielbazan7 Jul 27, 2026
8e14ce7
Modals: Fix - prevent premature unmounts and stuck native overlays
gabrielbazan7 Jul 27, 2026
80aee69
Performance: enhancement - optimize wallet flows and stabilize balanc…
gabrielbazan7 Jul 27, 2026
ad8570f
Charts: Fix - keep charts visible while balances are hidden
gabrielbazan7 Jul 29, 2026
5d6e73a
perf(wallet): add cache and preload infrastructure
gabrielbazan7 Jul 29, 2026
c1ea957
perf(navigation): preload home and wallet detail flows
gabrielbazan7 Jul 29, 2026
945e4bc
perf(send): preload receive and send flows
gabrielbazan7 Jul 29, 2026
fcdd94f
flash-list: fix - upgrade flash-list package
gabrielbazan7 Jul 29, 2026
54fcc77
Balance: Fix - improve balance visibility tap target
gabrielbazan7 Jul 30, 2026
06beb45
Buy/sell/swap: Enhancement - improve render performance
gabrielbazan7 Jul 30, 2026
86e9734
KeySettings: Enhancement - improve render performance
gabrielbazan7 Jul 30, 2026
e38e2af
Performance: Fix - stabilize persistent UI caches and remove navigati…
gabrielbazan7 Jul 31, 2026
70fa07e
WalletCache: Fix - clear derived caches on key deletion
gabrielbazan7 Jul 31, 2026
58a8699
Performance: Fix - prevent preload navigation stalls and stale transa…
gabrielbazan7 Jul 31, 2026
d8e70b4
Performance: Optimize notification screens and proposal rendering
gabrielbazan7 Jul 31, 2026
ba4b023
Performance: Fix - migrate newly integrated KYC views to React Native…
gabrielbazan7 Aug 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 2 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,7 @@ yarn-error.log
.metro-health-check*

.env
.env.development
.env.production
.env.*

# Jest
#
Expand All @@ -100,4 +99,4 @@ yalc.lock

# Sentry
ios/sentry.properties
android/sentry.properties
android/sentry.properties
29 changes: 13 additions & 16 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,12 @@ import {
import {SafeAreaProvider} from 'react-native-safe-area-context';
import {GestureHandlerRootView} from 'react-native-gesture-handler';
import {BottomSheetModalProvider} from '@gorhom/bottom-sheet';
import {ThemeProvider} from 'styled-components/native';
import {
PaymentSentProvider,
OngoingProcessProvider,
BottomSheetProvider,
TokenProvider,
LogProvider,
ThemeProvider,
} from './src/contexts';
import {BitPayDarkTheme, BitPayLightTheme} from './src/themes/bitpay';
import {useAppSelector} from './src/utils/hooks';
Expand Down Expand Up @@ -229,20 +228,18 @@ const AppWrapper = () => {
/>
<GestureHandlerRootView style={{flex: 1}}>
<TokenProvider>
<LogProvider>
<OngoingProcessProvider>
<BottomSheetModalProvider>
<BottomSheetProvider>
<PaymentSentProvider>
<DklsWorkerHost />
<AppInitialization>
<Root />
</AppInitialization>
</PaymentSentProvider>
</BottomSheetProvider>
</BottomSheetModalProvider>
</OngoingProcessProvider>
</LogProvider>
<OngoingProcessProvider>
<BottomSheetModalProvider>
<BottomSheetProvider>
<PaymentSentProvider>
<DklsWorkerHost />
<AppInitialization>
<Root />
</AppInitialization>
</PaymentSentProvider>
</BottomSheetProvider>
</BottomSheetModalProvider>
</OngoingProcessProvider>
</TokenProvider>
</GestureHandlerRootView>
</SafeAreaProvider>
Expand Down
6 changes: 1 addition & 5 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module.exports = {
],
transformIgnorePatterns: [
'\\.snap$',
'node_modules/(?!(@walletconnect/react-native-compat|@freakycoder|@react-native|react-native|(react-native(-.*))|@react-navigation|(react-navigation(-.*))|@sentry|uuid|victory|(victory(-.*))|lodash-es))',
'node_modules/(?!(@walletconnect/react-native-compat|@freakycoder|@react-native|react-native|(react-native(-.*))|\@react-navigation|(react-navigation(-.*))|\@sentry|\@shopify/flash-list|uuid|victory|(victory(-.*))|lodash-es))',
],
transform: {
'^.+\\.(js|jsx|ts|tsx)$': 'ts-jest',
Expand All @@ -23,10 +23,6 @@ module.exports = {
'\\.(css|less)$': '<rootDir>/test/mock.js',
'@/(.*)': '<rootDir>/src/$1',
'@test/(.*)': '<rootDir>/test/$1',
// Redirect bare styled-components to the native version (some files import
// 'styled-components' instead of 'styled-components/native', which breaks in tests)
'^styled-components$':
'<rootDir>/node_modules/styled-components/native/dist/styled-components.native.cjs.js',
// Force ESM-only crypto packages to CJS builds
'^uuid$': require.resolve('uuid'),
'^paillier-bigint$':
Expand Down
6 changes: 1 addition & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
"@react-navigation/stack": "7.4.8",
"@reown/walletkit": "1.2.10",
"@sentry/react-native": "7.11.0",
"@shopify/flash-list": "2.0.3",
"@shopify/flash-list": "2.3.2",
"@shopify/react-native-skia": "2.2.13",
"@solana-program/token-2022": "0.5.0",
"@solana/sysvars": "3.0.2",
Expand Down Expand Up @@ -200,7 +200,6 @@
"rn-swipe-button": "3.0.1",
"safe-json-utils": "1.1.1",
"stream-browserify": "1.0.0",
"styled-components": "5.3.3",
"text-encoding": "0.7.0",
"url": "0.10.3",
"yup": "0.32.11"
Expand Down Expand Up @@ -251,8 +250,6 @@
"@types/react-redux": "7.1.25",
"@types/react-test-renderer": "19.0.0",
"@types/redux-logger": "3.0.9",
"@types/styled-components": "5.1.25",
"@types/styled-components-react-native": "5.2.1",
"babel-jest": "29.6.3",
"babel-loader": "9.1.2",
"babel-plugin-transform-import-meta": "2.3.3",
Expand All @@ -263,7 +260,6 @@
"i18next-parser": "5.4.0",
"jest": "29.6.3",
"jest-cli": "^28.1.1",
"jest-styled-components": "^7.0.8",
"jest-svg-transformer": "^1.0.0",
"jest-transform-stub": "^2.0.0",
"metro-react-native-babel-transformer": "^0.77.0",
Expand Down
13 changes: 0 additions & 13 deletions patches/styled-components+5.3.3.patch

This file was deleted.

140 changes: 129 additions & 11 deletions src/Root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import 'react-native-gesture-handler';
import {SafeAreaView} from 'react-native-safe-area-context';
import BottomNotificationModal from './components/modal/bottom-notification/BottomNotification';
import OnGoingProcessModal from './components/modal/ongoing-process/OngoingProcess';
import FocusGatedReduxScreen from './components/focus-gated-redux-screen/FocusGatedReduxScreen';
import {DeviceEmitterEvents} from './constants/device-emitter-events';
import {baseNavigatorOptions} from './constants/NavigationOptions';
import {LOCK_AUTHORIZED_TIME} from './constants/Lock';
Expand All @@ -38,6 +39,7 @@ import {
useUrlEventHandler,
} from './utils/hooks';
import i18n from 'i18next';
import {useTranslation} from 'react-i18next';

import BitpayIdGroup, {
BitpayIdGroupParamList,
Expand Down Expand Up @@ -146,6 +148,10 @@ import {
successGetReceiveAddress,
} from './store/wallet/wallet.actions';
import {selectSettingsNotificationState} from './store/app/app.selectors';
import {getReduxPerformanceSnapshot} from './store/performanceDiagnostics';
import {logReactProfiler} from './utils/reactPerformanceProfiler';
import {PERF_DEBUG, performanceLog} from './utils/performanceDebug';
import PerformanceProfiler from './components/performance/PerformanceProfiler';
import {HeaderShownContext} from '@react-navigation/elements';
import PaymentSent from './navigation/wallet/components/PaymentSent';
import AllAssets from './navigation/tabs/home/screens/AllAssets';
Expand Down Expand Up @@ -290,6 +296,23 @@ export const getNavigationTabName = () => {

export const Root = createNativeStackNavigator<RootStackParamList>();

const focusGatedScreenLayout = ({
children,
route,
}: {
children: React.ReactElement;
route: {name: string; params?: {_preloadContent?: boolean}};
}) => (
<FocusGatedReduxScreen
renderWhenUnfocused={route.params?._preloadContent === true}>
<PerformanceProfiler
id={`screen:${route.name}`}
onRender={logReactProfiler}>
{children}
</PerformanceProfiler>
</FocusGatedReduxScreen>
);

const StartupGate = () => {
const navigation = useNavigation<any>();
const onboardingCompleted = useAppSelector(
Expand Down Expand Up @@ -328,6 +351,7 @@ const StartupGate = () => {
};

export default () => {
useTranslation();
const dispatch = useAppDispatch();
const reduxStore = useStore();
const linking = useDeeplinks();
Expand All @@ -336,6 +360,8 @@ export default () => {
const lastSystemEnabledRef = useRef<boolean | null>(null);
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
const splashHiddenRef = useRef(false);
const lastNavStartTsRef = useRef<number | null>(null);
const lastTransitionStartTsRef = useRef<number | null>(null);
const launchPopulateStartedRef = useRef(false);
const onboardingCompleted = useAppSelector(
({APP}) => APP.onboardingCompleted,
Expand Down Expand Up @@ -370,6 +396,21 @@ export default () => {
const currentLocation = useAppSelector(({LOCATION}) => LOCATION.locationData);
const showArchaxBanner = useAppSelector(({APP}) => APP.showArchaxBanner);

useEffect(() => {
if (!PERF_DEBUG) {
return;
}
const snapshot = getReduxPerformanceSnapshot();

performanceLog(
`[PERF-ROOT] render action:${
snapshot?.actionType ?? 'unknown'
} dispatchMs:${snapshot?.dispatchDurationMs ?? -1} changedSlices:${
snapshot?.changedSlices.join(',') || 'none'
}`,
);
});

const blurScreenList: string[] = [
OnboardingScreens.IMPORT,
OnboardingScreens.RECOVERY_PHRASE,
Expand Down Expand Up @@ -1004,6 +1045,10 @@ export default () => {
onStateChange={state => {
debouncedOnStateChange(state);

if (PERF_DEBUG) {
lastNavStartTsRef.current = Date.now();
}

if (splashHiddenRef.current) {
return;
}
Expand All @@ -1027,6 +1072,39 @@ export default () => {
}
}}>
<Root.Navigator
screenLayout={focusGatedScreenLayout}
screenListeners={{
transitionStart: e => {
if (!PERF_DEBUG || e.data.closing) {
return;
}
lastTransitionStartTsRef.current = performance.now();
const routeName = navigationRef.getCurrentRoute()?.name;

performanceLog(`[PERF-NAV] ${routeName} transitionStart`);
},
transitionEnd: e => {
if (!PERF_DEBUG || e.data.closing) {
return;
}
const startTs = lastNavStartTsRef.current;
if (startTs === null) {
return;
}
const deltaMs = Date.now() - startTs;
const transitionStartTs = lastTransitionStartTsRef.current;
const transitionDeltaMs =
transitionStartTs === null
? -1
: Math.round((performance.now() - transitionStartTs) * 10) /
10;
const routeName = navigationRef.getCurrentRoute()?.name;

performanceLog(
`[PERF-NAV] ${routeName} transitionEnd stateDeltaMs:${deltaMs} transitionDeltaMs:${transitionDeltaMs}`,
);
},
}}
screenOptions={{
...baseNavigatorOptions,
headerShown: false,
Expand Down Expand Up @@ -1105,18 +1183,58 @@ export default () => {
{ZenLedgerGroup({ZenLedger: Root, theme})}
{SecurityGroup({Security: Root, theme})}
</Root.Navigator>
<OnGoingProcessModal />
<InAppNotification />
<BottomNotificationModal />
<DecryptEnterPasswordModal />
<BlurContainer />
<PinModal />
<BiometricModal />
<PerformanceProfiler
id="overlay:ongoing-process"
onRender={logReactProfiler}>
<OnGoingProcessModal />
</PerformanceProfiler>
<PerformanceProfiler
id="overlay:in-app-notification"
onRender={logReactProfiler}>
<InAppNotification />
</PerformanceProfiler>
<PerformanceProfiler
id="overlay:bottom-notification"
onRender={logReactProfiler}>
<BottomNotificationModal />
</PerformanceProfiler>
<PerformanceProfiler
id="overlay:decrypt-password"
onRender={logReactProfiler}>
<DecryptEnterPasswordModal />
</PerformanceProfiler>
<PerformanceProfiler id="overlay:blur" onRender={logReactProfiler}>
<BlurContainer />
</PerformanceProfiler>
<PerformanceProfiler id="overlay:pin" onRender={logReactProfiler}>
<PinModal />
</PerformanceProfiler>
<PerformanceProfiler
id="overlay:biometric"
onRender={logReactProfiler}>
<BiometricModal />
</PerformanceProfiler>
{/* <ImportLedgerWalletModal /> */}
<WalletConnectStartModal />
<ChainSelectorModal />
<PaymentSent />
<MoonpayEmbeddedCredentialManager />
<PerformanceProfiler
id="overlay:wallet-connect"
onRender={logReactProfiler}>
<WalletConnectStartModal />
</PerformanceProfiler>
<PerformanceProfiler
id="overlay:chain-selector"
onRender={logReactProfiler}>
<ChainSelectorModal />
</PerformanceProfiler>
<PerformanceProfiler
id="overlay:payment-sent"
onRender={logReactProfiler}>
<PaymentSent />
</PerformanceProfiler>
<PerformanceProfiler
id="overlay:moonpay-credentials"
onRender={logReactProfiler}>
<MoonpayEmbeddedCredentialManager />
</PerformanceProfiler>
</NavigationContainer>
</HeaderShownContext.Provider>
</SafeAreaView>
Expand Down
10 changes: 4 additions & 6 deletions src/components/add/Add.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import {Platform} from 'react-native';
import {View} from 'react-native';
import {Circle, Color, G, Svg, Rect} from 'react-native-svg';
import styled, {useTheme} from 'styled-components/native';
import {useTheme} from '../../contexts';
import {LightBlack, NeutralSlate, SlateDark, White} from '../../styles/colors';

interface AddSvgProps {
Expand Down Expand Up @@ -75,21 +75,19 @@ const AddSvg: React.FC<AddSvgProps> = ({color, background, opacity}) => {
);
};

const AddContainer = styled.View<{platform: string}>``;

const Add = ({color, background, opacity}: Props) => {
const theme = useTheme();
const themedColor = theme.dark ? White : null;
const themedBackground = theme.dark ? LightBlack : NeutralSlate;

return (
<AddContainer platform={Platform.OS}>
<View>
<AddSvg
color={color || themedColor}
background={background || themedBackground}
opacity={opacity}
/>
</AddContainer>
</View>
);
};

Expand Down
Loading
Loading