Skip to content

Commit d312658

Browse files
Performance improvements (#6376)
* Replace persistedQueryStorage with MMKVPersister * Memoize favorites * Conditionally load boot-related modules * Clean up AppDelegate, fix warnings * Propagate dapps data changes to browser search Now when the data changes, search results will always update — fixes a bug where results would occasionally be empty if data only became available after initial mount * [Dev fix] Remove codegen changes from react-native-screen-corner-radius patch * Remove @tanstack/query-async-storage-persister dep * Fix userAssets memory management The previous Map structure was resulting in all userAssets stores accessed during runtime being held permanently in memory. On top of that, `useWalletsHiddenBalances` was repeatedly looping through all wallets on app launch, causing every userAssets store to be accessed and thus held in memory. Now, hidden asset balances are summed any time a specific wallet's assets are synced to Zustand, and any time `setHiddenAssets` is called. That total is saved to `userAssetsStoreManager`'s persisted state, allowing all of the user's hidden wallet balances to be read from a single source, with no need to loop through individual stores. The tradeoff here, which I think is acceptable, is that users will temporarily see their hidden balances reflected in each wallet's total balance, until that wallet next fetches assets. That seems benign enough to forgo a migration. * Add `time` util * Bump packages * Add `maxAge`, increase `queryClient` throttle time, remove `ENABLE_LOGS` * Make `isLoadingUserAssets` check more accurate `chainBalances.size` will only be zero if `setUserAssets` has never been called for the active store. If `setUserAssets` has been called, `chainBalances` will be populated, regardless of whether the wallet has assets. * [Browser] Avoid JS thread Shared Value reads The first run of any `useAnimatedStyle` or `useDerivedValue` is executed on the JS thread. The first run can be detected by checking if `_WORKLET` is `false`, which allows bypassing expensive JS thread SV reads if you can set the hook's initial return value through other means. These changes bypass the vast majority of JS thread SV reads throughout the browser, which reduces JS thread blocking post app launch and during browser tab creation. * [Browser] Fix tab switch gesture activation criteria Prevents tab switch gestures from activating when the browser search UI is open * Clean up `hiddenAssetsBalance` calculations, types * Fix `hiddenBalances` lookup * [Android] Fix bottom bar handling and boot jank - Fixes Android device height and safe area determinations, which were previously inconsistent in what was considered part of the safe area vs. part of the device height — this was causing various UI dimensions to be miscalculated, for instance browser tab heights - Provides the `SafeAreaProvider` with `initialWindowMetrics` which on Android prevents layout shift on initial app launch - Sets the bottom bar background to transparent when button navigation isn't being used - Now correctly handling dimensions regardless of whether the device uses button navigation * Reduce `useMeteorology` cache time * Replace `SwapSheetGestureBlocker` with `DecoyScrollView` The gesture blocking isn't needed * Merge cleanup * Fix Detox
1 parent 91af6c1 commit d312658

37 files changed

+505
-721
lines changed

android/app/src/main/res/values/styles.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<item name="colorAccent">@color/blue60</item>
77
</style>
88

9-
<style name="BootTheme" parent="Theme.BootSplash">
9+
<style name="BootTheme" parent="Theme.BootSplash.EdgeToEdge">
1010
<item name="bootSplashBackground">@color/blue100</item>
1111
<item adjustViewBounds="true" name="bootSplashLogo">@mipmap/bootsplash_logo</item>
1212
<item name="postBootSplashTheme">@style/AppTheme</item>

e2e/helpers.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ export async function checkIfElementHasString(elementID: string | RegExp, text:
392392
export async function relaunchApp() {
393393
try {
394394
await device.terminateApp('me.rainbow');
395-
return await device.launchApp({ newInstance: true });
395+
return await device.launchApp({ newInstance: true, launchArgs: { IS_TEST: true } });
396396
} catch (error) {
397397
throw new Error(`Error relaunching app: ${error}`);
398398
}
@@ -493,7 +493,7 @@ export async function sendETHtoTestWallet() {
493493
export async function openDeeplinkColdStart(url: string) {
494494
await device.terminateApp();
495495
await device.launchApp({
496-
launchArgs: { detoxEnableSynchronization: 0 },
496+
launchArgs: { detoxEnableSynchronization: 0, IS_TEST: true },
497497
newInstance: true,
498498
url,
499499
});
@@ -504,6 +504,7 @@ export async function openDeeplinkFromBackground(url: string) {
504504
await device.sendToHome();
505505
await device.enableSynchronization();
506506
await device.launchApp({
507+
launchArgs: { IS_TEST: true },
507508
newInstance: false,
508509
url,
509510
});

e2e/init.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ beforeAll(async () => {
1515
exec('yarn adb-all shell cmd overlay enable com.android.internal.systemui.navbar.threebutton');
1616
}
1717
await device.clearKeychain();
18-
await device.launchApp({ newInstance: true, delete: true });
18+
await device.launchApp({ newInstance: true, delete: true, launchArgs: { IS_TEST: true } });
1919
await device.setURLBlacklist([
2020
'.*api.thegraph.com.*',
2121
'.*gateway-arbitrum.network.thegraph.com.*',

ios/Podfile.lock

+18-18
Original file line numberDiff line numberDiff line change
@@ -208,9 +208,9 @@ PODS:
208208
- MetricsReporter (1.2.1):
209209
- RSCrashReporter (= 1.0.1)
210210
- RudderKit (= 1.4.0)
211-
- MMKV (1.3.9):
212-
- MMKVCore (~> 1.3.9)
213-
- MMKVCore (1.3.9)
211+
- MMKV (2.0.0):
212+
- MMKVCore (~> 2.0.0)
213+
- MMKVCore (2.0.0)
214214
- mobile-wallet-protocol-host (0.1.7):
215215
- CoinbaseWalletSDK/Host
216216
- React-Core
@@ -1268,7 +1268,7 @@ PODS:
12681268
- DoubleConversion
12691269
- glog
12701270
- hermes-engine
1271-
- MMKV (>= 1.3.3)
1271+
- MMKV (>= 2.0.0)
12721272
- RCT-Folly (= 2024.01.01.00)
12731273
- RCTRequired
12741274
- RCTTypeSafety
@@ -1303,7 +1303,7 @@ PODS:
13031303
- React-Core
13041304
- react-native-screen-corner-radius (0.2.2):
13051305
- React
1306-
- react-native-skia (1.5.10):
1306+
- react-native-skia (1.8.2):
13071307
- DoubleConversion
13081308
- glog
13091309
- hermes-engine
@@ -1751,7 +1751,7 @@ PODS:
17511751
- React-Core
17521752
- RNReactNativeHapticFeedback (2.2.0):
17531753
- React-Core
1754-
- RNReanimated (3.16.3):
1754+
- RNReanimated (3.16.6):
17551755
- DoubleConversion
17561756
- glog
17571757
- hermes-engine
@@ -1771,10 +1771,10 @@ PODS:
17711771
- React-utils
17721772
- ReactCommon/turbomodule/bridging
17731773
- ReactCommon/turbomodule/core
1774-
- RNReanimated/reanimated (= 3.16.3)
1775-
- RNReanimated/worklets (= 3.16.3)
1774+
- RNReanimated/reanimated (= 3.16.6)
1775+
- RNReanimated/worklets (= 3.16.6)
17761776
- Yoga
1777-
- RNReanimated/reanimated (3.16.3):
1777+
- RNReanimated/reanimated (3.16.6):
17781778
- DoubleConversion
17791779
- glog
17801780
- hermes-engine
@@ -1794,9 +1794,9 @@ PODS:
17941794
- React-utils
17951795
- ReactCommon/turbomodule/bridging
17961796
- ReactCommon/turbomodule/core
1797-
- RNReanimated/reanimated/apple (= 3.16.3)
1797+
- RNReanimated/reanimated/apple (= 3.16.6)
17981798
- Yoga
1799-
- RNReanimated/reanimated/apple (3.16.3):
1799+
- RNReanimated/reanimated/apple (3.16.6):
18001800
- DoubleConversion
18011801
- glog
18021802
- hermes-engine
@@ -1817,7 +1817,7 @@ PODS:
18171817
- ReactCommon/turbomodule/bridging
18181818
- ReactCommon/turbomodule/core
18191819
- Yoga
1820-
- RNReanimated/worklets (3.16.3):
1820+
- RNReanimated/worklets (3.16.6):
18211821
- DoubleConversion
18221822
- glog
18231823
- hermes-engine
@@ -2462,8 +2462,8 @@ SPEC CHECKSUMS:
24622462
hermes-engine: 1f547997900dd0752dc0cc0ae6dd16173c49e09b
24632463
libwebp: 1786c9f4ff8a279e4dac1e8f385004d5fc253009
24642464
MetricsReporter: 99596ee5003c69949ed2f50acc34aee83c42f843
2465-
MMKV: 817ba1eea17421547e01e087285606eb270a8dcb
2466-
MMKVCore: af055b00e27d88cd92fad301c5fecd1ff9b26dd9
2465+
MMKV: f7d1d5945c8765f97f39c3d121f353d46735d801
2466+
MMKVCore: c04b296010fcb1d1638f2c69405096aac12f6390
24672467
mobile-wallet-protocol-host: 8ed897dcf4f846d39b35767540e6a695631cab73
24682468
MultiplatformBleAdapter: b1fddd0d499b96b607e00f0faa8e60648343dc1d
24692469
nanopb: 438bc412db1928dac798aa6fd75726007be04262
@@ -2511,7 +2511,7 @@ SPEC CHECKSUMS:
25112511
react-native-mail: a864fb211feaa5845c6c478a3266de725afdce89
25122512
react-native-menu: c30eb7a85d7b04d51945f61ea8a8986ed366ac5c
25132513
react-native-minimizer: b94809a769ac3825b46fd081d4f0ae2560791536
2514-
react-native-mmkv: 8c9a677e64a1ac89b0c6cf240feea528318b3074
2514+
react-native-mmkv: c1610488a9960dc0e5f7c264caf7667930d439de
25152515
react-native-netinfo: 5b664b2945a8f02102b296f0f812bddd6827ed9c
25162516
react-native-pager-view: 95d0418c3c74279840abec6926653d32447bafb6
25172517
react-native-palette-full: 99a6fd796d16fab6a2d3770649070e31c2602fad
@@ -2520,7 +2520,7 @@ SPEC CHECKSUMS:
25202520
react-native-restart: 733a51ad137f15b0f8dc34c4082e55af7da00979
25212521
react-native-safe-area-context: 4532f1a0c5d34a46b9324ccaaedcb5582a302b7d
25222522
react-native-screen-corner-radius: 67064efbb78f2d48f01626713ae8142f6a20f925
2523-
react-native-skia: 6e137273ac478a9c840b45ca53b7a248f9103fe2
2523+
react-native-skia: 2bae63532997971033b297348f4156d6a012cbef
25242524
react-native-splash-screen: 4312f786b13a81b5169ef346d76d33bc0c6dc457
25252525
react-native-text-input-mask: 07227297075f9653315f43b0424d596423a01736
25262526
react-native-udp: 96a517e5a121cfe69f4b05eeeafefe00c623debf
@@ -2574,7 +2574,7 @@ SPEC CHECKSUMS:
25742574
RNOS: 31db6fa4a197d179afbba9e6b4d28d450a7f250b
25752575
RNPermissions: 4e3714e18afe7141d000beae3755e5b5fb2f5e05
25762576
RNReactNativeHapticFeedback: ec56a5f81c3941206fd85625fa669ffc7b4545f9
2577-
RNReanimated: e1c250aeb93d6738eaf51e3d93871873a0c41b81
2577+
RNReanimated: 5a19d7bc2fd0f1929d81301359a627d83c3684be
25782578
RNRudderSdk: 805d4b7064714f3295bf5f152d3812cc67f67a93
25792579
RNScreens: 6b641f232990a9d505a6d139fd18c3c759c9d290
25802580
RNSentry: 6a5d9f48370070c1d4697dfe74044b7f45512420
@@ -2597,7 +2597,7 @@ SPEC CHECKSUMS:
25972597
ToolTipMenu: 8ac61aded0fbc4acfe7e84a7d0c9479d15a9a382
25982598
TurboHaptics: 6381613d33ab97aeb30d9b15c3df94dc616a25e4
25992599
VisionCamera: 2af28201c3de77245f8c58b7a5274d5979df70df
2600-
Yoga: 04f1db30bb810187397fa4c37dd1868a27af229c
2600+
Yoga: 88480008ccacea6301ff7bf58726e27a72931c8d
26012601

26022602
PODFILE CHECKSUM: 98c3fc206d7041ac7388693bb0753109d1884b57
26032603

ios/Rainbow/AppDelegate.h

+1-3
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,10 @@
1515

1616
@class RCTBridge;
1717

18-
@interface AppDelegate : EXAppDelegateWrapper
18+
@interface AppDelegate : EXAppDelegateWrapper <UNUserNotificationCenterDelegate>
1919

2020
- (void)hideSplashScreenAnimated;
2121

22-
@property (nonatomic, strong) UIWindow *window;
2322
@property (nonatomic) BOOL isRapRunning;
24-
@property (nonatomic, strong) RCTBridge *bridge;
2523

2624
@end

ios/Rainbow/AppDelegate.mm

+43-55
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@
66
#import "Firebase.h"
77
#import "AppDelegate.h"
88

9-
// expo modules MUST be imported before Rainbow-Swift.h
9+
// Expo modules must be imported before Rainbow-Swift.h
1010
#import "ExpoModulesCore-Swift.h"
1111
#import "Rainbow-Swift.h"
12-
// end expo modules
1312

1413
#import <RNBranch/RNBranch.h>
1514
#import <React/RCTBundleURLProvider.h>
@@ -20,7 +19,6 @@
2019
#import <AVFoundation/AVFoundation.h>
2120
#import <mach/mach.h>
2221

23-
2422
@interface RainbowSplashScreenManager : NSObject <RCTBridgeModule>
2523
@end
2624

@@ -39,6 +37,7 @@ - (dispatch_queue_t)methodQueue {
3937
@end
4038

4139
@implementation AppDelegate
40+
4241
- (void)hideSplashScreenAnimated {
4342
UIView* subview = self.window.rootViewController.view.subviews.lastObject;
4443
UIView* rainbowIcon = subview.subviews.firstObject;
@@ -59,44 +58,49 @@ - (void)hideSplashScreenAnimated {
5958

6059
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
6160
{
62-
self.moduleName = @"Rainbow";
63-
// You can add your custom initial props in the dictionary below.
64-
// They will be passed down to the ViewController used by React Native.
61+
self.moduleName = @"Rainbow";
62+
// Add custom initial props in the dictionary below. These are passed to the React Native ViewController.
6563
self.initialProps = @{};
66-
64+
6765
NSLog(@"⚙️ Rainbow internals are %@.", RAINBOW_INTERNALS_ENABLED ? @"enabled" : @"disabled");
68-
69-
// Firebase Init
66+
7067
[FIRApp configure];
71-
72-
// Branch Init
7368
[RNBranch initSessionWithLaunchOptions:launchOptions isReferrable:YES];
74-
75-
// Define UNUserNotificationCenter
69+
7670
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
71+
center.delegate = self;
72+
73+
[[NSNotificationCenter defaultCenter] addObserver:self
74+
selector:@selector(handleRapInProgress:)
75+
name:@"rapInProgress"
76+
object:nil];
7777

78-
[[NSNotificationCenter defaultCenter] addObserver:self
79-
selector:@selector(handleRapInProgress:)
80-
name:@"rapInProgress"
81-
object:nil];
82-
8378
[[NSNotificationCenter defaultCenter] addObserver:self
84-
selector:@selector(handleRapComplete:)
85-
name:@"rapCompleted"
86-
object:nil];
79+
selector:@selector(handleRapComplete:)
80+
name:@"rapCompleted"
81+
object:nil];
8782

8883
[[NSNotificationCenter defaultCenter] addObserver:self
89-
selector:@selector(handleRsEscape:)
90-
name:@"rsEscape"
91-
object:nil];
84+
selector:@selector(handleRsEscape:)
85+
name:@"rsEscape"
86+
object:nil];
87+
88+
BOOL success = [super application:application didFinishLaunchingWithOptions:launchOptions];
89+
BOOL isDetox = [[[NSProcessInfo processInfo] arguments] containsObject:@"-IS_TEST"];
90+
91+
if (isDetox) return success;
9292

93-
return [super application:application didFinishLaunchingWithOptions:launchOptions];
93+
if (success) {
94+
UIView *rootView = self.window.rootViewController.view;
95+
[RNSplashScreen showSplash:@"LaunchScreen" inRootView:rootView];
96+
}
97+
return success;
9498
}
9599

96-
97100
- (void)handleRsEscape:(NSNotification *)notification {
98101
NSDictionary* userInfo = notification.userInfo;
99102
NSString *msg = [NSString stringWithFormat:@"Escape via %@", userInfo[@"url"]];
103+
100104
SentryBreadcrumb *breadcrumb = [[SentryBreadcrumb alloc] init];
101105
[breadcrumb setMessage:msg];
102106
[SentrySDK addBreadcrumb:breadcrumb];
@@ -125,53 +129,38 @@ - (NSURL *)bundleURL
125129
#endif
126130
}
127131

128-
//Called when a notification is delivered to a foreground app.
129-
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
132+
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification
133+
withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
130134
{
131-
if (@available(iOS 14.0, *)) {
132-
completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionBadge | UNNotificationPresentationOptionList | UNNotificationPresentationOptionBanner);
133-
} else {
134-
completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionBadge | UNNotificationPresentationOptionAlert);
135-
}
135+
completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionBadge | UNNotificationPresentationOptionList | UNNotificationPresentationOptionBanner);
136136
}
137137

138-
139-
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
140-
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
141-
{
142-
return [RCTLinkingManager application:application openURL:url
143-
sourceApplication:sourceApplication annotation:annotation];
138+
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
139+
if ([RNBranch application:application openURL:url options:options]) {
140+
return YES;
141+
}
142+
return [RCTLinkingManager application:application openURL:url options:options];
144143
}
145144

146-
// Only if your app is using [Universal Links]
147145
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity
148-
restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler
149-
{
146+
restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
150147
[RNBranch continueUserActivity:userActivity];
151148
return YES;
152-
153149
}
154150

155151
- (void)applicationWillTerminate:(UIApplication *)application {
156-
157-
if(self.isRapRunning){
152+
if (self.isRapRunning) {
158153
SentryMessage *msg = [[SentryMessage alloc] initWithFormatted:@"applicationWillTerminate was called"];
159154
SentryEvent *sentryEvent = [[SentryEvent alloc] init];
160155
[sentryEvent setMessage: msg];
161156
[SentrySDK captureEvent:sentryEvent];
162157
}
163-
164158
}
165159

166-
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
167-
[RNBranch application:app openURL:url options:options];
168-
return YES;
169-
}
170-
171-
- (void)applicationDidBecomeActive:(UIApplication *)application{
172-
// delete the badge
160+
- (void)applicationDidBecomeActive:(UIApplication *)application {
161+
// Reset the app icon badge
173162
[UIApplication sharedApplication].applicationIconBadgeNumber = 0;
174-
// delete the notifications from WC
163+
// Clear WC notifications
175164
[[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^(NSArray<UNNotification *> * _Nonnull notifications) {
176165
NSMutableArray *identifiers = [[NSMutableArray alloc] init];
177166
[notifications enumerateObjectsUsingBlock:^(UNNotification * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
@@ -184,7 +173,6 @@ - (void)applicationDidBecomeActive:(UIApplication *)application{
184173
}];
185174
[[UNUserNotificationCenter currentNotificationCenter] removeDeliveredNotificationsWithIdentifiers:identifiers];
186175
}];
187-
188176
}
189177

190178
@end

package.json

+3-4
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,7 @@
129129
"@rudderstack/rudder-sdk-react-native": "1.12.1",
130130
"@sentry/react-native": "5.35.0",
131131
"@shopify/flash-list": "1.7.2",
132-
"@shopify/react-native-skia": "1.5.10",
133-
"@tanstack/query-async-storage-persister": "4.2.1",
132+
"@shopify/react-native-skia": "1.8.2",
134133
"@tanstack/react-query": "4.2.1",
135134
"@tanstack/react-query-persist-client": "4.2.1",
136135
"@tradle/react-native-http": "2.0.1",
@@ -254,7 +253,7 @@
254253
"react-native-quick-md5": "3.0.6",
255254
"react-native-radial-gradient": "rainbow-me/react-native-radial-gradient#b99ab59d27dba70364ef516bd5193c37657ba95c",
256255
"react-native-randombytes": "3.5.3",
257-
"react-native-reanimated": "3.16.3",
256+
"react-native-reanimated": "3.16.6",
258257
"react-native-redash": "16.3.0",
259258
"react-native-restart": "0.0.22",
260259
"react-native-safe-area-context": "4.14.0",
@@ -306,7 +305,7 @@
306305
"url-join": "4.0.1",
307306
"url-parse": "1.5.10",
308307
"use-debounce": "10.0.0",
309-
"use-deep-compare": "1.1.0",
308+
"use-deep-compare": "1.3.0",
310309
"use-memo-one": "1.1.1",
311310
"util": "0.10.4",
312311
"viem": "2.21.54",

0 commit comments

Comments
 (0)